when using openbox-gnome/kde-session, use a separate config file (rc-gnome/kde.xml)
[mikachu/openbox.git] / openbox / startupnotify.c
index 66258c8..45a2b4c 100644 (file)
@@ -2,7 +2,7 @@
 
    startupnotify.c for the Openbox window manager
    Copyright (c) 2006        Mikael Magnusson
-   Copyright (c) 2003        Ben Jansens
+   Copyright (c) 2003-2007   Dana Jansens
 
    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
 */
 
 #include "startupnotify.h"
+#include "gettext.h"
+
+#include <stdlib.h>
 
 #ifndef USE_LIBSN
 
 void sn_startup(gboolean reconfig) {}
 void sn_shutdown(gboolean reconfig) {}
 gboolean sn_app_starting() { return FALSE; }
-void sn_app_started(gchar *wmclass) {}
+Time sn_app_started(const gchar *id, const gchar *wmclass)
+{
+    return CurrentTime;
+}
 gboolean sn_get_desktop(gchar *id, guint *desktop) { return FALSE; }
+void sn_setup_spawn_environment(gchar *program, gchar *name,
+                                gchar *icon_name, gint desktop, Time time) {}
+void sn_spawn_cancel() {}
 
 #else
 
@@ -36,18 +45,12 @@ gboolean sn_get_desktop(gchar *id, guint *desktop) { return FALSE; }
 #define SN_API_NOT_YET_FROZEN
 #include <libsn/sn.h>
 
-typedef struct {
-    SnStartupSequence *seq;
-    gboolean feedback;
-} ObWaitData;
-
 static SnDisplay *sn_display;
 static SnMonitorContext *sn_context;
-static GSList *sn_waits; /* list of ObWaitDatas */
+static SnLauncherContext *sn_launcher;
+static GSList *sn_waits; /* list of SnStartupSequences we're waiting on */
 
-static ObWaitData* wait_data_new(SnStartupSequence *seq);
-static void wait_data_free(ObWaitData *d);
-static ObWaitData* wait_find(const gchar *id);
+static SnStartupSequence* sequence_find(const gchar *id);
 
 static void sn_handler(const XEvent *e, gpointer data);
 static void sn_event_func(SnMonitorEvent *event, gpointer data);
@@ -56,9 +59,13 @@ void sn_startup(gboolean reconfig)
 {
     if (reconfig) return;
 
+    /* unset this so we don't pass it on unknowingly */
+    unsetenv("DESKTOP_STARTUP_ID");
+
     sn_display = sn_display_new(ob_display, NULL, NULL);
     sn_context = sn_monitor_context_new(sn_display, ob_screen,
                                         sn_event_func, NULL, NULL);
+    sn_launcher = sn_launcher_context_new(sn_display, ob_screen);
 
     ob_main_loop_x_add(ob_main_loop, sn_handler, NULL, NULL);
 }
@@ -72,45 +79,26 @@ void sn_shutdown(gboolean reconfig)
     ob_main_loop_x_remove(ob_main_loop, sn_handler);
 
     for (it = sn_waits; it; it = g_slist_next(it))
-        wait_data_free(it->data);
+        sn_startup_sequence_unref((SnStartupSequence*)it->data);
     g_slist_free(sn_waits);
     sn_waits = NULL;
 
     screen_set_root_cursor();
 
+    sn_launcher_context_unref(sn_launcher);
     sn_monitor_context_unref(sn_context);
     sn_display_unref(sn_display);
 }
 
-static ObWaitData* wait_data_new(SnStartupSequence *seq)
-{
-    ObWaitData *d = g_new(ObWaitData, 1);
-    d->seq = seq;
-    d->feedback = TRUE;
-
-    sn_startup_sequence_ref(d->seq);
-
-    return d;
-}
-
-static void wait_data_free(ObWaitData *d)
+static SnStartupSequence* sequence_find(const gchar *id)
 {
-    if (d) {
-        sn_startup_sequence_unref(d->seq);
-
-        g_free(d);
-    }
-}
-
-static ObWaitData* wait_find(const gchar *id)
-{
-    ObWaitData *ret = NULL;
+    SnStartupSequence*ret = NULL;
     GSList *it;
 
     for (it = sn_waits; it; it = g_slist_next(it)) {
-        ObWaitData *d = it->data;
-        if (!strcmp(id, sn_startup_sequence_get_id(d->seq))) {
-            ret = d;
+        SnStartupSequence *seq = it->data;
+        if (!strcmp(id, sn_startup_sequence_get_id(seq))) {
+            ret = seq;
             break;
         }
     }
@@ -119,31 +107,17 @@ static ObWaitData* wait_find(const gchar *id)
 
 gboolean sn_app_starting()
 {
-    GSList *it;
-
-    for (it = sn_waits; it; it = g_slist_next(it)) {
-        ObWaitData *d = it->data;
-        if (d->feedback)
-            return TRUE;
-    }
-    return FALSE;
+    return sn_waits != NULL;
 }
 
 static gboolean sn_wait_timeout(gpointer data)
 {
-    ObWaitData *d = data;
-    d->feedback = FALSE;
+    SnStartupSequence *seq = data;
+    sn_waits = g_slist_remove(sn_waits, seq);
     screen_set_root_cursor();
     return FALSE; /* don't repeat */
 }
 
-static void sn_wait_destroy(gpointer data)
-{
-    ObWaitData *d = data;
-    sn_waits = g_slist_remove(sn_waits, d);
-    wait_data_free(d);
-}
-
 static void sn_handler(const XEvent *e, gpointer data)
 {
     XEvent ec;
@@ -155,18 +129,20 @@ static void sn_event_func(SnMonitorEvent *ev, gpointer data)
 {
     SnStartupSequence *seq;
     gboolean change = FALSE;
-    ObWaitData *d;
 
     if (!(seq = sn_monitor_event_get_startup_sequence(ev)))
         return;
 
     switch (sn_monitor_event_get_type(ev)) {
     case SN_MONITOR_EVENT_INITIATED:
-        d = wait_data_new(seq);
-        sn_waits = g_slist_prepend(sn_waits, d);
-        /* 30 second timeout for apps to start */
+        sn_startup_sequence_ref(seq);
+        sn_waits = g_slist_prepend(sn_waits, seq);
+        /* 30 second timeout for apps to start if the launcher doesn't
+           have a timeout */
         ob_main_loop_timeout_add(ob_main_loop, 30 * G_USEC_PER_SEC,
-                                 sn_wait_timeout, d, sn_wait_destroy);
+                                 sn_wait_timeout, seq,
+                                 g_direct_equal,
+                                 (GDestroyNotify)sn_startup_sequence_unref);
         change = TRUE;
         break;
     case SN_MONITOR_EVENT_CHANGED:
@@ -175,10 +151,10 @@ static void sn_event_func(SnMonitorEvent *ev, gpointer data)
         break;
     case SN_MONITOR_EVENT_COMPLETED:
     case SN_MONITOR_EVENT_CANCELED:
-        if ((d = wait_find(sn_startup_sequence_get_id(seq)))) {
-            d->feedback = FALSE;
+        if ((seq = sequence_find(sn_startup_sequence_get_id(seq)))) {
+            sn_waits = g_slist_remove(sn_waits, seq);
             ob_main_loop_timeout_remove_data(ob_main_loop, sn_wait_timeout,
-                                             d, FALSE);
+                                             seq, FALSE);
             change = TRUE;
         }
         break;
@@ -188,27 +164,54 @@ static void sn_event_func(SnMonitorEvent *ev, gpointer data)
         screen_set_root_cursor();
 }
 
-void sn_app_started(gchar *wmclass)
+Time sn_app_started(const gchar *id, const gchar *wmclass)
 {
     GSList *it;
+    Time t = CurrentTime;
+
+    if (!id && !wmclass)
+        return t;
 
     for (it = sn_waits; it; it = g_slist_next(it)) {
-        ObWaitData *d = it->data;
-        if (sn_startup_sequence_get_wmclass(d->seq) &&
-            !strcmp(sn_startup_sequence_get_wmclass(d->seq), wmclass))
-        {
-            sn_startup_sequence_complete(d->seq);
+        SnStartupSequence *seq = it->data;
+        gboolean found = FALSE;
+        const gchar *seqid, *seqclass, *seqname, *seqbin;
+        seqid = sn_startup_sequence_get_id(seq);
+        seqclass = sn_startup_sequence_get_wmclass(seq);
+        seqname = sn_startup_sequence_get_name(seq);
+        seqbin = sn_startup_sequence_get_binary_name(seq);
+
+        if (id && seqid) {
+            /* if the app has a startup id, then look for that for highest
+               accuracy */
+            if (!strcmp(seqid, id))
+                found = TRUE;
+        } else {
+            seqclass = sn_startup_sequence_get_wmclass(seq);
+            seqname = sn_startup_sequence_get_name(seq);
+            seqbin = sn_startup_sequence_get_binary_name(seq);
+
+            if ((seqname && !g_ascii_strcasecmp(seqname, wmclass)) ||
+                (seqbin && !g_ascii_strcasecmp(seqbin, wmclass)) ||
+                (seqclass && !strcmp(seqclass, wmclass)))
+                found = TRUE;
+        }
+
+        if (found) {
+            sn_startup_sequence_complete(seq);
+            t = sn_startup_sequence_get_timestamp(seq);
             break;
         }
     }
+    return t;
 }
 
 gboolean sn_get_desktop(gchar *id, guint *desktop)
 {
-    ObWaitData *d;
+    SnStartupSequence *seq;
 
-    if (id && (d = wait_find(id))) {
-        gint desk = sn_startup_sequence_get_workspace(d->seq);
+    if (id && (seq = sequence_find(id))) {
+        gint desk = sn_startup_sequence_get_workspace(seq);
         if (desk != -1) {
             *desktop = desk;
             return TRUE;
@@ -217,4 +220,51 @@ gboolean sn_get_desktop(gchar *id, guint *desktop)
     return FALSE;
 }
 
+static gboolean sn_launch_wait_timeout(gpointer data)
+{
+    SnLauncherContext *sn = data;
+    sn_launcher_context_complete(sn);
+    return FALSE; /* don't repeat */
+}
+
+void sn_setup_spawn_environment(gchar *program, gchar *name,
+                                gchar *icon_name, gint desktop,
+                                Time time)
+{
+    gchar *desc;
+    const char *id;
+
+    desc = g_strdup_printf(_("Running %s\n"), program);
+
+    if (sn_launcher_context_get_initiated(sn_launcher)) {
+        sn_launcher_context_unref(sn_launcher);
+        sn_launcher = sn_launcher_context_new(sn_display, ob_screen);
+    }
+
+    sn_launcher_context_set_name(sn_launcher, name ? name : program);
+    sn_launcher_context_set_description(sn_launcher, desc);
+    sn_launcher_context_set_icon_name(sn_launcher, icon_name ? icon_name : program);
+    sn_launcher_context_set_binary_name(sn_launcher, program);
+    if (desktop >= 0 && (unsigned) desktop < screen_num_desktops)
+        sn_launcher_context_set_workspace(sn_launcher, (signed) desktop);
+    sn_launcher_context_initiate(sn_launcher, "openbox", program, time);
+    id = sn_launcher_context_get_startup_id(sn_launcher);
+
+    /* 30 second timeout for apps to start */
+    sn_launcher_context_ref(sn_launcher);
+    ob_main_loop_timeout_add(ob_main_loop, 30 * G_USEC_PER_SEC,
+                             sn_launch_wait_timeout, sn_launcher,
+                             g_direct_equal,
+                             (GDestroyNotify)sn_launcher_context_unref);
+
+    setenv("DESKTOP_STARTUP_ID", id, TRUE);
+
+    g_free(desc);
+}
+
+void sn_spawn_cancel()
+{
+    sn_launcher_context_complete(sn_launcher);
+}
+
 #endif