On Wed, 2005-07-06 at 16:39 -0400, Colin Walters wrote: And here's a further updated patch which thanks to sample code from X/metacity guru SÃren Sandmann makes Metacity display a minimization animation to the tray icon when you close the main window. This makes it much clearer what's going on by building a visual association between closing the window and the music icon. The animation code is something that should probably go in eggtrayicon actually, but I'm putting it in Rhythmbox for now so we can play around with it and see what it's like.
cvs server: Diffing . cvs server: Diffing component cvs server: Diffing corba cvs server: Diffing data cvs server: Diffing data/art cvs server: Diffing data/glade cvs server: Diffing data/node-views cvs server: Diffing data/ui Index: data/ui/rhythmbox-ui.xml =================================================================== RCS file: /cvs/gnome/rhythmbox/data/ui/rhythmbox-ui.xml,v retrieving revision 1.19 diff -u -p -r1.19 rhythmbox-ui.xml --- data/ui/rhythmbox-ui.xml 12 Jun 2005 17:21:44 -0000 1.19 +++ data/ui/rhythmbox-ui.xml 7 Jul 2005 18:15:32 -0000 @@ -18,6 +18,7 @@ <separator/> <menuitem name="MusicPropertiesMenu" action="MusicProperties"/> <separator/> + <menuitem name="MusicClose" action="MusicClose"/> <menuitem name="MusicQuit" action="MusicQuit"/> </menu> @@ -66,13 +67,14 @@ </menubar> <popup name="RhythmboxTrayPopup"> + <menuitem name="ShowWindowTray" action="TrayShowWindow"/> + <separator/> <menuitem name="PlayTray" action="ControlPlay"/> <menuitem name="PauseTray" action="ControlPause"/> <separator/> <menuitem name="PreviousTray" action="ControlPrevious"/> <menuitem name="NextTray" action="ControlNext"/> <separator/> - <menuitem name="ShowWindowTray" action="TrayShowWindow"/> <menuitem name="QuitTray" action="MusicQuit"/> </popup> cvs server: Diffing data/views cvs server: Diffing debian cvs server: Diffing doc cvs server: Diffing help cvs server: Diffing help/C cvs server: Diffing help/C/figures cvs server: Diffing help/ja cvs server: Diffing help/ja/figures cvs server: Diffing iradio cvs server: Diffing lib cvs server: Diffing lib/egg cvs server: Diffing lib/toolbar cvs server: Diffing lib/view cvs server: Diffing lib/widgets cvs server: Diffing library cvs server: Diffing macros cvs server: Diffing metadata cvs server: Diffing metadata/monkey-media cvs server: Diffing metadata/monkey-media/id3-vfs cvs server: Diffing metadata/monkey-media/stream-info-impl cvs server: Diffing metadata/monkey-media/stream-info-impl/id3-vfs cvs server: Diffing monkey-media cvs server: Diffing monkey-media/id3-vfs cvs server: Diffing monkey-media/stream-info-impl cvs server: Diffing monkey-media/stream-info-impl/id3-vfs cvs server: Diffing player cvs server: Diffing po cvs server: Diffing remote cvs server: Diffing remote/bonobo cvs server: Diffing remote/dbus cvs server: Diffing rhythmdb cvs server: Diffing shell Index: shell/rb-shell.c =================================================================== RCS file: /cvs/gnome/rhythmbox/shell/rb-shell.c,v retrieving revision 1.303 diff -u -p -r1.303 rb-shell.c --- shell/rb-shell.c 19 Jun 2005 18:30:57 -0000 1.303 +++ shell/rb-shell.c 7 Jul 2005 18:15:33 -0000 @@ -23,6 +23,8 @@ #include <gtk/gtk.h> #include <gdk/gdk.h> +#include <gdk/gdkx.h> +#include <X11/Xatom.h> #include <config.h> #include <libgnome/libgnome.h> #include <libgnomeui/gnome-stock-icons.h> @@ -151,6 +153,8 @@ static void rb_shell_cmd_about (GtkActio RBShell *shell); static void rb_shell_cmd_contents (GtkAction *action, RBShell *shell); +static void rb_shell_cmd_toggle_visibility (GtkAction *action, + RBShell *shell); static void rb_shell_cmd_quit (GtkAction *action, RBShell *shell); static void rb_shell_cmd_preferences (GtkAction *action, @@ -388,6 +392,9 @@ static GtkActionEntry rb_shell_actions [ { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1", N_("Display music player help"), G_CALLBACK (rb_shell_cmd_contents) }, + { "MusicClose", GTK_STOCK_CLOSE, N_("_Close"), "<control>W", + N_("Hide the music player window"), + G_CALLBACK (rb_shell_cmd_toggle_visibility) }, { "MusicQuit", GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", N_("Quit the music player"), G_CALLBACK (rb_shell_cmd_quit) }, @@ -889,6 +896,8 @@ rb_shell_construct (RBShell *shell) } rb_debug ("shell: setting up tray icon"); + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (shell->priv->window), TRUE); + /* gtk_window_set_skip_pager_hint (GTK_WINDOW (shell->priv->window), TRUE); */ tray_destroy_cb (NULL, shell); /* initialize shell services */ @@ -1149,13 +1158,77 @@ rb_shell_window_state_cb (GtkWidget *wid } #endif +/* Based on a function found in wnck */ +static void +set_icon_geometry (GdkWindow *window, + int x, + int y, + int width, + int height) +{ + gulong data[4]; + Display *dpy = gdk_x11_drawable_get_xdisplay (window); + + data[0] = x; + data[1] = y; + data[2] = width; + data[3] = height; + + XChangeProperty (dpy, + GDK_WINDOW_XID (window), + gdk_x11_get_xatom_by_name_for_display (gdk_drawable_get_display (window), + "_NET_WM_ICON_GEOMETRY"), + XA_CARDINAL, 32, PropModeReplace, + (guchar *)&data, 4); +} + +static void +rb_shell_set_visibility (RBShell *shell, gboolean visible) +{ + if (visible == shell->priv->visible) + return; + + if (visible) { + rb_debug ("showing main window"); + rb_shell_sync_window_state (shell); + + gtk_widget_realize (shell->priv->window); + gdk_flush (); + if ((shell->priv->window_x >= 0) && (shell->priv->window_y >= 0)) + gtk_window_move (GTK_WINDOW (shell->priv->window), + shell->priv->window_x, + shell->priv->window_y); + + gtk_window_deiconify (GTK_WINDOW (shell->priv->window)); + gtk_window_present (GTK_WINDOW (shell->priv->window)); + gtk_widget_show (shell->priv->window); + } else { + int x, y, width, height; + + /* should store this stuff in gconf instead? */ + rb_debug ("hiding main window"); + gtk_window_get_position (GTK_WINDOW (shell->priv->window), + &shell->priv->window_x, + &shell->priv->window_y); + rb_tray_icon_get_geom (shell->priv->tray_icon, + &x, &y, &width, &height); + set_icon_geometry (GTK_WIDGET (shell->priv->window)->window, + x, y, width, height); + gtk_window_iconify (GTK_WINDOW (shell->priv->window)); + } + + shell->priv->visible = visible; + g_signal_emit_by_name (shell, "visibility_changed", visible); + +} + static gboolean rb_shell_window_delete_cb (GtkWidget *win, GdkEventAny *event, RBShell *shell) { - rb_debug ("window deleted"); - rb_shell_quit (shell); + rb_debug ("window deleted, toggling visibility"); + rb_shell_set_visibility (shell, !shell->priv->visible); return TRUE; }; @@ -1624,6 +1697,13 @@ rb_shell_cmd_about (GtkAction *action, } static void +rb_shell_cmd_toggle_visibility (GtkAction *action, + RBShell *shell) +{ + rb_shell_set_visibility (shell, !shell->priv->visible); +} + +static void rb_shell_cmd_quit (GtkAction *action, RBShell *shell) { @@ -2095,20 +2175,21 @@ static gboolean tray_destroy_cb (GtkObject *object, RBShell *shell) { if (shell->priv->tray_icon) { - rb_debug ("caught destroy event for tray icon"); + rb_debug ("caught destroy event for tray icon %p", object); gtk_object_sink (object); shell->priv->tray_icon = NULL; + rb_debug ("finished sinking tray"); } rb_debug ("creating new tray icon"); shell->priv->tray_icon = rb_tray_icon_new (shell->priv->ui_manager, - shell->priv->actiongroup, RB_REMOTE_PROXY (shell)); g_signal_connect_object (G_OBJECT (shell->priv->tray_icon), "destroy", G_CALLBACK (tray_destroy_cb), shell, 0); gtk_widget_show_all (GTK_WIDGET (shell->priv->tray_icon)); + rb_debug ("done creating new tray icon %p", shell->priv->tray_icon); return TRUE; } @@ -2217,32 +2298,7 @@ static void rb_shell_set_visibility_impl (RBRemoteProxy *proxy, gboolean visible) { RBShell *shell = RB_SHELL (proxy); - if (visible == shell->priv->visible) - return; - - if (visible) { - rb_debug ("showing main window"); - rb_shell_sync_window_state (shell); - - gtk_widget_realize (shell->priv->window); - gdk_flush (); - if ((shell->priv->window_x >= 0) && (shell->priv->window_y >= 0)) - gtk_window_move (GTK_WINDOW (shell->priv->window), - shell->priv->window_x, - shell->priv->window_y); - - gtk_widget_show (shell->priv->window); - } else { - /* should store this stuff in gconf instead? */ - rb_debug ("hiding main window"); - gtk_window_get_position (GTK_WINDOW (shell->priv->window), - &shell->priv->window_x, - &shell->priv->window_y); - gtk_widget_hide (shell->priv->window); - } - - shell->priv->visible = visible; - g_signal_emit_by_name (proxy, "visibility_changed", visible); + rb_shell_set_visibility (shell, visible); } static gboolean Index: shell/rb-tray-icon.c =================================================================== RCS file: /cvs/gnome/rhythmbox/shell/rb-tray-icon.c,v retrieving revision 1.17 diff -u -p -r1.17 rb-tray-icon.c --- shell/rb-tray-icon.c 19 Jun 2005 18:30:57 -0000 1.17 +++ shell/rb-tray-icon.c 7 Jul 2005 18:15:33 -0000 @@ -94,8 +94,8 @@ enum static GtkToggleActionEntry rb_tray_icon_toggle_entries [] = { - { "TrayShowWindow", NULL, N_("_Show Window"), NULL, - N_("Change the visibility of the main window"), + { "TrayShowWindow", NULL, N_("_Show Music Player"), NULL, + N_("Choose music to play"), G_CALLBACK (rb_tray_icon_show_window_changed_cb) } }; static guint rb_tray_icon_n_toggle_entries = G_N_ELEMENTS (rb_tray_icon_toggle_entries); @@ -165,7 +165,7 @@ rb_tray_icon_class_init (RBTrayIconClass "GtkActionGroup", "GtkActionGroup object", GTK_TYPE_ACTION_GROUP, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_READABLE)); } static void @@ -217,6 +217,16 @@ rb_tray_icon_constructor (GType type, gu tray = RB_TRAY_ICON (parent_class->constructor (type, n_construct_properties, construct_properties)); + tray->priv->actiongroup = gtk_action_group_new ("TrayActions"); + gtk_action_group_add_toggle_actions (tray->priv->actiongroup, + rb_tray_icon_toggle_entries, + rb_tray_icon_n_toggle_entries, + tray); + rb_tray_icon_sync_action (NULL, FALSE, tray); + + gtk_ui_manager_insert_action_group (tray->priv->ui_manager, tray->priv->actiongroup, 0); + g_object_unref (tray->priv->actiongroup); + return G_OBJECT (tray); } @@ -230,6 +240,10 @@ rb_tray_icon_finalize (GObject *object) tray = RB_TRAY_ICON (object); + rb_debug ("tray icon %p finalizing", object); + + gtk_ui_manager_remove_action_group (tray->priv->ui_manager, tray->priv->actiongroup); + g_return_if_fail (tray->priv != NULL); gtk_object_destroy (GTK_OBJECT (tray->priv->tooltips)); @@ -272,14 +286,6 @@ rb_tray_icon_set_property (GObject *obje case PROP_UI_MANAGER: tray->priv->ui_manager = g_value_get_object (value); break; - case PROP_ACTION_GROUP: - tray->priv->actiongroup = g_value_get_object (value); - gtk_action_group_add_toggle_actions (tray->priv->actiongroup, - rb_tray_icon_toggle_entries, - rb_tray_icon_n_toggle_entries, - tray); - rb_tray_icon_sync_action (NULL, FALSE, tray); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -313,49 +319,64 @@ rb_tray_icon_get_property (GObject *obje RBTrayIcon * rb_tray_icon_new (GtkUIManager *mgr, - GtkActionGroup *group, RBRemoteProxy *remote) { return g_object_new (RB_TYPE_TRAY_ICON, "title", "Rhythmbox tray icon", "ui-manager", mgr, - "action-group", group, "remote", remote, NULL); } static void +tray_popup_position_menu (GtkMenu *menu, + int *x, + int *y, + gboolean *push_in, + gpointer user_data) +{ + GtkWidget *widget; + GtkRequisition requisition; + gint menu_xpos; + gint menu_ypos; + + widget = GTK_WIDGET (user_data); + + gtk_widget_size_request (GTK_WIDGET (menu), &requisition); + + gdk_window_get_origin (widget->window, &menu_xpos, &menu_ypos); + + menu_xpos += widget->allocation.x; + menu_ypos += widget->allocation.y; + + if (menu_ypos > gdk_screen_get_height (gtk_widget_get_screen (widget)) / 2) + menu_ypos -= requisition.height; + else + menu_ypos += widget->allocation.height; + + *x = menu_xpos; + *y = menu_ypos; + *push_in = TRUE; +} + +static void rb_tray_icon_button_press_event_cb (GtkWidget *ebox, GdkEventButton *event, RBTrayIcon *icon) { + GtkWidget *popup; + /* filter out double, triple clicks */ if (event->type != GDK_BUTTON_PRESS) return; rb_debug ("tray button press"); - switch (event->button) { - case 1: - { - gboolean visible = rb_remote_proxy_get_visibility (icon->priv->proxy); - rb_remote_proxy_set_visibility (icon->priv->proxy, visible ? FALSE : TRUE); - break; - } - - case 3: - { - GtkWidget *popup; - popup = gtk_ui_manager_get_widget (GTK_UI_MANAGER (icon->priv->ui_manager), - "/RhythmboxTrayPopup"); - gtk_menu_set_screen (GTK_MENU (popup), gtk_widget_get_screen (GTK_WIDGET (icon))); - gtk_menu_popup (GTK_MENU (popup), NULL, NULL, - NULL, NULL, 2, - gtk_get_current_event_time ()); - } - break; - default: - break; - } + popup = gtk_ui_manager_get_widget (GTK_UI_MANAGER (icon->priv->ui_manager), + "/RhythmboxTrayPopup"); + gtk_menu_set_screen (GTK_MENU (popup), gtk_widget_get_screen (GTK_WIDGET (icon))); + gtk_menu_popup (GTK_MENU (popup), NULL, NULL, + tray_popup_position_menu, ebox, 2, + gtk_get_current_event_time ()); } static void @@ -442,9 +463,25 @@ static void rb_tray_icon_show_window_changed_cb (GtkAction *action, RBTrayIcon *icon) { - rb_debug ("show window clicked"); + rb_debug ("show window clicked for %p", icon); rb_remote_proxy_set_visibility (icon->priv->proxy, gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); +} + +void +rb_tray_icon_get_geom (RBTrayIcon *icon, int *x, int *y, int *width, int *height) +{ + GtkWidget *widget; + GtkRequisition requisition; + + widget = GTK_WIDGET (icon->priv->ebox); + + gtk_widget_size_request (widget, &requisition); + + gdk_window_get_origin (widget->window, x, y); + + *width = widget->allocation.x; + *height = widget->allocation.y; } void Index: shell/rb-tray-icon.h =================================================================== RCS file: /cvs/gnome/rhythmbox/shell/rb-tray-icon.h,v retrieving revision 1.6 diff -u -p -r1.6 rb-tray-icon.h --- shell/rb-tray-icon.h 19 Jun 2005 18:30:57 -0000 1.6 +++ shell/rb-tray-icon.h 7 Jul 2005 18:15:33 -0000 @@ -54,8 +54,9 @@ typedef struct GType rb_tray_icon_get_type (void); RBTrayIcon * rb_tray_icon_new (GtkUIManager *mgr, - GtkActionGroup *actiongroup, RBRemoteProxy *remote); + +void rb_tray_icon_get_geom (RBTrayIcon *icon, int *x, int *y, int *width, int *height); void rb_tray_icon_set_tooltip(RBTrayIcon *icon, const char *tooltip); cvs server: Diffing sources cvs server: Diffing tests cvs server: Diffing views cvs server: Diffing widgets cvs server: Diffing xine-output
Attachment:
signature.asc
Description: This is a digitally signed message part