aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac4
-rw-r--r--data/Makefile.am1
-rw-r--r--data/album_artwork.pngbin0 -> 552 bytes
-rw-r--r--data/sound_icon.pngbin0 -> 467 bytes
-rw-r--r--src/Makefile.am3
-rw-r--r--src/common-defs.h3
-rw-r--r--src/dbus-menu-manager.c4
-rw-r--r--src/familiar-players-db.vala3
-rw-r--r--src/indicator-sound.c24
-rw-r--r--src/metadata-menu-item.vala7
-rw-r--r--src/mpris-controller.vala5
-rw-r--r--src/music-player-bridge.vala85
-rw-r--r--src/player-controller.vala101
-rw-r--r--src/player-item.vala41
-rw-r--r--src/sound-service.c4
-rw-r--r--src/title-menu-item.vala48
-rw-r--r--src/title-widget.c191
-rw-r--r--src/title-widget.h51
-rw-r--r--src/transport-menu-item.vala14
-rw-r--r--vapi/common-defs.vapi6
20 files changed, 489 insertions, 106 deletions
diff --git a/configure.ac b/configure.ac
index b302f5b..b6c4fe3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,10 +1,10 @@
-AC_INIT(indicator-sound, 0.3.3, conor.curran@canonical.com)
+AC_INIT(indicator-sound, 0.3.4, conor.curran@canonical.com)
AC_PREREQ(2.53)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(indicator-sound, 0.3.3)
+AM_INIT_AUTOMAKE(indicator-sound, 0.3.4)
AM_MAINTAINER_MODE
diff --git a/data/Makefile.am b/data/Makefile.am
index 0389576..9fa0c9b 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,4 +1,3 @@
-
dbus_servicesdir = $(DBUSSERVICEDIR)
service_in_files = indicator-sound.service.in
dbus_services_DATA = $(service_in_files:.service.in=.service)
diff --git a/data/album_artwork.png b/data/album_artwork.png
new file mode 100644
index 0000000..940a69b
--- /dev/null
+++ b/data/album_artwork.png
Binary files differ
diff --git a/data/sound_icon.png b/data/sound_icon.png
new file mode 100644
index 0000000..b52d6c4
--- /dev/null
+++ b/data/sound_icon.png
Binary files differ
diff --git a/src/Makefile.am b/src/Makefile.am
index 71a3068..79ba7d2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,6 +16,8 @@ libsoundmenu_la_SOURCES = \
play-button.c \
play-button.h \
indicator-sound.c \
+ title-widget.c \
+ title-widget.h \
dbus-shared-names.h \
sound-service-client.h
@@ -56,6 +58,7 @@ music_bridge_VALASOURCES = \
music-player-bridge.vala \
transport-menu-item.vala \
metadata-menu-item.vala \
+ title-menu-item.vala \
player-controller.vala \
mpris-controller-v2.vala \
mpris-controller.vala \
diff --git a/src/common-defs.h b/src/common-defs.h
index dca21cc..9c1fbab 100644
--- a/src/common-defs.h
+++ b/src/common-defs.h
@@ -34,3 +34,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#define DBUSMENU_METADATA_MENUITEM_TEXT_TITLE "x-canonical-metadata-text-title"
#define DBUSMENU_METADATA_MENUITEM_TEXT_ALBUM "x-canonical-metadata-text-album"
#define DBUSMENU_METADATA_MENUITEM_ARTURL "x-canonical-metadata-arturl"
+
+#define DBUSMENU_TITLE_MENUITEM_TYPE "x-canonical-sound-menu-player-title-menu-item"
+#define DBUSMENU_TITLE_MENUITEM_TEXT_NAME "x-canonical-sound-menu-player-title-name"
diff --git a/src/dbus-menu-manager.c b/src/dbus-menu-manager.c
index d19bfbb..4cd4a6b 100644
--- a/src/dbus-menu-manager.c
+++ b/src/dbus-menu-manager.c
@@ -172,7 +172,9 @@ Bring up the gnome volume preferences dialog
static void show_sound_settings_dialog (DbusmenuMenuitem *mi, gpointer user_data)
{
GError * error = NULL;
- if (!g_spawn_command_line_async("gnome-volume-control", &error)) {
+ if (!g_spawn_command_line_async("gnome-volume-control", &error) &&
+ !g_spawn_command_line_async("xfce4-mixer", &error))
+ {
g_warning("Unable to show dialog: %s", error->message);
g_error_free(error);
}
diff --git a/src/familiar-players-db.vala b/src/familiar-players-db.vala
index 88bc01f..b83caa3 100644
--- a/src/familiar-players-db.vala
+++ b/src/familiar-players-db.vala
@@ -143,7 +143,8 @@ public class FamiliarPlayersDB : GLib.Object
public bool already_familiar(string desktop)
{
- return this.players_DB.get(desktop);
+ debug("playerDB->already_familiar - result %s", this.players_DB.keys.contains(desktop).to_string());
+ return this.players_DB.keys.contains(desktop);
}
public Gee.Set<string> records()
diff --git a/src/indicator-sound.c b/src/indicator-sound.c
index 3f0d2d3..10333fe 100644
--- a/src/indicator-sound.c
+++ b/src/indicator-sound.c
@@ -40,6 +40,7 @@ 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 "dbus-shared-names.h"
#include "sound-service-client.h"
#include "common-defs.h"
@@ -96,6 +97,7 @@ static void style_changed_cb(GtkWidget *widget, gpointer user_data);
//player widgets related
static gboolean new_transport_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
static gboolean new_metadata_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+static gboolean new_title_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
// DBUS communication
static DBusGProxy *sound_dbus_proxy = NULL;
@@ -243,7 +245,7 @@ get_menu (IndicatorObject * io)
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_SLIDER_MENUITEM_TYPE, new_slider_item);
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_TRANSPORT_MENUITEM_TYPE, new_transport_widget);
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);
// register Key-press listening on the menu widget as the slider does not allow this.
g_signal_connect(menu, "key-press-event", G_CALLBACK(key_press_cb), NULL);
return GTK_MENU(menu);
@@ -353,9 +355,25 @@ new_metadata_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm
return TRUE;
}
-//const gchar* path = dbusmenu_menuitem_property_get(new_item, DBUSMENU_METADATA_MENUITEM_IMAGE_PATH);
+static gboolean
+new_title_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
+{
+ g_debug("indicator-sound: new_title_widget");
+
+ GtkWidget* title = NULL;
+
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
+ g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
+
+ title = title_widget_new (newitem);
+ GtkMenuItem *menu_title_widget = GTK_MENU_ITEM(title);
+
+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, menu_title_widget, parent);
-//g_debug("New transport bar path = %s", path);
+ gtk_widget_show_all(title);
+
+ return TRUE;
+}
static void
diff --git a/src/metadata-menu-item.vala b/src/metadata-menu-item.vala
index 541fbf4..cfcb3bc 100644
--- a/src/metadata-menu-item.vala
+++ b/src/metadata-menu-item.vala
@@ -25,7 +25,7 @@ public class MetadataMenuitem : PlayerItem
{
public MetadataMenuitem()
{
- this.property_set(MENUITEM_PROP_TYPE, MENUITEM_TYPE);
+ Object(item_type: MENUITEM_TYPE);
}
public static HashSet<string> attributes_format()
@@ -37,11 +37,6 @@ public class MetadataMenuitem : PlayerItem
attrs.add(MENUITEM_ARTURL);
return attrs;
}
-
- public override void check_layout(){
- this.property_set_bool(MENUITEM_PROP_VISIBLE, this.populated());
- debug("check layout for the metadata = %s", this.populated().to_string());
- }
public bool populated()
{
diff --git a/src/mpris-controller.vala b/src/mpris-controller.vala
index beaf02c..b1e66f3 100644
--- a/src/mpris-controller.vala
+++ b/src/mpris-controller.vala
@@ -76,6 +76,11 @@ public class MprisController : GLib.Object
this.mpris_player.Pause();
}
}
+
+ public bool connected()
+ {
+ return (this.mpris_player != null);
+ }
private void onStatusChange(dynamic DBus.Object mpris_client, status st)
{
diff --git a/src/music-player-bridge.vala b/src/music-player-bridge.vala
index 6fc9032..46723cb 100644
--- a/src/music-player-bridge.vala
+++ b/src/music-player-bridge.vala
@@ -42,25 +42,29 @@ public class MusicPlayerBridge : GLib.Object
listener.server_removed.connect(on_server_removed);
listener.server_count_changed.connect(on_server_count_changed);
}
- // Alpha 2 not in use ... yet.
+
private void try_to_add_inactive_familiar_clients(){
- // for now just use one of the entries.
+ // TODO handle multple players - just working with one right now
int count = 0;
foreach(string app in this.playersDB.records()){
if(count == 0){
- debug("we have found %s", app);
- string[] bits = app.split("/");
-
+ if(app == null){
+ warning("App string in keyfile is null therefore moving on to next player");
+ continue;
+ }
try{
- string app_name = bits[bits.length -1].split(".")[0];
- debug("we have found %s", app_name);
+ DesktopAppInfo info = new DesktopAppInfo.from_filename(app);
+ if(info == null){
+ warning("Could not create a desktopappinfo instance from app: %s", app);
+ continue;
+ }
+ GLib.AppInfo app_info = info as GLib.AppInfo;
PlayerController ctrl = new PlayerController(this.root_menu,
- app_name,
- false);
- this.registered_clients.set(app_name, ctrl);
- DesktopAppInfo info = new DesktopAppInfo.from_filename(app_name);
- string desc = info.get_display_name();
- debug("description from app %s", desc);
+ app_info.get_name(),
+ PlayerController.OFFLINE);
+ ctrl.set("app_info", app_info);
+ this.registered_clients.set(app_info.get_name().down().strip(), ctrl);
+ debug("Created a player controller for %s which was found in the cache file", app_info.get_name().down().strip());
count += 1;
}
catch(Error er){
@@ -75,13 +79,25 @@ public class MusicPlayerBridge : GLib.Object
{
debug("MusicPlayerBridge -> on_server_added with value %s", type);
if(server_is_not_of_interest(type)) return;
- string client_name = type.split(".")[1];
+ string client_name = type.split(".")[1];
if (root_menu != null && client_name != null){
- listener_get_server_property_cb cb = (listener_get_server_property_cb)desktop_info_callback;
- this.listener.server_get_desktop(object, cb, this);
- PlayerController ctrl = new PlayerController(root_menu, client_name, true);
- registered_clients.set(client_name, ctrl);
- debug("client of name %s has successfully registered with us", client_name);
+ // If we have an instance already for this player, ensure it is switched to active
+ if(this.registered_clients.keys.contains(client_name)){
+ debug("It figured out that it already has an instance for this player already");
+ this.registered_clients[client_name].update_state(PlayerController.READY);
+ this.registered_clients[client_name].activate();
+ }
+ //else init a new one
+ else{
+ PlayerController ctrl = new PlayerController(root_menu, client_name, PlayerController.READY);
+ registered_clients.set(client_name, ctrl);
+ debug("New Client of name %s has successfully registered with us", client_name);
+ }
+ // irregardless check that it has a desktop file if not kick off a request for it
+ if(this.registered_clients[client_name].app_info == null){
+ listener_get_server_property_cb cb = (listener_get_server_property_cb)desktop_info_callback;
+ this.listener.server_get_desktop(object, cb, this);
+ }
}
}
@@ -93,7 +109,8 @@ public class MusicPlayerBridge : GLib.Object
if (root_menu != null && client_name != null){
registered_clients[client_name].vanish();
registered_clients.remove(client_name);
- debug("Successively removed menu_item for client %s from registered_clients", client_name);
+ debug("Successively removed menu_item for client %s from registered_clients",
+ client_name);
}
}
@@ -109,15 +126,26 @@ public class MusicPlayerBridge : GLib.Object
private void desktop_info_callback(Indicate.ListenerServer server,
owned string path, void* data)
{
- debug("we got a desktop file path hopefully: %s", path);
MusicPlayerBridge bridge = data as MusicPlayerBridge;
- bridge.playersDB.insert(path);
+ if(path.contains("/") && bridge.playersDB.already_familiar(path) == false){
+ debug("About to store desktop file path: %s", path);
+ bridge.playersDB.insert(path);
+ AppInfo? app_info = create_app_info(path);
+ if(app_info != null){
+ PlayerController ctrl = bridge.registered_clients[app_info.get_name().down().strip()];
+ ctrl.set("app_info", app_info);
+ debug("successfully created appinfo from path and set it on the respective instance");
+ }
+ }
+ else{
+ debug("Ignoring desktop file path because its either invalid of the db cache file has it already: %s", path);
+ }
}
public void set_root_menu_item(Dbusmenu.Menuitem menu)
{
this.root_menu = menu;
- //try_to_add_inactive_familiar_clients();
+ try_to_add_inactive_familiar_clients();
}
public void on_server_count_changed(Indicate.ListenerServer object, uint i)
@@ -139,6 +167,17 @@ public class MusicPlayerBridge : GLib.Object
debug("MusicPlayerBridge -> indicator_modified with vale %s", s );
}
+ public static AppInfo? create_app_info(string path)
+ {
+ DesktopAppInfo info = new DesktopAppInfo.from_filename(path);
+ if(path == null){
+ warning("Could not create a desktopappinfo instance from app: %s", path);
+ return null;
+ }
+ GLib.AppInfo app_info = info as GLib.AppInfo;
+ return app_info;
+ }
+
}
diff --git a/src/player-controller.vala b/src/player-controller.vala
index 0d8dc01..88dc3a7 100644
--- a/src/player-controller.vala
+++ b/src/player-controller.vala
@@ -25,66 +25,119 @@ public class PlayerController : GLib.Object
{
public const int METADATA = 2;
private const int TRANSPORT = 3;
+
+ public static const int OFFLINE = 0;
+ public static const int INSTANTIATING = 1;
+ public static const int READY = 2;
+ public static const int CONNECTED = 3;
+ public static const int DISCONNECTED = 4;
+
+ public int current_state = OFFLINE;
+
private Dbusmenu.Menuitem root_menu;
- private string name;
- private bool is_active;
+ public string name { get; set;}
public ArrayList<PlayerItem> custom_items;
- private MprisController mpris_adaptor;
- private string desktop_path;
-
- public PlayerController(Dbusmenu.Menuitem root, string client_name, bool active)
+ public MprisController mpris_adaptor;
+ public AppInfo? app_info { get; set;}
+
+ public PlayerController(Dbusmenu.Menuitem root, string client_name, int state = OFFLINE)
{
this.root_menu = root;
this.name = format_client_name(client_name.strip());
- this.is_active = active;
this.custom_items = new ArrayList<PlayerItem>();
- self_construct();
-
- // Temporary scenario to handle both v1 and v2 of MPRIS.
+ this.update_state(state);
+ construct_widgets();
+ establish_mpris_connection();
+ update_layout();
+ }
+
+ public void update_state(int new_state)
+ {
+ debug("update_state : new state %i", new_state);
+ this.current_state = new_state;
+ }
+
+ public void activate()
+ {
+ this.establish_mpris_connection();
+ this.custom_items[METADATA].property_set_bool(MENUITEM_PROP_VISIBLE, true);
+ }
+
+ /*
+ instantiate()
+ The user should be able to start the app from the transport bar when in an offline state
+ There is a need to wait before the application is on DBus before attempting to access its mpris address
+ Hence only when the it has registered with us via libindicate do we attempt to kick off mpris communication
+ */
+ public void instantiate()
+ {
+ this.app_info.launch(null, null);
+ this.update_state(INSTANTIATING);
+ }
+
+ private void establish_mpris_connection()
+ {
+ if(this.current_state != READY){
+ debug("establish_mpris_connection - Not ready to connect");
+ return;
+ }
if(this.name == "Vlc"){
this.mpris_adaptor = new MprisControllerV2(this.name, this);
}
else{
this.mpris_adaptor = new MprisController(this.name, this);
- }
- this.custom_items[TRANSPORT].set_adaptor(this.mpris_adaptor);
-
- // At start up if there is no metadata then hide the item.
- // TODO: NOT working -> dbus menu bug ?
- //((MetadataMenuitem)this.custom_items[METADATA]).check_layout();
+ }
+ if(this.mpris_adaptor.connected() == true){
+ this.update_state(CONNECTED);
+ }
+ else{
+ this.update_state(DISCONNECTED);
+ }
+ this.update_layout();
}
-
+
public void vanish()
{
foreach(Dbusmenu.Menuitem item in this.custom_items){
root_menu.child_delete(item);
}
}
+
+ private void update_layout()
+ {
+ bool visibility = true;
+ if(this.current_state != CONNECTED){
+ visibility = false;
+ }
+ this.custom_items[TRANSPORT].property_set_bool(MENUITEM_PROP_VISIBLE, visibility);
+ this.custom_items[METADATA].property_set_bool(MENUITEM_PROP_VISIBLE, visibility);
+ }
+
- private bool self_construct()
+ private void construct_widgets()
{
// Separator item
- this.custom_items.add(PlayerItem.new_separator_item());
+ this.custom_items.add(new PlayerItem(CLIENT_TYPES_SEPARATOR));
// Title item
- this.custom_items.add(PlayerItem.new_title_item(this.name));
+ TitleMenuitem title_menu_item = new TitleMenuitem(this, this.name);
+ this.custom_items.add(title_menu_item);
// Metadata item
MetadataMenuitem metadata_item = new MetadataMenuitem();
this.custom_items.add(metadata_item);
// Transport item
- TransportMenuitem transport_item = new TransportMenuitem();
+ TransportMenuitem transport_item = new TransportMenuitem(this);
this.custom_items.add(transport_item);
int offset = 2;
foreach(PlayerItem item in this.custom_items){
root_menu.child_add_position(item, offset + this.custom_items.index_of(item));
}
- return true;
}
-
+
private static string format_client_name(string client_name)
{
string formatted = client_name;
@@ -94,5 +147,5 @@ public class PlayerController : GLib.Object
}
return formatted;
}
-
+
} \ No newline at end of file
diff --git a/src/player-item.vala b/src/player-item.vala
index a5c5512..171c140 100644
--- a/src/player-item.vala
+++ b/src/player-item.vala
@@ -22,10 +22,16 @@ using Gee;
public class PlayerItem : Dbusmenu.Menuitem
{
- public MprisController mpris_adaptor;
-
- public PlayerItem()
+ public PlayerController owner {get; construct;}
+ public string item_type { get; construct; }
+
+ public PlayerItem(string type)
{
+ Object(item_type: type);
+ }
+
+ construct {
+ this.property_set(MENUITEM_PROP_TYPE, item_type);
}
public void reset(HashSet<string> attrs){
@@ -60,15 +66,8 @@ public class PlayerItem : Dbusmenu.Menuitem
this.property_set_bool(property, v.get_boolean());
}
}
- // TODO: not working
- //this.check_layout();
}
- public void set_adaptor(MprisController adaptor)
- {
- this.mpris_adaptor = adaptor;
- }
-
private static bool ensure_valid_updates(HashTable<string, Value?> data, HashSet<string> attributes)
{
if(data == null){
@@ -91,27 +90,5 @@ public class PlayerItem : Dbusmenu.Menuitem
return result;
}
-
- //----- Custom constructors for player items ----------------//
- // Title item
- public static PlayerItem new_title_item(dynamic string name)
- {
- PlayerItem item = new PlayerItem();
- item.property_set(MENUITEM_PROP_LABEL, name);
- item.property_set(MENUITEM_PROP_ICON_NAME, "applications-multimedia");
- return item;
- }
-
- // Separator item
- public static PlayerItem new_separator_item()
- {
- PlayerItem separator = new PlayerItem();
- separator.property_set(MENUITEM_PROP_TYPE, CLIENT_TYPES_SEPARATOR);
- return separator;
- }
-
- public virtual void check_layout(){
- warning("this should not be hit");
- }
}
diff --git a/src/sound-service.c b/src/sound-service.c
index bcdac07..8f4e941 100644
--- a/src/sound-service.c
+++ b/src/sound-service.c
@@ -4,9 +4,7 @@ Copyright 2010 Canonical Ltd.
Authors:
Conor Curran <conor.curran@canonical.com>
- Ted Gould <ted@canonical.com>
- Cody Russell <crussell@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.
diff --git a/src/title-menu-item.vala b/src/title-menu-item.vala
new file mode 100644
index 0000000..0acd97f
--- /dev/null
+++ b/src/title-menu-item.vala
@@ -0,0 +1,48 @@
+/*
+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, string name)
+ {
+ Object(item_type: MENUITEM_TYPE, owner: parent);
+ this.property_set(MENUITEM_TEXT_NAME, name);
+ }
+
+ public override void handle_event(string name, GLib.Value input_value, uint timestamp)
+ {
+ debug("handle_event with bool value %s", input_value.get_boolean().to_string());
+ if(this.owner.current_state == PlayerController.OFFLINE)
+ {
+ this.owner.instantiate();
+ }
+ }
+
+
+ public static HashSet<string> attributes_format()
+ {
+ HashSet<string> attrs = new HashSet<string>();
+ attrs.add(MENUITEM_TEXT_NAME);
+ return attrs;
+ }
+} \ No newline at end of file
diff --git a/src/title-widget.c b/src/title-widget.c
new file mode 100644
index 0000000..9951754
--- /dev/null
+++ b/src/title-widget.c
@@ -0,0 +1,191 @@
+/*
+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>
+
+static DbusmenuMenuitem* twin_item;
+
+typedef struct _TitleWidgetPrivate TitleWidgetPrivate;
+
+struct _TitleWidgetPrivate
+{
+ GtkWidget* hbox;
+ GtkWidget* name;
+ GtkWidget* player_icon;
+};
+
+#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_press_event (GtkWidget *menuitem,
+ GdkEventButton *event);
+static gboolean title_widget_button_release_event (GtkWidget *menuitem,
+ GdkEventButton *event);
+static gboolean title_widget_expose_event(GtkWidget* widget,
+ GdkEventExpose* event);
+
+// Dbusmenuitem properties update callback
+static void title_widget_property_update(DbusmenuMenuitem* item, gchar* property,
+ GValue* value, gpointer userdata);
+static void style_name_text(TitleWidget* self);
+G_DEFINE_TYPE (TitleWidget, title_widget, GTK_TYPE_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_press_event = title_widget_button_press_event;
+ widget_class->button_release_event = title_widget_button_release_event;
+ widget_class->expose_event = title_widget_expose_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");
+
+ TitleWidgetPrivate * priv = TITLE_WIDGET_GET_PRIVATE(self);
+
+ GtkWidget *hbox;
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ priv->hbox = hbox;
+ g_signal_connect(G_OBJECT(twin_item), "property-changed",
+ G_CALLBACK(title_widget_property_update), self);
+ // TODO - waiting theme icon name for correct usage
+ priv->player_icon = gtk_image_new_from_file("/home/ronoc/branches/sound-menu-v2/finish-indicate/indicator-sound/data/sound_icon.png");
+ gtk_box_pack_start(GTK_BOX (priv->hbox), priv->player_icon, FALSE, FALSE, 0);
+
+ priv->name = gtk_label_new(dbusmenu_menuitem_property_get(twin_item,
+ DBUSMENU_TITLE_MENUITEM_TEXT_NAME));
+ gtk_misc_set_padding(GTK_MISC(priv->name), 10, 0);
+ gtk_box_pack_start (GTK_BOX (priv->hbox), priv->name, FALSE, FALSE, 0);
+
+ style_name_text(self);
+
+ gtk_widget_show_all (priv->hbox);
+ gtk_container_add (GTK_CONTAINER (self), hbox);
+
+}
+
+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_press_event (GtkWidget *menuitem,
+ GdkEventButton *event)
+{
+ g_debug("TitleWidget::menu_press_event");
+
+ GValue value = {0};
+ g_value_init(&value, G_TYPE_BOOLEAN);
+
+ g_value_set_boolean(&value, TRUE);
+ dbusmenu_menuitem_handle_event (twin_item, "Title menu event", &value, 0);
+
+ return TRUE;
+}
+
+static gboolean
+title_widget_button_release_event (GtkWidget *menuitem,
+ GdkEventButton *event)
+{
+ g_debug("TitleWidget::menu_release_event");
+ return TRUE;
+}
+
+static gboolean
+title_widget_expose_event(GtkWidget* widget, GdkEventExpose* event)
+{
+ TitleWidgetPrivate * priv = TITLE_WIDGET_GET_PRIVATE(widget);
+
+ gtk_container_propagate_expose(GTK_CONTAINER(widget), priv->hbox, event);
+ return TRUE;
+}
+
+static void
+title_widget_property_update(DbusmenuMenuitem* item, gchar* property,
+ GValue* value, gpointer userdata)
+{
+ g_return_if_fail (IS_TITLE_WIDGET (userdata));
+ TitleWidget* mitem = TITLE_WIDGET(userdata);
+ TitleWidgetPrivate * priv = TITLE_WIDGET_GET_PRIVATE(mitem);
+
+ if(g_ascii_strcasecmp(DBUSMENU_TITLE_MENUITEM_TEXT_NAME, property) == 0){
+ gtk_label_set_text(GTK_LABEL(priv->name), g_value_get_string(value));
+ style_name_text(mitem);
+ }
+}
+
+static void
+style_name_text(TitleWidget* self)
+{
+ TitleWidgetPrivate * priv = TITLE_WIDGET_GET_PRIVATE(self);
+
+ char* markup;
+ markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>",
+ gtk_label_get_text(GTK_LABEL(priv->name)));
+ gtk_label_set_markup (GTK_LABEL (priv->name), markup);
+ g_free(markup);
+}
+
+ /**
+ * transport_new:
+ * @returns: a new #TitleWidget.
+ **/
+GtkWidget*
+title_widget_new(DbusmenuMenuitem *item)
+{
+ twin_item = item;
+ return g_object_new(TITLE_WIDGET_TYPE, NULL);
+}
+
diff --git a/src/title-widget.h b/src/title-widget.h
new file mode 100644
index 0000000..efc0c78
--- /dev/null
+++ b/src/title-widget.h
@@ -0,0 +1,51 @@
+/*
+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/gtkmenuitem.h>
+#include <libdbusmenu-gtk/menu.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 {
+ GtkMenuItemClass parent_class;
+};
+
+struct _TitleWidget {
+ GtkMenuItem parent;
+};
+
+GType title_widget_get_type (void);
+GtkWidget* title_widget_new(DbusmenuMenuitem *twin_item);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/transport-menu-item.vala b/src/transport-menu-item.vala
index 264e153..7a1bb4a 100644
--- a/src/transport-menu-item.vala
+++ b/src/transport-menu-item.vala
@@ -24,10 +24,9 @@ using DbusmenuTransport;
public class TransportMenuitem : PlayerItem
{
- public TransportMenuitem()
+ public TransportMenuitem(PlayerController parent)
{
- this.property_set(MENUITEM_PROP_TYPE, MENUITEM_TYPE);
- debug("transport on the vala side");
+ Object(item_type: MENUITEM_TYPE, owner: parent);
}
public void change_play_state(int state)
@@ -38,13 +37,8 @@ public class TransportMenuitem : PlayerItem
public override void handle_event(string name, GLib.Value input_value, uint timestamp)
{
debug("handle_event with bool value %s", input_value.get_boolean().to_string());
- this.mpris_adaptor.toggle_playback(input_value.get_boolean());
- }
-
- public override void check_layout(){
- // nothing to be done for this item - always active
- }
-
+ this.owner.mpris_adaptor.toggle_playback(input_value.get_boolean());
+ }
public static HashSet<string> attributes_format()
{
diff --git a/vapi/common-defs.vapi b/vapi/common-defs.vapi
index 222fb67..6649b26 100644
--- a/vapi/common-defs.vapi
+++ b/vapi/common-defs.vapi
@@ -30,4 +30,10 @@ namespace DbusmenuMetadata{
namespace DbusmenuTransport{
public const string MENUITEM_TYPE;
public const string MENUITEM_PLAY_STATE;
+}
+
+[CCode (cheader_filename = "common-defs.h")]
+namespace DbusmenuTitle{
+ public const string MENUITEM_TYPE;
+ public const string MENUITEM_TEXT_NAME;
} \ No newline at end of file