Hi, Here's an updated patch which only does the minimization if you have a notification area, and also has what I think are better rules for handling clicks on the icon. Now it always presents the window if it doesn't have focus, and only does the minimization if the window doesn't have focus. Can people play around with this and see how it feels?
? .project
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.20
diff -u -p -r1.20 rhythmbox-ui.xml
--- data/ui/rhythmbox-ui.xml 26 Jul 2005 14:07:28 -0000 1.20
+++ data/ui/rhythmbox-ui.xml 31 Aug 2005 16:02:15 -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.325
diff -u -p -r1.325 rb-shell.c
--- shell/rb-shell.c 30 Aug 2005 21:03:28 -0000 1.325
+++ shell/rb-shell.c 31 Aug 2005 16:02:15 -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>
@@ -146,6 +148,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,
@@ -275,7 +279,7 @@ enum
struct RBShellPrivate
{
GtkWidget *window;
- gboolean visible;
+ gboolean iconified;
GtkUIManager *ui_manager;
GtkActionGroup *actiongroup;
@@ -358,6 +362,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) },
@@ -792,12 +799,12 @@ rb_shell_constructor (GType type, guint
gtk_window_set_title (win, _("Music Player"));
shell->priv->window = GTK_WIDGET (win);
- shell->priv->visible = TRUE;
-
+ shell->priv->iconified = FALSE;
g_signal_connect_object (G_OBJECT (win), "window-state-event",
G_CALLBACK (rb_shell_window_state_cb),
shell, 0);
+
g_signal_connect_object (G_OBJECT (win), "delete_event",
G_CALLBACK (rb_shell_window_delete_cb),
shell, 0);
@@ -848,6 +855,8 @@ rb_shell_constructor (GType type, guint
}
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 */
@@ -1062,26 +1071,78 @@ rb_shell_constructor (GType type, guint
return G_OBJECT (shell);
}
+/* 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 gboolean
rb_shell_window_state_cb (GtkWidget *widget,
GdkEvent *event,
RBShell *shell)
{
- gboolean visible;
+ if (event->type == GDK_WINDOW_STATE) {
+ shell->priv->iconified = (event->window_state.new_window_state
+ & GDK_WINDOW_STATE_ICONIFIED);
+ }
+ return FALSE;
+}
+
+static gboolean
+rb_shell_get_visibility (RBShell *shell)
+{
+ return GTK_WIDGET_REALIZED (shell->priv->window)
+ && !shell->priv->iconified
+ && gtk_window_is_active (GTK_WINDOW (shell->priv->window));
+}
- g_return_val_if_fail (widget != NULL, FALSE);
- rb_debug ("caught window state change");
+static void
+rb_shell_set_visibility (RBShell *shell, gboolean visible)
+{
+ gboolean current_visible;
- if (event->type == GDK_WINDOW_STATE) {
- visible = ! ((event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||
- (event->window_state.new_window_state & GDK_WINDOW_STATE_WITHDRAWN));
- if (visible != shell->priv->visible) {
- shell->priv->visible = visible;
- g_signal_emit_by_name (RB_REMOTE_PROXY (shell), "visibility_changed", visible);
- }
+ current_visible = rb_shell_get_visibility (shell);
+ if (visible == current_visible)
+ return;
+
+ if (visible) {
+ rb_debug ("showing main window");
+ rb_shell_sync_window_state (shell);
+
+ gtk_window_deiconify (GTK_WINDOW (shell->priv->window));
+ rb_shell_present (shell, gtk_get_current_event_time (), NULL);
+ } else {
+ int x, y, width, height;
+
+ rb_debug ("hiding main window");
+ 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));
}
- return FALSE;
+ g_signal_emit_by_name (shell, "visibility_changed", visible);
+
}
static gboolean
@@ -1089,9 +1150,13 @@ rb_shell_window_delete_cb (GtkWidget *wi
GdkEventAny *event,
RBShell *shell)
{
- rb_debug ("window deleted");
- rb_shell_quit (shell);
-
+ if (egg_tray_icon_have_manager (EGG_TRAY_ICON (shell->priv->tray_icon))) {
+ rb_debug ("window deleted, hiding");
+ rb_shell_set_visibility (shell, FALSE);
+ } else {
+ rb_debug ("no tray icon to minimize to, quitting");
+ rb_shell_quit (shell);
+ }
return TRUE;
}
@@ -1530,6 +1595,23 @@ rb_shell_cmd_about (GtkAction *action,
g_string_free (comment, TRUE);
}
+void
+rb_shell_toggle_visibility (RBShell *shell)
+{
+ gboolean visible;
+
+ visible = rb_shell_get_visibility (shell);
+
+ rb_shell_set_visibility (shell, !visible);
+}
+
+static void
+rb_shell_cmd_toggle_visibility (GtkAction *action,
+ RBShell *shell)
+{
+ rb_shell_toggle_visibility (shell);
+}
+
static void
rb_shell_cmd_quit (GtkAction *action,
RBShell *shell)
@@ -1947,20 +2029,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;
}
@@ -1972,7 +2055,7 @@ rb_shell_hidden_notify (RBShell *shell,
const char *secondary)
{
- if (shell->priv->visible) {
+ if (rb_shell_get_visibility (shell)) {
rb_debug ("shell is visible, not notifying");
return;
}
@@ -2220,29 +2303,14 @@ static gboolean
rb_shell_get_visibility_impl (RBRemoteProxy *proxy)
{
RBShell *shell = RB_SHELL (proxy);
- return shell->priv->visible;
+ return rb_shell_get_visibility (shell);
}
static void
rb_shell_set_visibility_impl (RBRemoteProxy *proxy, gboolean visible)
{
RBShell *shell = RB_SHELL (proxy);
-
- rb_debug ("setting visibility %s current visibility %s",
- visible ? "TRUE" : "FALSE",
- shell->priv->visible ? "TRUE" : "FALSE");
-
- if (visible == shell->priv->visible)
- return;
-
- if (visible) {
- gtk_window_present (GTK_WINDOW (shell->priv->window));
- } else {
- 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-shell.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-shell.h,v
retrieving revision 1.19
diff -u -p -r1.19 rb-shell.h
--- shell/rb-shell.h 30 Aug 2005 20:22:37 -0000 1.19
+++ shell/rb-shell.h 31 Aug 2005 16:02:15 -0000
@@ -86,6 +86,8 @@ GObject * rb_shell_get_player
const char * rb_shell_get_player_path(RBShell *shell);
+void rb_shell_toggle_visibility (RBShell *shell);
+
gboolean rb_shell_get_song_properties (RBShell *shell,
const char *uri,
GHashTable **properties,
Index: shell/rb-tray-icon.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-tray-icon.c,v
retrieving revision 1.19
diff -u -p -r1.19 rb-tray-icon.c
--- shell/rb-tray-icon.c 14 Aug 2005 02:49:07 -0000 1.19
+++ shell/rb-tray-icon.c 31 Aug 2005 16:02:15 -0000
@@ -96,8 +96,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);
@@ -167,7 +167,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
@@ -219,6 +219,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);
}
@@ -232,6 +242,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));
@@ -274,14 +288,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;
@@ -315,21 +321,52 @@ 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;
@@ -337,27 +374,22 @@ rb_tray_icon_button_press_event_cb (GtkW
rb_debug ("tray button press");
switch (event->button) {
- case 1:
- {
+ 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;
+
+ case 3: {
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,
+ tray_popup_position_menu, ebox, 2,
gtk_get_current_event_time ());
- }
- break;
- default:
break;
}
+ }
}
static void
@@ -367,7 +399,7 @@ rb_tray_icon_scroll_event_cb (GtkWidget
float volume;
rb_debug ("tray button scroll");
volume = eel_gconf_get_float (CONF_STATE_VOLUME);
- switch(event->scroll.direction) {
+ switch (event->scroll.direction) {
case GDK_SCROLL_UP:
volume += 0.1;
if (volume > 1.0)
@@ -444,9 +476,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.7
diff -u -p -r1.7 rb-tray-icon.h
--- shell/rb-tray-icon.h 13 Aug 2005 23:34:03 -0000 1.7
+++ shell/rb-tray-icon.h 31 Aug 2005 16:02:15 -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_notify (RBTrayIcon *icon,
guint timeout,
cvs server: Diffing sources
cvs server: Diffing tests
cvs server: Diffing views
cvs server: Diffing widgets
Index: widgets/eggtrayicon.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/widgets/eggtrayicon.c,v
retrieving revision 1.3
diff -u -p -r1.3 eggtrayicon.c
--- widgets/eggtrayicon.c 13 Aug 2005 23:34:03 -0000 1.3
+++ widgets/eggtrayicon.c 31 Aug 2005 16:02:15 -0000
@@ -367,6 +367,17 @@ egg_tray_icon_manager_window_destroyed (
#endif
+gboolean
+egg_tray_icon_have_manager (EggTrayIcon *icon)
+{
+ GtkPlug * plug = GTK_PLUG (icon);
+
+ if (plug->socket_window)
+ return TRUE;
+ else
+ return FALSE;
+}
+
static void
egg_tray_icon_realize (GtkWidget *widget)
{
Index: widgets/eggtrayicon.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/widgets/eggtrayicon.h,v
retrieving revision 1.2
diff -u -p -r1.2 eggtrayicon.h
--- widgets/eggtrayicon.h 13 Aug 2005 23:34:03 -0000 1.2
+++ widgets/eggtrayicon.h 31 Aug 2005 16:02:15 -0000
@@ -75,6 +75,8 @@ guint egg_tray_icon_send_message
void egg_tray_icon_cancel_message (EggTrayIcon *icon,
guint id);
+gboolean egg_tray_icon_have_manager (EggTrayIcon *icon);
+
EggNotificationBubble *egg_tray_icon_notify (EggTrayIcon *icon,
guint timeout,
const char *primary,
cvs server: Diffing xine-output
Attachment:
signature.asc
Description: This is a digitally signed message part