From cfa4bc89e1603c29c7aa9ae7f4d45bd1ba70af08 Mon Sep 17 00:00:00 2001 From: "xico.atelo@gmail.com" Date: Mon, 2 Jul 2012 16:50:30 +0000 Subject: [PATCH] Adding startup-notification support. git-svn-id: http://tint2.googlecode.com/svn/trunk@650 121b4492-b84c-0410-8b4c-0d4edfb3f3cc --- CMakeLists.txt | 16 +++++++-- src/launcher/launcher.c | 51 ++++++++++++++++++++++++++-- src/launcher/launcher.h | 2 +- src/server.h | 9 +++++ src/tint.c | 75 ++++++++++++++++++++++++++++++++++++++++- 5 files changed, 146 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c687ab3..3b5a0f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ pkg_check_modules( CAIRO REQUIRED cairo ) pkg_check_modules( GLIB2 REQUIRED glib-2.0 ) pkg_check_modules( GOBJECT2 REQUIRED gobject-2.0 ) pkg_check_modules( IMLIB2 REQUIRED imlib2>=1.4.2 ) +pkg_check_modules( SN libstartup-notification-1.0>=0.12 ) find_library( RT_LIBRARY rt ) if( NOT X11_FOUND OR NOT PANGOCAIRO_FOUND OR NOT PANGO_FOUND OR NOT CAIRO_FOUND OR NOT GLIB2_FOUND OR NOT GOBJECT2_FOUND OR NOT IMLIB2_FOUND ) @@ -38,7 +39,8 @@ include_directories( ${PROJECT_BINARY_DIR} ${CAIRO_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS} ${GOBJECT2_INCLUDE_DIRS} - ${IMLIB2_INCLUDE_DIRS} ) + ${IMLIB2_INCLUDE_DIRS} + ${SN_INCLUDE_DIRS} ) set( SOURCES src/config.c src/panel.c @@ -61,6 +63,12 @@ set( SOURCES src/config.c option( ENABLE_BATTERY "Enable battery status plugin" ON ) option( ENABLE_TINT2CONF "Enable tint2conf build, a GTK+2 theme switcher for tint2" ON ) option( ENABLE_EXAMPLES "Install additional tin2rc examples" OFF ) +option( ENABLE_SN "Startup notification support" ON ) +if( ENABLE_SN ) + if( SN_FOUND ) + add_definitions( -DHAVE_SN -DSN_API_NOT_YET_FROZEN ) + endif( SN_FOUND ) +endif( ENABLE_SN) if( ENABLE_BATTERY ) set( SOURCES ${SOURCES} src/battery/battery.c ) @@ -86,7 +94,8 @@ link_directories( ${X11_LIBRARY_DIRS} ${CAIRO_LIBRARY_DIRS} ${GLIB2_LIBRARY_DIRS} ${GOBJECT2_LIBRARY_DIRS} - ${IMLIB2_LIBRARY_DIRS} ) + ${IMLIB2_LIBRARY_DIRS} + ${SN_LIBRARY_DIRS} ) add_executable(tint2 ${SOURCES}) target_link_libraries( tint2 ${X11_LIBRARIES} ${PANGOCAIRO_LIBRARIES} @@ -94,7 +103,8 @@ target_link_libraries( tint2 ${X11_LIBRARIES} ${CAIRO_LIBRARIES} ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES} - ${IMLIB2_LIBRARIES} ) + ${IMLIB2_LIBRARIES} + ${SN_LIBRARIES} ) if( RT_LIBRARY ) target_link_libraries( tint2 ${RT_LIBRARY} ) endif( RT_LIBRARY ) diff --git a/src/launcher/launcher.c b/src/launcher/launcher.c index 2d1f8e8..69c31fb 100644 --- a/src/launcher/launcher.c +++ b/src/launcher/launcher.c @@ -26,6 +26,10 @@ #include #include +#ifdef HAVE_SN +#include +#endif + #include "window.h" #include "server.h" #include "area.h" @@ -332,11 +336,54 @@ void free_icon(Imlib_Image icon) } } -void launcher_action(LauncherIcon *icon) +void launcher_action(LauncherIcon *icon, XEvent* evt) { char *cmd = malloc(strlen(icon->cmd) + 10); sprintf(cmd, "(%s&)", icon->cmd); - tint_exec(cmd); +#if HAVE_SN + SnLauncherContext* ctx; + Time time; + + ctx = sn_launcher_context_new(server.sn_dsp, server.screen); + sn_launcher_context_set_name(ctx, icon->icon_tooltip); + sn_launcher_context_set_description(ctx, "Application launched from tint2"); + sn_launcher_context_set_binary_name (ctx, icon->cmd); + // Get a timestamp from the X event + if (evt->type == ButtonPress || evt->type == ButtonRelease) { + time = evt->xbutton.time; + } + else { + fprintf(stderr, "Unknown X event: %d\n", evt->type); + free(cmd); + return; + } + sn_launcher_context_initiate(ctx, "tint2", icon->cmd, time); +#endif /* HAVE_SN */ + pid_t pid; + pid = fork(); + if (pid < 0) { + fprintf(stderr, "Could not fork\n"); + } + else if (pid == 0) { +#if HAVE_SN + sn_launcher_context_setup_child_process (ctx); +#endif // HAVE_SN + // Allow children to exist after parent destruction + setsid (); + // Run the command + execl("/bin/sh", "/bin/sh", "-c", icon->cmd, NULL); + + fprintf(stderr, "Failed to execlp %s\n", icon->cmd); +#if HAVE_SN + sn_launcher_context_unref (ctx); +#endif // HAVE_SN + _exit(1); + } +#if HAVE_SN + else { + g_tree_insert (server.pids, GINT_TO_POINTER (pid), ctx); + } +#endif // HAVE_SN free(cmd); } diff --git a/src/launcher/launcher.h b/src/launcher/launcher.h index dc853a7..f60acee 100644 --- a/src/launcher/launcher.h +++ b/src/launcher/launcher.h @@ -83,7 +83,7 @@ void draw_launcher (void *obj, cairo_t *c); void launcher_load_themes(Launcher *launcher); // Populates the list_icons list void launcher_load_icons(Launcher *launcher); -void launcher_action(LauncherIcon *icon); +void launcher_action(LauncherIcon *icon, XEvent* e); void test_launcher_read_desktop_file(); void test_launcher_read_theme_file(); diff --git a/src/server.h b/src/server.h index 7a725a8..07876c6 100644 --- a/src/server.h +++ b/src/server.h @@ -13,6 +13,11 @@ #include #include +#ifdef HAVE_SN +#include +#include +#endif + typedef struct Global_atom { @@ -118,6 +123,10 @@ typedef struct Colormap colormap; Colormap colormap32; Global_atom atom; +#ifdef HAVE_SN + SnDisplay *sn_dsp; + GTree *pids; +#endif // HAVE_SN } Server_global; diff --git a/src/tint.c b/src/tint.c index cfd24bb..7b6e637 100644 --- a/src/tint.c +++ b/src/tint.c @@ -31,6 +31,11 @@ #include #include +#ifdef HAVE_SN +#include +#include +#endif + #include #include "server.h" #include "window.h" @@ -120,6 +125,58 @@ void init (int argc, char *argv[]) // sigprocmask(SIG_BLOCK, &block_mask, 0); } +#ifdef HAVE_SN +static int error_trap_depth = 0; + +static void +error_trap_push (SnDisplay *display, + Display *xdisplay) +{ + ++error_trap_depth; +} + +static void +error_trap_pop (SnDisplay *display, + Display *xdisplay) +{ + if (error_trap_depth == 0) + { + fprintf(stderr, "Error trap underflow!\n"); + return; + } + + XSync(xdisplay, False); /* get all errors out of the queue */ + --error_trap_depth; +} + +static void sigchld_handler(int sig) { + // Wait for all dead processes + pid_t pid; + while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { + SnLauncherContext *ctx; + ctx = (SnLauncherContext *) g_tree_lookup (server.pids, GINT_TO_POINTER (pid)); + if (ctx == NULL) { + fprintf(stderr, "Unknown child %d terminated!\n", pid); + } + else { + g_tree_remove (server.pids, GINT_TO_POINTER (pid)); + sn_launcher_context_complete (ctx); + sn_launcher_context_unref (ctx); + } + } +} + +static gint cmp_ptr(gconstpointer a, gconstpointer b) { + if (a < b) + return -1; + else if (a == b) + return 0; + else + return 1; +} + +#endif // HAVE_SN + void init_X11() { server.dsp = XOpenDisplay (NULL); @@ -134,6 +191,19 @@ void init_X11() server_init_visual(); XSetErrorHandler ((XErrorHandler) server_catch_error); +#ifdef HAVE_SN + // Initialize startup-notification + server.sn_dsp = sn_display_new (server.dsp, error_trap_push, error_trap_pop); + server.pids = g_tree_new (cmp_ptr); + // Setup a handler for child termination + struct sigaction act; + memset (&act, 0, sizeof (struct sigaction)); + act.sa_handler = sigchld_handler; + if (sigaction(SIGCHLD, &act, 0)) { + perror("sigaction"); + } +#endif // HAVE_SN + imlib_context_set_display (server.dsp); imlib_context_set_visual (server.visual); imlib_context_set_colormap (server.colormap); @@ -446,7 +516,7 @@ void event_button_release (XEvent *e) if ( click_launcher(panel, e->xbutton.x, e->xbutton.y)) { LauncherIcon *icon = click_launcher_icon(panel, e->xbutton.x, e->xbutton.y); if (icon) { - launcher_action(icon); + launcher_action(icon, e); } task_drag = 0; return; @@ -1035,6 +1105,9 @@ start: if (select(x11_fd+1, &fdset, 0, 0, timeout) > 0) { while (XPending (server.dsp)) { XNextEvent(server.dsp, &e); +#if HAVE_SN + sn_display_process_event (server.sn_dsp, &e); +#endif // HAVE_SN panel = get_panel(e.xany.window); if (panel && panel_autohide) {