Statistics
| Revision:

root / src / notificationwindow.c @ 3211

History | View | Annotate | Download (7.45 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                280
38
#define NOTIFICATIONWINDOW_HEIGHT                96
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
        guint timeout;
58
};
59

    
60
static NotificationWindow notify_window;
61

    
62
static void notification_window_destroy(void);
63

    
64
static gboolean notify_timeout_cb(gpointer         data);
65

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

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

    
79

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

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

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

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

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

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

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

    
141
        vbox = gtk_vbox_new(FALSE, 4);
142
        gtk_container_add(GTK_CONTAINER(window), vbox);
143

    
144
        msglabel = gtk_label_new(message);
145
        gtk_box_pack_start(GTK_BOX(vbox), msglabel, FALSE, FALSE, 4);
146

    
147
        sublabel = gtk_label_new("");
148
        gtk_label_set_ellipsize(GTK_LABEL(sublabel), PANGO_ELLIPSIZE_END);
149
        gtk_label_set_markup(GTK_LABEL(sublabel), submessage);
150
        gtk_box_pack_start(GTK_BOX(vbox), sublabel, FALSE, FALSE, 4);
151

    
152
        gtk_widget_show_all(window);
153

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

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

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

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

    
177
        return 0;
178
}
179

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

    
187
void notification_window_close(void)
188
{
189
        notification_window_destroy();
190
}
191

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

    
200
                gtk_widget_destroy(notify_window.window);
201

    
202
                notify_window.window = NULL;
203
                notify_window.msglabel = NULL;
204
                notify_window.sublabel = NULL;
205

    
206
                debug_print("notification window removed\n");
207
        }
208
}
209

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

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

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

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

    
237
        return FALSE;
238
}
239

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

    
246
        notification_window_destroy();
247
        main_window_popup(main_window_get());
248

    
249
        return TRUE;
250
}
251

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

    
258
static gboolean nwin_motion_notify(GtkWidget *widget, GdkEventMotion *event,
259
                                   gpointer data)
260
{
261
        if (notify_window.notify_tag > 0) {
262
                g_source_remove(notify_window.notify_tag);
263
                notify_window.notify_tag = 0;
264
        }
265
        notify_window.fade_count = 0;
266
        gtk_window_move(GTK_WINDOW(notify_window.window),
267
                        notify_window.x, notify_window.y);
268
        notify_window.notify_tag = g_timeout_add(notify_window.timeout * 1000,
269
                                                 notify_timeout_cb, NULL);
270

    
271
        return FALSE;
272
}
273

    
274
static void nwin_destroy_cb(GtkWidget *widget, gpointer data)
275
{
276
}