summaryrefslogtreecommitdiff
path: root/src/notificationwindow.c
diff options
context:
space:
mode:
authorSimeon Simeonov2018-02-26 11:23:00 +0100
committerSimeon Simeonov2018-02-26 11:23:00 +0100
commit0b3cbf57875fd692e4ba0b336fefa4bee1ed00dc (patch)
treeaf916a30553c78ce9d4f2d8658656a175c5b6921 /src/notificationwindow.c
Initial commit for sylpheed 3.7.0
Diffstat (limited to 'src/notificationwindow.c')
-rw-r--r--src/notificationwindow.c347
1 files changed, 347 insertions, 0 deletions
diff --git a/src/notificationwindow.c b/src/notificationwindow.c
new file mode 100644
index 0000000..966c708
--- /dev/null
+++ b/src/notificationwindow.c
@@ -0,0 +1,347 @@
1/*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2014 Hiroyuki Yamamoto
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21# include "config.h"
22#endif
23
24#include <glib.h>
25#include <glib/gi18n.h>
26#include <gtk/gtk.h>
27
28#ifdef G_OS_WIN32
29# include <windows.h>
30#endif
31
32#include "notificationwindow.h"
33#include "mainwindow.h"
34#include "utils.h"
35#include "gtkutils.h"
36
37#define NOTIFICATIONWINDOW_NOTIFY_PERIOD 10000
38#define NOTIFICATIONWINDOW_WIDTH 380
39#define NOTIFICATIONWINDOW_HEIGHT 80
40#define FADE_REFRESH_RATE 50 /* ms */
41#define FADE_SPEED 5 /* pixels */
42#define FADE_IN_LENGTH 10 /* counts */
43
44typedef struct _NotificationWindow
45{
46 GtkWidget *window;
47
48 GtkWidget *msglabel;
49 GtkWidget *sublabel;
50
51 guint notify_tag;
52
53 gint x;
54 gint y;
55 gint width;
56 gint height;
57 gint fade_length;
58 gint fade_count;
59 gint notify_event_count;
60 guint timeout;
61} NotificationWindow;
62
63static NotificationWindow notify_window;
64
65static void notification_window_destroy(void);
66
67#if GTK_CHECK_VERSION(2, 12, 0)
68static gboolean notify_fadein_timeout_cb(gpointer data);
69#endif
70
71static gboolean notify_timeout_cb (gpointer data);
72
73static gboolean nwin_button_pressed (GtkWidget *widget,
74 GdkEventButton *event,
75 gpointer data);
76static gboolean nwin_entered (GtkWidget *widget,
77 GdkEventCrossing *event,
78 gpointer data);
79static gboolean nwin_motion_notify (GtkWidget *widget,
80 GdkEventMotion *event,
81 gpointer data);
82
83static void nwin_destroy_cb (GtkWidget *widget,
84 gpointer data);
85
86
87static void get_work_area(GdkRectangle *rect)
88{
89#ifdef G_OS_WIN32
90 RECT rc;
91
92 SystemParametersInfoW(SPI_GETWORKAREA, 0, &rc, 0);
93 rect->x = rc.left;
94 rect->y = rc.top;
95 rect->width = rc.right - rc.left;
96 rect->height = rc.bottom - rc.top;
97#else
98 rect->x = 0;
99 rect->y = 0;
100 rect->width = gdk_screen_width();
101 rect->height = gdk_screen_height();
102#endif
103}
104
105gint notification_window_open(const gchar *message, const gchar *submessage,
106 guint timeout)
107{
108 GtkWidget *window;
109 GtkWidget *vbox;
110 GtkWidget *msglabel;
111 GtkWidget *sublabel;
112 GdkRectangle rect;
113 gint x, y;
114 GtkRequisition requisition;
115 gint window_width;
116 gint window_height;
117
118 window_width = NOTIFICATIONWINDOW_WIDTH * gtkut_get_dpi_multiplier();
119 window_height = NOTIFICATIONWINDOW_HEIGHT * gtkut_get_dpi_multiplier();
120
121 if (notify_window.window) {
122 notification_window_destroy();
123 }
124
125 window = gtk_window_new(GTK_WINDOW_POPUP);
126 gtk_window_set_title(GTK_WINDOW(window), _("Notification"));
127 gtk_window_set_wmclass(GTK_WINDOW(window), "notification", "Sylpheed");
128 gtk_container_set_border_width(GTK_CONTAINER(window), 8);
129 gtk_widget_set_events(window, GDK_EXPOSURE_MASK|GDK_BUTTON_MOTION_MASK|GDK_POINTER_MOTION_MASK|GDK_POINTER_MOTION_HINT_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK);
130 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window), TRUE);
131 gtk_window_set_gravity(GTK_WINDOW(window), GDK_GRAVITY_SOUTH_EAST);
132 gtk_widget_set_size_request(window, window_width, -1);
133#if GTK_CHECK_VERSION(2, 12, 0)
134 gtk_window_set_opacity(GTK_WINDOW(window), 0.0);
135#endif
136 gtk_widget_realize(window);
137 gdk_window_set_type_hint(window->window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
138
139 /* move window bottom-right */
140 get_work_area(&rect);
141 x = rect.x + rect.width - window_width - 2;
142 if (x < 0) x = 0;
143 y = rect.y + rect.height - window_height - 2;
144 if (y < 0) y = 0;
145 gtk_window_move(GTK_WINDOW(window), x, y);
146
147 g_signal_connect(G_OBJECT(window), "destroy",
148 G_CALLBACK(nwin_destroy_cb), NULL);
149 g_signal_connect(G_OBJECT(window), "button_press_event",
150 G_CALLBACK(nwin_button_pressed), NULL);
151 g_signal_connect(G_OBJECT(window), "enter_notify_event",
152 G_CALLBACK(nwin_entered), NULL);
153 g_signal_connect(G_OBJECT(window), "motion_notify_event",
154 G_CALLBACK(nwin_motion_notify), NULL);
155
156 vbox = gtk_vbox_new(FALSE, 8);
157 gtk_container_add(GTK_CONTAINER(window), vbox);
158
159 msglabel = gtk_label_new(message);
160 gtk_box_pack_start(GTK_BOX(vbox), msglabel, FALSE, FALSE, 0);
161
162 sublabel = gtk_label_new("");
163 gtk_label_set_ellipsize(GTK_LABEL(sublabel), PANGO_ELLIPSIZE_END);
164 gtk_label_set_markup(GTK_LABEL(sublabel), submessage);
165 gtk_box_pack_start(GTK_BOX(vbox), sublabel, FALSE, FALSE, 0);
166 gtk_label_set_justify(GTK_LABEL(sublabel), GTK_JUSTIFY_LEFT);
167 gtk_misc_set_alignment(GTK_MISC(sublabel), 0.0, 0.5);
168
169 gtk_widget_show_all(window);
170
171 /* adjust window size and position */
172 gtk_widget_get_child_requisition(window, &requisition);
173 notify_window.width = window_width;
174 notify_window.height = MAX(requisition.height, window_height);
175 gtk_widget_set_size_request(window, window_width, notify_window.height);
176 y = rect.y + rect.height - notify_window.height - 2;
177 if (y < 0) y = 0;
178 gtk_window_move(GTK_WINDOW(window), x, y);
179
180#if GTK_CHECK_VERSION(2, 12, 0)
181 notify_window.notify_tag = g_timeout_add(FADE_REFRESH_RATE,
182 notify_fadein_timeout_cb,
183 NULL);
184#else
185 if (timeout > 0) {
186 notify_window.notify_tag = g_timeout_add(timeout * 1000,
187 notify_timeout_cb, NULL);
188 }
189#endif
190
191 debug_print("notification window created\n");
192
193 notify_window.window = window;
194 notify_window.msglabel = msglabel;
195 notify_window.sublabel = sublabel;
196 notify_window.x = x;
197 notify_window.y = y;
198 notify_window.fade_length = FADE_IN_LENGTH;
199 notify_window.fade_count = 0;
200 notify_window.notify_event_count = 0;
201 notify_window.timeout = timeout;
202
203 return 0;
204}
205
206void notification_window_set_message(const gchar *message,
207 const gchar *submessage)
208{
209 if (notify_window.window) {
210 gtk_label_set_text(GTK_LABEL(notify_window.msglabel), message);
211 gtk_label_set_markup(GTK_LABEL(notify_window.sublabel), submessage);
212 }
213}
214
215void notification_window_close(void)
216{
217 notification_window_destroy();
218}
219
220static void notification_window_destroy(void)
221{
222 if (notify_window.window) {
223 if (notify_window.notify_tag > 0) {
224 g_source_remove(notify_window.notify_tag);
225 notify_window.notify_tag = 0;
226 }
227
228 gtk_widget_destroy(notify_window.window);
229
230 notify_window.window = NULL;
231 notify_window.msglabel = NULL;
232 notify_window.sublabel = NULL;
233
234 debug_print("notification window removed\n");
235 }
236}
237
238#if GTK_CHECK_VERSION(2, 12, 0)
239static gboolean notify_fadein_timeout_cb(gpointer data)
240{
241 gdk_threads_enter();
242 notify_window.fade_length--;
243 notify_window.fade_count++;
244
245 gtk_window_set_opacity(GTK_WINDOW(notify_window.window),
246 (gdouble)notify_window.fade_count / FADE_IN_LENGTH);
247
248 if (notify_window.fade_length <= 0) {
249 notify_window.fade_length = 0;
250 notify_window.fade_count = 0;
251 if (notify_window.timeout > 0) {
252 notify_window.notify_tag =
253 g_timeout_add(notify_window.timeout * 1000,
254 notify_timeout_cb, NULL);
255 }
256 gdk_threads_leave();
257 return FALSE;
258 }
259 gdk_threads_leave();
260 return TRUE;
261}
262#endif
263
264static gboolean notify_fadeout_timeout_cb(gpointer data)
265{
266 gdk_threads_enter();
267 notify_window.fade_length -= FADE_SPEED;
268 notify_window.fade_count++;
269
270 gtk_window_move(GTK_WINDOW(notify_window.window),
271 notify_window.x, notify_window.y + notify_window.fade_count * FADE_SPEED);
272#if GTK_CHECK_VERSION(2, 12, 0)
273 gtk_window_set_opacity(GTK_WINDOW(notify_window.window),
274 (gdouble)notify_window.fade_length / (gdk_screen_height() - notify_window.y));
275#endif
276
277 if (notify_window.fade_length <= 0) {
278 notification_window_destroy();
279 gdk_threads_leave();
280 return FALSE;
281 }
282 gdk_threads_leave();
283 return TRUE;
284}
285
286static gboolean notify_timeout_cb(gpointer data)
287{
288 gdk_threads_enter();
289 notify_window.fade_length = gdk_screen_height() - notify_window.y;
290 notify_window.notify_tag = g_timeout_add(FADE_REFRESH_RATE,
291 notify_fadeout_timeout_cb,
292 NULL);
293 gdk_threads_leave();
294
295 return FALSE;
296}
297
298static gboolean nwin_button_pressed(GtkWidget *widget, GdkEventButton *event,
299 gpointer data)
300{
301 if (!event)
302 return FALSE;
303
304 notification_window_destroy();
305 main_window_popup(main_window_get());
306
307 return TRUE;
308}
309
310static gboolean nwin_entered(GtkWidget *widget, GdkEventCrossing *event,
311 gpointer data)
312{
313 return FALSE;
314}
315
316static gboolean nwin_motion_notify(GtkWidget *widget, GdkEventMotion *event,
317 gpointer data)
318{
319 if (notify_window.fade_count > 0 &&
320 notify_window.notify_event_count == 0) {
321 notify_window.notify_event_count++;
322 return FALSE;
323 }
324
325 if (notify_window.notify_tag > 0) {
326 g_source_remove(notify_window.notify_tag);
327 notify_window.notify_tag = 0;
328 }
329 notify_window.fade_count = 0;
330 notify_window.notify_event_count = 0;
331#if GTK_CHECK_VERSION(2, 12, 0)
332 gtk_window_set_opacity(GTK_WINDOW(notify_window.window), 1.0);
333#endif
334 gtk_window_move(GTK_WINDOW(notify_window.window),
335 notify_window.x, notify_window.y);
336 if (notify_window.timeout > 0) {
337 notify_window.notify_tag =
338 g_timeout_add(notify_window.timeout * 1000,
339 notify_timeout_cb, NULL);
340 }
341
342 return FALSE;
343}
344
345static void nwin_destroy_cb(GtkWidget *widget, gpointer data)
346{
347}