From cb27f0c4bea9a6aa402d46512eee1653b04b18a6 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 25 Oct 2002 23:35:50 +0000 Subject: [PATCH] Add "busy cursor on app startup" support, conditionally - works only if 2002-10-25 Havoc Pennington Add "busy cursor on app startup" support, conditionally - works only if libstartup-notification is found, and in practice requires a GTK patch that's not in yet. * src/screen.c: monitor startup events and set busy cursor if appropriate * src/display.c (meta_display_open): create SnDisplay * configure.in: check for startup notification, and add the cute "configure summary" at the end --- ChangeLog | 14 ++++ acconfig.h | 2 + configure.in | 58 ++++++++++--- src/Makefile.am | 2 +- src/common.h | 3 +- src/display.c | 48 ++++++++++- src/display.h | 8 ++ src/screen.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++ src/screen.h | 6 ++ src/util.c | 2 + src/util.h | 3 +- 11 files changed, 346 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 49e34a3e0..44bc825e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2002-10-25 Havoc Pennington + + Add "busy cursor on app startup" support, conditionally - works + only if libstartup-notification is found, and in practice requires + a GTK patch that's not in yet. + + * src/screen.c: monitor startup events and set busy cursor if + appropriate + + * src/display.c (meta_display_open): create SnDisplay + + * configure.in: check for startup notification, + and add the cute "configure summary" at the end + 2002-10-24 Havoc Pennington * src/theme.c (meta_frame_layout_calc_geometry): if only one diff --git a/acconfig.h b/acconfig.h index 3d823e363..7cf408aa3 100644 --- a/acconfig.h +++ b/acconfig.h @@ -15,3 +15,5 @@ #undef HAVE_XFREE_XINERAMA #undef HAVE_SHAPE #undef HAVE_RANDR +#undef HAVE_STARTUP_NOTIFICATION + diff --git a/configure.in b/configure.in index ced924892..879e12b4c 100644 --- a/configure.in +++ b/configure.in @@ -91,13 +91,27 @@ ALL_LINGUAS="az ca cs da de el es fr gl hu it ja ko lv ms no pl pt pt_BR ro ru s AM_GLIB_GNU_GETTEXT ## here we get the flags we'll actually use -PKG_CHECK_MODULES(METACITY, gtk+-2.0 >= 2.0.0 gconf-2.0 >= 1.1.9) PKG_CHECK_MODULES(METACITY_MESSAGE, gtk+-2.0 >= 2.0.0) PKG_CHECK_MODULES(METACITY_WINDOW_DEMO, gtk+-2.0 >= 2.0.0) PKG_CHECK_MODULES(METACITY_PROPS, gtk+-2.0 >= 2.0.0 gconf-2.0 >= 1.1.9 libglade-2.0) +STARTUP_NOTIFICATION_VERSION=0.2 +if $PKG_CONFIG --atleast-version $STARTUP_NOTIFICATION_VERSION libstartup-notification-1.0; then + echo "Building with libstartup-notification" + PKG_CHECK_MODULES(METACITY, gtk+-2.0 >= 2.0.0 gconf-2.0 >= 1.1.9 libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_VERSION) + AC_DEFINE(HAVE_STARTUP_NOTIFICATION) + with_startup_notification=yes +else + echo "Building without libstartup-notification" + PKG_CHECK_MODULES(METACITY, gtk+-2.0 >= 2.0.0 gconf-2.0 >= 1.1.9) + with_startup_notification=no +fi + if $PKG_CONFIG --atleast-version 2.1.0 gtk+-2.0; then AC_DEFINE(HAVE_GTK_MULTIHEAD,,[gtk+ with multihead support found]) + with_multihead=yes +else + with_multihead=no fi AC_PATH_XTRA @@ -108,6 +122,8 @@ ALL_X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" metacity_save_cppflags="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $X_CFLAGS" +use_solaris_xinerama=no +use_xfree_xinerama=no case "$host" in *-*-solaris*) # Check for solaris @@ -150,25 +166,25 @@ esac CPPFLAGS="$metacity_save_cppflags" SHAPE_LIBS= -found_shape=false +found_shape=no AC_CHECK_LIB(Xext, XShapeQueryExtension, [AC_CHECK_HEADERS(X11/extensions/shape.h, - SHAPE_LIBS=-lXext found_shape=true)], + SHAPE_LIBS=-lXext found_shape=yes)], , $ALL_X_LIBS) -if test "$found_shape" = "true"; then +if test "$found_shape" = "no"; then AC_DEFINE(HAVE_SHAPE) fi RANDR_LIBS= -found_randr=false +found_randr=no AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration, [AC_CHECK_HEADERS(X11/extensions/Xrandr.h, - RANDR_LIBS=-lXrandr, found_randr=true, + RANDR_LIBS=-lXrandr, found_randr=yes, [#include ])], , -lXrender $ALL_X_LIBS) -if test "$found_randr" = "true"; then +if test "$found_randr" = "yes"; then AC_DEFINE(HAVE_RANDR) fi @@ -177,24 +193,24 @@ METACITY_MESSAGE_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $METACITY_MESSAGE METACITY_WINDOW_DEMO_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $METACITY_WINDOW_DEMO_LIBS" METACITY_PROPS_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $METACITY_PROPS_LIBS" -found_sm=false +found_sm=no case "$METACITY_LIBS" in *-lSM*) - found_sm=true + found_sm=yes ;; *) AC_CHECK_LIB(SM, SmcSaveYourselfDone, [AC_CHECK_HEADERS(X11/SM/SMlib.h, - METACITY_LIBS="-lSM -lICE $METACITY_LIBS" found_sm=true)], + METACITY_LIBS="-lSM -lICE $METACITY_LIBS" found_sm=no)], , $METACITY_LIBS) ;; esac -if test "$found_sm" = "true"; then +if test "$found_sm" = "yes"; then AC_DEFINE(HAVE_SM) fi -AM_CONDITIONAL(HAVE_SM, test "$found_sm" = "true") +AM_CONDITIONAL(HAVE_SM, test "$found_sm" = "yes") HOST_ALIAS=$host_alias AC_SUBST(HOST_ALIAS) @@ -230,3 +246,21 @@ src/themes/Makefile po/Makefile.in metacity.spec ]) + +dnl ========================================================================== +echo " +metacity-$VERSION: + + prefix: ${prefix} + source code location: ${srcdir} + compiler: ${CC} + + XFree86 Xinerama: ${use_xfree_xinerama} + Solaris Xinerama: ${use_solaris_xinerama} + Multihead: ${with_multihead} + Startup notification: ${with_startup_notification} + Session management: ${found_sm} + Shape extension: ${found_shape} + Resize-and-rotate: ${found_randr} + +" diff --git a/src/Makefile.am b/src/Makefile.am index fe789c24e..2590a32de 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS=wm-tester tools themes -INCLUDES=@METACITY_CFLAGS@ -DMETACITY_LIBEXECDIR=\"$(libexecdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\" -DMETACITY_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DMETACITY_PKGDATADIR=\"$(pkgdatadir)\" -DMETACITY_DATADIR=\"$(datadir)\" -DG_LOG_DOMAIN=\"metacity\" +INCLUDES=@METACITY_CFLAGS@ -DMETACITY_LIBEXECDIR=\"$(libexecdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\" -DMETACITY_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" -DMETACITY_PKGDATADIR=\"$(pkgdatadir)\" -DMETACITY_DATADIR=\"$(datadir)\" -DG_LOG_DOMAIN=\"metacity\" -DSN_API_NOT_YET_FROZEN=1 EGGFILES= \ eggaccelerators.c \ diff --git a/src/common.h b/src/common.h index 204ccc3b0..f88dce584 100644 --- a/src/common.h +++ b/src/common.h @@ -129,7 +129,8 @@ typedef enum META_CURSOR_NE_RESIZE, META_CURSOR_NW_RESIZE, META_CURSOR_MOVE_WINDOW, - META_CURSOR_RESIZE_WINDOW + META_CURSOR_RESIZE_WINDOW, + META_CURSOR_BUSY } MetaCursor; diff --git a/src/display.c b/src/display.c index 6be190300..83413043a 100644 --- a/src/display.c +++ b/src/display.c @@ -138,6 +138,27 @@ remove_pending_pings_for_window (MetaDisplay *display, Window xwindow) g_slist_free (dead); } + +static void +sn_error_trap_push (SnDisplay *sn_display, + Display *xdisplay) +{ + MetaDisplay *display; + display = meta_display_for_x_display (xdisplay); + if (display != NULL) + meta_error_trap_push (display); +} + +static void +sn_error_trap_pop (SnDisplay *sn_display, + Display *xdisplay) +{ + MetaDisplay *display; + display = meta_display_for_x_display (xdisplay); + if (display != NULL) + meta_error_trap_pop (display, FALSE); +} + gboolean meta_display_open (const char *name) { @@ -372,6 +393,12 @@ meta_display_open (const char *name) display->groups_by_leader = NULL; display->screens = NULL; + +#ifdef HAVE_STARTUP_NOTIFICATION + display->sn_display = sn_display_new (display->xdisplay, + sn_error_trap_push, + sn_error_trap_pop); +#endif #ifdef USE_GDK_DISPLAY display->events = NULL; @@ -594,14 +621,14 @@ meta_display_close (MetaDisplay *display) g_source_remove (display->autoraise_timeout_id); display->autoraise_timeout_id = 0; } - + #ifdef USE_GDK_DISPLAY /* Stop caring about events */ meta_ui_remove_event_func (display->xdisplay, event_callback, display); #endif - + /* Free all screens */ tmp = display->screens; while (tmp != NULL) @@ -613,6 +640,14 @@ meta_display_close (MetaDisplay *display) g_slist_free (display->screens); display->screens = NULL; + +#ifdef HAVE_STARTUP_NOTIFICATION + if (display->sn_display) + { + sn_display_unref (display->sn_display); + display->sn_display = NULL; + } +#endif /* Must be after all calls to meta_window_free() since they * unregister windows @@ -967,6 +1002,10 @@ event_callback (XEvent *event, if (dump_events) meta_spew_event (display, event); + +#ifdef HAVE_STARTUP_NOTIFICATION + sn_display_process_event (display->sn_display, event); +#endif filter_out_event = FALSE; display->current_time = event_get_time (display, event); @@ -2192,7 +2231,10 @@ meta_display_create_x_cursor (MetaDisplay *display, case META_CURSOR_RESIZE_WINDOW: glyph = XC_fleur; break; - + case META_CURSOR_BUSY: + glyph = XC_watch; + break; + default: g_assert_not_reached (); glyph = 0; /* silence compiler */ diff --git a/src/display.h b/src/display.h index 82a2d3249..395e97868 100644 --- a/src/display.h +++ b/src/display.h @@ -27,6 +27,10 @@ #include "eventqueue.h" #include "common.h" +#ifdef HAVE_STARTUP_NOTIFICATION +#include +#endif + #define meta_XFree(p) do { if ((p)) XFree ((p)); } while (0) /* this doesn't really belong here, oh well. */ @@ -149,6 +153,10 @@ struct _MetaDisplay Atom atom_net_wm_action_close; Atom atom_net_wm_state_above; Atom atom_net_wm_state_below; + +#ifdef HAVE_STARTUP_NOTIFICATION + SnDisplay *sn_display; +#endif /* This is the actual window from focus events, * not the one we last set diff --git a/src/screen.c b/src/screen.c index e9dade24b..4bcae0e77 100644 --- a/src/screen.c +++ b/src/screen.c @@ -54,6 +54,11 @@ static void update_focus_mode (MetaScreen *screen); static void prefs_changed_callback (MetaPreference pref, gpointer data); +#ifdef HAVE_STARTUP_NOTIFICATION +static void meta_screen_sn_event (SnMonitorEvent *event, + void *user_data); +#endif + static int set_wm_check_hint (MetaScreen *screen) { @@ -580,6 +585,17 @@ meta_screen_new (MetaDisplay *display, screen->stack = meta_stack_new (screen); meta_prefs_add_listener (prefs_changed_callback, screen); + +#ifdef HAVE_STARTUP_NOTIFICATION + screen->sn_context = + sn_monitor_context_new (screen->display->sn_display, + screen->number, + meta_screen_sn_event, + screen, + NULL); + screen->startup_sequences = NULL; + screen->startup_sequence_timeout = 0; +#endif meta_verbose ("Added screen %d ('%s') root 0x%lx\n", screen->number, screen->screen_name, screen->xroot); @@ -604,6 +620,24 @@ meta_screen_free (MetaScreen *screen) meta_screen_ungrab_keys (screen); +#ifdef HAVE_STARTUP_NOTIFICATION + g_slist_foreach (screen->startup_sequences, + (GFunc) sn_startup_sequence_unref, NULL); + g_slist_free (screen->startup_sequences); + screen->startup_sequences = NULL; + + if (screen->startup_sequence_timeout != 0) + { + g_source_remove (screen->startup_sequence_timeout); + screen->startup_sequence_timeout = 0; + } + if (screen->sn_context) + { + sn_monitor_context_unref (screen->sn_context); + screen->sn_context = NULL; + } +#endif + meta_ui_free (screen->ui); meta_stack_free (screen->stack); @@ -1619,3 +1653,187 @@ meta_screen_unshow_desktop (MetaScreen *screen) meta_screen_focus_top_window (screen, NULL); } + +#ifdef HAVE_STARTUP_NOTIFICATION +static gboolean startup_sequence_timeout (void *data); + +static void +update_startup_feedback (MetaScreen *screen) +{ + if (screen->startup_sequences != NULL) + { + meta_topic (META_DEBUG_STARTUP, + "Setting busy cursor\n"); + meta_screen_set_cursor (screen, META_CURSOR_BUSY); + } + else + { + meta_topic (META_DEBUG_STARTUP, + "Setting default cursor\n"); + meta_screen_set_cursor (screen, META_CURSOR_DEFAULT); + } +} + +static void +add_sequence (MetaScreen *screen, + SnStartupSequence *sequence) +{ + meta_topic (META_DEBUG_STARTUP, + "Adding sequence %s\n", + sn_startup_sequence_get_id (sequence)); + sn_startup_sequence_ref (sequence); + screen->startup_sequences = g_slist_prepend (screen->startup_sequences, + sequence); + + /* our timeout just polls every second, instead of bothering + * to compute exactly when we may next time out + */ + if (screen->startup_sequence_timeout == 0) + screen->startup_sequence_timeout = g_timeout_add (1000, + startup_sequence_timeout, + screen); + + update_startup_feedback (screen); +} + +static void +remove_sequence (MetaScreen *screen, + SnStartupSequence *sequence) +{ + meta_topic (META_DEBUG_STARTUP, + "Removing sequence %s\n", + sn_startup_sequence_get_id (sequence)); + + screen->startup_sequences = g_slist_remove (screen->startup_sequences, + sequence); + sn_startup_sequence_unref (sequence); + + if (screen->startup_sequences == NULL && + screen->startup_sequence_timeout != 0) + { + g_source_remove (screen->startup_sequence_timeout); + screen->startup_sequence_timeout = 0; + } + + update_startup_feedback (screen); +} + +typedef struct +{ + GSList *list; + GTimeVal now; +} CollectTimedOutData; + +#define STARTUP_TIMEOUT 5000 + +static void +collect_timed_out_foreach (void *element, + void *data) +{ + CollectTimedOutData *ctod = data; + SnStartupSequence *sequence = element; + long tv_sec, tv_usec; + double elapsed; + + sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec); + + elapsed = + ((((double)ctod->now.tv_sec - tv_sec) * G_USEC_PER_SEC + + (ctod->now.tv_usec - tv_usec))) / 1000.0; + + meta_topic (META_DEBUG_STARTUP, + "Sequence used %g seconds vs. %g max: %s\n", + elapsed, (double) STARTUP_TIMEOUT, + sn_startup_sequence_get_id (sequence)); + + if (elapsed > STARTUP_TIMEOUT) + ctod->list = g_slist_prepend (ctod->list, sequence); +} + +static gboolean +startup_sequence_timeout (void *data) +{ + MetaScreen *screen = data; + CollectTimedOutData ctod; + GSList *tmp; + + ctod.list = NULL; + g_get_current_time (&ctod.now); + g_slist_foreach (screen->startup_sequences, + collect_timed_out_foreach, + &ctod); + + tmp = ctod.list; + while (tmp != NULL) + { + SnStartupSequence *sequence = tmp->data; + + meta_topic (META_DEBUG_STARTUP, + "Timed out sequence %s\n", + sn_startup_sequence_get_id (sequence)); + + remove_sequence (screen, sequence); + + tmp = tmp->next; + } + + g_slist_free (ctod.list); + + if (screen->startup_sequences != NULL) + { + return TRUE; + } + else + { + /* remove */ + screen->startup_sequence_timeout = 0; + return FALSE; + } +} + +static void +meta_screen_sn_event (SnMonitorEvent *event, + void *user_data) +{ + MetaScreen *screen; + SnStartupSequence *sequence; + + screen = user_data; + + sequence = sn_monitor_event_get_startup_sequence (event); + + switch (sn_monitor_event_get_type (event)) + { + case SN_MONITOR_EVENT_INITIATED: + { + meta_topic (META_DEBUG_STARTUP, + "Received startup initiated for %s\n", + sn_startup_sequence_get_id (sequence)); + add_sequence (screen, sequence); + } + break; + + case SN_MONITOR_EVENT_COMPLETED: + { + meta_topic (META_DEBUG_STARTUP, + "Received startup completed for %s\n", + sn_startup_sequence_get_id (sequence)); + remove_sequence (screen, + sn_monitor_event_get_startup_sequence (event)); + } + break; + + case SN_MONITOR_EVENT_CHANGED: + meta_topic (META_DEBUG_STARTUP, + "Received startup changed for %s\n", + sn_startup_sequence_get_id (sequence)); + break; + + case SN_MONITOR_EVENT_CANCELED: + meta_topic (META_DEBUG_STARTUP, + "Received startup canceled for %s\n", + sn_startup_sequence_get_id (sequence)); + break; + } +} +#endif diff --git a/src/screen.h b/src/screen.h index a5811b633..04de75cfb 100644 --- a/src/screen.h +++ b/src/screen.h @@ -79,6 +79,12 @@ struct _MetaScreen /* Cache the current Xinerama */ int last_xinerama_index; + +#ifdef HAVE_STARTUP_NOTIFICATION + SnMonitorContext *sn_context; + GSList *startup_sequences; + guint startup_sequence_timeout; +#endif guint work_area_idle; diff --git a/src/util.c b/src/util.c index c6b6b7e96..36851ee0e 100644 --- a/src/util.c +++ b/src/util.c @@ -258,6 +258,8 @@ topic_name (MetaDebugTopic topic) return "SYNC"; case META_DEBUG_ERRORS: return "ERRORS"; + case META_DEBUG_STARTUP: + return "STARTUP"; } return "Window manager"; diff --git a/src/util.h b/src/util.h index 07ebc42e8..ae2e6ee17 100644 --- a/src/util.h +++ b/src/util.h @@ -60,7 +60,8 @@ typedef enum META_DEBUG_XINERAMA = 1 << 11, META_DEBUG_KEYBINDINGS = 1 << 12, META_DEBUG_SYNC = 1 << 13, - META_DEBUG_ERRORS = 1 << 14 + META_DEBUG_ERRORS = 1 << 14, + META_DEBUG_STARTUP = 1 << 15 } MetaDebugTopic;