diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | applets/Makefile.am | 4 | ||||
-rw-r--r-- | applets/startup-notify/Makefile.am | 14 | ||||
-rw-r--r-- | applets/startup-notify/startup.c | 265 | ||||
-rw-r--r-- | configure.ac | 2 |
5 files changed, 294 insertions, 0 deletions
@@ -1,3 +1,12 @@ +2008-01-17 Ross Burton <ross@openedhand.com> + + * configure.ac: + * applets/Makefile.am: + * applets/startup-notify/Makefile.am: + * applets/startup-notify/startup.c: + Add new startup notification applet which uses libnotify instead + of appearing in the panel. + 2007-12-13 Ross Burton <ross@openedhand.com> * applets/launcher/launcher.c: diff --git a/applets/Makefile.am b/applets/Makefile.am index 1a7377a..d5e17a3 100644 --- a/applets/Makefile.am +++ b/applets/Makefile.am @@ -6,6 +6,10 @@ endif if HAVE_LIBSN SUBDIRS += startup +if HAVE_LIBNOTIFY + SUBDIRS += startup-notify endif +endif + MAINTAINERCLEANFILES = Makefile.in diff --git a/applets/startup-notify/Makefile.am b/applets/startup-notify/Makefile.am new file mode 100644 index 0000000..74b7273 --- /dev/null +++ b/applets/startup-notify/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS=-DPKGDATADIR=\"$(pkgdatadir)\" \ + -DGETTEXT_PACKAGE=\"matchbox-panel\" +AM_CFLAGS = -Wall -g $(MATCHBOX_PANEL_CFLAGS) \ + -I$(top_srcdir) -I$(top_builddir) -Werror \ + $(SN_CFLAGS) $(LIBNOTIFY_CFLAGS) + +appletdir = $(pkglibdir) +applet_LTLIBRARIES = libstartup-notify.la + +libstartup_notify_la_SOURCES = startup.c +libstartup_notify_la_LIBADD = $(SN_LIBS) $(LIBNOTIFY_LIBS) +libstartup_notify_la_LDFLAGS = -avoid-version + +MAINTAINERCLEANFILES = Makefile.in diff --git a/applets/startup-notify/startup.c b/applets/startup-notify/startup.c new file mode 100644 index 0000000..48158be --- /dev/null +++ b/applets/startup-notify/startup.c @@ -0,0 +1,265 @@ +/* + * startup-monitor - A tray app that provides feedback on application startup. + * + * Copyright 2004 - 2007, Openedhand Ltd. + * By Matthew Allum <mallum@o-hand.com>, + * Stefan Schmidt <stefan@openmoko.org>, + * Ross Burton <ross@openedhand.com> + * + * Originally based on mb-applet-startup-monitor + * + * 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; version 2 of the license. + * + * 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include <glib.h> +#include <gdk/gdkx.h> +#include <gdk/gdk.h> +#include <gtk/gtk.h> + +#define SN_API_NOT_YET_FROZEN 1 +#include <libsn/sn.h> +#include <libnotify/notify.h> + +#include <string.h> + +#define TIMEOUT 20 + +typedef struct LaunchItem { + char *id; + char *name; + time_t when; + guint timeout_id; +} LaunchItem; + +typedef struct { + GdkWindow *root_window; + SnDisplay *sn_display; + GList *launch_list; + NotifyNotification *notify; +} StartupApplet; + +static GdkFilterReturn filter_func (GdkXEvent *gdk_xevent, + GdkEvent *event, StartupApplet *applet); + +static gboolean timeout (StartupApplet *applet); + +/* Destroy applet */ +static void +startup_applet_free (StartupApplet *applet) +{ + gdk_window_remove_filter (applet->root_window, + (GdkFilterFunc) filter_func, applet); + g_slice_free (StartupApplet, applet); +} + +static void +update_notify (StartupApplet *applet) +{ + LaunchItem *item; + char *msg; + + g_return_if_fail (applet->launch_list != NULL); + + item = applet->launch_list->data; + + msg = g_strdup_printf ("Starting %s...", item->name); + + if (applet->notify) { + notify_notification_update (applet->notify, msg, NULL, NULL); + } else { + applet->notify = notify_notification_new (msg, NULL, NULL, NULL); + } + notify_notification_show (applet->notify, NULL); + + g_free (msg); +} + +static void +hide_notify (StartupApplet *applet) +{ + if (applet->notify) { + notify_notification_close (applet->notify, NULL); + g_object_unref (applet->notify); + applet->notify = NULL; + } +} + +static LaunchItem * +new_item (StartupApplet *applet, const char *id, const char *name) +{ + LaunchItem *item; + + g_return_val_if_fail (applet != NULL, NULL); + g_return_val_if_fail (id != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + item = g_new0 (LaunchItem, 1); + item->id = g_strdup (id); + item->name = g_strdup (name); + + item->when = time (NULL) + TIMEOUT; + + /* TODO: keep track of the earliest timeout and only wake up then */ +#if GLIB_CHECK_VERSION(2, 14, 0) + item->timeout_id = g_timeout_add_seconds (2, (GSourceFunc) timeout, applet); +#else + item->timeout_id = g_timeout_add (2, (GSourceFunc) timeout, applet); +#endif + + return item; +} + +static void +free_item (LaunchItem *item) +{ + g_return_if_fail (item != NULL); + + g_source_remove (item->timeout_id); + g_free (item->id); + g_free (item->name); + g_free (item); +} + +static void +monitor_event_func (SnMonitorEvent *event, gpointer user_data) +{ + SnStartupSequence *sequence; + const char *id, *name; + StartupApplet *applet = (StartupApplet *) user_data; + + sequence = sn_monitor_event_get_startup_sequence (event); + id = sn_startup_sequence_get_id (sequence); + name = sn_startup_sequence_get_name (sequence); + + switch (sn_monitor_event_get_type (event)) { + case SN_MONITOR_EVENT_INITIATED: + { + LaunchItem *item; + item = new_item (applet, id, name); + applet->launch_list = g_list_prepend (applet->launch_list, item); + update_notify (applet); + } + break; + + case SN_MONITOR_EVENT_COMPLETED: + case SN_MONITOR_EVENT_CANCELED: + { + GList *l; + + for (l = applet->launch_list; l; l = l->next) { + LaunchItem *item = l->data; + if (!strcmp (item->id, id)) { + applet->launch_list = g_list_delete_link (applet->launch_list, l); + free_item (item); + break; + } + } + + if (applet->launch_list) + update_notify (applet); + else + hide_notify (applet); + } + break; + + case SN_MONITOR_EVENT_CHANGED: + /* TODO */ + break; + } +} + +static gboolean +timeout (StartupApplet *applet) +{ + time_t t; + GList *l; + + if (!applet->notify) + return TRUE; + + t = time (NULL); + + /* handle launchee timeouts */ + for (l = applet->launch_list; l; l = l->next) { + LaunchItem *item = l->data; + if ((item->when - t) <= 0) { + applet->launch_list = g_list_delete_link (applet->launch_list, l); + free_item (item); + break; + } + } + + if (applet->launch_list) { + update_notify (applet); + return TRUE; + } else { + hide_notify (applet); + return TRUE; + } + + return TRUE; +} + +static GdkFilterReturn +filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, StartupApplet *applet) +{ + XEvent *xevent = (XEvent *) gdk_xevent; + + sn_display_process_event (applet->sn_display, xevent); + + return GDK_FILTER_CONTINUE; +} + +G_MODULE_EXPORT GtkWidget * +mb_panel_applet_create (const char *id, GtkOrientation orientation) +{ + StartupApplet *applet; + GtkWidget *widget; + Display *xdisplay; + SnMonitorContext *context; + + if (!notify_is_initted ()) + notify_init ("matchbox-panel"); + + applet = g_slice_new0 (StartupApplet); + + widget = gtk_hbox_new (0, FALSE); /* grr */ + g_object_weak_ref (G_OBJECT (widget), (GWeakNotify)startup_applet_free, applet); + + xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)); + + applet->sn_display = sn_display_new (xdisplay, NULL, NULL); + + context = sn_monitor_context_new (applet->sn_display, + DefaultScreen (xdisplay), + monitor_event_func, + applet, NULL); + + /* We have to select for property events on at least one root window (but not + * all as INITIATE messages go to all root windows) + */ + XSelectInput (xdisplay, DefaultRootWindow (xdisplay), PropertyChangeMask); + + applet->root_window = gdk_window_lookup_for_display + (gdk_x11_lookup_xdisplay (xdisplay), 0); + + gdk_window_add_filter (applet->root_window, (GdkFilterFunc)filter_func, applet); + + /* TODO: need to fix the panel to support invisible widgets */ + return widget; +} diff --git a/configure.ac b/configure.ac index c3dd772..1a6f5be 100644 --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,7 @@ if test x$enable_libnotify != xno; then AC_DEFINE(USE_LIBNOTIFY, [1], [Has libnotify Support]) fi +AM_CONDITIONAL(HAVE_LIBNOTIFY, test x$enable_libnotify = xyes) # apm AC_CHECK_HEADERS(apm.h, enable_linux_apm=yes, enable_linux_apm=no) @@ -69,6 +70,7 @@ applets/clock/Makefile applets/launcher/Makefile applets/startup/Makefile applets/startup/data/Makefile +applets/startup-notify/Makefile applets/systray/Makefile applets/showdesktop/Makefile applets/windowselector/Makefile |