+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.
#
gdk_public_h_sources = \
gdk.h \
+ gdkapplaunchcontext.h \
gdkcairo.h \
gdkcolor.h \
gdkcursor.h \
gdk_c_sources = \
$(medialib_sources) \
gdk.c \
+ gdkapplaunchcontext.c \
gdkcairo.c \
gdkcolor.c \
gdkcursor.c \
noinst_LTLIBRARIES = libgdk-directfb.la
libgdk_directfb_la_SOURCES = \
+ gdkapplaunchcontext-directfb.c \
gdkcolor-directfb.c \
gdkcursor-directfb.c \
gdkdnd-directfb.c \
--- /dev/null
+/* 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)
+{
+}
+
+
#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
--- /dev/null
+/* 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"
--- /dev/null
+/* 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__ */
+
+
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 *
************************************/
GdkQuartzView.h \
GdkQuartzWindow.c \
GdkQuartzWindow.h \
+ gdkapplaunchcontext-quartz.c \
gdkcolor-quartz.c \
gdkcursor-quartz.c \
gdkdisplay-quartz.c \
--- /dev/null
+/* 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)
+{
+}
+
+
libgdk_win32_la_SOURCES = \
xcursors.h \
+ gdkapplaunchcontext-win32.c \
gdkcolor-win32.c \
gdkcursor-win32.c \
gdkdisplay-win32.c \
--- /dev/null
+/* 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)
+{
+}
+
+
libgdk_x11_la_SOURCES = \
MwmUtil.h \
+ gdkapplaunchcontext-x11.c \
gdkasync.c \
gdkasync.h \
gdkcolor-x11.c \
--- /dev/null
+/* 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;
+ }
+ }
+}