chiark / gitweb /
Use a GtkToolbar for the toolbar icons. The image is now fixed and
authorRichard Kettlewell <rjk@greenend.org.uk>
Sun, 6 Dec 2009 16:04:52 +0000 (16:04 +0000)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sun, 6 Dec 2009 16:04:52 +0000 (16:04 +0000)
the togglable ones "stay depressed" when active.

In full mode you get text as well as the icon, in compact mode just
the icons.

The manual screenshots are going to have to be redone l-(

disobedience/control.c
disobedience/disobedience.c

index 7d96aa2a8bc14915c534448327a9f2874ea8b1ef..13cd68db7f4109ebe7086a8a1273dc69583c17ce 100644 (file)
@@ -25,7 +25,9 @@
 
 struct icon;
 
 
 struct icon;
 
-static void clicked_icon(GtkButton *, gpointer);
+static void clicked_icon(GtkToolButton *, gpointer);
+static void toggled_icon(GtkToggleToolButton *button,
+                         gpointer user_data);
 static void clicked_menu(GtkMenuItem *, gpointer userdata);
 static void toggled_menu(GtkCheckMenuItem *, gpointer userdata);
 
 static void clicked_menu(GtkMenuItem *, gpointer userdata);
 static void toggled_menu(GtkCheckMenuItem *, gpointer userdata);
 
@@ -60,6 +62,9 @@ static void control_minimode(const char *event,
 /** @brief Guard against feedback */
 int suppress_actions = 1;
 
 /** @brief Guard against feedback */
 int suppress_actions = 1;
 
+/** @brief Toolbar widget */
+static GtkWidget *toolbar;
+
 /** @brief Definition of an icon
  *
  * We have two kinds of icon:
 /** @brief Definition of an icon
  *
  * We have two kinds of icon:
@@ -72,24 +77,27 @@ int suppress_actions = 1;
  * (All icons can be sensitive or insensitive, separately to the above.)
  */
 struct icon {
  * (All icons can be sensitive or insensitive, separately to the above.)
  */
 struct icon {
-  /** @brief True to use GTK+ stock icons instead of filenames */
+  /** @brief TRUE to use GTK+ stock icons instead of filenames */
   gboolean stock;
 
   gboolean stock;
 
-  /** @brief Filename for 'on' image */
-  const char *icon_on;
+  /** @brief TRUE for toggle buttons, FALSE for action buttons */
+  gboolean toggle;
+  
+  /** @brief Filename for image or stock string */
+  const char *icon;
 
   /** @brief Text for 'on' tooltip */
   const char *tip_on;
 
 
   /** @brief Text for 'on' tooltip */
   const char *tip_on;
 
-  /** @brief Filename for 'off' image or NULL for an action icon */
-  const char *icon_off;
-
   /** @brief Text for 'off' tooltip */
   const char *tip_off;
 
   /** @brief Associated menu item or NULL */
   const char *menuitem;
 
   /** @brief Text for 'off' tooltip */
   const char *tip_off;
 
   /** @brief Associated menu item or NULL */
   const char *menuitem;
 
+  /** @brief Label text */
+  const char *label;
+
   /** @brief Events that change this icon, separated by spaces */
   const char *events;
 
   /** @brief Events that change this icon, separated by spaces */
   const char *events;
 
@@ -127,12 +135,11 @@ struct icon {
   /** @brief Pointer to menu item */
   GtkWidget *item;
 
   /** @brief Pointer to menu item */
   GtkWidget *item;
 
-  GtkWidget *image_on;
-  GtkWidget *image_off;
+  GtkWidget *image;
 };
 
 static int pause_resume_on(void) {
 };
 
 static int pause_resume_on(void) {
-  return !(last_state & DISORDER_TRACK_PAUSED);
+  return !!(last_state & DISORDER_TRACK_PAUSED);
 }
 
 static int pause_resume_sensitive(void) {
 }
 
 static int pause_resume_sensitive(void) {
@@ -154,7 +161,6 @@ static int random_enabled(void) {
   return !!(last_state & DISORDER_RANDOM_ENABLED);
 }
 
   return !!(last_state & DISORDER_RANDOM_ENABLED);
 }
 
-#if 0
 static int playing_sensitive(void) {
   return !!(last_rights & RIGHT_GLOBAL_PREFS);
 }
 static int playing_sensitive(void) {
   return !!(last_rights & RIGHT_GLOBAL_PREFS);
 }
@@ -162,7 +168,6 @@ static int playing_sensitive(void) {
 static int playing_enabled(void) {
   return !!(last_state & DISORDER_PLAYING_ENABLED);
 }
 static int playing_enabled(void) {
   return !!(last_state & DISORDER_PLAYING_ENABLED);
 }
-#endif
 
 static int rtp_enabled(void) {
   return rtp_is_running;
 
 static int rtp_enabled(void) {
   return rtp_is_running;
@@ -175,21 +180,23 @@ static int rtp_sensitive(void) {
 /** @brief Table of all icons */
 static struct icon icons[] = {
   {
 /** @brief Table of all icons */
 static struct icon icons[] = {
   {
+    toggle: TRUE,
     stock: TRUE,
     stock: TRUE,
-    icon_on: GTK_STOCK_MEDIA_PAUSE,
+    icon: GTK_STOCK_MEDIA_PAUSE,
+    label: "Pause",
     tip_on: "Pause playing track",
     tip_on: "Pause playing track",
-    icon_off: GTK_STOCK_MEDIA_PLAY,
     tip_off: "Resume playing track",
     menuitem: "<GdisorderMain>/Control/Playing",
     on: pause_resume_on,
     sensitive: pause_resume_sensitive,
     tip_off: "Resume playing track",
     menuitem: "<GdisorderMain>/Control/Playing",
     on: pause_resume_on,
     sensitive: pause_resume_sensitive,
-    action_go_on: disorder_eclient_resume,
-    action_go_off: disorder_eclient_pause,
+    action_go_on: disorder_eclient_pause,
+    action_go_off: disorder_eclient_resume,
     events: "pause-changed playing-changed rights-changed playing-track-changed",
   },
   {
     stock: TRUE,
     events: "pause-changed playing-changed rights-changed playing-track-changed",
   },
   {
     stock: TRUE,
-    icon_on: GTK_STOCK_STOP,
+    icon: GTK_STOCK_STOP,
+    label: "Scratch",
     tip_on: "Cancel playing track",
     menuitem: "<GdisorderMain>/Control/Scratch",
     sensitive: scratch_sensitive,
     tip_on: "Cancel playing track",
     menuitem: "<GdisorderMain>/Control/Scratch",
     sensitive: scratch_sensitive,
@@ -197,10 +204,11 @@ static struct icon icons[] = {
     events: "playing-track-changed rights-changed",
   },
   {
     events: "playing-track-changed rights-changed",
   },
   {
+    toggle: TRUE,
     stock: TRUE,
     stock: TRUE,
-    icon_on: GTK_STOCK_YES,
+    icon: GTK_STOCK_REFRESH,
+    label: "Random",
     tip_on: "Disable random play",
     tip_on: "Disable random play",
-    icon_off: GTK_STOCK_NO,
     tip_off: "Enable random play",
     menuitem: "<GdisorderMain>/Control/Random play",
     on: random_enabled,
     tip_off: "Enable random play",
     menuitem: "<GdisorderMain>/Control/Random play",
     on: random_enabled,
@@ -209,12 +217,12 @@ static struct icon icons[] = {
     action_go_off: disorder_eclient_random_disable,
     events: "random-changed rights-changed",
   },
     action_go_off: disorder_eclient_random_disable,
     events: "random-changed rights-changed",
   },
-#if 0
   {
   {
+    toggle: TRUE,
     stock: TRUE,
     stock: TRUE,
-    icon_on: GTK_STOCK_YES,
+    icon: GTK_STOCK_MEDIA_PLAY,
+    label: "Play",
     tip_on: "Disable play",
     tip_on: "Disable play",
-    icon_off: GTK_STOCK_NO,
     tip_off: "Enable play",
     on: playing_enabled,
     sensitive: playing_sensitive,
     tip_off: "Enable play",
     on: playing_enabled,
     sensitive: playing_sensitive,
@@ -222,12 +230,12 @@ static struct icon icons[] = {
     action_go_off: disorder_eclient_disable,
     events: "enabled-changed rights-changed",
   },
     action_go_off: disorder_eclient_disable,
     events: "enabled-changed rights-changed",
   },
-#endif
   {
   {
+    toggle: TRUE,
     stock: TRUE,
     stock: TRUE,
-    icon_on: GTK_STOCK_CONNECT,
+    icon: GTK_STOCK_CONNECT,
+    label: "RTP",
     tip_on: "Stop playing network stream",
     tip_on: "Stop playing network stream",
-    icon_off: GTK_STOCK_DISCONNECT,
     tip_off: "Play network stream",
     menuitem: "<GdisorderMain>/Control/Network player",
     on: rtp_enabled,
     tip_off: "Play network stream",
     menuitem: "<GdisorderMain>/Control/Network player",
     on: rtp_enabled,
@@ -248,48 +256,52 @@ static GtkWidget *balance_widget;
 
 /** @brief Create the control bar */
 GtkWidget *control_widget(void) {
 
 /** @brief Create the control bar */
 GtkWidget *control_widget(void) {
-  GtkWidget *hbox = gtk_hbox_new(FALSE, 1), *vbox;
+  GtkWidget *hbox = gtk_hbox_new(FALSE, 1);
   int n;
 
   D(("control_widget"));
   assert(mainmenufactory);              /* ordering must be right */
   int n;
 
   D(("control_widget"));
   assert(mainmenufactory);              /* ordering must be right */
+  toolbar = gtk_toolbar_new();
+  /* Don't permit overflow arrow as otherwise the toolbar isn't greedy enough
+   * in asking for space.  The ideal is probably to make the volume and balance
+   * sliders hang down from the toolbar so it unavoidably gets the whole width
+   * of the window to play with. */
+  gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolbar), FALSE);
+  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), 
+                        full_mode ? GTK_TOOLBAR_BOTH : GTK_TOOLBAR_ICONS);
   for(n = 0; n < NICONS; ++n) {
   for(n = 0; n < NICONS; ++n) {
-    /* Create the button */
-    icons[n].button = gtk_button_new();
+    struct icon *const icon = &icons[n];
+    icon->button = (icon->toggle
+                    ? GTK_WIDGET(gtk_toggle_tool_button_new())
+                    : GTK_WIDGET(gtk_tool_button_new(NULL, NULL)));
     gtk_widget_set_style(icons[n].button, tool_style);
     if(icons[n].stock) {
       /* We'll use the stock icons for this one */
     gtk_widget_set_style(icons[n].button, tool_style);
     if(icons[n].stock) {
       /* We'll use the stock icons for this one */
-      gtk_button_set_use_stock(GTK_BUTTON(icons[n].button), TRUE);
-      icons[n].image_on = gtk_image_new_from_stock(icons[n].icon_on,
-                                                   GTK_ICON_SIZE_LARGE_TOOLBAR);
-      if(icons[n].icon_off)
-        icons[n].image_off = gtk_image_new_from_stock(icons[n].icon_off,
-                                                     GTK_ICON_SIZE_LARGE_TOOLBAR);
+      icon->image = gtk_image_new_from_stock(icons[n].icon,
+                                             GTK_ICON_SIZE_LARGE_TOOLBAR);
     } else {
       /* Create the 'on' image */
     } else {
       /* Create the 'on' image */
-      icons[n].image_on = gtk_image_new_from_pixbuf(find_image(icons[n].icon_on));
-      gtk_widget_set_style(icons[n].image_on, tool_style);
-      /* If it's a toggle icon, create the 'off' half too */
-      if(icons[n].icon_off) {
-        icons[n].image_off = gtk_image_new_from_pixbuf(find_image(icons[n].icon_off));
-        gtk_widget_set_style(icons[n].image_off, tool_style);
-      }
+      icon->image = gtk_image_new_from_pixbuf(find_image(icons[n].icon));
     }
     }
-    g_object_ref(icons[n].image_on);
-    if(icons[n].image_off)
-      g_object_ref(icons[n].image_off);
-    g_signal_connect(G_OBJECT(icons[n].button), "clicked",
-                     G_CALLBACK(clicked_icon), &icons[n]);
-    /* pop the icon in a vbox so it doesn't get vertically stretch if there are
-     * taller things in the control bar */
-    vbox = gtk_vbox_new(FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(vbox), icons[n].button, TRUE, FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
+    assert(icon->image);
+    gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(icon->button),
+                                    icon->image);
+    gtk_tool_button_set_label(GTK_TOOL_BUTTON(icon->button),
+                                    icon->label);
+    if(icon->toggle)
+      g_signal_connect(G_OBJECT(icon->button), "toggled",
+                       G_CALLBACK(toggled_icon), icon);
+    else
+      g_signal_connect(G_OBJECT(icon->button), "clicked",
+                       G_CALLBACK(clicked_icon), icon);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar),
+                       GTK_TOOL_ITEM(icon->button),
+                       -1);
     if(icons[n].menuitem) {
       /* Find the menu item */
       icons[n].item = gtk_item_factory_get_widget(mainmenufactory,
                                                   icons[n].menuitem);
     if(icons[n].menuitem) {
       /* Find the menu item */
       icons[n].item = gtk_item_factory_get_widget(mainmenufactory,
                                                   icons[n].menuitem);
-      if(icons[n].icon_off)
+      if(icon->toggle)
         g_signal_connect(G_OBJECT(icons[n].item), "toggled",
                          G_CALLBACK(toggled_menu), &icons[n]);
       else
         g_signal_connect(G_OBJECT(icons[n].item), "toggled",
                          G_CALLBACK(toggled_menu), &icons[n]);
       else
@@ -319,8 +331,12 @@ GtkWidget *control_widget(void) {
   gtk_widget_set_size_request(balance_widget, 192, -1);
   gtk_widget_set_tooltip_text(volume_widget, "Volume");
   gtk_widget_set_tooltip_text(balance_widget, "Balance");
   gtk_widget_set_size_request(balance_widget, 192, -1);
   gtk_widget_set_tooltip_text(volume_widget, "Volume");
   gtk_widget_set_tooltip_text(balance_widget, "Balance");
-  gtk_box_pack_start(GTK_BOX(hbox), volume_widget, FALSE, TRUE, 0);
-  gtk_box_pack_start(GTK_BOX(hbox), balance_widget, FALSE, TRUE, 0);
+  gtk_box_pack_start(GTK_BOX(hbox), toolbar,
+                     FALSE/*expand*/, TRUE/*fill*/, 0);
+  gtk_box_pack_start(GTK_BOX(hbox), volume_widget,
+                     FALSE/*expand*/, TRUE/*fill*/, 0);
+  gtk_box_pack_start(GTK_BOX(hbox), balance_widget,
+                     FALSE/*expand*/, TRUE/*fill*/, 0);
   /* space updates rather than hammering the server */
   gtk_range_set_update_policy(GTK_RANGE(volume_widget), GTK_UPDATE_DELAYED);
   gtk_range_set_update_policy(GTK_RANGE(balance_widget), GTK_UPDATE_DELAYED);
   /* space updates rather than hammering the server */
   gtk_range_set_update_policy(GTK_RANGE(volume_widget), GTK_UPDATE_DELAYED);
   gtk_range_set_update_policy(GTK_RANGE(balance_widget), GTK_UPDATE_DELAYED);
@@ -382,22 +398,14 @@ static void icon_changed(const char attribute((unused)) *event,
   int on = icon->on ? icon->on() : 1;
   int sensitive = icon->sensitive ? icon->sensitive() : 1;
   //fprintf(stderr, "sensitive->%d\n", sensitive);
   int on = icon->on ? icon->on() : 1;
   int sensitive = icon->sensitive ? icon->sensitive() : 1;
   //fprintf(stderr, "sensitive->%d\n", sensitive);
-  GtkWidget *child, *newchild;
 
   ++suppress_actions;
   /* If the connection is down nothing is ever usable */
   if(!(last_state & DISORDER_CONNECTED))
     sensitive = 0;
 
   ++suppress_actions;
   /* If the connection is down nothing is ever usable */
   if(!(last_state & DISORDER_CONNECTED))
     sensitive = 0;
-  //fprintf(stderr, "(checked connected) sensitive->%d\n", sensitive);
-  /* Replace the child */
-  newchild = on ? icon->image_on : icon->image_off;
-  child = gtk_bin_get_child(GTK_BIN(icon->button));
-  if(child != newchild) {
-    if(child)
-      gtk_container_remove(GTK_CONTAINER(icon->button), child);
-    gtk_container_add(GTK_CONTAINER(icon->button), newchild);
-    gtk_widget_show(newchild);
-  }
+  if(icon->toggle)
+    gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(icon->button),
+                                      on);
   /* If you disable play or random play NOT via the icon (for instance, via the
    * edit menu or via a completely separate command line invocation) then the
    * icon shows up as insensitive.  Hover the mouse over it and the correct
   /* If you disable play or random play NOT via the icon (for instance, via the
    * edit menu or via a completely separate command line invocation) then the
    * icon shows up as insensitive.  Hover the mouse over it and the correct
@@ -409,7 +417,7 @@ static void icon_changed(const char attribute((unused)) *event,
   gtk_widget_set_sensitive(icon->button, sensitive);
   /* Icons with an associated menu item */
   if(icon->item) {
   gtk_widget_set_sensitive(icon->button, sensitive);
   /* Icons with an associated menu item */
   if(icon->item) {
-    if(icon->icon_off)
+    if(icon->toggle)
       gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(icon->item), on);
     gtk_widget_set_sensitive(icon->item, sensitive);
   }
       gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(icon->item), on);
     gtk_widget_set_sensitive(icon->item, sensitive);
   }
@@ -422,13 +430,22 @@ static void icon_action_completed(void attribute((unused)) *v,
     popup_protocol_error(0, err);
 }
 
     popup_protocol_error(0, err);
 }
 
-static void clicked_icon(GtkButton attribute((unused)) *button,
+static void clicked_icon(GtkToolButton attribute((unused)) *button,
                          gpointer userdata) {
   const struct icon *icon = userdata;
 
   if(suppress_actions)
     return;
                          gpointer userdata) {
   const struct icon *icon = userdata;
 
   if(suppress_actions)
     return;
-  if(!icon->on || icon->on())
+  icon->action_go_off(client, icon_action_completed, 0);
+}
+
+static void toggled_icon(GtkToggleToolButton attribute((unused)) *button,
+                         gpointer user_data) {
+  const struct icon *icon = user_data;
+
+  if(suppress_actions)
+    return;
+  if(icon->on())
     icon->action_go_off(client, icon_action_completed, 0);
   else
     icon->action_go_on(client, icon_action_completed, 0);
     icon->action_go_off(client, icon_action_completed, 0);
   else
     icon->action_go_on(client, icon_action_completed, 0);
@@ -599,6 +616,8 @@ static void control_minimode(const char attribute((unused)) *event,
     gtk_widget_hide(balance_widget);
     gtk_scale_set_value_pos(GTK_SCALE(volume_widget), GTK_POS_RIGHT);
   }
     gtk_widget_hide(balance_widget);
     gtk_scale_set_value_pos(GTK_SCALE(volume_widget), GTK_POS_RIGHT);
   }
+  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), 
+                        full_mode ? GTK_TOOLBAR_BOTH : GTK_TOOLBAR_ICONS);
 }
 
 /*
 }
 
 /*
index 6511b13555a15337df5cafb12ea912e10feb77d6..639eb73c2e74efba3e67a618177ba8740cb2ef52 100644 (file)
@@ -230,7 +230,7 @@ static void check_toplevel_size(const char attribute((unused)) *event,
 
 /** @brief Create and populate the main window */
 static void make_toplevel_window(void) {
 
 /** @brief Create and populate the main window */
 static void make_toplevel_window(void) {
-  GtkWidget *const vbox = gtk_vbox_new(FALSE, 1);
+  GtkWidget *const vbox = gtk_vbox_new(FALSE/*homogeneous*/, 1/*spacing*/);
   GtkWidget *const rb = report_box();
 
   D(("top_window"));
   GtkWidget *const rb = report_box();
 
   D(("top_window"));