all repos — tint2 @ cfa4bc89e1603c29c7aa9ae7f4d45bd1ba70af08

fork of the tint2 desktop panel for my custom setup - only minimized windows across all desktops for the taskbar

Adding startup-notification support.


git-svn-id: http://tint2.googlecode.com/svn/trunk@650 121b4492-b84c-0410-8b4c-0d4edfb3f3cc
xico.atelo@gmail.com xico.atelo@gmail.com@121b4492-b84c-0410-8b4c-0d4edfb3f3cc
commit

cfa4bc89e1603c29c7aa9ae7f4d45bd1ba70af08

parent

13b0d7612ac3ea2321790af3cf2ab8a1d75f3bb9

5 files changed, 146 insertions(+), 7 deletions(-)

jump to
M CMakeLists.txtCMakeLists.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 @@ ${PANGO_INCLUDE_DIRS}

${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 @@

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 @@ ${PANGO_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 @@ ${PANGO_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 )
M src/launcher/launcher.csrc/launcher/launcher.c

@@ -26,6 +26,10 @@ #include <signal.h>

#include <stdlib.h> #include <glib/gi18n.h> +#ifdef HAVE_SN +#include <libsn/sn.h> +#endif + #include "window.h" #include "server.h" #include "area.h"

@@ -332,11 +336,54 @@ imlib_free_image();

} } -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); }
M src/launcher/launcher.hsrc/launcher/launcher.h

@@ -83,7 +83,7 @@ // Populates the list_themes list

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();
M src/server.hsrc/server.h

@@ -13,6 +13,11 @@ #include <X11/Xlib.h>

#include <X11/Xatom.h> #include <X11/extensions/Xinerama.h> +#ifdef HAVE_SN +#include <libsn/sn.h> +#include <glib.h> +#endif + typedef struct Global_atom {

@@ -118,6 +123,10 @@ GC gc;

Colormap colormap; Colormap colormap32; Global_atom atom; +#ifdef HAVE_SN + SnDisplay *sn_dsp; + GTree *pids; +#endif // HAVE_SN } Server_global;
M src/tint.csrc/tint.c

@@ -31,6 +31,11 @@ #include <X11/extensions/Xdamage.h>

#include <Imlib2.h> #include <signal.h> +#ifdef HAVE_SN +#include <libsn/sn.h> +#include <sys/wait.h> +#endif + #include <version.h> #include "server.h" #include "window.h"

@@ -120,6 +125,58 @@ // sigaddset(&block_mask, SIGUSR1);

// 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);

@@ -133,6 +190,19 @@ server.root_win = RootWindow(server.dsp, server.screen);

server.desktop = server_get_current_desktop (); 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);

@@ -446,7 +516,7 @@

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 @@ // Wait for X Event or a Timer

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) {