Statistics
| Revision:

root / src / notificationwindow.c @ 3220

History | View | Annotate | Download (7.86 KB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2013 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

    
36
#define NOTIFICATIONWINDOW_NOTIFY_PERIOD        10000
37
#define NOTIFICATIONWINDOW_WIDTH                300
38
#define NOTIFICATIONWINDOW_HEIGHT                64
39
#define FADE_REFRESH_RATE                        50
40
#define FADE_SPEED                                5
41

    
42
typedef struct _NotificationWindow
43
{
44
        GtkWidget *window;
45

    
46
        GtkWidget *msglabel;
47
        GtkWidget *sublabel;
48

    
49
        guint notify_tag;
50

    
51
        gint x;
52
        gint y;
53
        gint width;
54
        gint height;
55
        gint fade_length;
56
        gint fade_count;
57
        gint notify_event_count;
58
        guint timeout;
59
} NotificationWindow;
60

    
61
static NotificationWindow notify_window;
62

    
63
static void notification_window_destroy(void);
64

    
65
static gboolean notify_timeout_cb(gpointer         data);
66

    
67
static gboolean nwin_button_pressed        (GtkWidget        *widget,
68
                                         GdkEventButton        *event,
69
                                         gpointer         data);
70
static gboolean nwin_entered                (GtkWidget        *widget,
71
                                         GdkEventCrossing *event,
72
                                         gpointer         data);
73
static gboolean nwin_motion_notify        (GtkWidget        *widget,
74
                                         GdkEventMotion *event,
75
                                         gpointer         data);
76

    
77
static void nwin_destroy_cb        (GtkWidget        *widget,
78
                                 gpointer         data);
79

    
80

    
81
static void get_work_area(GdkRectangle *rect)
82
{
83
#ifdef G_OS_WIN32
84
        RECT rc;
85

    
86
        SystemParametersInfoW(SPI_GETWORKAREA, 0, &rc, 0);
87
        rect->x = rc.left;
88
        rect->y = rc.top;
89
        rect->width = rc.right - rc.left;
90
        rect->height = rc.bottom - rc.top;
91
#else
92
        rect->x = 0;
93
        rect->y = 0;
94
        rect->width = gdk_screen_width();
95
        rect->height = gdk_screen_height();
96
#endif
97
}
98

    
99
gint notification_window_open(const gchar *message, const gchar *submessage,
100
                              guint timeout)
101
{
102
        GtkWidget *window;
103
        GtkWidget *vbox;
104
        GtkWidget *msglabel;
105
        GtkWidget *sublabel;
106
        GdkRectangle rect;
107
        gint x, y;
108
        GtkRequisition requisition;
109

    
110
        if (notify_window.window) {
111
                notification_window_destroy();
112
        }
113

    
114
        window = gtk_window_new(GTK_WINDOW_POPUP);
115
        gtk_window_set_title(GTK_WINDOW(window), _("Notification"));
116
        gtk_window_set_wmclass(GTK_WINDOW(window), "notification", "Sylpheed");
117
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);
118
        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);
119
        gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window), TRUE);
120
        gtk_window_set_gravity(GTK_WINDOW(window), GDK_GRAVITY_SOUTH_EAST);
121
        gtk_widget_set_size_request(window, NOTIFICATIONWINDOW_WIDTH, -1);
122
        gtk_widget_realize(window);
123
        gdk_window_set_type_hint(window->window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
124

    
125
        /* move window bottom-right */
126
        get_work_area(&rect);
127
        x = rect.x + rect.width - NOTIFICATIONWINDOW_WIDTH - 2;
128
        if (x < 0) x = 0;
129
        y = rect.y + rect.height - NOTIFICATIONWINDOW_HEIGHT - 2;
130
        if (y < 0) y = 0;
131
        gtk_window_move(GTK_WINDOW(window), x, y);
132

    
133
        g_signal_connect(G_OBJECT(window), "destroy",
134
                         G_CALLBACK(nwin_destroy_cb), NULL);
135
        g_signal_connect(G_OBJECT(window), "button_press_event",
136
                         G_CALLBACK(nwin_button_pressed), NULL);
137
        g_signal_connect(G_OBJECT(window), "enter_notify_event",
138
                         G_CALLBACK(nwin_entered), NULL);
139
        g_signal_connect(G_OBJECT(window), "motion_notify_event",
140
                         G_CALLBACK(nwin_motion_notify), NULL);
141

    
142
        vbox = gtk_vbox_new(FALSE, 8);
143
        gtk_container_add(GTK_CONTAINER(window), vbox);
144

    
145
        msglabel = gtk_label_new(message);
146
        gtk_box_pack_start(GTK_BOX(vbox), msglabel, FALSE, FALSE, 0);
147

    
148
        sublabel = gtk_label_new("");
149
        gtk_label_set_ellipsize(GTK_LABEL(sublabel), PANGO_ELLIPSIZE_END);
150
        gtk_label_set_markup(GTK_LABEL(sublabel), submessage);
151
        gtk_box_pack_start(GTK_BOX(vbox), sublabel, FALSE, FALSE, 0);
152
        gtk_label_set_justify(GTK_LABEL(sublabel), GTK_JUSTIFY_LEFT);
153
        gtk_misc_set_alignment(GTK_MISC(sublabel), 0.0, 0.5);
154

    
155
        gtk_widget_show_all(window);
156

    
157
        /* adjust window size and position */
158
        gtk_widget_get_child_requisition(window, &requisition);
159
        notify_window.width = NOTIFICATIONWINDOW_WIDTH;
160
        notify_window.height = MAX(requisition.height, NOTIFICATIONWINDOW_HEIGHT);
161
        gtk_widget_set_size_request(window, NOTIFICATIONWINDOW_WIDTH, notify_window.height);
162
        y = rect.y + rect.height - notify_window.height - 2;
163
        if (y < 0) y = 0;
164
        gtk_window_move(GTK_WINDOW(window), x, y);
165

    
166
        if (timeout == 0)
167
                timeout = 1;
168
        notify_window.notify_tag = g_timeout_add(timeout * 1000,
169
                                                 notify_timeout_cb, NULL);
170

    
171
        debug_print("notification window created\n");
172

    
173
        notify_window.window = window;
174
        notify_window.msglabel = msglabel;
175
        notify_window.sublabel = sublabel;
176
        notify_window.x = x;
177
        notify_window.y = y;
178
        notify_window.fade_length = 0;
179
        notify_window.fade_count = 0;
180
        notify_window.notify_event_count = 0;
181
        notify_window.timeout = timeout;
182

    
183
        return 0;
184
}
185

    
186
void notification_window_set_message(const gchar *message,
187
                                     const gchar *submessage)
188
{
189
        gtk_label_set_text(GTK_LABEL(notify_window.msglabel), message);
190
        gtk_label_set_markup(GTK_LABEL(notify_window.sublabel), submessage);
191
}
192

    
193
void notification_window_close(void)
194
{
195
        notification_window_destroy();
196
}
197

    
198
static void notification_window_destroy(void)
199
{
200
        if (notify_window.window) {
201
                if (notify_window.notify_tag > 0) {
202
                        g_source_remove(notify_window.notify_tag);
203
                        notify_window.notify_tag = 0;
204
                }
205

    
206
                gtk_widget_destroy(notify_window.window);
207

    
208
                notify_window.window = NULL;
209
                notify_window.msglabel = NULL;
210
                notify_window.sublabel = NULL;
211

    
212
                debug_print("notification window removed\n");
213
        }
214
}
215

    
216
static gboolean notify_fadeout_timeout_cb(gpointer data)
217
{
218
        gdk_threads_enter();
219
        notify_window.fade_length -= FADE_SPEED;
220
        notify_window.fade_count++;
221

    
222
        gtk_window_move(GTK_WINDOW(notify_window.window),
223
                        notify_window.x, notify_window.y + notify_window.fade_count * FADE_SPEED);
224

    
225
        if (notify_window.fade_length <= 0) {
226
                notification_window_destroy();
227
                gdk_threads_leave();
228
                return FALSE;
229
        }
230
        gdk_threads_leave();
231
        return TRUE;
232
}
233

    
234
static gboolean notify_timeout_cb(gpointer data)
235
{
236
        gdk_threads_enter();
237
        notify_window.fade_length = gdk_screen_height() - notify_window.y;
238
        notify_window.notify_tag = g_timeout_add(FADE_REFRESH_RATE,
239
                                                 notify_fadeout_timeout_cb,
240
                                                 NULL);
241
        gdk_threads_leave();
242

    
243
        return FALSE;
244
}
245

    
246
static gboolean nwin_button_pressed(GtkWidget *widget, GdkEventButton *event,
247
                                    gpointer data)
248
{
249
        if (!event)
250
                return FALSE;
251

    
252
        notification_window_destroy();
253
        main_window_popup(main_window_get());
254

    
255
        return TRUE;
256
}
257

    
258
static gboolean nwin_entered(GtkWidget *widget, GdkEventCrossing *event,
259
                             gpointer data)
260
{
261
        return FALSE;
262
}
263

    
264
static gboolean nwin_motion_notify(GtkWidget *widget, GdkEventMotion *event,
265
                                   gpointer data)
266
{
267
        if (notify_window.fade_count > 0 &&
268
            notify_window.notify_event_count == 0) {
269
                notify_window.notify_event_count++;
270
                return FALSE;
271
        }
272

    
273
        if (notify_window.notify_tag > 0) {
274
                g_source_remove(notify_window.notify_tag);
275
                notify_window.notify_tag = 0;
276
        }
277
        notify_window.fade_count = 0;
278
        notify_window.notify_event_count = 0;
279
        gtk_window_move(GTK_WINDOW(notify_window.window),
280
                        notify_window.x, notify_window.y);
281
        notify_window.notify_tag = g_timeout_add(notify_window.timeout * 1000,
282
                                                 notify_timeout_cb, NULL);
283

    
284
        return FALSE;
285
}
286

    
287
static void nwin_destroy_cb(GtkWidget *widget, gpointer data)
288
{
289
}