changeset 12016:24c7fb94d3a3

[gaim-migrate @ 14309] Patch from charkins to fix potential problems with the buddy list becoming invisible with no way to restore visiblity. This (re)introduces the concept of a "visibility manager" that, if present, will be in charge of controlling the visibility of the buddy list. committer: Tailor Script <tailor@pidgin.im>
author Daniel Atallah <daniel.atallah@gmail.com>
date Wed, 09 Nov 2005 02:25:26 +0000
parents 5a63ea24ac83
children 2b6e0be024fb
files doc/gtkblist-signals.dox plugins/ChangeLog.API plugins/docklet/docklet-win32.c plugins/docklet/docklet.c plugins/docklet/docklet.h src/gtkblist.c
diffstat 6 files changed, 141 insertions(+), 107 deletions(-) [+]
line wrap: on
line diff
--- a/doc/gtkblist-signals.dox	Wed Nov 09 01:36:28 2005 +0000
+++ b/doc/gtkblist-signals.dox	Wed Nov 09 02:25:26 2005 +0000
@@ -1,12 +1,32 @@
 /** @page gtkblist-signals GtkBlist Signals
 
  @signals
+  @signal gtkblist-hiding
+  @signal gtkblist-unhiding
   @signal gtkblist-created
   @signal drawing-tooltip
  @endsignals
 
  <hr>
 
+ @signaldef gtkblist-hiding
+  @signalproto
+void (*gtkblist-hiding)(GaimBuddyList *blist);
+  @endsignalproto
+  @signaldesc
+   Emitted when the buddy list is about to be hidden.
+  @param blist The buddy list.
+ @endsignaldef
+
+ @signaldef gtkblist-unhiding
+  @signalproto
+void (*gtkblist-unhiding)(GaimBuddyList *blist);
+  @endsignalproto
+  @signaldesc
+   Emitted when the buddy list is about to be unhidden.
+  @param blist The buddy list.
+ @endsignaldef
+
  @signaldef gtkblist-created
   @signalproto
 void (*gtkblist-created)(GaimBuddyList *blist);
--- a/plugins/ChangeLog.API	Wed Nov 09 01:36:28 2005 +0000
+++ b/plugins/ChangeLog.API	Wed Nov 09 02:25:26 2005 +0000
@@ -135,6 +135,12 @@
 	  a given string
 	* gaim_util_chrreplace() to replace a given character with a
 	  different character
+	* gaim_gtk_blist_toggle_visibility() to intelligently toggle the
+	  visiblity of the buddy list
+	* gaim_gtk_blist_visibility_manager_add() to indicate the addition of a
+	  visibility manager - see the docs for more information
+	* gaim_gtk_blist_visibility_manager_remove() to indicate the removal of
+	  a visibility manager - see the docs for more information
 
 	Signals - Changed:
 	* "received-im-msg" and "received-chat-msg" to match, both now pass a
@@ -172,6 +178,8 @@
 	* "buddy-status-changed": A buddy changed status; see Doxygen docs for full details.
 	* "buddy-idle-changed": A buddy's idle status changed; see Doxygen docs for full details.
 		See Doxygen docs for details.
+	* "gtkblist-hiding": See Doxygen docs for details.
+	* "gtkblist-unhiding": See Doxygen docs for details.
 
 	Signals - Removed:
 	* "buddy-away": replaced by buddy-status-changed
--- a/plugins/docklet/docklet-win32.c	Wed Nov 09 01:36:28 2005 +0000
+++ b/plugins/docklet/docklet-win32.c	Wed Nov 09 02:25:26 2005 +0000
@@ -190,6 +190,15 @@
 	systray_change_icon(sysicon_blank, NULL);
 }
 
+void wgaim_tray_minimize(GaimGtkBuddyList *gtkblist) {
+	MinimizeWndToTray(GDK_WINDOW_HWND(gtkblist->window->window));
+}
+
+void wgaim_tray_maximize(GaimGtkBuddyList *gtkblist) {
+	RestoreWndFromTray(GDK_WINDOW_HWND(gtkblist->window->window));
+}
+
+
 static void wgaim_tray_create() {
 	OSVERSIONINFO osinfo;
 	/* dummy window to process systray messages */
@@ -220,31 +229,28 @@
 
 	/* Create icon in systray */
 	systray_init_icon(systray_hwnd, sysicon_disconn);
+
+	gaim_signal_connect(gaim_gtk_blist_get_handle(), "gtkblist-hiding", 
+			&handle, GAIM_CALLBACK(wgaim_tray_minimize), NULL);
+	gaim_signal_connect(gaim_gtk_blist_get_handle(), "gtkblist-unhiding", 
+			&handle, GAIM_CALLBACK(wgaim_tray_maximize), NULL);
+
 	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "created\n");
 }
 
 static void wgaim_tray_destroy() {
+	gaim_signals_disconnect_by_handle(&handle);
 	systray_remove_nid();
 	DestroyWindow(systray_hwnd);
 	docklet_remove(TRUE);
 }
 
-void wgaim_tray_minimize(GtkWidget *window) {
-	MinimizeWndToTray(GDK_WINDOW_HWND(window->window));
-}
-
-void wgaim_tray_maximize(GtkWidget *window) {
-	RestoreWndFromTray(GDK_WINDOW_HWND(window->window));
-}
-
 static struct docklet_ui_ops wgaim_tray_ops =
 {
 	wgaim_tray_create,
 	wgaim_tray_destroy,
 	wgaim_tray_update_icon,
 	wgaim_tray_blank_icon,
-	wgaim_tray_minimize,
-	wgaim_tray_maximize,
 	NULL
 };
 
--- a/plugins/docklet/docklet.c	Wed Nov 09 01:36:28 2005 +0000
+++ b/plugins/docklet/docklet.c	Wed Nov 09 02:25:26 2005 +0000
@@ -52,7 +52,6 @@
 GaimPlugin *handle = NULL;
 static struct docklet_ui_ops *ui_ops = NULL;
 static DockletStatus status = DOCKLET_STATUS_OFFLINE;
-static gulong gtkblist_delete_cb_id = 0;
 static gboolean enable_join_chat = FALSE;
 static guint docklet_blinking_timer = 0;
 
@@ -212,74 +211,8 @@
 }
 
 /**************************************************************************
- * minimize to and unminimize from the tray icon
- **************************************************************************/
-static void
-minimize_to_tray()
-{
-	GaimGtkBuddyList *blist = gaim_gtk_blist_get_default_gtk_blist();
-
-	if(!blist || !blist->window)
-		return;
-
-	if (ui_ops && ui_ops->minimize)
-		ui_ops->minimize(blist->window);
-
-	gaim_prefs_set_bool("/gaim/gtk/blist/list_visible", FALSE);
-	gtk_widget_hide(blist->window);
-
-	docklet_update_status();
-}
-
-static void
-unminimize_from_tray()
-{
-	GaimGtkBuddyList *blist = gaim_gtk_blist_get_default_gtk_blist();
-
-	if(!blist || !blist->window)
-		return;
-
-	if (ui_ops && ui_ops->maximize)
-		ui_ops->maximize(blist->window);
-
-	gaim_blist_set_visible(TRUE);
-
-	docklet_update_status();
-}
-
-static void
-docklet_toggle_blist()
-{
-	if(gaim_prefs_get_bool("/gaim/gtk/blist/list_visible"))
-		minimize_to_tray();
-	else
-		unminimize_from_tray();
-}
-
-/**************************************************************************
  * callbacks and signal handlers
  **************************************************************************/
-/* catch delete events on gtkblist and hide it instead */
-static gboolean
-gtkblist_delete_cb(GtkWidget *widget) {
-	gaim_debug(GAIM_DEBUG_INFO, "docklet", "hiding buddy list\n");
-	minimize_to_tray(widget);
-	return TRUE;
-}
-
-/* connect to delete signal when gtkblist is created */
-static void
-gtkblist_created_cb(GaimBuddyList *list)
-{
-	if(list!=NULL && GAIM_IS_GTK_BLIST(list) && 
-			GAIM_GTK_BLIST(list)->window!=NULL && 
-			gtkblist_delete_cb_id==0) {
-
-		gtkblist_delete_cb_id = g_signal_connect(G_OBJECT(GAIM_GTK_BLIST(list)->window), 
-				"delete_event", G_CALLBACK(gtkblist_delete_cb), NULL);
-	}
-}
-
 static void 
 gaim_quit_cb() 
 {
@@ -334,6 +267,12 @@
 	gaim_prefs_set_bool("/gaim/gtk/sound/mute", GTK_CHECK_MENU_ITEM(toggle)->active);
 }
 
+static void
+docklet_toggle_blist(GtkWidget *toggle, void *data)
+{
+	gaim_blist_set_visible(GTK_CHECK_MENU_ITEM(toggle)->active);
+}
+
 #ifdef _WIN32
 /* This is a workaround for a bug in windows GTK+. Clicking outside of the
    menu does not get rid of it, so instead we get rid of it as soon as the
@@ -440,7 +379,7 @@
 					|| status==DOCKLET_STATUS_AWAY_PENDING)
 				focus_first_unseen_conv();
 			else
-				docklet_toggle_blist();
+				gaim_gtk_blist_toggle_visibility();
 			break;
 		case 3:
 			docklet_menu();
@@ -451,6 +390,7 @@
 void
 docklet_embedded()
 {
+	gaim_gtk_blist_visibility_manager_add();
 	docklet_update_status();
 	if (ui_ops && ui_ops->update_icon)
 		ui_ops->update_icon(status);
@@ -459,7 +399,7 @@
 void
 docklet_remove(gboolean visible)
 {
-	unminimize_from_tray();
+	gaim_gtk_blist_visibility_manager_remove();
 }
 
 void
@@ -508,36 +448,22 @@
 	gaim_signal_connect(conv_handle, "conversation-updated",
 						plugin, GAIM_CALLBACK(docklet_conv_updated_cb), NULL);
 
-	gaim_signal_connect(gaim_gtk_blist_get_handle(), "gtkblist-created",
-						plugin, GAIM_CALLBACK(gtkblist_created_cb), NULL);
-	gtkblist_created_cb(gaim_get_blist());
-
 	gaim_signal_connect(core_handle, "quitting",
 						plugin, GAIM_CALLBACK(gaim_quit_cb), NULL);
 
 	enable_join_chat = online_account_supports_chat();
 
-	if(!gaim_prefs_get_bool("/gaim/gtk/blist/list_visible"))
-		minimize_to_tray();
-
 	return TRUE;
 }
 
 static gboolean
 plugin_unload(GaimPlugin *plugin)
 {
-	GaimGtkBuddyList *gtkblist = gaim_gtk_blist_get_default_gtk_blist();
-
 	if (ui_ops && ui_ops->destroy)
 		ui_ops->destroy();
 
 	/* remove callbacks */
-    gaim_signals_disconnect_by_handle(handle);
-	if(gtkblist_delete_cb_id!=0)
-		g_signal_handler_disconnect(G_OBJECT(gtkblist->window), gtkblist_delete_cb_id);
-	gtkblist_delete_cb_id = 0;
-
-	unminimize_from_tray();
+	gaim_signals_disconnect_by_handle(handle);
 
 	gaim_debug(GAIM_DEBUG_INFO, "docklet", "plugin unloaded\n");
 
--- a/plugins/docklet/docklet.h	Wed Nov 09 01:36:28 2005 +0000
+++ b/plugins/docklet/docklet.h	Wed Nov 09 02:25:26 2005 +0000
@@ -41,8 +41,6 @@
 	void (*destroy)();
 	void (*update_icon)(DockletStatus);
 	void (*blank_icon)();
-	void (*minimize)(GtkWidget *);
-	void (*maximize)(GtkWidget *);
 	GtkMenuPositionFunc position_menu;
 };
 
--- a/src/gtkblist.c	Wed Nov 09 01:36:28 2005 +0000
+++ b/src/gtkblist.c	Wed Nov 09 02:25:26 2005 +0000
@@ -101,6 +101,9 @@
 
 static GtkWidget *protomenu = NULL;
 
+static guint visibility_manager_count = 0;
+static gboolean gtk_blist_obscured = FALSE;
+
 static GList *gaim_gtk_blist_sort_methods = NULL;
 static struct gaim_gtk_blist_sort_method *current_sort_method = NULL;
 static GtkTreeIter sort_method_none(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur);
@@ -150,10 +153,42 @@
 /***************************************************
  *              Callbacks                          *
  ***************************************************/
+static gboolean gtk_blist_visibility_cb(GtkWidget *w, GdkEventVisibility *event, gpointer data)
+{
+	if (event->state == GDK_VISIBILITY_FULLY_OBSCURED)
+		gtk_blist_obscured = TRUE;
+	else
+		gtk_blist_obscured = FALSE;
+
+	/* continue to handle event normally */
+	return FALSE;
+}
+
+static gboolean gtk_blist_window_state_cb(GtkWidget *w, GdkEventWindowState *event, gpointer data)
+{
+	if(event->changed_mask & GDK_WINDOW_STATE_WITHDRAWN) {
+		if(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)
+			gaim_prefs_set_bool("/gaim/gtk/blist/list_visible", FALSE);
+		else
+			gaim_prefs_set_bool("/gaim/gtk/blist/list_visible", TRUE);
+	}
+
+	if(event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) {
+		if(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED)
+			gaim_prefs_set_bool("/gaim/gtk/blist/list_visible", FALSE);
+		else
+			gaim_prefs_set_bool("/gaim/gtk/blist/list_visible", TRUE);
+	}
+
+	return FALSE;
+}
 
 static gboolean gtk_blist_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data)
 {
-	gaim_core_quit();
+	if(visibility_manager_count)
+		gaim_blist_set_visible(FALSE);
+	else
+		gaim_core_quit();
 
 	/* we handle everything, event should not propogate further */
 	return TRUE;
@@ -3218,8 +3253,7 @@
 				{"application/x-im-contact", 0, DRAG_BUDDY},
 				{"text/x-vcard", 0, DRAG_VCARD }};
 	if (gtkblist && gtkblist->window) {
-		if (gaim_prefs_get_bool("/gaim/gtk/blist/list_visible"))
-			gtk_widget_show(gtkblist->window);
+		gaim_blist_set_visible(gaim_prefs_get_bool("/gaim/gtk/blist/list_visible"));
 		return;
 	}
 
@@ -3233,8 +3267,10 @@
 	gtk_widget_show(gtkblist->vbox);
 	gtk_container_add(GTK_CONTAINER(gtkblist->window), gtkblist->vbox);
 
-	g_signal_connect_after(G_OBJECT(gtkblist->window), "delete_event", G_CALLBACK(gtk_blist_delete_cb), NULL);
+	g_signal_connect(G_OBJECT(gtkblist->window), "delete_event", G_CALLBACK(gtk_blist_delete_cb), NULL);
 	g_signal_connect(G_OBJECT(gtkblist->window), "configure_event", G_CALLBACK(gtk_blist_configure_cb), NULL);
+	g_signal_connect(G_OBJECT(gtkblist->window), "visibility_notify_event", G_CALLBACK(gtk_blist_visibility_cb), NULL);
+	g_signal_connect(G_OBJECT(gtkblist->window), "window_state_event", G_CALLBACK(gtk_blist_window_state_cb), NULL);
 	gtk_widget_add_events(gtkblist->window, GDK_VISIBILITY_NOTIFY_MASK);
 
 	/******************************* Menu bar *************************************/
@@ -3400,11 +3436,8 @@
 	gaim_gtk_blist_update_sort_methods();
 
 	/* OK... let's show this bad boy. */
-	if (gaim_prefs_get_bool("/gaim/gtk/blist/list_visible")) {
-		gaim_gtk_blist_refresh(list);
-		gaim_gtk_blist_restore_position();
-		gtk_widget_show(gtkblist->window);
-	}
+	gaim_gtk_blist_refresh(list);
+	gaim_blist_set_visible(gaim_prefs_get_bool("/gaim/gtk/blist/list_visible"));
 
 	/* start the refresh timer */
 	gtkblist->refresh_timer = g_timeout_add(30000, (GSourceFunc)gaim_gtk_blist_refresh_timer, list);
@@ -3943,13 +3976,20 @@
 	if (!(gtkblist && gtkblist->window))
 		return;
 
-	gaim_prefs_set_bool("/gaim/gtk/blist/list_visible", show);
+	//gaim_prefs_set_bool("/gaim/gtk/blist/list_visible", show);
 
 	if (show) {
+		if(!GAIM_WINDOW_ICONIFIED(gtkblist->window) && !GTK_WIDGET_VISIBLE(gtkblist->window))
+			gaim_signal_emit(gaim_gtk_blist_get_handle(), "gtkblist-unhiding", gtkblist);
 		gaim_gtk_blist_restore_position();
 		gtk_window_present(GTK_WINDOW(gtkblist->window));
 	} else {
-		gtk_window_iconify(GTK_WINDOW(gtkblist->window));
+		if(visibility_manager_count) {
+			gaim_signal_emit(gaim_gtk_blist_get_handle(), "gtkblist-hiding", gtkblist);
+			gtk_widget_hide(gtkblist->window);
+		} else {
+			gtk_window_iconify(GTK_WINDOW(gtkblist->window));
+		}
 	}
 }
 
@@ -4569,6 +4609,34 @@
 					   _("Cancel"), NULL, NULL);
 }
 
+void
+gaim_gtk_blist_toggle_visibility()
+{
+	if (gtkblist && gtkblist->window) {
+		if (GTK_WIDGET_VISIBLE(gtkblist->window)) {
+			gaim_blist_set_visible(GAIM_WINDOW_ICONIFIED(gtkblist->window) || gtk_blist_obscured);
+		} else {
+			gaim_blist_set_visible(TRUE);
+		}
+	}
+}
+
+void
+gaim_gtk_blist_visibility_manager_add()
+{
+	visibility_manager_count++;
+}
+
+void
+gaim_gtk_blist_visibility_manager_remove()
+{
+	if (visibility_manager_count)
+		visibility_manager_count--;
+	if (!visibility_manager_count)
+		gaim_blist_set_visible(TRUE);
+}
+
+
 static GaimBlistUiOps blist_ui_ops =
 {
 	gaim_gtk_blist_new_list,
@@ -4691,6 +4759,14 @@
 	gaim_prefs_add_int("/gaim/gtk/blist/tooltip_delay", 500);
 
 	/* Register our signals */
+	gaim_signal_register(gtk_blist_handle, "gtkblist-hiding",
+						 gaim_marshal_VOID__POINTER, NULL, 1,
+						 gaim_value_new(GAIM_TYPE_POINTER));
+
+	gaim_signal_register(gtk_blist_handle, "gtkblist-unhiding",
+						 gaim_marshal_VOID__POINTER, NULL, 1,
+						 gaim_value_new(GAIM_TYPE_SUBTYPE));
+
 	gaim_signal_register(gtk_blist_handle, "gtkblist-created",
 						 gaim_marshal_VOID__POINTER, NULL, 1,
 						 gaim_value_new(GAIM_TYPE_SUBTYPE,