1 /* gdkapplaunchcontext-x11.c - Gtk+ implementation for GAppLaunchContext
3 Copyright (C) 2007 Red Hat, Inc.
5 The Gnome Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The Gnome Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the Gnome Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
20 Author: Alexander Larsson <alexl@redhat.com>
31 #include "gdkapplaunchcontext.h"
32 #include "gdkscreen.h"
33 #include "gdkinternals.h"
39 get_display_name (GFile *file)
44 /* This does sync I/O, which isn't ideal.
45 * It should probably use the NautilusFile machinery
49 info = g_file_query_info (file,
50 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, 0, NULL, NULL);
53 name = g_strdup (g_file_info_get_display_name (info));
54 g_object_unref (info);
59 name = g_file_get_basename (file);
60 if (!g_utf8_validate (name, -1, NULL))
64 g_uri_escape_string (name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH,
74 get_icon (GFile *file)
80 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_ICON, 0, NULL, NULL);
83 icon = g_file_info_get_icon (info);
86 g_object_unref (info);
93 gicon_to_string (GIcon *icon)
96 const char *const *names;
98 if (G_IS_FILE_ICON (icon))
100 file = g_file_icon_get_file (G_FILE_ICON (icon));
102 return g_file_get_path (file);
104 else if (G_IS_THEMED_ICON (icon))
106 names = g_themed_icon_get_names (G_THEMED_ICON (icon));
108 return g_strdup (names[0]);
115 end_startup_notification (GdkDisplay *display,
116 const char *startup_id)
118 gdk_x11_display_broadcast_startup_message (display, "remove",
124 /* This should be fairly long, as it's confusing to users if a startup
125 * ends when it shouldn't (it appears that the startup failed, and
126 * they have to relaunch the app). Also the timeout only matters when
127 * there are bugs and apps don't end their own startup sequence.
129 * This timeout is a "last resort" timeout that ignores whether the
130 * startup sequence has shown activity or not. Metacity and the
131 * tasklist have smarter, and correspondingly able-to-be-shorter
132 * timeouts. The reason our timeout is dumb is that we don't monitor
133 * the sequence (don't use an SnMonitorContext)
135 #define STARTUP_TIMEOUT_LENGTH_SECONDS 30
136 #define STARTUP_TIMEOUT_LENGTH (STARTUP_TIMEOUT_LENGTH_SECONDS * 1000)
143 } StartupNotificationData;
146 free_startup_notification_data (gpointer data)
148 StartupNotificationData *sn_data = data;
150 g_object_unref (sn_data->display);
151 g_free (sn_data->startup_id);
159 } StartupTimeoutData;
162 free_startup_timeout (void *data)
164 StartupTimeoutData *std;
168 g_slist_foreach (std->contexts, (GFunc) free_startup_notification_data, NULL);
169 g_slist_free (std->contexts);
171 if (std->timeout_id != 0)
173 g_source_remove (std->timeout_id);
181 startup_timeout (void *data)
183 StartupTimeoutData *std;
190 min_timeout = STARTUP_TIMEOUT_LENGTH;
192 g_get_current_time (&now);
197 StartupNotificationData *sn_data;
205 ((((double) now.tv_sec - sn_data->time.tv_sec) * G_USEC_PER_SEC +
206 (now.tv_usec - sn_data->time.tv_usec))) / 1000.0;
208 if (elapsed >= STARTUP_TIMEOUT_LENGTH)
210 std->contexts = g_slist_remove (std->contexts, sn_data);
211 end_startup_notification (sn_data->display, sn_data->startup_id);
212 free_startup_notification_data (sn_data);
216 min_timeout = MIN (min_timeout, (STARTUP_TIMEOUT_LENGTH - elapsed));
222 if (std->contexts == NULL)
225 std->timeout_id = g_timeout_add_seconds ((min_timeout + 500)/1000, startup_timeout, std);
227 /* always remove this one, but we may have reinstalled another one. */
233 add_startup_timeout (GdkScreen *screen,
234 const char *startup_id)
236 StartupTimeoutData *data;
237 StartupNotificationData *sn_data;
239 data = g_object_get_data (G_OBJECT (screen), "appinfo-startup-data");
243 data = g_new (StartupTimeoutData, 1);
244 data->contexts = NULL;
245 data->timeout_id = 0;
247 g_object_set_data_full (G_OBJECT (screen), "appinfo-startup-data",
248 data, free_startup_timeout);
251 sn_data = g_new (StartupNotificationData, 1);
252 sn_data->display = g_object_ref (gdk_screen_get_display (screen));
253 sn_data->startup_id = g_strdup (startup_id);
254 g_get_current_time (&sn_data->time);
256 data->contexts = g_slist_prepend (data->contexts, sn_data);
258 if (data->timeout_id == 0)
259 data->timeout_id = g_timeout_add_seconds (STARTUP_TIMEOUT_LENGTH_SECONDS,
260 startup_timeout, data);
265 _gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
269 static int sequence = 0;
270 GdkAppLaunchContextPrivate *priv;
276 const char *binary_name;
283 priv = GDK_APP_LAUNCH_CONTEXT (context)->priv;
287 screen = priv->screen;
288 display = gdk_screen_get_display (priv->screen);
290 else if (priv->display)
292 display = priv->display;
293 screen = gdk_display_get_default_screen (display);
297 display = gdk_display_get_default ();
298 screen = gdk_display_get_default_screen (display);
301 files_count = g_list_length (files);
302 if (files_count == 0)
303 description = g_strdup_printf (_("Starting %s"), g_app_info_get_name (info));
304 else if (files_count == 1)
305 description = g_strdup_printf (_("Opening %s"), get_display_name (files->data));
307 description = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
310 files_count), files_count);
314 icon_name = g_strdup (priv->icon_name);
319 if (priv->icon != NULL)
320 icon = g_object_ref (priv->icon);
321 else if (files_count == 1)
322 icon = get_icon (files->data);
326 icon = g_app_info_get_icon (info);
331 icon_name = gicon_to_string (icon);
333 g_object_unref (icon);
336 binary_name = g_app_info_get_executable (info);
338 timestamp = priv->timestamp;
339 if (timestamp == GDK_CURRENT_TIME)
340 timestamp = gdk_x11_display_get_user_time (display);
342 screen_str = g_strdup_printf ("%d", gdk_screen_get_number (screen));
343 if (priv->workspace > -1)
344 workspace_str = g_strdup_printf ("%d", priv->workspace);
346 workspace_str = NULL;
349 startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu",
351 (unsigned long)getpid (),
355 (unsigned long)timestamp);
358 gdk_x11_display_broadcast_startup_message (display, "new",
360 "NAME", g_app_info_get_name (info),
361 "SCREEN", screen_str,
364 "DESKTOP", workspace_str,
365 "DESCRIPTION", description,
366 "WMCLASS", NULL, /* FIXME */
369 g_free (description);
371 g_free (workspace_str);
374 add_startup_timeout (screen, startup_id);
381 _gdk_windowing_launch_failed (GAppLaunchContext *context,
382 const char *startup_notify_id)
384 GdkAppLaunchContextPrivate *priv;
386 StartupTimeoutData *data;
387 StartupNotificationData *sn_data;
390 priv = GDK_APP_LAUNCH_CONTEXT (context)->priv;
393 screen = priv->screen;
394 else if (priv->display)
395 screen = gdk_display_get_default_screen (priv->display);
397 screen = gdk_display_get_default_screen (gdk_display_get_default ());
399 data = g_object_get_data (G_OBJECT (screen), "appinfo-startup-data");
403 for (l = data->contexts; l != NULL; l = l->next)
406 if (strcmp (startup_notify_id, sn_data->startup_id) == 0)
408 data->contexts = g_slist_remove (data->contexts, sn_data);
409 end_startup_notification (sn_data->display, sn_data->startup_id);
410 free_startup_notification_data (sn_data);
416 if (data->contexts == NULL)
418 g_source_remove (data->timeout_id);
419 data->timeout_id = 0;