diff options
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/common-defs.h | 19 | ||||
-rw-r--r-- | src/indicator-sound.c | 41 | ||||
-rw-r--r-- | src/metadata-menu-item.vala | 73 | ||||
-rw-r--r-- | src/metadata-widget.c | 321 | ||||
-rw-r--r-- | src/metadata-widget.h | 4 | ||||
-rw-r--r-- | src/mpris2-controller.vala | 21 | ||||
-rw-r--r-- | src/player-controller.vala | 35 | ||||
-rw-r--r-- | src/player-item.vala | 6 | ||||
-rw-r--r-- | src/sound-service-dbus.c | 6 | ||||
-rw-r--r-- | src/sound-service.c | 6 | ||||
-rw-r--r-- | src/title-menu-item.vala | 68 | ||||
-rw-r--r-- | src/title-widget.c | 248 | ||||
-rw-r--r-- | src/title-widget.h | 52 | ||||
-rw-r--r-- | vapi/common-defs.vapi | 13 |
16 files changed, 387 insertions, 533 deletions
diff --git a/configure.ac b/configure.ac index 22f04c5..ab02d4e 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ -AC_INIT(indicator-sound, 0.7.0, conor.curran@canonical.com) +AC_INIT(indicator-sound, 0.7.1, conor.curran@canonical.com) AC_PREREQ(2.53) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(indicator-sound, 0.7.0) +AM_INIT_AUTOMAKE(indicator-sound, 0.7.1) AM_MAINTAINER_MODE diff --git a/src/Makefile.am b/src/Makefile.am index 59c8f14..fde333a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,8 +18,6 @@ libsoundmenu_la_SOURCES = \ transport-widget.h \ metadata-widget.c \ metadata-widget.h \ - title-widget.c \ - title-widget.h \ volume-widget.c \ volume-widget.h \ voip-input-widget.c \ @@ -50,7 +48,6 @@ music_bridge_VALASOURCES = \ transport-menu-item.vala \ track-specific-menu-item.vala \ metadata-menu-item.vala \ - title-menu-item.vala \ player-controller.vala \ mpris2-interfaces.vala \ mpris2-watcher.vala \ diff --git a/src/common-defs.h b/src/common-defs.h index 65829a3..a20fb03 100644 --- a/src/common-defs.h +++ b/src/common-defs.h @@ -69,16 +69,15 @@ typedef enum { #define DBUSMENU_TRACK_SPECIFIC_MENUITEM_TYPE "x-canonical-sound-menu-player-track-specific-type" -#define DBUSMENU_METADATA_MENUITEM_TYPE "x-canonical-sound-menu-player-metadata-type" -#define DBUSMENU_METADATA_MENUITEM_ARTIST "x-canonical-sound-menu-player-metadata-xesam:artist" -#define DBUSMENU_METADATA_MENUITEM_TITLE "x-canonical-sound-menu-player-metadata-xesam:title" -#define DBUSMENU_METADATA_MENUITEM_ALBUM "x-canonical-sound-menu-player-metadata-xesam:album" -#define DBUSMENU_METADATA_MENUITEM_ARTURL "x-canonical-sound-menu-player-metadata-mpris:artUrl" - -#define DBUSMENU_TITLE_MENUITEM_TYPE "x-canonical-sound-menu-player-title-type" -#define DBUSMENU_TITLE_MENUITEM_NAME "x-canonical-sound-menu-player-title-name" -#define DBUSMENU_TITLE_MENUITEM_ICON "x-canonical-sound-menu-player-title-icon" -#define DBUSMENU_TITLE_MENUITEM_RUNNING "x-canonical-sound-menu-player-title-running" +#define DBUSMENU_METADATA_MENUITEM_TYPE "x-canonical-sound-menu-player-metadata-type" +#define DBUSMENU_METADATA_MENUITEM_ARTIST "x-canonical-sound-menu-player-metadata-xesam:artist" +#define DBUSMENU_METADATA_MENUITEM_TITLE "x-canonical-sound-menu-player-metadata-xesam:title" +#define DBUSMENU_METADATA_MENUITEM_ALBUM "x-canonical-sound-menu-player-metadata-xesam:album" +#define DBUSMENU_METADATA_MENUITEM_ARTURL "x-canonical-sound-menu-player-metadata-mpris:artUrl" +#define DBUSMENU_METADATA_MENUITEM_PLAYER_NAME "x-canonical-sound-menu-player-metadata-player-name" +#define DBUSMENU_METADATA_MENUITEM_PLAYER_ICON "x-canonical-sound-menu-player-metadata-player-icon" +#define DBUSMENU_METADATA_MENUITEM_PLAYER_RUNNING "x-canonical-sound-menu-player-metadata-player-running" +#define DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS "x-canonical-sound-menu-player-metadata-hide-track-details" #define DBUSMENU_SCRUB_MENUITEM_TYPE "x-canonical-sound-menu-player-scrub-type" #define DBUSMENU_SCRUB_MENUITEM_DURATION "x-canonical-sound-menu-player-scrub-mpris:length" diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 5002463..f2ec0a2 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -31,7 +31,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include "indicator-sound.h" #include "transport-widget.h" #include "metadata-widget.h" -#include "title-widget.h" #include "volume-widget.h" #include "voip-input-widget.h" #include "dbus-shared-names.h" @@ -94,10 +93,6 @@ static gboolean new_metadata_widget (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data); -static gboolean new_title_widget (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data); // DBUS communication static GDBusNodeInfo *node_info = NULL; @@ -208,9 +203,6 @@ get_menu (IndicatorObject * io) dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), DBUSMENU_METADATA_MENUITEM_TYPE, new_metadata_widget); - dbusmenu_client_add_type_handler (DBUSMENU_CLIENT(client), - DBUSMENU_TITLE_MENUITEM_TYPE, - new_title_widget); // Note: Not ideal but all key handling needs to be managed here and then // delegated to the appropriate widget. g_signal_connect (menu, "key-press-event", G_CALLBACK(key_press_cb), io); @@ -360,36 +352,19 @@ new_metadata_widget (DbusmenuMenuitem * newitem, g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); + metadata = metadata_widget_new (newitem); + + g_debug ("%s (\"%s\")", __func__, + dbusmenu_menuitem_property_get(newitem, DBUSMENU_METADATA_MENUITEM_PLAYER_NAME)); + GtkMenuItem *menu_metadata_widget = GTK_MENU_ITEM(metadata); gtk_widget_show_all(metadata); dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client), - newitem, menu_metadata_widget, parent); - return TRUE; -} - -static gboolean -new_title_widget(DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data) -{ - g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); - g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); - - g_debug ("%s (\"%s\")", __func__, dbusmenu_menuitem_property_get(newitem, DBUSMENU_TITLE_MENUITEM_NAME)); - - GtkWidget* title = NULL; - - title = title_widget_new (newitem); - GtkMenuItem *menu_title_widget = GTK_MENU_ITEM(title); - - gtk_widget_show_all(title); - - dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), - newitem, - menu_title_widget, parent); + newitem, + menu_metadata_widget, + parent); return TRUE; } diff --git a/src/metadata-menu-item.vala b/src/metadata-menu-item.vala index 741bb9f..995d248 100644 --- a/src/metadata-menu-item.vala +++ b/src/metadata-menu-item.vala @@ -18,6 +18,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. */ using Gee; +using Dbusmenu; using DbusmenuMetadata; using Gdk; @@ -29,16 +30,21 @@ public class MetadataMenuitem : PlayerItem private static FetchFile fetcher; private string previous_temp_album_art_path; - public MetadataMenuitem() + public MetadataMenuitem (PlayerController parent) { - Object(item_type: MENUITEM_TYPE); - reset(attributes_format()); + Object(item_type: MENUITEM_TYPE, owner: parent); } construct{ MetadataMenuitem.clean_album_art_temp_dir(); - this.previous_temp_album_art_path = null; + this.previous_temp_album_art_path = null; this.album_art_cache_dir = MetadataMenuitem.create_album_art_temp_dir(); + debug ("JUST ABOUT TO ATTEMPT PLAYER NAME SETTING %s", this.owner.app_info.get_name()); + this.property_set (MENUITEM_PLAYER_NAME, this.owner.app_info.get_name()); + this.property_set (MENUITEM_PLAYER_ICON, this.owner.icon_name); + this.property_set_bool (MENUITEM_PLAYER_RUNNING, false); + this.property_set_bool (MENUITEM_HIDE_TRACK_DETAILS, true); + reset (relevant_attributes_for_ui()); } private static void clean_album_art_temp_dir() @@ -98,10 +104,16 @@ public class MetadataMenuitem : PlayerItem public void fetch_art(string uri, string prop) { File art_file = File.new_for_uri(uri); - if(art_file.is_native() == true){ + if (art_file.is_native() == true){ + if (art_file.query_exists() == false){ + // Can't load the image, set prop to empty and return. + this.property_set_int ( prop, EMPTY ); + return; + } string path; try{ - path = Filename.from_uri ( uri.strip() ); + path = Filename.from_uri ( uri.strip() ); + debug ("Populating the artwork field with %s", uri.strip()); this.property_set ( prop, path ); } catch(ConvertError e){ @@ -135,7 +147,7 @@ public class MetadataMenuitem : PlayerItem PixbufLoader loader = new PixbufLoader (); loader.write (update.data); loader.close (); - Pixbuf icon = loader.get_pixbuf (); + Pixbuf icon = loader.get_pixbuf (); string path = this.album_art_cache_dir.concat("/downloaded-coverart-XXXXXX"); int r = FileUtils.mkstemp(path); if(r != -1){ @@ -144,7 +156,7 @@ public class MetadataMenuitem : PlayerItem if(this.previous_temp_album_art_path != null){ FileUtils.remove(this.previous_temp_album_art_path); } - this.previous_temp_album_art_path = path; + this.previous_temp_album_art_path = path; } } catch(GLib.Error e){ @@ -152,7 +164,37 @@ public class MetadataMenuitem : PlayerItem e.message); } } + + public override void handle_event (string name, + Variant input_value, + uint timestamp) + { + if(this.owner.current_state == PlayerController.state.OFFLINE) + { + this.owner.instantiate(); + } + else if(this.owner.current_state == PlayerController.state.CONNECTED){ + this.owner.mpris_bridge.expose(); + } + } + public void alter_label (string new_title) + { + if (new_title == null) return; + this.property_set (MENUITEM_PLAYER_NAME, new_title); + } + + public void toggle_active_triangle (bool update) + { + debug ("toggle active triangle"); + this.property_set_bool (MENUITEM_PLAYER_RUNNING, update); + } + + public void should_collapse(bool collapse) + { + this.property_set_bool (MENUITEM_HIDE_TRACK_DETAILS, collapse); + } + public static HashSet<string> attributes_format() { HashSet<string> attrs = new HashSet<string>(); @@ -160,6 +202,19 @@ public class MetadataMenuitem : PlayerItem attrs.add(MENUITEM_ARTIST); attrs.add(MENUITEM_ALBUM); attrs.add(MENUITEM_ARTURL); + attrs.add(MENUITEM_PLAYER_NAME); + attrs.add(MENUITEM_PLAYER_ICON); + attrs.add(MENUITEM_PLAYER_RUNNING); + return attrs; + } + + public static HashSet<string> relevant_attributes_for_ui() + { + HashSet<string> attrs = new HashSet<string>(); + attrs.add(MENUITEM_TITLE); + attrs.add(MENUITEM_ARTIST); + attrs.add(MENUITEM_ALBUM); + attrs.add(MENUITEM_ARTURL); return attrs; - } + } } diff --git a/src/metadata-widget.c b/src/metadata-widget.c index 38ed529..f687d0c 100644 --- a/src/metadata-widget.c +++ b/src/metadata-widget.c @@ -28,20 +28,24 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <gtk/gtk.h> #include <glib.h> #include "transport-widget.h" +#include <libindicator/indicator-image-helper.h> typedef struct _MetadataWidgetPrivate MetadataWidgetPrivate; struct _MetadataWidgetPrivate { gboolean theme_change_occured; - GtkWidget* hbox; + GtkWidget* meta_data_h_box; + GtkWidget* meta_data_v_box; GtkWidget* album_art; GString* image_path; GString* old_image_path; GtkWidget* artist_label; GtkWidget* piece_label; GtkWidget* container_label; - DbusmenuMenuitem* twin_item; + GtkWidget* player_label; + GdkPixbuf* icon_buf; + DbusmenuMenuitem* twin_item; }; #define METADATA_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), METADATA_WIDGET_TYPE, MetadataWidgetPrivate)) @@ -51,12 +55,15 @@ static void metadata_widget_class_init (MetadataWidgetClass *klass); static void metadata_widget_init (MetadataWidget *self); static void metadata_widget_dispose (GObject *object); static void metadata_widget_finalize (GObject *object); -static gboolean metadata_image_expose (GtkWidget *image, GdkEventExpose *event, gpointer user_data); +static gboolean metadata_image_expose (GtkWidget *image, + GdkEventExpose *event, + gpointer user_data); static void metadata_widget_set_style (GtkWidget* button, GtkStyle* style); -static void metadata_widget_set_twin_item (MetadataWidget* self, DbusmenuMenuitem* twin_item); +static void metadata_widget_set_twin_item (MetadataWidget* self, + DbusmenuMenuitem* twin_item); // keyevent consumers -static gboolean metadata_widget_button_press_event (GtkWidget *menuitem, +static gboolean metadata_widget_button_release_event (GtkWidget *menuitem, GdkEventButton *event); // Dbusmenuitem properties update callback static void metadata_widget_property_update (DbusmenuMenuitem* item, @@ -71,16 +78,23 @@ static void metadata_widget_selection_received_event_callback( GtkWidget GtkSelectionData *data, guint time, gpointer user_data); -G_DEFINE_TYPE (MetadataWidget, metadata_widget, GTK_TYPE_MENU_ITEM); +static gboolean metadata_widget_icon_triangle_draw_cb ( GtkWidget *image, + GdkEventExpose *event, + gpointer user_data ); + +static void metadata_widget_set_icon (MetadataWidget *self); +static void metadata_widget_handle_resizing (MetadataWidget* self); +G_DEFINE_TYPE (MetadataWidget, metadata_widget, GTK_TYPE_MENU_ITEM); + static void metadata_widget_class_init (MetadataWidgetClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - widget_class->button_press_event = metadata_widget_button_press_event; + widget_class->button_release_event = metadata_widget_button_release_event; g_type_class_add_private (klass, sizeof (MetadataWidgetPrivate)); @@ -88,16 +102,20 @@ metadata_widget_class_init (MetadataWidgetClass *klass) gobject_class->finalize = metadata_widget_finalize; } + + static void metadata_widget_init (MetadataWidget *self) { - //g_debug("MetadataWidget::metadata_widget_init"); - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(self); GtkWidget *hbox; - + GtkWidget *outer_v_box; + priv->icon_buf = NULL; + + outer_v_box = gtk_vbox_new (FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); - priv->hbox = hbox; + + priv->meta_data_h_box = hbox; // image priv->album_art = gtk_image_new(); @@ -107,8 +125,12 @@ metadata_widget_init (MetadataWidget *self) g_signal_connect(priv->album_art, "expose-event", G_CALLBACK(metadata_image_expose), GTK_WIDGET(self)); + + g_signal_connect_after (GTK_WIDGET(self), "expose-event", + G_CALLBACK(metadata_widget_icon_triangle_draw_cb), + GTK_WIDGET(self)); - gtk_box_pack_start (GTK_BOX (priv->hbox), + gtk_box_pack_start (GTK_BOX (priv->meta_data_h_box), priv->album_art, FALSE, FALSE, @@ -150,20 +172,36 @@ metadata_widget_init (MetadataWidget *self) gtk_box_pack_start (GTK_BOX (vbox), priv->artist_label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), priv->container_label, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (priv->hbox), vbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (priv->meta_data_h_box), vbox, FALSE, FALSE, 0); g_signal_connect(self, "style-set", G_CALLBACK(metadata_widget_set_style), GTK_WIDGET(self)); g_signal_connect (self, "selection-received", G_CALLBACK(metadata_widget_selection_received_event_callback), GTK_WIDGET(self)); - gtk_widget_set_size_request(GTK_WIDGET(self), 200, 75); - gtk_container_add (GTK_CONTAINER (self), hbox); + + // player label + GtkWidget* player_label; + player_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(player_label), (gfloat)0, (gfloat)0); + gtk_misc_set_padding (GTK_MISC(player_label), (gfloat)1, (gfloat)0); + gtk_widget_set_size_request (player_label, 200, 25); + priv->player_label = player_label; + + gtk_box_pack_start (GTK_BOX(outer_v_box), priv->player_label, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX(outer_v_box), priv->meta_data_h_box, FALSE, FALSE, 0); + + gtk_container_add (GTK_CONTAINER (self), outer_v_box); } static void metadata_widget_dispose (GObject *object) { + MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(METADATA_WIDGET(object)); + + if (priv->icon_buf != NULL){ + gdk_pixbuf_unref(priv->icon_buf); + } G_OBJECT_CLASS (metadata_widget_parent_class)->dispose (object); } @@ -183,37 +221,46 @@ metadata_image_expose (GtkWidget *metadata, GdkEventExpose *event, gpointer user { g_return_val_if_fail(IS_METADATA_WIDGET(user_data), FALSE); MetadataWidget* widget = METADATA_WIDGET(user_data); - MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(widget); - draw_album_border(metadata, FALSE); + MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(widget); + + if ( TRUE == dbusmenu_menuitem_property_get_bool (DBUSMENU_MENUITEM(priv->twin_item), + DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS)) + { + return FALSE; + } + + draw_album_border(metadata, FALSE); + if(priv->image_path->len > 0){ if(g_string_equal(priv->image_path, priv->old_image_path) == FALSE || priv->theme_change_occured == TRUE){ - priv->theme_change_occured = FALSE; + priv->theme_change_occured = FALSE; GdkPixbuf* pixbuf; pixbuf = gdk_pixbuf_new_from_file_at_size(priv->image_path->str, 60, 60, NULL); - //g_debug("metadata_load_new_image -> pixbuf from %s", - // priv->image_path->str); + if(GDK_IS_PIXBUF(pixbuf) == FALSE){ - //g_debug("problem loading the downloaded image just use the placeholder instead"); + gtk_image_clear ( GTK_IMAGE(priv->album_art)); gtk_widget_set_size_request(GTK_WIDGET(priv->album_art), 60, 60); draw_album_art_placeholder(metadata); - return TRUE; + return FALSE; } + gtk_image_set_from_pixbuf(GTK_IMAGE(priv->album_art), pixbuf); gtk_widget_set_size_request(GTK_WIDGET(priv->album_art), gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); - g_string_erase(priv->old_image_path, 0, -1); - g_string_overwrite(priv->old_image_path, 0, priv->image_path->str); + g_string_erase (priv->old_image_path, 0, -1); + g_string_overwrite (priv->old_image_path, 0, priv->image_path->str); g_object_unref(pixbuf); } return FALSE; } + gtk_image_clear (GTK_IMAGE(priv->album_art)); gtk_widget_set_size_request(GTK_WIDGET(priv->album_art), 60, 60); draw_album_art_placeholder(metadata); - return TRUE; + return FALSE; } static void @@ -308,7 +355,7 @@ draw_album_border(GtkWidget *metadata, gboolean selected) static void draw_album_art_placeholder(GtkWidget *metadata) -{ +{ cairo_t *cr; cr = gdk_cairo_create (metadata->window); GtkStyle *style; @@ -341,7 +388,6 @@ draw_album_art_placeholder(GtkWidget *metadata) _color_shade ( &fg_normal, 0.78, &light_bottom_color ); - cairo_set_source_rgba (cr, light_bottom_color.r, light_bottom_color.g, @@ -349,14 +395,13 @@ draw_album_art_placeholder(GtkWidget *metadata) 1.0); pango_cairo_update_layout(cr, layout); - cairo_move_to (cr, alloc.x + alloc.width/6, alloc.y + alloc.height/8); + cairo_move_to (cr, alloc.x + alloc.width/6, alloc.y + 3); pango_cairo_show_layout(cr, layout); g_object_unref(layout); g_object_unref(pcontext); g_string_free (string, TRUE); cairo_destroy (cr); - } static void @@ -366,33 +411,48 @@ metadata_widget_selection_received_event_callback ( GtkWidget *widget, gpointer user_data ) { - //g_return_val_if_fail(IS_METADATA_WIDGET(user_data), FALSE); - //MetadataWidget* widget = METADATA_WIDGET(user_data); - //MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(widget); - g_debug("metadata_widget_selection_request_event_callback"); draw_album_border(widget, TRUE); } /* Suppress/consume keyevents */ static gboolean -metadata_widget_button_press_event (GtkWidget *menuitem, - GdkEventButton *event) +metadata_widget_button_release_event (GtkWidget *menuitem, + GdkEventButton *event) { - GtkClipboard* board = gtk_clipboard_get (GDK_NONE); - - MetadataWidgetPrivate* priv = METADATA_WIDGET_GET_PRIVATE(METADATA_WIDGET(menuitem)); - - gchar* contents = g_strdup_printf("artist: %s \ntitle: %s \nalbum: %s", - dbusmenu_menuitem_property_get(priv->twin_item, - DBUSMENU_METADATA_MENUITEM_ARTIST), - dbusmenu_menuitem_property_get(priv->twin_item, - DBUSMENU_METADATA_MENUITEM_TITLE), - dbusmenu_menuitem_property_get(priv->twin_item, - DBUSMENU_METADATA_MENUITEM_ALBUM)); - gtk_clipboard_set_text (board, contents, -1); - gtk_clipboard_store (board); - g_free(contents); - return FALSE; + g_return_val_if_fail (IS_METADATA_WIDGET (menuitem), FALSE); + MetadataWidgetPrivate* priv = METADATA_WIDGET_GET_PRIVATE(METADATA_WIDGET(menuitem)); + // For the left raise/launch the player + if (event->button == 1){ + GVariant* new_title_event = g_variant_new_boolean(TRUE); + dbusmenu_menuitem_handle_event (priv->twin_item, + "Title menu event", + new_title_event, + 0); + } + // For the right copy track details to clipboard only if the player is running + // and there is something there + else if (event->button == 3){ + gboolean running = dbusmenu_menuitem_property_get_bool (priv->twin_item, + DBUSMENU_METADATA_MENUITEM_PLAYER_RUNNING); + gboolean hidden = dbusmenu_menuitem_property_get_bool (priv->twin_item, + DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS); + g_return_val_if_fail ( running, FALSE ); + + g_return_val_if_fail ( !hidden, FALSE ); + + GtkClipboard* board = gtk_clipboard_get (GDK_NONE); + gchar* contents = g_strdup_printf("artist: %s \ntitle: %s \nalbum: %s", + dbusmenu_menuitem_property_get(priv->twin_item, + DBUSMENU_METADATA_MENUITEM_ARTIST), + dbusmenu_menuitem_property_get(priv->twin_item, + DBUSMENU_METADATA_MENUITEM_TITLE), + dbusmenu_menuitem_property_get(priv->twin_item, + DBUSMENU_METADATA_MENUITEM_ALBUM)); + gtk_clipboard_set_text (board, contents, -1); + gtk_clipboard_store (board); + g_free(contents); + } + return TRUE; } static void @@ -403,7 +463,6 @@ metadata_widget_property_update(DbusmenuMenuitem* item, gchar* property, if(g_variant_is_of_type(value, G_VARIANT_TYPE_INT32) == TRUE && g_variant_get_int32(value) == DBUSMENU_PROPERTY_EMPTY){ - //g_debug("Metadata widget: property update - reset"); GVariant* new_value = g_variant_new_string (""); value = new_value; } @@ -427,11 +486,48 @@ metadata_widget_property_update(DbusmenuMenuitem* item, gchar* property, g_string_erase(priv->image_path, 0, -1); g_string_overwrite(priv->image_path, 0, g_variant_get_string (value, NULL)); // if its a remote image queue a redraw incase the download took too long - if (g_str_has_prefix(g_variant_get_string (value, NULL), g_get_user_cache_dir())){ - //g_debug("the image update is a download so redraw"); - gtk_widget_queue_draw(GTK_WIDGET(mitem)); - } - } + //if (g_str_has_prefix(g_variant_get_string (value, NULL), g_get_user_cache_dir())){ + gtk_widget_queue_draw(GTK_WIDGET(mitem)); + //} + } + else if (g_ascii_strcasecmp (DBUSMENU_METADATA_MENUITEM_PLAYER_NAME, property) == 0){ + gtk_label_set_label (GTK_LABEL (priv->player_label), + g_variant_get_string(value, NULL)); + } + else if (g_ascii_strcasecmp (DBUSMENU_METADATA_MENUITEM_PLAYER_ICON, property) == 0){ + metadata_widget_set_icon (mitem); + } + else if(g_ascii_strcasecmp(DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS, property) == 0){ + metadata_widget_handle_resizing (mitem); + } +} + +static void +metadata_widget_handle_resizing (MetadataWidget* self) +{ + MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(self); + + if (dbusmenu_menuitem_property_get_bool (priv->twin_item, + DBUSMENU_METADATA_MENUITEM_HIDE_TRACK_DETAILS) == TRUE){ + gtk_widget_hide (priv->meta_data_h_box); + gtk_widget_hide (priv->artist_label); + gtk_widget_hide (priv->piece_label); + gtk_widget_hide (priv->container_label); + gtk_widget_hide (priv->album_art); + gtk_widget_hide (priv->meta_data_v_box); + gtk_widget_set_size_request(GTK_WIDGET(self), 200, 20); + } + else{ + + gtk_widget_show (priv->meta_data_h_box); + gtk_widget_show (priv->artist_label); + gtk_widget_show (priv->piece_label); + gtk_widget_show (priv->container_label); + gtk_widget_show (priv->album_art); + gtk_widget_show (priv->meta_data_v_box); + gtk_widget_set_size_request(GTK_WIDGET(self), 200, 95); + } + gtk_widget_queue_draw(GTK_WIDGET(self)); } static void @@ -454,9 +550,54 @@ metadata_widget_set_style(GtkWidget* metadata, GtkStyle* style) gtk_widget_queue_draw(GTK_WIDGET(metadata)); } +static void +metadata_widget_set_icon (MetadataWidget *self) +{ + MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(self); + + if (priv->icon_buf != NULL){ + gdk_pixbuf_unref(priv->icon_buf); + priv->icon_buf = NULL; + } + + gint padding = 0; + gtk_widget_style_get(GTK_WIDGET(self), "horizontal-padding", &padding, NULL); + gint width, height; + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); + + GString* banshee_string = g_string_new ( "banshee" ); + GString* app_panel = g_string_new ( g_utf8_strdown (dbusmenu_menuitem_property_get(priv->twin_item, DBUSMENU_METADATA_MENUITEM_PLAYER_NAME), + -1)); + GdkPixbuf* icon_buf; + + // Banshee Special case! + // Not ideal but apparently we want the banshee icon to be the greyscale one + // and any others to be the icon from the desktop file => colour. + if ( g_string_equal ( banshee_string, app_panel ) == TRUE && + gtk_icon_theme_has_icon ( gtk_icon_theme_get_default(), app_panel->str ) ){ + g_string_append ( app_panel, "-panel" ); + } + else{ + // Otherwise use what is stored in the props + g_string_erase (app_panel, 0, -1); + g_string_overwrite (app_panel, + 0, + dbusmenu_menuitem_property_get ( priv->twin_item, + DBUSMENU_METADATA_MENUITEM_PLAYER_ICON )); + } + icon_buf = gtk_icon_theme_load_icon ( gtk_icon_theme_get_default(), + app_panel->str, + (width > height) ? width : height, + GTK_ICON_LOOKUP_GENERIC_FALLBACK, + NULL ); + priv->icon_buf = icon_buf; + g_string_free ( app_panel, TRUE); + g_string_free ( banshee_string, TRUE); +} + static void -metadata_widget_set_twin_item(MetadataWidget* self, - DbusmenuMenuitem* twin_item) +metadata_widget_set_twin_item (MetadataWidget* self, + DbusmenuMenuitem* twin_item) { MetadataWidgetPrivate* priv = METADATA_WIDGET_GET_PRIVATE(self); priv->twin_item = twin_item; @@ -479,16 +620,77 @@ metadata_widget_set_twin_item(MetadataWidget* self, g_string_erase(priv->image_path, 0, -1); const gchar *arturl = dbusmenu_menuitem_property_get( priv->twin_item, DBUSMENU_METADATA_MENUITEM_ARTURL ); + + gtk_label_set_label (GTK_LABEL(priv->player_label), + dbusmenu_menuitem_property_get(priv->twin_item, + DBUSMENU_METADATA_MENUITEM_PLAYER_NAME)); + + metadata_widget_set_icon(self); + if (arturl != NULL){ g_string_overwrite( priv->image_path, 0, arturl); - // if its a remote image queue a redraw incase the download took too long if (g_str_has_prefix (arturl, g_get_user_cache_dir())){ gtk_widget_queue_draw(GTK_WIDGET(self)); } } + metadata_widget_handle_resizing (self); +} + +// Draw the triangle if the player is running ... +static gboolean +metadata_widget_icon_triangle_draw_cb (GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data) +{ + g_return_val_if_fail(IS_METADATA_WIDGET(user_data), FALSE); + MetadataWidget* meta = METADATA_WIDGET(user_data); + MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(meta); + + GtkStyle *style; + cairo_t *cr; + int x, y, arrow_width, arrow_height; + + gint offset = 3; + arrow_width = 5; + arrow_height = 9; + + style = gtk_widget_get_style (widget); + + cr = (cairo_t*) gdk_cairo_create (widget->window); + + x = widget->allocation.x; + y = widget->allocation.y; + + // Draw player icon + if (priv->icon_buf != NULL){ + gdk_cairo_set_source_pixbuf (cr, + priv->icon_buf, + x + arrow_width + 1, + y + offset); + cairo_paint (cr); + } + + // Draw triangle but only if the player is running. + if (dbusmenu_menuitem_property_get_bool (priv->twin_item, + DBUSMENU_METADATA_MENUITEM_PLAYER_RUNNING)){ + y += (double)arrow_height/2.0 + offset; + cairo_set_line_width (cr, 1.0); + + cairo_move_to (cr, x, y); + cairo_line_to (cr, x, y + arrow_height); + cairo_line_to (cr, x + arrow_width, y + (double)arrow_height/2.0); + cairo_close_path (cr); + cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, + style->fg[gtk_widget_get_state(widget)].green/65535.0, + style->fg[gtk_widget_get_state(widget)].blue/65535.0); + cairo_fill (cr); + } + + cairo_destroy (cr); + return FALSE; } /** @@ -498,7 +700,6 @@ metadata_widget_set_twin_item(MetadataWidget* self, GtkWidget* metadata_widget_new(DbusmenuMenuitem *item) { - GtkWidget* widget = g_object_new(METADATA_WIDGET_TYPE, NULL); metadata_widget_set_twin_item ( METADATA_WIDGET(widget), item ); diff --git a/src/metadata-widget.h b/src/metadata-widget.h index 6021af5..30b629c 100644 --- a/src/metadata-widget.h +++ b/src/metadata-widget.h @@ -35,11 +35,11 @@ typedef struct _MetadataWidget MetadataWidget; typedef struct _MetadataWidgetClass MetadataWidgetClass; struct _MetadataWidgetClass { - GtkMenuItemClass parent_class; + GtkMenuItemClass parent_class; }; struct _MetadataWidget { - GtkMenuItem parent; + GtkMenuItem parent; }; GType metadata_widget_get_type (void); diff --git a/src/mpris2-controller.vala b/src/mpris2-controller.vala index 04ceb88..2975066 100644 --- a/src/mpris2-controller.vala +++ b/src/mpris2-controller.vala @@ -83,13 +83,16 @@ public class Mpris2Controller : GLib.Object } Variant? meta_v = changed_properties.lookup("Metadata"); if(meta_v != null){ - GLib.HashTable<string, Variant?> changed_updates = clean_metadata(); + GLib.HashTable<string, Variant?> changed_updates = clean_metadata(); PlayerItem metadata = this.owner.custom_items[PlayerController.widget_order.METADATA]; - metadata.reset ( MetadataMenuitem.attributes_format()); + metadata.reset (MetadataMenuitem.relevant_attributes_for_ui()); metadata.update ( changed_updates, - MetadataMenuitem.attributes_format()); - metadata.property_set_bool ( MENUITEM_PROP_VISIBLE, - metadata.populated(MetadataMenuitem.attributes_format())); + MetadataMenuitem.relevant_attributes_for_ui()); + MetadataMenuitem md = this.owner.custom_items[PlayerController.widget_order.METADATA] as MetadataMenuitem; + bool collapsing = !metadata.populated(MetadataMenuitem.relevant_attributes_for_ui()); + md.should_collapse(collapsing); + + debug ("Should metadata collapse %s", collapsing.to_string()); } Variant? playlist_v = changed_properties.lookup("ActivePlaylist"); if ( playlist_v != null && this.owner.use_playlists == true ){ @@ -109,8 +112,8 @@ public class Mpris2Controller : GLib.Object } Variant? identity_v = changed_properties.lookup("Identity"); if (identity_v != null){ - TitleMenuitem title = this.owner.custom_items[PlayerController.widget_order.TITLE] as TitleMenuitem; - title.alter_label (this.mpris2_root.Identity); + MetadataMenuitem md = this.owner.custom_items[PlayerController.widget_order.METADATA] as MetadataMenuitem; + md.alter_label (this.mpris2_root.Identity); } } @@ -162,8 +165,8 @@ public class Mpris2Controller : GLib.Object update = determine_play_state (this.player.PlaybackStatus); } if (this.mpris2_root.Identity != null){ - TitleMenuitem title = this.owner.custom_items[PlayerController.widget_order.TITLE] as TitleMenuitem; - title.alter_label (this.mpris2_root.Identity); + MetadataMenuitem md = this.owner.custom_items[PlayerController.widget_order.METADATA] as MetadataMenuitem; + md.alter_label (this.mpris2_root.Identity); } (this.owner.custom_items[PlayerController.widget_order.TRANSPORT] as TransportMenuitem).change_play_state (update); GLib.HashTable<string, Value?>? cleaned_metadata = this.clean_metadata(); diff --git a/src/player-controller.vala b/src/player-controller.vala index 8a7bda5..52adb23 100644 --- a/src/player-controller.vala +++ b/src/player-controller.vala @@ -23,11 +23,10 @@ using Gee; public class PlayerController : GLib.Object { - public const int WIDGET_QUANTITY = 6; + public const int WIDGET_QUANTITY = 5; public static enum widget_order{ SEPARATOR, - TITLE, METADATA, TRANSPORT, TRACK_SPECIFIC, @@ -72,6 +71,7 @@ public class PlayerController : GLib.Object this.construct_widgets(); this.establish_mpris_connection(); this.update_layout(); + debug ("New player controller for %s with icon name %s", this.app_info.get_name(), this.icon_name); } public void update_state(state new_state) @@ -144,26 +144,27 @@ public class PlayerController : GLib.Object update_state(PlayerController.state.OFFLINE); TransportMenuitem transport = this.custom_items[widget_order.TRANSPORT] as TransportMenuitem; transport.change_play_state (Transport.State.PAUSED); - this.custom_items[widget_order.METADATA].reset(MetadataMenuitem.attributes_format()); - TitleMenuitem title = this.custom_items[widget_order.TITLE] as TitleMenuitem; - title.toggle_active_triangle(false); + this.custom_items[widget_order.METADATA].reset(MetadataMenuitem.relevant_attributes_for_ui()); + MetadataMenuitem md = this.custom_items[widget_order.METADATA] as MetadataMenuitem; + md.toggle_active_triangle (false); this.mpris_bridge = null; } public void update_layout() - { + { + debug ("a call to update layout"); PlaylistsMenuitem playlists_menuitem = this.custom_items[widget_order.PLAYLISTS] as PlaylistsMenuitem; + MetadataMenuitem metadata_menuitem = this.custom_items[widget_order.METADATA] as MetadataMenuitem; if(this.current_state != state.CONNECTED){ - this.custom_items[widget_order.METADATA].property_set_bool (MENUITEM_PROP_VISIBLE, - false); + // TODO + metadata_menuitem.should_collapse (true); playlists_menuitem.root_item.property_set_bool (MENUITEM_PROP_VISIBLE, false ); this.custom_items[widget_order.TRANSPORT].property_set_bool (MENUITEM_PROP_VISIBLE, this.app_info.get_id() == "banshee.desktop"); return; } - this.custom_items[widget_order.METADATA].property_set_bool (MENUITEM_PROP_VISIBLE, - this.custom_items[widget_order.METADATA].populated(MetadataMenuitem.attributes_format())); + metadata_menuitem.should_collapse (!this.custom_items[widget_order.METADATA].populated (MetadataMenuitem.relevant_attributes_for_ui()) ); if (this.app_info.get_id() == "banshee.desktop"){ TransportMenuitem transport = this.custom_items[widget_order.TRANSPORT] as TransportMenuitem; transport.handle_cached_action(); @@ -181,12 +182,8 @@ public class PlayerController : GLib.Object // Separator item this.custom_items.add(new PlayerItem(CLIENT_TYPES_SEPARATOR)); - // Title item - TitleMenuitem title_menu_item = new TitleMenuitem(this); - this.custom_items.add(title_menu_item); - // Metadata item - MetadataMenuitem metadata_item = new MetadataMenuitem(); + MetadataMenuitem metadata_item = new MetadataMenuitem(this); this.custom_items.add(metadata_item); // Transport item @@ -202,11 +199,11 @@ public class PlayerController : GLib.Object this.custom_items.add(playlist_menuitem); foreach(PlayerItem item in this.custom_items){ - if (this.custom_items.index_of(item) == 5) { + if (this.custom_items.index_of(item) == 4) { PlaylistsMenuitem playlists_menuitem = item as PlaylistsMenuitem; root_menu.child_add_position(playlists_menuitem.root_item, this.menu_offset + this.custom_items.index_of(item)); } - else if (this.custom_items.index_of(item) == 4) { + else if (this.custom_items.index_of(item) == 3) { TrackSpecificMenuitem trackspecific_menuitem = item as TrackSpecificMenuitem; root_menu.child_add_position(trackspecific_menuitem.root_item, this.menu_offset + this.custom_items.index_of(item)); } @@ -220,8 +217,8 @@ public class PlayerController : GLib.Object { if(this.mpris_bridge.connected() == true){ this.update_state(state.CONNECTED); - TitleMenuitem title = this.custom_items[widget_order.TITLE] as TitleMenuitem; - title.toggle_active_triangle(true); + MetadataMenuitem md = this.custom_items[widget_order.METADATA] as MetadataMenuitem; + md.toggle_active_triangle(true); this.mpris_bridge.initial_update(); } else{ diff --git a/src/player-item.vala b/src/player-item.vala index f71b166..162dbea 100644 --- a/src/player-item.vala +++ b/src/player-item.vala @@ -24,7 +24,7 @@ public class PlayerItem : Dbusmenu.Menuitem { public PlayerController owner {get; construct;} public string item_type { get; construct; } - private const int EMPTY = -1; + public const int EMPTY = -1; public PlayerItem(string type) { @@ -37,7 +37,6 @@ public class PlayerItem : Dbusmenu.Menuitem public void reset(HashSet<string> attrs){ foreach(string s in attrs){ - //debug("attempting to set prop %s to EMPTY", s); this.property_set_int(s, EMPTY); } } @@ -87,15 +86,12 @@ public class PlayerItem : Dbusmenu.Menuitem this.property_set_bool(property, v.get_boolean()); } } - this.property_set_bool(MENUITEM_PROP_VISIBLE, populated(attributes)); } public bool populated(HashSet<string> attrs) { foreach(string prop in attrs){ - //debug("populated ? - prop: %s", prop); if(property_get_int(prop) != EMPTY){ - //debug("populated - prop %s and value %i", prop, property_get_int(prop)); return true; } } diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index afb4f04..5d7c4cd 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -124,14 +124,16 @@ sound_service_dbus_class_init (SoundServiceDbusClass *klass) 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); + G_TYPE_NONE, 2, G_TYPE_STRING, + G_TYPE_STRING); signals[PLAYER_SPECIFIC_ITEM] = g_signal_new("player-specific-item-requested", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); + G_TYPE_NONE, 2, G_TYPE_STRING, + G_TYPE_STRING); } static void diff --git a/src/sound-service.c b/src/sound-service.c index 918bde6..dd957a0 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -47,8 +47,9 @@ service_shutdown (IndicatorService *service, gpointer user_data) void on_player_specific_item_requested (SoundServiceDbus* sound_service, - const gchar* player_object_path, - gpointer userdata) + const gchar* desktop_id, + const gchar* player_object_path, + gpointer userdata) { music_player_bridge_enable_player_specific_items_for_client (player_bridge, desktop_id); g_debug ("ON PLAYER SPECIFIC ITEM REQUESTED %s", desktop_id); @@ -57,6 +58,7 @@ on_player_specific_item_requested (SoundServiceDbus* sound_service, void on_track_specific_item_requested (SoundServiceDbus* sound_service, const gchar* desktop_id, + const gchar* player_object_path, gpointer userdata) { music_player_bridge_enable_track_specific_items_for_client (player_bridge, desktop_id); diff --git a/src/title-menu-item.vala b/src/title-menu-item.vala deleted file mode 100644 index ac93b89..0000000 --- a/src/title-menu-item.vala +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -using Dbusmenu; -using DbusmenuTitle; -using Gee; - -public class TitleMenuitem : PlayerItem -{ - public TitleMenuitem(PlayerController parent) - { - Object(item_type: MENUITEM_TYPE, owner: parent); - } - - construct - { - this.property_set(MENUITEM_NAME, this.owner.app_info.get_name()); - this.property_set(MENUITEM_ICON, this.owner.icon_name); - this.property_set_bool(MENUITEM_RUNNING, false); - } - - public override void handle_event(string name, Variant input_value, uint timestamp) - { - if(this.owner.current_state == PlayerController.state.OFFLINE) - { - this.owner.instantiate(); - } - else if(this.owner.current_state == PlayerController.state.CONNECTED){ - this.owner.mpris_bridge.expose(); - } - } - - public void alter_label (string new_title) - { - if (new_title == null) return; - this.property_set(MENUITEM_NAME, new_title); - } - - public void toggle_active_triangle(bool update) - { - this.property_set_bool(MENUITEM_RUNNING, update); - } - - public static HashSet<string> attributes_format() - { - HashSet<string> attrs = new HashSet<string>(); - attrs.add(MENUITEM_NAME); - attrs.add(MENUITEM_RUNNING); - attrs.add(MENUITEM_ICON); - return attrs; - } -}
\ No newline at end of file diff --git a/src/title-widget.c b/src/title-widget.c deleted file mode 100644 index b8058b8..0000000 --- a/src/title-widget.c +++ /dev/null @@ -1,248 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <glib/gi18n.h> -#include "title-widget.h" -#include "common-defs.h" -#include <gtk/gtk.h> -#include <libindicator/indicator-image-helper.h> - - -typedef struct _TitleWidgetPrivate TitleWidgetPrivate; - -struct _TitleWidgetPrivate -{ - DbusmenuMenuitem* twin_item; -}; - -#define TITLE_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TITLE_WIDGET_TYPE, TitleWidgetPrivate)) - -/* Prototypes */ -static void title_widget_class_init (TitleWidgetClass *klass); -static void title_widget_init (TitleWidget *self); -static void title_widget_dispose (GObject *object); -static void title_widget_finalize (GObject *object); - -// keyevent consumers -static gboolean title_widget_button_release_event (GtkWidget *menuitem, - GdkEventButton *event); - -// Dbusmenuitem properties update callback -static void title_widget_property_update(DbusmenuMenuitem* item, gchar* property, - GVariant* value, gpointer userdata); -static void title_widget_set_twin_item( TitleWidget* self, - DbusmenuMenuitem* twin_item); -static gboolean title_widget_triangle_draw_cb (GtkWidget *widget, - GdkEventExpose *event, - gpointer data); - -G_DEFINE_TYPE (TitleWidget, title_widget, GTK_TYPE_IMAGE_MENU_ITEM); - -static void -title_widget_class_init (TitleWidgetClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - widget_class->button_release_event = title_widget_button_release_event; - - g_type_class_add_private (klass, sizeof (TitleWidgetPrivate)); - - gobject_class->dispose = title_widget_dispose; - gobject_class->finalize = title_widget_finalize; -} - -static void -title_widget_init (TitleWidget *self) -{ - //g_debug("TitleWidget::title_widget_init"); -} - -static void -title_widget_set_icon(TitleWidget *self) -{ - TitleWidgetPrivate *priv = TITLE_WIDGET_GET_PRIVATE(self); - - gint padding = 0; - gtk_widget_style_get(GTK_WIDGET(self), "horizontal-padding", &padding, NULL); - gint width, height; - gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); - - GString* banshee_string = g_string_new ( "banshee" ); - GString* app_panel = g_string_new ( g_utf8_strdown ( dbusmenu_menuitem_property_get(priv->twin_item, DBUSMENU_TITLE_MENUITEM_NAME), - -1 )); - GtkWidget * icon = NULL; - - // Not ideal but apparently we want the banshee icon to be the greyscale one - // and any others to be the icon from the desktop file => colour. - if ( g_string_equal ( banshee_string, app_panel ) == TRUE && - gtk_icon_theme_has_icon ( gtk_icon_theme_get_default(), app_panel->str ) ){ - g_string_append ( app_panel, "-panel" ); - icon = gtk_image_new_from_icon_name ( app_panel->str, - GTK_ICON_SIZE_MENU ); - } - else{ - icon = gtk_image_new_from_icon_name ( g_strdup (dbusmenu_menuitem_property_get ( priv->twin_item, DBUSMENU_TITLE_MENUITEM_ICON )), - GTK_ICON_SIZE_MENU ); - } - g_string_free ( app_panel, FALSE) ; - g_string_free ( banshee_string, FALSE) ; - - gtk_widget_set_size_request(icon, width - + 5 /* ref triangle is 5x9 pixels */ - + 1 /* padding */, - height); - gtk_misc_set_alignment(GTK_MISC(icon), 0.5 /* right aligned */, 0); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(self), GTK_WIDGET(icon)); - gtk_widget_show(icon); -} - - -static void -title_widget_dispose (GObject *object) -{ - G_OBJECT_CLASS (title_widget_parent_class)->dispose (object); -} - -static void -title_widget_finalize (GObject *object) -{ - G_OBJECT_CLASS (title_widget_parent_class)->finalize (object); -} - -/* Suppress/consume keyevents */ -static gboolean -title_widget_button_release_event (GtkWidget *menuitem, - GdkEventButton *event) -{ - //g_debug("TitleWidget::menu_press_event"); - TitleWidgetPrivate * priv = TITLE_WIDGET_GET_PRIVATE(menuitem); - - GVariant* new_title_event = g_variant_new_boolean(TRUE); - dbusmenu_menuitem_handle_event (priv->twin_item, - "Title menu event", - new_title_event, - 0); - return FALSE; -} - -static void -title_widget_property_update (DbusmenuMenuitem* item, gchar* property, - GVariant* value, gpointer userdata) -{ - g_return_if_fail (IS_TITLE_WIDGET (userdata)); - TitleWidget* mitem = TITLE_WIDGET(userdata); - if(g_ascii_strcasecmp(DBUSMENU_TITLE_MENUITEM_NAME, property) == 0){ - gtk_menu_item_set_label (GTK_MENU_ITEM(mitem), - g_variant_get_string(value, NULL)); - } - else if(g_ascii_strcasecmp(DBUSMENU_TITLE_MENUITEM_ICON, property) == 0){ - title_widget_set_icon (mitem); - } -} - -static void -title_widget_set_twin_item(TitleWidget* self, - DbusmenuMenuitem* twin_item) -{ - TitleWidgetPrivate *priv = TITLE_WIDGET_GET_PRIVATE(self); - - priv->twin_item = twin_item; - - g_signal_connect (G_OBJECT (twin_item), - "property-changed", - G_CALLBACK (title_widget_property_update), - self); - g_signal_connect_after (G_OBJECT (self), - "expose_event", - G_CALLBACK (title_widget_triangle_draw_cb), - twin_item); - - gtk_menu_item_set_label (GTK_MENU_ITEM(self), - dbusmenu_menuitem_property_get(priv->twin_item, - DBUSMENU_TITLE_MENUITEM_NAME)); - title_widget_set_icon(self); -} - -static gboolean -title_widget_triangle_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data) -{ - GtkStyle *style; - cairo_t *cr; - int x, y, arrow_width, arrow_height; - - if (!GTK_IS_WIDGET (widget)) return FALSE; - if (!DBUSMENU_IS_MENUITEM (data)) return FALSE; - - /* render the triangle indicator only if the application is running */ - if (! dbusmenu_menuitem_property_get_bool (DBUSMENU_MENUITEM(data), - DBUSMENU_TITLE_MENUITEM_RUNNING)){ - return FALSE; - } - - /* get style */ - style = gtk_widget_get_style (widget); - - /* set arrow position / dimensions */ - arrow_width = 5; /* the pixel-based reference triangle is 5x9 */ - arrow_height = 9; - x = widget->allocation.x; - y = widget->allocation.y + widget->allocation.height/2.0 - (double)arrow_height/2.0; - - /* initialize cairo drawing area */ - cr = (cairo_t*) gdk_cairo_create (widget->window); - - /* set line width */ - cairo_set_line_width (cr, 1.0); - - /* cairo drawing code */ - cairo_move_to (cr, x, y); - cairo_line_to (cr, x, y + arrow_height); - cairo_line_to (cr, x + arrow_width, y + (double)arrow_height/2.0); - cairo_close_path (cr); - cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, - style->fg[gtk_widget_get_state(widget)].green/65535.0, - style->fg[gtk_widget_get_state(widget)].blue/65535.0); - cairo_fill (cr); - - /* remember to destroy cairo context to avoid leaks */ - cairo_destroy (cr); - - return FALSE; -} - - /** - * transport_new: - * @returns: a new #TitleWidget. - **/ -GtkWidget* -title_widget_new(DbusmenuMenuitem *item) -{ - GtkWidget* widget = g_object_new (TITLE_WIDGET_TYPE, - NULL); - gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (widget), TRUE); - title_widget_set_twin_item((TitleWidget*)widget, item); - - return widget; -} - diff --git a/src/title-widget.h b/src/title-widget.h deleted file mode 100644 index 2be904a..0000000 --- a/src/title-widget.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright 2010 Canonical Ltd. - -Authors: - Conor Curran <conor.curran@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __TITLE_WIDGET_H__ -#define __TITLE_WIDGET_H__ - -#include <gtk/gtkimagemenuitem.h> -#include <libdbusmenu-glib/menuitem.h> - - -G_BEGIN_DECLS - -#define TITLE_WIDGET_TYPE (title_widget_get_type ()) -#define TITLE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TITLE_WIDGET_TYPE, TitleWidget)) -#define TITLE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TITLE_WIDGET_TYPE, TitleWidgetClass)) -#define IS_TITLE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TITLE_WIDGET_TYPE)) -#define IS_TITLE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TITLE_WIDGET_TYPE)) -#define TITLE_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TITLE_WIDGET_TYPE, TitleWidgetClass)) - -typedef struct _TitleWidget TitleWidget; -typedef struct _TitleWidgetClass TitleWidgetClass; - -struct _TitleWidgetClass { - GtkImageMenuItemClass parent_class; -}; - -struct _TitleWidget { - GtkImageMenuItem parent; -}; - -GType title_widget_get_type (void); -GtkWidget* title_widget_new(DbusmenuMenuitem *twin_item); - -G_END_DECLS - -#endif - diff --git a/vapi/common-defs.vapi b/vapi/common-defs.vapi index cd21389..33b4aad 100644 --- a/vapi/common-defs.vapi +++ b/vapi/common-defs.vapi @@ -24,6 +24,10 @@ namespace DbusmenuMetadata{ public const string MENUITEM_TITLE; public const string MENUITEM_ALBUM; public const string MENUITEM_ARTURL; + public const string MENUITEM_PLAYER_NAME; + public const string MENUITEM_PLAYER_ICON; + public const string MENUITEM_PLAYER_RUNNING; + public const string MENUITEM_HIDE_TRACK_DETAILS; } [CCode (cheader_filename = "common-defs.h")] @@ -38,14 +42,6 @@ namespace DbusmenuTrackSpecific{ } [CCode (cheader_filename = "common-defs.h")] -namespace DbusmenuTitle{ - public const string MENUITEM_TYPE; - public const string MENUITEM_NAME; - public const string MENUITEM_ICON; - public const string MENUITEM_RUNNING; -} - -[CCode (cheader_filename = "common-defs.h")] namespace DbusmenuPlaylists{ public const string MENUITEM_TYPE; public const string MENUITEM_TITLE; @@ -56,7 +52,6 @@ namespace DbusmenuPlaylist{ public const string MENUITEM_PATH; } - [CCode (cprefix ="Transport", cheader_filename = "common-defs.h")] namespace Transport{ public enum Action{ |