aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2013-02-08 06:24:28 +0000
committerhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2013-02-08 06:24:28 +0000
commit6224779aca608fd457f1cb0d24ff516afe72694d (patch)
treed649345a1cf7b464e43cabc52f6a7bc613049c51 /src
parent90f27721aa04778bfc238f1af95462c206aa6ce4 (diff)
implemented new message notification popup window.
git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@3211 ee746299-78ed-0310-b773-934348b2243d
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/inc.c158
-rw-r--r--src/inc.h3
-rw-r--r--src/notificationwindow.c276
-rw-r--r--src/notificationwindow.h35
5 files changed, 433 insertions, 42 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index cc0feb3c..1c613e63 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -93,7 +93,8 @@ sylpheed_SOURCES = \
update_check.c update_check.h \
quote_fmt_lex.l quote_fmt_lex.h \
quote_fmt_parse.y quote_fmt.h \
- sylpheed-marshal.c sylpheed-marshal.h
+ sylpheed-marshal.c sylpheed-marshal.h \
+ notificationwindow.c notificationwindow.h
BUILT_SOURCES = \
quote_fmt_lex.c \
diff --git a/src/inc.c b/src/inc.c
index d8bb3c8f..fe563df9 100644
--- a/src/inc.c
+++ b/src/inc.c
@@ -1,6 +1,6 @@
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2012 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2013 Hiroyuki Yamamoto
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -58,6 +58,7 @@
#include "progressdialog.h"
#include "alertpanel.h"
#include "trayicon.h"
+#include "notificationwindow.h"
#include "filter.h"
#include "folder.h"
#include "procheader.h"
@@ -70,6 +71,18 @@ typedef struct _IncAccountNewMsgCount
gint new_messages;
} IncAccountNewMsgCount;
+typedef struct _IncMsgSummary
+{
+ gchar *subject;
+ gchar *from;
+} IncMsgSummary;
+
+struct _IncResult
+{
+ GSList *count_list;
+ GSList *msg_summaries;
+};
+
static GList *inc_dialog_list = NULL;
@@ -84,15 +97,18 @@ static GdkPixbuf *ok_pixbuf;
static void inc_finished (MainWindow *mainwin,
- GSList *msg_counts);
+ IncResult *result);
static GSList *inc_add_message_count (GSList *list,
PrefsAccount *account,
gint new_messages);
+static void inc_result_free (IncResult *result,
+ gboolean free_self);
static gint inc_remote_account_mail (MainWindow *mainwin,
PrefsAccount *account);
static gint inc_account_mail_real (MainWindow *mainwin,
- PrefsAccount *account);
+ PrefsAccount *account,
+ IncResult *result);
static IncProgressDialog *inc_progress_dialog_create
(gboolean autocheck);
@@ -101,8 +117,7 @@ static void inc_progress_dialog_destroy (IncProgressDialog *inc_dialog);
static IncSession *inc_session_new (PrefsAccount *account);
static void inc_session_destroy (IncSession *session);
-static gint inc_start (IncProgressDialog *inc_dialog,
- GSList **count_list);
+static gint inc_start (IncProgressDialog *inc_dialog);
static IncState inc_pop3_session_do (IncSession *session);
static void inc_progress_dialog_update (IncProgressDialog *inc_dialog,
@@ -161,14 +176,14 @@ static gint inc_autocheck_func (gpointer data);
/**
* inc_finished:
* @mainwin: Main window.
- * @msg_counts: GSList of Number of received messages for each account.
+ * @result: Information of incorporation result.
* @new_messages: Number of received messages.
*
* Update the folder view and the summary view after receiving
* messages. If @new_messages is 0, this function avoids unneeded
* updating.
**/
-static void inc_finished(MainWindow *mainwin, GSList *msg_counts)
+static void inc_finished(MainWindow *mainwin, IncResult *result)
{
FolderItem *item;
gint new_messages = 0;
@@ -176,10 +191,12 @@ static void inc_finished(MainWindow *mainwin, GSList *msg_counts)
IncAccountNewMsgCount *count;
GSList *cur;
- for (cur = msg_counts; cur != NULL; cur = cur->next) {
- count = cur->data;
- if (count->new_messages > 0)
- new_messages += count->new_messages;
+ if (result) {
+ for (cur = result->count_list; cur != NULL; cur = cur->next) {
+ count = cur->data;
+ if (count->new_messages > 0)
+ new_messages += count->new_messages;
+ }
}
debug_print("inc_finished: %d new message(s)\n", new_messages);
@@ -190,14 +207,15 @@ static void inc_finished(MainWindow *mainwin, GSList *msg_counts)
}
if (new_messages > 0 && !block_notify) {
+ gchar buf[1024];
GString *str;
gint c = 0;
str = g_string_new("");
g_string_printf(str, _("Sylpheed: %d new messages"),
new_messages);
- if (msg_counts) {
- for (cur = msg_counts; cur != NULL; cur = cur->next) {
+ if (result) {
+ for (cur = result->count_list; cur != NULL; cur = cur->next) {
count = cur->data;
if (count->new_messages > 0) {
if (c == 0)
@@ -214,6 +232,24 @@ static void inc_finished(MainWindow *mainwin, GSList *msg_counts)
debug_print("inc_finished: %s\n", str->str);
trayicon_set_tooltip(str->str);
trayicon_set_notify(TRUE);
+
+ g_snprintf(buf, sizeof(buf), _("Sylpheed: %d new messages"), new_messages);
+ g_string_truncate(str, 0);
+ if (result) {
+ for (cur = result->msg_summaries; cur != NULL; cur = cur->next) {
+ IncMsgSummary *summary = cur->data;
+ gchar *markup;
+
+ if (str->len > 0)
+ g_string_append_c(str, '\n');
+ markup = g_markup_printf_escaped("<b>%s</b> %s", summary->subject, summary->from);
+ g_string_append(str, markup);
+ g_free(markup);
+ }
+ }
+
+ notification_window_create(buf, str->str, 5);
+
g_string_free(str, TRUE);
}
@@ -271,10 +307,28 @@ static GSList *inc_add_message_count(GSList *list, PrefsAccount *account,
return g_slist_append(list, count);
}
+static void inc_result_free(IncResult *result, gboolean free_self)
+{
+ GSList *cur;
+
+ slist_free_strings(result->count_list);
+ g_slist_free(result->count_list);
+ for (cur = result->msg_summaries; cur != NULL; cur = cur->next) {
+ IncMsgSummary *sum = cur->data;
+ g_free(sum->subject);
+ g_free(sum->from);
+ g_free(sum);
+ }
+ g_slist_free(result->msg_summaries);
+
+ if (free_self)
+ g_free(result);
+}
+
void inc_mail(MainWindow *mainwin)
{
+ IncResult result = {NULL, NULL};
gint new_msgs = 0;
- GSList *list = NULL;
if (inc_lock_count) return;
if (inc_is_active()) return;
@@ -301,23 +355,21 @@ void inc_mail(MainWindow *mainwin)
if (prefs_common.inc_local) {
new_msgs = inc_spool();
- list = inc_add_message_count(list, NULL, new_msgs);
+ result.count_list = inc_add_message_count(result.count_list, NULL, new_msgs);
}
} else {
if (prefs_common.inc_local) {
new_msgs = inc_spool();
if (new_msgs < 0)
new_msgs = 0;
- list = inc_add_message_count(list, NULL, new_msgs);
+ result.count_list = inc_add_message_count(result.count_list, NULL, new_msgs);
}
- new_msgs = inc_account_mail_real(mainwin, cur_account);
- list = inc_add_message_count(list, cur_account, new_msgs);
+ new_msgs = inc_account_mail_real(mainwin, cur_account, &result);
}
- inc_finished(mainwin, list);
- slist_free_strings(list);
- g_slist_free(list);
+ inc_finished(mainwin, &result);
+ inc_result_free(&result, FALSE);
inc_is_running = FALSE;
@@ -455,7 +507,8 @@ static gint inc_remote_account_mail(MainWindow *mainwin, PrefsAccount *account)
return new_msgs;
}
-static gint inc_account_mail_real(MainWindow *mainwin, PrefsAccount *account)
+static gint inc_account_mail_real(MainWindow *mainwin, PrefsAccount *account,
+ IncResult *result)
{
IncProgressDialog *inc_dialog;
IncSession *session;
@@ -471,18 +524,19 @@ static gint inc_account_mail_real(MainWindow *mainwin, PrefsAccount *account)
inc_dialog = inc_progress_dialog_create(FALSE);
inc_dialog->queue_list = g_list_append(inc_dialog->queue_list, session);
inc_dialog->mainwin = mainwin;
+ inc_dialog->result = result;
inc_progress_dialog_set_list(inc_dialog);
main_window_set_toolbar_sensitive(mainwin);
main_window_set_menu_sensitive(mainwin);
- return inc_start(inc_dialog, NULL);
+ return inc_start(inc_dialog);
}
gint inc_account_mail(MainWindow *mainwin, PrefsAccount *account)
{
+ IncResult result = {NULL, NULL};
gint new_msgs;
- GSList *list;
if (inc_lock_count) return 0;
if (inc_is_active()) return 0;
@@ -498,12 +552,10 @@ gint inc_account_mail(MainWindow *mainwin, PrefsAccount *account)
syl_plugin_signal_emit("inc-mail-start", account);
- new_msgs = inc_account_mail_real(mainwin, account);
+ new_msgs = inc_account_mail_real(mainwin, account, &result);
- list = inc_add_message_count(NULL, account, new_msgs);
- inc_finished(mainwin, list);
- slist_free_strings(list);
- g_slist_free(list);
+ inc_finished(mainwin, &result);
+ inc_result_free(&result, FALSE);
inc_is_running = FALSE;
@@ -517,7 +569,7 @@ void inc_all_account_mail(MainWindow *mainwin, gboolean autocheck)
{
GList *list, *queue_list = NULL;
IncProgressDialog *inc_dialog;
- GSList *count_list = NULL;
+ IncResult result = {NULL, NULL};
gint new_msgs = 0;
if (inc_lock_count) return;
@@ -538,7 +590,7 @@ void inc_all_account_mail(MainWindow *mainwin, gboolean autocheck)
new_msgs = inc_spool();
if (new_msgs < 0)
new_msgs = 0;
- count_list = inc_add_message_count(count_list, NULL, new_msgs);
+ result.count_list = inc_add_message_count(result.count_list, NULL, new_msgs);
}
/* check IMAP4 / News folders */
@@ -547,7 +599,7 @@ void inc_all_account_mail(MainWindow *mainwin, gboolean autocheck)
if ((account->protocol == A_IMAP4 ||
account->protocol == A_NNTP) && account->recv_at_getall) {
new_msgs = inc_remote_account_mail(mainwin, account);
- count_list = inc_add_message_count(count_list, account, new_msgs);
+ result.count_list = inc_add_message_count(result.count_list, account, new_msgs);
}
}
@@ -567,17 +619,17 @@ void inc_all_account_mail(MainWindow *mainwin, gboolean autocheck)
inc_dialog = inc_progress_dialog_create(autocheck);
inc_dialog->queue_list = queue_list;
inc_dialog->mainwin = mainwin;
+ inc_dialog->result = &result;
inc_progress_dialog_set_list(inc_dialog);
main_window_set_toolbar_sensitive(mainwin);
main_window_set_menu_sensitive(mainwin);
- inc_start(inc_dialog, &count_list);
+ inc_start(inc_dialog);
}
- inc_finished(mainwin, count_list);
- slist_free_strings(count_list);
- g_slist_free(count_list);
+ inc_finished(mainwin, &result);
+ inc_result_free(&result, FALSE);
inc_is_running = FALSE;
@@ -612,13 +664,14 @@ gint inc_pop_before_smtp(PrefsAccount *account)
_("Authenticating with POP3"));
inc_dialog->queue_list = g_list_append(inc_dialog->queue_list, session);
inc_dialog->mainwin = mainwin;
+ inc_dialog->result = NULL;
inc_progress_dialog_set_list(inc_dialog);
inc_dialog->show_dialog = TRUE;
main_window_set_toolbar_sensitive(mainwin);
main_window_set_menu_sensitive(mainwin);
- inc_start(inc_dialog, NULL);
+ inc_start(inc_dialog);
inc_is_running = FALSE;
@@ -776,7 +829,7 @@ static void inc_update_folder_foreach(GHashTable *table)
folderview_update_item_foreach(table, TRUE);
}
-static gint inc_start(IncProgressDialog *inc_dialog, GSList **count_list)
+static gint inc_start(IncProgressDialog *inc_dialog)
{
IncSession *session;
GList *qlist;
@@ -903,8 +956,8 @@ static gint inc_start(IncProgressDialog *inc_dialog, GSList **count_list)
break;
}
- if (count_list)
- *count_list = inc_add_message_count(*count_list, pop3_session->ac_prefs, session->new_msgs);
+ if (inc_dialog->result)
+ inc_dialog->result->count_list = inc_add_message_count(inc_dialog->result->count_list, pop3_session->ac_prefs, session->new_msgs);
new_msgs += session->new_msgs;
if (!prefs_common.scan_all_after_inc) {
@@ -1394,6 +1447,17 @@ static gint inc_recv_message(Session *session, const gchar *msg, gpointer data)
return 0;
}
+/**
+ * inc_drop_message:
+ * @session: Current Pop3Session.
+ * @file: Received message file.
+ *
+ * Callback function to drop received message into local mailbox.
+ *
+ * Return value: DROP_OK if succeeded. DROP_ERROR if error occurred.
+ * DROP_DONT_RECEIVE if the message should be skipped.
+ * DROP_DELETE if the message should be deleted.
+ **/
static gint inc_drop_message(Pop3Session *session, const gchar *file)
{
FolderItem *inbox;
@@ -1404,11 +1468,14 @@ static gint inc_drop_message(Pop3Session *session, const gchar *file)
gint val;
gboolean is_junk = FALSE;
gboolean is_counted = FALSE;
+ IncProgressDialog *inc_dialog;
g_return_val_if_fail(inc_session != NULL, DROP_ERROR);
gdk_threads_enter();
+ inc_dialog = (IncProgressDialog *)inc_session->data;
+
if (session->ac_prefs->inbox) {
inbox = folder_find_item_from_identifier
(session->ac_prefs->inbox);
@@ -1521,8 +1588,17 @@ static gint inc_drop_message(Pop3Session *session, const gchar *file)
else {
val = DROP_OK;
if (!is_junk && is_counted &&
- fltinfo->actions[FLT_ACTION_MARK_READ] == FALSE)
+ fltinfo->actions[FLT_ACTION_MARK_READ] == FALSE) {
inc_session->new_msgs++;
+
+ if (inc_dialog->result && msginfo->subject && g_slist_length(inc_dialog->result->msg_summaries) < 5) {
+ IncMsgSummary *summary;
+ summary = g_new(IncMsgSummary, 1);
+ summary->subject = g_strdup(msginfo->subject);
+ summary->from = g_strdup(msginfo->fromname);
+ inc_dialog->result->msg_summaries = g_slist_append(inc_dialog->result->msg_summaries, summary);
+ }
+ }
}
procmsg_msginfo_free(msginfo);
diff --git a/src/inc.h b/src/inc.h
index 8c7846c7..98ca1989 100644
--- a/src/inc.h
+++ b/src/inc.h
@@ -32,6 +32,7 @@
#include "session.h"
#include "pop.h"
+typedef struct _IncResult IncResult;
typedef struct _IncProgressDialog IncProgressDialog;
typedef struct _IncSession IncSession;
@@ -64,6 +65,8 @@ struct _IncProgressDialog
GList *queue_list; /* list of IncSession */
gint cur_row;
+
+ IncResult *result;
};
struct _IncSession
diff --git a/src/notificationwindow.c b/src/notificationwindow.c
new file mode 100644
index 00000000..7c8b0258
--- /dev/null
+++ b/src/notificationwindow.c
@@ -0,0 +1,276 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2013 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#ifdef G_OS_WIN32
+# include <windows.h>
+#endif
+
+#include "notificationwindow.h"
+#include "mainwindow.h"
+#include "utils.h"
+
+#define NOTIFICATIONWINDOW_NOTIFY_PERIOD 10000
+#define NOTIFICATIONWINDOW_WIDTH 280
+#define NOTIFICATIONWINDOW_HEIGHT 96
+#define FADE_REFRESH_RATE 50
+#define FADE_SPEED 5
+
+struct _NotificationWindow
+{
+ GtkWidget *window;
+
+ GtkWidget *msglabel;
+ GtkWidget *sublabel;
+
+ guint notify_tag;
+
+ gint x;
+ gint y;
+ gint width;
+ gint height;
+ gint fade_length;
+ gint fade_count;
+ guint timeout;
+};
+
+static NotificationWindow notify_window;
+
+static void notification_window_destroy(void);
+
+static gboolean notify_timeout_cb(gpointer data);
+
+static gboolean nwin_button_pressed (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data);
+static gboolean nwin_entered (GtkWidget *widget,
+ GdkEventCrossing *event,
+ gpointer data);
+static gboolean nwin_motion_notify (GtkWidget *widget,
+ GdkEventMotion *event,
+ gpointer data);
+
+static void nwin_destroy_cb (GtkWidget *widget,
+ gpointer data);
+
+
+static void get_work_area(GdkRectangle *rect)
+{
+#ifdef G_OS_WIN32
+ RECT rc;
+
+ SystemParametersInfoW(SPI_GETWORKAREA, 0, &rc, 0);
+ rect->x = rc.left;
+ rect->y = rc.top;
+ rect->width = rc.right - rc.left;
+ rect->height = rc.bottom - rc.top;
+#else
+ rect->x = 0;
+ rect->y = 0;
+ rect->width = gdk_screen_width();
+ rect->height = gdk_screen_height();
+#endif
+}
+
+gint notification_window_create(const gchar *message, const gchar *submessage,
+ guint timeout)
+{
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *msglabel;
+ GtkWidget *sublabel;
+ GdkRectangle rect;
+ gint x, y;
+ GtkRequisition requisition;
+
+ if (notify_window.window) {
+ notification_window_destroy();
+ }
+
+ window = gtk_window_new(GTK_WINDOW_POPUP);
+ gtk_window_set_title(GTK_WINDOW(window), _("Notification"));
+ gtk_window_set_wmclass(GTK_WINDOW(window), "notification", "Sylpheed");
+ gtk_container_set_border_width(GTK_CONTAINER(window), 4);
+ 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);
+ gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window), TRUE);
+ gtk_window_set_gravity(GTK_WINDOW(window), GDK_GRAVITY_SOUTH_EAST);
+ gtk_widget_set_size_request(window, NOTIFICATIONWINDOW_WIDTH, -1);
+ gtk_widget_realize(window);
+ gdk_window_set_type_hint(window->window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
+
+ /* move window bottom-right */
+ get_work_area(&rect);
+ x = rect.x + rect.width - NOTIFICATIONWINDOW_WIDTH - 2;
+ if (x < 0) x = 0;
+ y = rect.y + rect.height - NOTIFICATIONWINDOW_HEIGHT - 2;
+ if (y < 0) y = 0;
+ gtk_window_move(GTK_WINDOW(window), x, y);
+
+ g_signal_connect(G_OBJECT(window), "destroy",
+ G_CALLBACK(nwin_destroy_cb), NULL);
+ g_signal_connect(G_OBJECT(window), "button_press_event",
+ G_CALLBACK(nwin_button_pressed), NULL);
+ g_signal_connect(G_OBJECT(window), "enter_notify_event",
+ G_CALLBACK(nwin_entered), NULL);
+ g_signal_connect(G_OBJECT(window), "motion_notify_event",
+ G_CALLBACK(nwin_motion_notify), NULL);
+
+ vbox = gtk_vbox_new(FALSE, 4);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+
+ msglabel = gtk_label_new(message);
+ gtk_box_pack_start(GTK_BOX(vbox), msglabel, FALSE, FALSE, 4);
+
+ sublabel = gtk_label_new("");
+ gtk_label_set_ellipsize(GTK_LABEL(sublabel), PANGO_ELLIPSIZE_END);
+ gtk_label_set_markup(GTK_LABEL(sublabel), submessage);
+ gtk_box_pack_start(GTK_BOX(vbox), sublabel, FALSE, FALSE, 4);
+
+ gtk_widget_show_all(window);
+
+ /* adjust window size and position */
+ gtk_widget_get_child_requisition(window, &requisition);
+ notify_window.width = NOTIFICATIONWINDOW_WIDTH;
+ notify_window.height = MAX(requisition.height, NOTIFICATIONWINDOW_HEIGHT);
+ gtk_widget_set_size_request(window, NOTIFICATIONWINDOW_WIDTH, notify_window.height);
+ y = rect.y + rect.height - notify_window.height - 2;
+ if (y < 0) y = 0;
+ gtk_window_move(GTK_WINDOW(window), x, y);
+
+ notify_window.notify_tag = g_timeout_add(timeout * 1000,
+ notify_timeout_cb, NULL);
+
+ debug_print("notification window created\n");
+
+ notify_window.window = window;
+ notify_window.msglabel = msglabel;
+ notify_window.sublabel = sublabel;
+ notify_window.x = x;
+ notify_window.y = y;
+ notify_window.fade_length = 0;
+ notify_window.fade_count = 0;
+ notify_window.timeout = timeout;
+
+ return 0;
+}
+
+void notification_window_set_message(const gchar *message,
+ const gchar *submessage)
+{
+ gtk_label_set_text(GTK_LABEL(notify_window.msglabel), message);
+ gtk_label_set_markup(GTK_LABEL(notify_window.sublabel), submessage);
+}
+
+void notification_window_close(void)
+{
+ notification_window_destroy();
+}
+
+static void notification_window_destroy(void)
+{
+ if (notify_window.window) {
+ if (notify_window.notify_tag > 0) {
+ g_source_remove(notify_window.notify_tag);
+ notify_window.notify_tag = 0;
+ }
+
+ gtk_widget_destroy(notify_window.window);
+
+ notify_window.window = NULL;
+ notify_window.msglabel = NULL;
+ notify_window.sublabel = NULL;
+
+ debug_print("notification window removed\n");
+ }
+}
+
+static gboolean notify_fadeout_timeout_cb(gpointer data)
+{
+ gdk_threads_enter();
+ notify_window.fade_length -= FADE_SPEED;
+ notify_window.fade_count++;
+
+ gtk_window_move(GTK_WINDOW(notify_window.window),
+ notify_window.x, notify_window.y + notify_window.fade_count * FADE_SPEED);
+
+ if (notify_window.fade_length <= 0) {
+ notification_window_destroy();
+ gdk_threads_leave();
+ return FALSE;
+ }
+ gdk_threads_leave();
+ return TRUE;
+}
+
+static gboolean notify_timeout_cb(gpointer data)
+{
+ gdk_threads_enter();
+ notify_window.fade_length = gdk_screen_height() - notify_window.y;
+ notify_window.notify_tag = g_timeout_add(FADE_REFRESH_RATE,
+ notify_fadeout_timeout_cb,
+ NULL);
+ gdk_threads_leave();
+
+ return FALSE;
+}
+
+static gboolean nwin_button_pressed(GtkWidget *widget, GdkEventButton *event,
+ gpointer data)
+{
+ if (!event)
+ return FALSE;
+
+ notification_window_destroy();
+ main_window_popup(main_window_get());
+
+ return TRUE;
+}
+
+static gboolean nwin_entered(GtkWidget *widget, GdkEventCrossing *event,
+ gpointer data)
+{
+ return FALSE;
+}
+
+static gboolean nwin_motion_notify(GtkWidget *widget, GdkEventMotion *event,
+ gpointer data)
+{
+ if (notify_window.notify_tag > 0) {
+ g_source_remove(notify_window.notify_tag);
+ notify_window.notify_tag = 0;
+ }
+ notify_window.fade_count = 0;
+ gtk_window_move(GTK_WINDOW(notify_window.window),
+ notify_window.x, notify_window.y);
+ notify_window.notify_tag = g_timeout_add(notify_window.timeout * 1000,
+ notify_timeout_cb, NULL);
+
+ return FALSE;
+}
+
+static void nwin_destroy_cb(GtkWidget *widget, gpointer data)
+{
+}
diff --git a/src/notificationwindow.h b/src/notificationwindow.h
new file mode 100644
index 00000000..d724af27
--- /dev/null
+++ b/src/notificationwindow.h
@@ -0,0 +1,35 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2013 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __NOTIFICATIONWINDOW_H__
+#define __NOTIFICATIONWINDOW_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+typedef struct _NotificationWindow NotificationWindow;
+
+gint notification_window_create (const gchar *message,
+ const gchar *submessage,
+ guint timeout);
+void notification_window_set_message (const gchar *message,
+ const gchar *submessage);
+void notification_window_close (void);
+
+#endif /* __NOTIFICATIONWINDOW_H__ */