]> Pileus Git - ~andy/gtk/commitdiff
Implement GAppLaunchContext in gdk, providing startup notification.
authorMatthias Clasen <mclasen@redhat.com>
Thu, 13 Dec 2007 05:16:33 +0000 (05:16 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Thu, 13 Dec 2007 05:16:33 +0000 (05:16 +0000)
2007-12-12  Matthias Clasen  <mclasen@redhat.com>

        * gdk/gdkapplaunchcontext.[hc]: Implement GAppLaunchContext
        in gdk, providing startup notification.  (#503203)

        * gdk/x11/gdkapplaunchcontext-x11.c:
        * gdk/win32/gdkapplaunchcontext-win32.c:
        * gdk/quartz/gdkapplaunchcontext-quartz.c:
        * gdk/directfb/gdkapplaunchcontext-directfb.c: Backend-specific
        parts. All but X11 are just empty stubs for now.

        * gdk/gdk.symbols:
        * gdk/gdkinternals.h:
        * gdk/Makefile.am:
        * gdk/x11/Makefile.am:
        * gdk/win32/Makefile.am:
        * gdk/quartz/Makefile.am:
        * gdk/directfb/Makefile.am: Necessary glue.

svn path=/trunk/; revision=19165

14 files changed:
ChangeLog
gdk/Makefile.am
gdk/directfb/Makefile.am
gdk/directfb/gdkapplaunchcontext-directfb.c [new file with mode: 0644]
gdk/gdk.symbols
gdk/gdkapplaunchcontext.c [new file with mode: 0644]
gdk/gdkapplaunchcontext.h [new file with mode: 0644]
gdk/gdkinternals.h
gdk/quartz/Makefile.am
gdk/quartz/gdkapplaunchcontext-quartz.c [new file with mode: 0644]
gdk/win32/Makefile.am
gdk/win32/gdkapplaunchcontext-win32.c [new file with mode: 0644]
gdk/x11/Makefile.am
gdk/x11/gdkapplaunchcontext-x11.c [new file with mode: 0644]

index ef1605d2443719713f029c499774b17da4b659e8..558433b70ade4720432b56000e0a83df1d8c8ef7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2007-12-12  Matthias Clasen  <mclasen@redhat.com>
+
+       * gdk/gdkapplaunchcontext.[hc]: Implement GAppLaunchContext 
+       in gdk, providing startup notification.  (#503203)
+
+       * gdk/x11/gdkapplaunchcontext-x11.c: 
+       * gdk/win32/gdkapplaunchcontext-win32.c:
+       * gdk/quartz/gdkapplaunchcontext-quartz.c: 
+       * gdk/directfb/gdkapplaunchcontext-directfb.c: Backend-specific
+       parts. All but X11 are just empty stubs for now.
+
+       * gdk/gdk.symbols:
+       * gdk/gdkinternals.h:
+       * gdk/Makefile.am:
+       * gdk/x11/Makefile.am: 
+       * gdk/win32/Makefile.am: 
+       * gdk/quartz/Makefile.am: 
+       * gdk/directfb/Makefile.am: Necessary glue.
+
 2007-12-12  Mathias Hasselmann  <mathias@openismus.com>
 
        * gtk/gtkdnd.c: Another attempt to improve gtk_drag_dest_set docs.
index aeba1389ceebbca55324306d7d17a6e163eb294f..7baec09371d9e07059e3e77e74154484ee322d5b 100644 (file)
@@ -64,6 +64,7 @@ endif
 #
 gdk_public_h_sources =                         \
        gdk.h                                   \
+       gdkapplaunchcontext.h                   \
        gdkcairo.h                              \
        gdkcolor.h                              \
        gdkcursor.h                             \
@@ -102,6 +103,7 @@ gdk_headers =                     \
 gdk_c_sources =                 \
        $(medialib_sources)     \
        gdk.c                   \
+       gdkapplaunchcontext.c   \
        gdkcairo.c              \
        gdkcolor.c              \
        gdkcursor.c             \
index 6e5f27296873fc26453869d120bbfacc45bf3789..e7b7966eaf6d2b5925302276b3f133d70f86793c 100644 (file)
@@ -19,6 +19,7 @@ LDADDS =              \
 noinst_LTLIBRARIES = libgdk-directfb.la
 
 libgdk_directfb_la_SOURCES =   \
+       gdkapplaunchcontext-directfb.c \
        gdkcolor-directfb.c     \
        gdkcursor-directfb.c    \
        gdkdnd-directfb.c       \
diff --git a/gdk/directfb/gdkapplaunchcontext-directfb.c b/gdk/directfb/gdkapplaunchcontext-directfb.c
new file mode 100644 (file)
index 0000000..f838ad2
--- /dev/null
@@ -0,0 +1,42 @@
+/* gdkapplaunchcontext-directfb.c - Gtk+ implementation for GAppLaunchContext
+
+   Copyright (C) 2007 Red Hat, Inc.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Matthias Clasen <mclasen@redhat.com>
+*/
+
+#include <config.h>
+
+#include "gdkapplaunchcontext.h"
+
+
+char *
+_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
+                                      GAppInfo          *info,
+                                      GList             *files)
+{
+       return NULL;
+}
+
+void
+_gdk_windowing_launch_failed (GAppLaunchContext *context,
+                              const char        *startup_notify_id)
+{
+}
+
+
index 1512936339966d3f87ccb4d9e085b7daff6bd2c6..40f05a2f5e88d3369dd099b1b6a0f2b2e94b2411 100644 (file)
@@ -1254,6 +1254,18 @@ gdk_xid_table_lookup_for_display
 #endif
 #endif
 
+#if IN_HEADER(__GDK_APP_LAUNCH_CONTEXT_H__)
+#if IN_FILE(__GDK_APP_LAUNCH_CONTEXT_C__)
+gdk_app_launch_context_new
+gdk_app_launch_context_set_display
+gdk_app_launch_context_set_screen
+gdk_app_launch_context_set_desktop
+gdk_app_launch_context_set_timestamp
+gdk_app_launch_context_set_icon
+gdk_app_launch_context_set_icon_name
+#endif
+#endif
+
 #ifdef INCLUDE_VARIABLES
 gdk_threads_mutex
 gdk_threads_lock
diff --git a/gdk/gdkapplaunchcontext.c b/gdk/gdkapplaunchcontext.c
new file mode 100644 (file)
index 0000000..d63a2fc
--- /dev/null
@@ -0,0 +1,186 @@
+/* gdkapplaunchcontext.c - Gtk+ implementation for GAppLaunchContext
+
+   Copyright (C) 2007 Red Hat, Inc.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#include <config.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <gio/gfileicon.h>
+#include <gio/gthemedicon.h>
+
+#include "gdkapplaunchcontext.h"
+#include "gdkinternals.h"
+#include "gdkscreen.h"
+#include "gdkintl.h"
+#include "gdkalias.h"
+
+
+G_DEFINE_TYPE (GdkAppLaunchContext, gdk_app_launch_context,
+              G_TYPE_APP_LAUNCH_CONTEXT);
+
+static void
+gdk_app_launch_context_finalize (GObject *object)
+{
+  GdkAppLaunchContext *context;
+  GdkAppLaunchContextPrivate *priv;
+
+  context = GDK_APP_LAUNCH_CONTEXT (object);
+
+  priv = context->priv;
+
+  if (priv->display)
+    g_object_unref (priv->display);
+
+  if (priv->screen)
+    g_object_unref (priv->screen);
+
+  if (priv->icon)
+    g_object_unref (priv->icon);
+
+  g_free (priv->icon_name);
+
+  (*G_OBJECT_CLASS (gdk_app_launch_context_parent_class)->finalize) (object);
+}
+
+static char *
+get_display (GAppLaunchContext *context, 
+             GAppInfo          *info, 
+             GList             *files)
+{
+  GdkDisplay *display;
+  GdkAppLaunchContextPrivate *priv;
+
+  priv = GDK_APP_LAUNCH_CONTEXT (context)->priv;
+
+  if (priv->screen)
+    return gdk_screen_make_display_name (priv->screen);
+
+  if (priv->display)
+    display = priv->display;
+  else
+    display = gdk_display_get_default ();
+
+  return g_strdup (gdk_display_get_name (display));
+}
+
+static void
+gdk_app_launch_context_class_init (GdkAppLaunchContextClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GAppLaunchContextClass *context_class = G_APP_LAUNCH_CONTEXT_CLASS (klass);
+
+  gobject_class->finalize = gdk_app_launch_context_finalize;
+
+  context_class->get_display = get_display;
+  context_class->get_startup_notify_id = _gdk_windowing_get_startup_notify_id;
+  context_class->launch_failed = _gdk_windowing_launch_failed;
+
+  g_type_class_add_private (klass, sizeof (GdkAppLaunchContextPrivate));
+}
+
+static void
+gdk_app_launch_context_init (GdkAppLaunchContext *context)
+{
+  context->priv = G_TYPE_INSTANCE_GET_PRIVATE (context,
+                                              GDK_TYPE_APP_LAUNCH_CONTEXT,
+                                              GdkAppLaunchContextPrivate);
+  context->priv->workspace = -1;
+}
+
+void
+gdk_app_launch_context_set_display (GdkAppLaunchContext *context,
+                                   GdkDisplay          *display)
+{
+  if (context->priv->display)
+    {
+      g_object_unref (context->priv->display);
+      context->priv->display = NULL;
+    }
+
+  if (display)
+    context->priv->display = g_object_ref (display);
+}
+void
+gdk_app_launch_context_set_screen (GdkAppLaunchContext *context,
+                                  GdkScreen           *screen)
+{
+  if (context->priv->screen)
+    {
+      g_object_unref (context->priv->screen);
+      context->priv->screen = NULL;
+    }
+
+  if (screen)
+    context->priv->screen = g_object_ref (screen);
+}
+
+
+void
+gdk_app_launch_context_set_desktop (GdkAppLaunchContext *context,
+                                   gint                 desktop)
+{
+  context->priv->workspace = desktop;
+}
+
+void
+gdk_app_launch_context_set_timestamp (GdkAppLaunchContext *context,
+                                     guint32              timestamp)
+{
+  context->priv->timestamp = timestamp;
+}
+
+void
+gdk_app_launch_context_set_icon (GdkAppLaunchContext *context, 
+                                 GIcon               *icon)
+{
+  if (context->priv->icon)
+    {
+      g_object_unref (context->priv->icon);
+      context->priv->icon = NULL;
+    }
+
+  if (icon)
+    context->priv->icon = g_object_ref (icon);
+}
+
+void
+gdk_app_launch_context_set_icon_name (GdkAppLaunchContext *context,
+                                     const char          *icon_name)
+{
+  g_free (context->priv->icon_name);
+  context->priv->icon_name = g_strdup (icon_name);
+}
+
+GdkAppLaunchContext *
+gdk_app_launch_context_new (void)
+{
+  GdkAppLaunchContext *context;
+
+  context = g_object_new (gdk_app_launch_context_get_type (), NULL);
+  return context;
+}
+
+
+#define __GDK_APP_LAUNCH_CONTEXT_C__
+#include "gdkaliasdef.c"
diff --git a/gdk/gdkapplaunchcontext.h b/gdk/gdkapplaunchcontext.h
new file mode 100644 (file)
index 0000000..70b814c
--- /dev/null
@@ -0,0 +1,75 @@
+/* gdkapplaunchcontext.h - Gtk+ implementation for GAppLaunchContext
+
+   Copyright (C) 2007 Red Hat, Inc.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#ifndef __GDK_APP_LAUNCH_CONTEXT_H__
+#define __GDK_APP_LAUNCH_CONTEXT_H__
+
+#include <glib.h>
+#include <gio/gappinfo.h>
+#include <gdk/gdkdisplay.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_APP_LAUNCH_CONTEXT         (gdk_app_launch_context_get_type ())
+#define GDK_APP_LAUNCH_CONTEXT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_APP_LAUNCH_CONTEXT, GdkAppLaunchContext))
+#define GDK_APP_LAUNCH_CONTEXT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDK_TYPE_APP_LAUNCH_CONTEXT, GdkAppLaunchContextClass))
+#define GDK_IS_APP_LAUNCH_CONTEXT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDGDK_TYPE_APP_LAUNCH_CONTEXT))
+#define GDK_IS_APP_LAUNCH_CONTEXT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDK_TYPE_APP_LAUNCH_CONTEXT))
+#define GDK_APP_LAUNCH_CONTEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_APP_LAUNCH_CONTEXT, GdkAppLaunchContextClass))
+
+typedef struct GdkAppLaunchContext           GdkAppLaunchContext;
+typedef struct GdkAppLaunchContextClass       GdkAppLaunchContextClass;
+typedef struct GdkAppLaunchContextPrivate     GdkAppLaunchContextPrivate;
+
+struct GdkAppLaunchContext
+{
+       GAppLaunchContext parent_instance;
+       
+       GdkAppLaunchContextPrivate *priv;
+};
+
+struct GdkAppLaunchContextClass 
+{
+       GAppLaunchContextClass parent_class;
+};
+
+GType gdk_app_launch_context_get_type (void);
+
+GdkAppLaunchContext *gdk_app_launch_context_new           (void);
+void                 gdk_app_launch_context_set_display   (GdkAppLaunchContext *context,
+                                                          GdkDisplay          *display);
+void                 gdk_app_launch_context_set_screen    (GdkAppLaunchContext *context,
+                                                          GdkScreen           *screen);
+void                 gdk_app_launch_context_set_desktop   (GdkAppLaunchContext *context,
+                                                          gint                 desktop);
+void                 gdk_app_launch_context_set_timestamp (GdkAppLaunchContext *context,
+                                                          guint32              timestamp);
+void                 gdk_app_launch_context_set_icon      (GdkAppLaunchContext *context,
+                                                          GIcon               *icon);
+void                 gdk_app_launch_context_set_icon_name (GdkAppLaunchContext *context,
+                                                          const char          *icon_name);
+
+G_END_DECLS
+
+#endif /* __GDK_APP_LAUNCH_CONTEXT_H__ */
+
+
index 45887c27c5df122a0f43e59d7e650577c9de45b2..b8c84c51dc1da16247ab1b08fcb25a8682b6a1ce 100644 (file)
@@ -409,6 +409,23 @@ void _gdk_windowing_gc_get_foreground (GdkGC    *gc,
 void _gdk_windowing_gc_get_background (GdkGC    *gc,
                                       GdkColor *color);
 
+struct GdkAppLaunchContextPrivate
+{
+  GdkDisplay *display;
+  GdkScreen *screen;
+  gint workspace;
+  guint32 timestamp;
+  GIcon *icon;
+  char *icon_name;
+};
+
+char *_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
+                                           GAppInfo          *info, 
+                                           GList             *files);
+void  _gdk_windowing_launch_failed         (GAppLaunchContext *context, 
+                                           const char        *startup_notify_id);
+
+
 /************************************
  * Initialization and exit routines *
  ************************************/
index bbf7db58f8051b8766a9c19ec6ec574dd442bb38..2e2fbc888f9faa01dd843c282e418d2e06006f73 100644 (file)
@@ -21,6 +21,7 @@ libgdk_quartz_la_SOURCES =            \
        GdkQuartzView.h         \
        GdkQuartzWindow.c       \
        GdkQuartzWindow.h       \
+       gdkapplaunchcontext-quartz.c \
        gdkcolor-quartz.c       \
        gdkcursor-quartz.c      \
        gdkdisplay-quartz.c     \
diff --git a/gdk/quartz/gdkapplaunchcontext-quartz.c b/gdk/quartz/gdkapplaunchcontext-quartz.c
new file mode 100644 (file)
index 0000000..769e476
--- /dev/null
@@ -0,0 +1,42 @@
+/* gdkapplaunchcontext-quartz.c - Gtk+ implementation for GAppLaunchContext
+
+   Copyright (C) 2007 Red Hat, Inc.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Matthias Clasen <mclasen@redhat.com>
+*/
+
+#include <config.h>
+
+#include "gdkapplaunchcontext.h"
+
+
+char *
+_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
+                                      GAppInfo          *info,
+                                      GList             *files)
+{
+       return NULL;
+}
+
+void
+_gdk_windowing_launch_failed (GAppLaunchContext *context,
+                              const char        *startup_notify_id)
+{
+}
+
+
index 08f58775a19ffba1c89eb86e242d56ce7ecef461..02f8c2f7aa86cc34fffb30280d7e9ac5f8fdb342 100644 (file)
@@ -26,6 +26,7 @@ EXTRA_DIST += \
 
 libgdk_win32_la_SOURCES = \
        xcursors.h \
+       gdkapplaunchcontext-win32.c \
        gdkcolor-win32.c \
        gdkcursor-win32.c \
        gdkdisplay-win32.c \
diff --git a/gdk/win32/gdkapplaunchcontext-win32.c b/gdk/win32/gdkapplaunchcontext-win32.c
new file mode 100644 (file)
index 0000000..39a53e9
--- /dev/null
@@ -0,0 +1,42 @@
+/* gdkapplaunchcontext-win32.c - Gtk+ implementation for GAppLaunchContext
+
+   Copyright (C) 2007 Red Hat, Inc.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Matthias Clasen <mclasen@redhat.com>
+*/
+
+#include <config.h>
+
+#include "gdkapplaunchcontext.h"
+
+
+char *
+_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
+                                      GAppInfo          *info,
+                                      GList             *files)
+{
+       return NULL;
+}
+
+void
+_gdk_windowing_launch_failed (GAppLaunchContext *context,
+                              const char        *startup_notify_id)
+{
+}
+
+
index 11b284bd1890c4fa3fd00990a3c55e8d7574e5b6..eb88a70cd0208195a7d639afd21bf9adae6ed393 100644 (file)
@@ -19,6 +19,7 @@ noinst_LTLIBRARIES = libgdk-x11.la
 
 libgdk_x11_la_SOURCES =        \
        MwmUtil.h               \
+       gdkapplaunchcontext-x11.c \
        gdkasync.c              \
        gdkasync.h              \
        gdkcolor-x11.c          \
diff --git a/gdk/x11/gdkapplaunchcontext-x11.c b/gdk/x11/gdkapplaunchcontext-x11.c
new file mode 100644 (file)
index 0000000..17d3340
--- /dev/null
@@ -0,0 +1,424 @@
+/* gdkapplaunchcontext-x11.c - Gtk+ implementation for GAppLaunchContext
+
+   Copyright (C) 2007 Red Hat, Inc.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#include <config.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <gio/gfileicon.h>
+#include <gio/gthemedicon.h>
+
+#include "gdkx.h"
+#include "gdkapplaunchcontext.h"
+#include "gdkscreen.h"
+#include "gdkinternals.h"
+#include "gdkintl.h"
+#include "gdkalias.h"
+
+
+static char *
+get_display_name (GFile *file)
+{
+  GFileInfo *info;
+  char *name, *tmp;
+
+  /* This does sync I/O, which isn't ideal.
+   * It should probably use the NautilusFile machinery
+   */
+
+  name = NULL;
+  info = g_file_query_info (file,
+                           G_FILE_ATTRIBUTE_STD_DISPLAY_NAME, 0, NULL, NULL);
+  if (info)
+    {
+      name = g_strdup (g_file_info_get_display_name (info));
+      g_object_unref (info);
+    }
+
+  if (name == NULL)
+    {
+      name = g_file_get_basename (file);
+      if (!g_utf8_validate (name, -1, NULL))
+       {
+         tmp = name;
+         name =
+           g_uri_escape_string (name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH,
+                                TRUE);
+         g_free (tmp);
+       }
+    }
+
+  return name;
+}
+
+static GIcon *
+get_icon (GFile *file)
+{
+  GFileInfo *info;
+  GIcon *icon;
+
+  icon = NULL;
+  info = g_file_query_info (file, G_FILE_ATTRIBUTE_STD_ICON, 0, NULL, NULL);
+  if (info)
+    {
+      icon = g_file_info_get_icon (info);
+      if (icon)
+       g_object_ref (icon);
+      g_object_unref (info);
+    }
+
+  return icon;
+}
+
+static char *
+gicon_to_string (GIcon *icon)
+{
+  GFile *file;
+  const char *const *names;
+
+  if (G_IS_FILE_ICON (icon))
+    {
+      file = g_file_icon_get_file (G_FILE_ICON (icon));
+      if (file)
+       return g_file_get_path (file);
+    }
+  else if (G_IS_THEMED_ICON (icon))
+    {
+      names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+      if (names)
+       return g_strdup (names[0]);
+    }
+
+  return NULL;
+}
+
+static void
+end_startup_notification (GdkDisplay *display,
+                         const char *startup_id)
+{
+  gdk_x11_display_broadcast_startup_message (display, "remove",
+                                            "ID", startup_id,
+                                            NULL);
+}
+
+
+/* This should be fairly long, as it's confusing to users if a startup
+ * ends when it shouldn't (it appears that the startup failed, and
+ * they have to relaunch the app). Also the timeout only matters when
+ * there are bugs and apps don't end their own startup sequence.
+ *
+ * This timeout is a "last resort" timeout that ignores whether the
+ * startup sequence has shown activity or not.  Metacity and the
+ * tasklist have smarter, and correspondingly able-to-be-shorter
+ * timeouts. The reason our timeout is dumb is that we don't monitor
+ * the sequence (don't use an SnMonitorContext)
+ */
+#define STARTUP_TIMEOUT_LENGTH_SECONDS 30 
+#define STARTUP_TIMEOUT_LENGTH (STARTUP_TIMEOUT_LENGTH_SECONDS * 1000)
+
+typedef struct 
+{
+  GdkDisplay *display;
+  char *startup_id;
+  GTimeVal time;
+} StartupNotificationData;
+
+static void
+free_startup_notification_data (gpointer data)
+{
+  StartupNotificationData *sn_data = data;
+
+  g_object_unref (sn_data->display);
+  g_free (sn_data->startup_id);
+  g_free (sn_data);
+}
+
+typedef struct 
+{
+  GSList *contexts;
+  guint timeout_id;
+} StartupTimeoutData;
+
+static void
+free_startup_timeout (void *data)
+{
+  StartupTimeoutData *std;
+
+  std = data;
+
+  g_slist_foreach (std->contexts, (GFunc) free_startup_notification_data, NULL);
+  g_slist_free (std->contexts);
+
+  if (std->timeout_id != 0)
+    {
+      g_source_remove (std->timeout_id);
+      std->timeout_id = 0;
+    }
+
+  g_free (std);
+}
+
+static gboolean
+startup_timeout (void *data)
+{
+  StartupTimeoutData *std;
+  GSList *tmp;
+  GTimeVal now;
+  int min_timeout;
+
+  std = data;
+
+  min_timeout = STARTUP_TIMEOUT_LENGTH;
+
+  g_get_current_time (&now);
+
+  tmp = std->contexts;
+  while (tmp != NULL)
+    {
+      StartupNotificationData *sn_data;
+      GSList *next;
+      double elapsed;
+
+      sn_data = tmp->data;
+      next = tmp->next;
+
+      elapsed =
+       ((((double) now.tv_sec - sn_data->time.tv_sec) * G_USEC_PER_SEC +
+         (now.tv_usec - sn_data->time.tv_usec))) / 1000.0;
+
+      if (elapsed >= STARTUP_TIMEOUT_LENGTH)
+       {
+         std->contexts = g_slist_remove (std->contexts, sn_data);
+         end_startup_notification (sn_data->display, sn_data->startup_id);
+         free_startup_notification_data (sn_data);
+       }
+      else
+       {
+         min_timeout = MIN (min_timeout, (STARTUP_TIMEOUT_LENGTH - elapsed));
+       }
+
+      tmp = next;
+    }
+
+  if (std->contexts == NULL)
+    std->timeout_id = 0;
+  else
+    std->timeout_id = g_timeout_add_seconds ((min_timeout + 500)/1000, startup_timeout, std);
+
+  /* always remove this one, but we may have reinstalled another one. */
+  return FALSE;
+}
+
+
+static void
+add_startup_timeout (GdkScreen  *screen,
+                    const char *startup_id)
+{
+  StartupTimeoutData *data;
+  StartupNotificationData *sn_data;
+
+  data = g_object_get_data (G_OBJECT (screen), "appinfo-startup-data");
+
+  if (data == NULL)
+    {
+      data = g_new (StartupTimeoutData, 1);
+      data->contexts = NULL;
+      data->timeout_id = 0;
+
+      g_object_set_data_full (G_OBJECT (screen), "appinfo-startup-data",
+                             data, free_startup_timeout);
+    }
+
+  sn_data = g_new (StartupNotificationData, 1);
+  sn_data->display = g_object_ref (gdk_screen_get_display (screen));
+  sn_data->startup_id = g_strdup (startup_id);
+  g_get_current_time (&sn_data->time);
+
+  data->contexts = g_slist_prepend (data->contexts, sn_data);
+
+  if (data->timeout_id == 0)
+    data->timeout_id = g_timeout_add_seconds (STARTUP_TIMEOUT_LENGTH_SECONDS,
+                                             startup_timeout, data);
+}
+
+
+char *
+_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
+                                     GAppInfo          *info, 
+                                     GList             *files)
+{
+  static int sequence = 0;
+  GdkAppLaunchContextPrivate *priv;
+  GdkDisplay *display;
+  GdkScreen *screen;
+  int files_count;
+  char *description;
+  char *icon_name;
+  const char *binary_name;
+  char *screen_str;
+  char *workspace_str;
+  GIcon *icon;
+  guint32 timestamp;
+  char *startup_id;
+
+  priv = GDK_APP_LAUNCH_CONTEXT (context)->priv;
+
+  if (priv->screen)
+    {
+      screen = priv->screen;
+      display = gdk_screen_get_display (priv->screen);
+    }
+  else if (priv->display)
+    {
+      display = priv->display;
+      screen = gdk_display_get_default_screen (display);
+    }
+  else
+    {
+      display = gdk_display_get_default ();
+      screen = gdk_display_get_default_screen (display);
+    }
+
+  files_count = g_list_length (files);
+  if (files_count == 0)
+    description = g_strdup_printf (_("Starting %s"), g_app_info_get_name (info));
+  else if (files_count == 1)
+    description = g_strdup_printf (_("Opening %s"), get_display_name (files->data));
+  else
+    description = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+                                             "Opening %d Item",
+                                             "Opening %d Items",
+                                             files_count), files_count);
+
+  icon_name = NULL;
+  if (priv->icon_name)
+    icon_name = g_strdup (priv->icon_name);
+  else
+    {
+      icon = NULL;
+
+      if (priv->icon != NULL)
+       icon = g_object_ref (priv->icon);
+      else if (files_count == 1)
+       icon = get_icon (files->data);
+
+      if (icon == NULL)
+       {
+         icon = g_app_info_get_icon (info);
+         g_object_ref (icon);
+       }
+
+      if (icon)
+       icon_name = gicon_to_string (icon);
+
+      g_object_unref (icon);
+    }
+
+  binary_name = g_app_info_get_executable (info);
+
+  timestamp = priv->timestamp;
+  if (timestamp == GDK_CURRENT_TIME)
+    timestamp = gdk_x11_display_get_user_time (display);
+
+  screen_str = g_strdup_printf ("%d", gdk_screen_get_number (screen));
+  if (priv->workspace > -1) 
+    workspace_str = g_strdup_printf ("%d", priv->workspace);
+  else
+    workspace_str = NULL;
+
+
+  startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu",
+                               g_get_prgname (),
+                               (unsigned long)getpid (),
+                               g_get_host_name (),
+                               binary_name,
+                               sequence++,
+                               (unsigned long)timestamp);
+
+  
+  gdk_x11_display_broadcast_startup_message (display, "new",
+                                            "ID", startup_id,
+                                            "NAME", g_app_info_get_name (info),
+                                            "SCREEN", screen_str,
+                                            "BIN", binary_name,
+                                            "ICON", icon_name,
+                                            "DESKTOP", workspace_str,
+                                            "DESCRIPTION", description,
+                                            "WMCLASS", NULL, /* FIXME */
+                                            NULL);
+
+  g_free (description);
+  g_free (screen_str);
+  g_free (workspace_str);
+  g_free (icon_name);
+
+  add_startup_timeout (screen, startup_id);
+
+  return startup_id;
+}
+
+
+void
+_gdk_windowing_launch_failed (GAppLaunchContext *context, 
+                             const char        *startup_notify_id)
+{
+  GdkAppLaunchContextPrivate *priv;
+  GdkScreen *screen;
+  StartupTimeoutData *data;
+  StartupNotificationData *sn_data;
+  GSList *l;
+
+  priv = GDK_APP_LAUNCH_CONTEXT (context)->priv;
+
+  if (priv->screen)
+    screen = priv->screen;
+  else if (priv->display)
+    screen = gdk_display_get_default_screen (priv->display);
+  else
+    screen = gdk_display_get_default_screen (gdk_display_get_default ());
+
+  data = g_object_get_data (G_OBJECT (screen), "appinfo-startup-data");
+
+  if (data)
+    {
+      for (l = data->contexts; l != NULL; l = l->next)
+       {
+         sn_data = l->data;
+         if (strcmp (startup_notify_id, sn_data->startup_id) == 0)
+           {
+             data->contexts = g_slist_remove (data->contexts, sn_data);
+             end_startup_notification (sn_data->display, sn_data->startup_id);
+             free_startup_notification_data (sn_data);
+                                             
+             break;
+           }
+       }
+
+      if (data->contexts == NULL)
+       {
+         g_source_remove (data->timeout_id);
+         data->timeout_id = 0;
+       }
+    }
+}