diff --git a/ChangeLog b/ChangeLog index 7e6252ff06..39fb620bc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +Sat Nov 2 00:22:33 2002 Owen Taylor + + Add startup notification hooks - mostly based on patch + by Havoc Pennington in #96772. + + * gdk/gdk.h gdk/x11/gdkdisplay-x11.c + gdk/{win32,linux-fb}/gdkmain-*.c: (gdk_notify_startup_complete): + new function that indicates an application has finished starting + up. + + * gdk/x11/gdkmain-x11.c gdk/x11/gdkdisplay-x11.c + (_gdk_windowing_set_default_display): store value of + DESKTOP_STARTUP_ID on the default screen, and clear it from the + environment. + + * gdk/x11/gdkdisplay-x11.c: + Set _NET_STARTUP_ID hint on display's group leader window. + + * gtk/gtkwindow.c (gtk_window_set_auto_startup_notification): + function to toggle whether we automatically broadcast that we've + started up, after mapping the first toplevel window. + (gtk_window_map): call gdk_screen_notify_startup_complete() by + default, unless enabled by above. + + * gtk/gtkmain.c gtk/gtkcombo.c gtk/gtktoolbar.c: + Couple of warning fixes. + Fri Nov 1 21:03:59 2002 Owen Taylor * gtk/gtkfilesel.c: Add a mnemonic to the "selection" diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 7e6252ff06..39fb620bc2 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,30 @@ +Sat Nov 2 00:22:33 2002 Owen Taylor + + Add startup notification hooks - mostly based on patch + by Havoc Pennington in #96772. + + * gdk/gdk.h gdk/x11/gdkdisplay-x11.c + gdk/{win32,linux-fb}/gdkmain-*.c: (gdk_notify_startup_complete): + new function that indicates an application has finished starting + up. + + * gdk/x11/gdkmain-x11.c gdk/x11/gdkdisplay-x11.c + (_gdk_windowing_set_default_display): store value of + DESKTOP_STARTUP_ID on the default screen, and clear it from the + environment. + + * gdk/x11/gdkdisplay-x11.c: + Set _NET_STARTUP_ID hint on display's group leader window. + + * gtk/gtkwindow.c (gtk_window_set_auto_startup_notification): + function to toggle whether we automatically broadcast that we've + started up, after mapping the first toplevel window. + (gtk_window_map): call gdk_screen_notify_startup_complete() by + default, unless enabled by above. + + * gtk/gtkmain.c gtk/gtkcombo.c gtk/gtktoolbar.c: + Couple of warning fixes. + Fri Nov 1 21:03:59 2002 Owen Taylor * gtk/gtkfilesel.c: Add a mnemonic to the "selection" diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 7e6252ff06..39fb620bc2 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,30 @@ +Sat Nov 2 00:22:33 2002 Owen Taylor + + Add startup notification hooks - mostly based on patch + by Havoc Pennington in #96772. + + * gdk/gdk.h gdk/x11/gdkdisplay-x11.c + gdk/{win32,linux-fb}/gdkmain-*.c: (gdk_notify_startup_complete): + new function that indicates an application has finished starting + up. + + * gdk/x11/gdkmain-x11.c gdk/x11/gdkdisplay-x11.c + (_gdk_windowing_set_default_display): store value of + DESKTOP_STARTUP_ID on the default screen, and clear it from the + environment. + + * gdk/x11/gdkdisplay-x11.c: + Set _NET_STARTUP_ID hint on display's group leader window. + + * gtk/gtkwindow.c (gtk_window_set_auto_startup_notification): + function to toggle whether we automatically broadcast that we've + started up, after mapping the first toplevel window. + (gtk_window_map): call gdk_screen_notify_startup_complete() by + default, unless enabled by above. + + * gtk/gtkmain.c gtk/gtkcombo.c gtk/gtktoolbar.c: + Couple of warning fixes. + Fri Nov 1 21:03:59 2002 Owen Taylor * gtk/gtkfilesel.c: Add a mnemonic to the "selection" diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 7e6252ff06..39fb620bc2 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,30 @@ +Sat Nov 2 00:22:33 2002 Owen Taylor + + Add startup notification hooks - mostly based on patch + by Havoc Pennington in #96772. + + * gdk/gdk.h gdk/x11/gdkdisplay-x11.c + gdk/{win32,linux-fb}/gdkmain-*.c: (gdk_notify_startup_complete): + new function that indicates an application has finished starting + up. + + * gdk/x11/gdkmain-x11.c gdk/x11/gdkdisplay-x11.c + (_gdk_windowing_set_default_display): store value of + DESKTOP_STARTUP_ID on the default screen, and clear it from the + environment. + + * gdk/x11/gdkdisplay-x11.c: + Set _NET_STARTUP_ID hint on display's group leader window. + + * gtk/gtkwindow.c (gtk_window_set_auto_startup_notification): + function to toggle whether we automatically broadcast that we've + started up, after mapping the first toplevel window. + (gtk_window_map): call gdk_screen_notify_startup_complete() by + default, unless enabled by above. + + * gtk/gtkmain.c gtk/gtkcombo.c gtk/gtktoolbar.c: + Couple of warning fixes. + Fri Nov 1 21:03:59 2002 Owen Taylor * gtk/gtkfilesel.c: Add a mnemonic to the "selection" diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 7e6252ff06..39fb620bc2 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,30 @@ +Sat Nov 2 00:22:33 2002 Owen Taylor + + Add startup notification hooks - mostly based on patch + by Havoc Pennington in #96772. + + * gdk/gdk.h gdk/x11/gdkdisplay-x11.c + gdk/{win32,linux-fb}/gdkmain-*.c: (gdk_notify_startup_complete): + new function that indicates an application has finished starting + up. + + * gdk/x11/gdkmain-x11.c gdk/x11/gdkdisplay-x11.c + (_gdk_windowing_set_default_display): store value of + DESKTOP_STARTUP_ID on the default screen, and clear it from the + environment. + + * gdk/x11/gdkdisplay-x11.c: + Set _NET_STARTUP_ID hint on display's group leader window. + + * gtk/gtkwindow.c (gtk_window_set_auto_startup_notification): + function to toggle whether we automatically broadcast that we've + started up, after mapping the first toplevel window. + (gtk_window_map): call gdk_screen_notify_startup_complete() by + default, unless enabled by above. + + * gtk/gtkmain.c gtk/gtkcombo.c gtk/gtktoolbar.c: + Couple of warning fixes. + Fri Nov 1 21:03:59 2002 Owen Taylor * gtk/gtkfilesel.c: Add a mnemonic to the "selection" diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 7e6252ff06..39fb620bc2 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,30 @@ +Sat Nov 2 00:22:33 2002 Owen Taylor + + Add startup notification hooks - mostly based on patch + by Havoc Pennington in #96772. + + * gdk/gdk.h gdk/x11/gdkdisplay-x11.c + gdk/{win32,linux-fb}/gdkmain-*.c: (gdk_notify_startup_complete): + new function that indicates an application has finished starting + up. + + * gdk/x11/gdkmain-x11.c gdk/x11/gdkdisplay-x11.c + (_gdk_windowing_set_default_display): store value of + DESKTOP_STARTUP_ID on the default screen, and clear it from the + environment. + + * gdk/x11/gdkdisplay-x11.c: + Set _NET_STARTUP_ID hint on display's group leader window. + + * gtk/gtkwindow.c (gtk_window_set_auto_startup_notification): + function to toggle whether we automatically broadcast that we've + started up, after mapping the first toplevel window. + (gtk_window_map): call gdk_screen_notify_startup_complete() by + default, unless enabled by above. + + * gtk/gtkmain.c gtk/gtkcombo.c gtk/gtktoolbar.c: + Couple of warning fixes. + Fri Nov 1 21:03:59 2002 Owen Taylor * gtk/gtkfilesel.c: Add a mnemonic to the "selection" diff --git a/gdk/gdk.h b/gdk/gdk.h index 811c484935..e48683e2ea 100644 --- a/gdk/gdk.h +++ b/gdk/gdk.h @@ -160,6 +160,9 @@ void gdk_event_send_clientmessage_toall (GdkEvent *event); gboolean gdk_event_send_client_message_for_display (GdkDisplay *display, GdkEvent *event, GdkNativeWindow winid); + +void gdk_notify_startup_complete (void); + /* Threading */ diff --git a/gdk/linux-fb/gdkmain-fb.c b/gdk/linux-fb/gdkmain-fb.c index 24c910f15f..2325d57344 100644 --- a/gdk/linux-fb/gdkmain-fb.c +++ b/gdk/linux-fb/gdkmain-fb.c @@ -1592,3 +1592,8 @@ gdk_error_trap_pop (void) { return 0; } + +void +gdk_notify_startup_complete (void) +{ +} diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c index f0feada707..f36be88830 100644 --- a/gdk/win32/gdkmain-win32.c +++ b/gdk/win32/gdkmain-win32.c @@ -213,3 +213,8 @@ gdk_error_trap_pop (void) { return 0; } + +void +gdk_notify_startup_complete (void) +{ +} diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 5ff1bb4699..964c83491c 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -143,7 +143,8 @@ gdk_display_open (const gchar *display_name) display_x11->default_screen = display_x11->screens[DefaultScreen (display_x11->xdisplay)]; display_x11->leader_window = XCreateSimpleWindow (display_x11->xdisplay, GDK_SCREEN_X11 (display_x11->default_screen)->xroot_window, - 10, 10, 10, 10, 0, 0, 0); + 10, 10, 10, 10, 0, 0, 0); + display_x11->have_shape = GDK_UNKNOWN; display_x11->gravity_works = GDK_UNKNOWN; @@ -568,6 +569,8 @@ gdk_display_x11_finalize (GObject *object) for (i = 0; i < ScreenCount (display_x11->xdisplay); i++) g_object_unref (display_x11->screens[i]); g_free (display_x11->screens); + g_free (display_x11->startup_notification_id); + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -632,3 +635,193 @@ gdk_x11_display_get_xdisplay (GdkDisplay *display) { return GDK_DISPLAY_X11 (display)->xdisplay; } + +void +_gdk_windowing_set_default_display (GdkDisplay *display) +{ + GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display); + const gchar *startup_id; + + if (display) + gdk_display = GDK_DISPLAY_XDISPLAY (display); + else + gdk_display = NULL; + + g_free (display_x11->startup_notification_id); + display_x11->startup_notification_id = NULL; + + startup_id = g_getenv ("DESKTOP_STARTUP_ID"); + if (startup_id && *startup_id != '\0') + { + if (!g_utf8_validate (startup_id, -1, NULL)) + g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8"); + else + display_x11->startup_notification_id = g_strdup (startup_id); + + /* Clear the environment variable so it won't be inherited by + * child processes and confuse things. unsetenv isn't portable, + * right... + */ + putenv ("DESKTOP_STARTUP_ID="); + + /* Set the startup id on the leader window so it + * applies to all windows we create on this display + */ + XChangeProperty (display_x11->xdisplay, + display_x11->leader_window, + gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"), + gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8, + PropModeReplace, + startup_id, strlen (startup_id)); + } +} + +char* +escape_for_xmessage (const char *str) +{ + GString *retval; + const char *p; + + retval = g_string_new (""); + + p = str; + while (*p) + { + switch (*p) + { + case ' ': + case '"': + case '\\': + g_string_append_c (retval, '\\'); + break; + } + + g_string_append_c (retval, *p); + ++p; + } + + return g_string_free (retval, FALSE); +} + +static void +broadcast_xmessage (GdkDisplay *display, + const char *message_type, + const char *message_type_begin, + const char *message) +{ + Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); + GdkScreen *screen = gdk_display_get_default_screen (display); + GdkWindow *root_window = gdk_screen_get_root_window (screen); + Window xroot_window = GDK_WINDOW_XID (root_window); + + Atom type_atom; + Atom type_atom_begin; + Window xwindow; + + { + XSetWindowAttributes attrs; + + attrs.override_redirect = True; + attrs.event_mask = PropertyChangeMask | StructureNotifyMask; + + xwindow = + XCreateWindow (xdisplay, + xroot_window, + -100, -100, 1, 1, + 0, + CopyFromParent, + CopyFromParent, + CopyFromParent, + CWOverrideRedirect | CWEventMask, + &attrs); + } + + type_atom = gdk_x11_get_xatom_by_name_for_display (display, + message_type); + type_atom_begin = gdk_x11_get_xatom_by_name_for_display (display, + message_type_begin); + + { + XEvent xevent; + const char *src; + const char *src_end; + char *dest; + char *dest_end; + + xevent.xclient.type = ClientMessage; + xevent.xclient.message_type = type_atom_begin; + xevent.xclient.display =xdisplay; + xevent.xclient.window = xwindow; + xevent.xclient.format = 8; + + src = message; + src_end = message + strlen (message) + 1; /* +1 to include nul byte */ + + while (src != src_end) + { + dest = &xevent.xclient.data.b[0]; + dest_end = dest + 20; + + while (dest != dest_end && + src != src_end) + { + *dest = *src; + ++dest; + ++src; + } + + XSendEvent (xdisplay, + xroot_window, + False, + PropertyChangeMask, + &xevent); + + xevent.xclient.message_type = type_atom; + } + } + + XDestroyWindow (xdisplay, xwindow); + XFlush (xdisplay); +} + +/** + * gdk_notify_startup_complete: + * + * Indicates to the GUI environment that the application has finished + * loading. If the applications opens windows, this function is + * normally called after opening the application's initial set of + * windows. + * + * GTK+ will call this function automatically after opening the first + * #GtkWindow unless + * gtk_window_set_auto_startup_notification() is called to disable + * that feature. + **/ +void +gdk_notify_startup_complete (void) +{ + GdkDisplay *display; + GdkDisplayX11 *display_x11; + gchar *escaped_id; + gchar *message; + + display = gdk_display_get_default (); + if (!display) + return; + + display_x11 = GDK_DISPLAY_X11 (display); + + if (display_x11->startup_notification_id == NULL) + return; + + escaped_id = escape_for_xmessage (display_x11->startup_notification_id); + message = g_strdup_printf ("remove: ID=%s", escaped_id); + g_free (escaped_id); + + broadcast_xmessage (display, + "_NET_STARTUP_INFO", + "_NET_STARTUP_INFO_BEGIN", + message); + + g_free (message); +} diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h index f0a076ebfc..2cc7522456 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -132,6 +132,9 @@ struct _GdkDisplayX11 gint input_gxid_port; gint use_xft; + + /* Startup notification */ + gchar *startup_notification_id; }; struct _GdkDisplayX11Class diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c index 27a09b3a34..2d8828db35 100644 --- a/gdk/x11/gdkmain-x11.c +++ b/gdk/x11/gdkmain-x11.c @@ -104,15 +104,6 @@ _gdk_windowing_init (gint *argc, _gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE); } -void -_gdk_windowing_set_default_display (GdkDisplay *display) -{ - if (display) - gdk_display = GDK_DISPLAY_XDISPLAY (display); - else - gdk_display = NULL; -} - void gdk_set_use_xshm (gboolean use_xshm) { diff --git a/gtk/gtkcombo.c b/gtk/gtkcombo.c index bb9e222d3a..11424632ae 100644 --- a/gtk/gtkcombo.c +++ b/gtk/gtkcombo.c @@ -535,7 +535,7 @@ gtk_combo_popup_list (GtkCombo * combo) else { GTK_WIDGET_SET_FLAGS (list, GTK_CAN_FOCUS); - gtk_widget_grab_focus (list); + gtk_widget_grab_focus (combo->list); GTK_WIDGET_UNSET_FLAGS (list, GTK_CAN_FOCUS); } diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index a21d95aca4..0f02777260 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -866,8 +866,6 @@ gboolean gtk_init_check (int *argc, char ***argv) { - GdkDisplay *display; - if (!gtk_parse_args (argc, argv)) return FALSE; @@ -902,7 +900,7 @@ gtk_init (int *argc, char ***argv) { if (!gtk_init_check (argc, argv)) { - char *display_name_arg = gdk_get_display_arg_name (); + const char *display_name_arg = gdk_get_display_arg_name (); g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : " "); exit (1); } diff --git a/gtk/gtktoolbar.c b/gtk/gtktoolbar.c index 11d4a5e436..420e6a141b 100644 --- a/gtk/gtktoolbar.c +++ b/gtk/gtktoolbar.c @@ -713,7 +713,7 @@ gtk_toolbar_size_allocate (GtkWidget *widget, gint space_size; gint ipadding; GtkTextDirection direction; - gint ltr_x; + gint ltr_x = 0; /* Quiet GCC */ g_return_if_fail (GTK_IS_TOOLBAR (widget)); g_return_if_fail (allocation != NULL); diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 1c12218f66..019bb5201a 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -261,6 +261,8 @@ static GtkBinClass *parent_class = NULL; static guint window_signals[LAST_SIGNAL] = { 0 }; static GList *default_icon_list = NULL; static guint default_icon_serial = 0; +static gboolean disable_startup_notification = FALSE; +static gboolean sent_startup_notification = FALSE; static void gtk_window_set_property (GObject *object, guint prop_id, @@ -3548,6 +3550,13 @@ gtk_window_map (GtkWidget *widget) if (window->frame) gdk_window_show (window->frame); + + if (!disable_startup_notification && + !sent_startup_notification) + { + sent_startup_notification = TRUE; + gdk_notify_startup_complete (); + } } static void @@ -6709,3 +6718,25 @@ _gtk_window_set_has_toplevel_focus (GtkWindow *window, g_object_notify (G_OBJECT (window), "has_toplevel_focus"); } } + +/** + * gtk_window_set_auto_startup_notification: + * @setting: %TRUE to automatically do startup notification + * + * By default, after showing the first #GtkWindow for each #GdkScreen, + * GTK+ calls gdk_screen_notify_startup_complete(). Call this + * function to disable the automatic startup notification. You might + * do this if your first window is a splash screen, and you want to + * delay notification until after your real main window has been + * shown, for example. + * + * In that example, you would disable startup notification + * temporarily, show your splash screen, then re-enable it so that + * showing the main window would automatically result in notification. + * + **/ +void +gtk_window_set_auto_startup_notification (gboolean setting) +{ + disable_startup_notification = !setting; +} diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index 9afd9404ff..1bd48843c2 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -255,6 +255,7 @@ GList* gtk_window_get_default_icon_list (void); gboolean gtk_window_set_default_icon_from_file (const gchar *filename, GError **err); +void gtk_window_set_auto_startup_notification (gboolean setting); /* If window is set modal, input will be grabbed when show and released when hide */ void gtk_window_set_modal (GtkWindow *window,