Statistics
| Revision:

root / src / notificationwindow.c @ 3216

History | View | Annotate | Download (7.69 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
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
};
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), 4);
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, 4);
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, 4);
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, 4);
152

    
153
        gtk_widget_show_all(window);
154

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

    
164
        notify_window.notify_tag = g_timeout_add(timeout * 1000,
165
                                                 notify_timeout_cb, NULL);
166

    
167
        debug_print("notification window created\n");
168

    
169
        notify_window.window = window;
170
        notify_window.msglabel = msglabel;
171
        notify_window.sublabel = sublabel;
172
        notify_window.x = x;
173
        notify_window.y = y;
174
        notify_window.fade_length = 0;
175
        notify_window.fade_count = 0;
176
        notify_window.notify_event_count = 0;
177
        notify_window.timeout = timeout;
178

    
179
        return 0;
180
}
181

    
182
void notification_window_set_message(const gchar *message,
183
                                     const gchar *submessage)
184
{
185
        gtk_label_set_text(GTK_LABEL(notify_window.msglabel), message);
186
        gtk_label_set_markup(GTK_LABEL(notify_window.sublabel), submessage);
187
}
188

    
189
void notification_window_close(void)
190
{
191
        notification_window_destroy();
192
}
193

    
194
static void notification_window_destroy(void)
195
{
196
        if (notify_window.window) {
197
                if (notify_window.notify_tag > 0) {
198
                        g_source_remove(notify_window.notify_tag);
199
                        notify_window.notify_tag = 0;
200
                }
201

    
202
                gtk_widget_destroy(notify_window.window);
203

    
204
                notify_window.window = NULL;
205
                notify_window.msglabel = NULL;
206
                notify_window.sublabel = NULL;
207

    
208
                debug_print("notification window removed\n");
209
        }
210
}
211

    
212
static gboolean notify_fadeout_timeout_cb(gpointer data)
213
{
214
        gdk_threads_enter();
215
        notify_window.fade_length -= FADE_SPEED;
216
        notify_window.fade_count++;
217

    
218
        gtk_window_move(GTK_WINDOW(notify_window.window),
219
                        notify_window.x, notify_window.y + notify_window.fade_count * FADE_SPEED);
220

    
221
        if (notify_window.fade_length <= 0) {
222
                notification_window_destroy();
223
                gdk_threads_leave();
224
                return FALSE;
225
        }
226
        gdk_threads_leave();
227
        return TRUE;
228
}
229

    
230
static gboolean notify_timeout_cb(gpointer data)
231
{
232
        gdk_threads_enter();
233
        notify_window.fade_length = gdk_screen_height() - notify_window.y;
234
        notify_window.notify_tag = g_timeout_add(FADE_REFRESH_RATE,
235
                                                 notify_fadeout_timeout_cb,
236
                                                 NULL);
237
        gdk_threads_leave();
238

    
239
        return FALSE;
240
}
241

    
242
static gboolean nwin_button_pressed(GtkWidget *widget, GdkEventButton *event,
243
                                    gpointer data)
244
{
245
        if (!event)
246
                return FALSE;
247

    
248
        notification_window_destroy();
249
        main_window_popup(main_window_get());
250

    
251
        return TRUE;
252
}
253

    
254
static gboolean nwin_entered(GtkWidget *widget, GdkEventCrossing *event,
255
                             gpointer data)
256
{
257
        return FALSE;
258
}
259

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

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

    
280
        return FALSE;
281
}
282

    
283
static void nwin_destroy_cb(GtkWidget *widget, gpointer data)
284
{
285
}