From 21d2a15d77eb470969669d9cb1afde6efbcdf574 Mon Sep 17 00:00:00 2001 From: Rory Fewell Date: Mon, 8 Sep 2025 23:50:16 +0100 Subject: [PATCH] Cleaning: Fixes #526, Migrate taskband toolbars to WinTCShextUIHost/Controller --- shared/shelldpa/src/api.c | 20 + shell/taskband/CMakeLists.txt | 11 +- shell/taskband/deps | 1 + shell/taskband/src/intapi.h | 16 + shell/taskband/src/start/personal.c | 14 +- shell/taskband/src/start/shared.h | 12 +- shell/taskband/src/start/toolbar.c | 72 +-- shell/taskband/src/start/toolbar.h | 16 +- shell/taskband/src/systray/behaviour.c | 190 ------- shell/taskband/src/systray/behaviour.h | 39 -- shell/taskband/src/systray/icon.c | 497 ++++++++++++++++++ shell/taskband/src/systray/icon.h | 33 ++ shell/taskband/src/systray/network.c | 87 ++- shell/taskband/src/systray/network.h | 26 +- shell/taskband/src/systray/notifarea.c | 264 ++++------ shell/taskband/src/systray/notifarea.h | 16 +- shell/taskband/src/systray/power.c | 64 +-- shell/taskband/src/systray/power.h | 26 +- shell/taskband/src/systray/toolbar.c | 52 +- shell/taskband/src/systray/toolbar.h | 19 +- shell/taskband/src/systray/volume.c | 76 ++- shell/taskband/src/systray/volume.h | 26 +- .../taskband/src/taskbuttons/taskbuttonbar.c | 1 + shell/taskband/src/taskbuttons/toolbar.c | 54 +- shell/taskband/src/taskbuttons/toolbar.h | 19 +- shell/taskband/src/toolbar.c | 94 ---- shell/taskband/src/toolbar.h | 38 -- shell/taskband/src/window.c | 165 +++--- 28 files changed, 1067 insertions(+), 881 deletions(-) create mode 100644 shell/taskband/src/intapi.h delete mode 100644 shell/taskband/src/systray/behaviour.c delete mode 100644 shell/taskband/src/systray/behaviour.h create mode 100644 shell/taskband/src/systray/icon.c create mode 100644 shell/taskband/src/systray/icon.h delete mode 100644 shell/taskband/src/toolbar.c delete mode 100644 shell/taskband/src/toolbar.h diff --git a/shared/shelldpa/src/api.c b/shared/shelldpa/src/api.c index d508d68..c215aca 100644 --- a/shared/shelldpa/src/api.c +++ b/shared/shelldpa/src/api.c @@ -179,6 +179,26 @@ void wintc_dpa_show_popup( &y ); + // Adjust pos if the window doesn't have its own GDK window + // + if (!gtk_widget_get_has_window(owner)) + { + gint off_x = 0; + gint off_y = 0; + + gtk_widget_translate_coordinates( + owner, + GTK_WIDGET(wintc_widget_get_toplevel_window(owner)), + 0, + 0, + &off_x, + &off_y + ); + + x += off_x; + y += off_y; + } + gtk_window_move( GTK_WINDOW(popup), x, diff --git a/shell/taskband/CMakeLists.txt b/shell/taskband/CMakeLists.txt index dca8ae0..5d2dacc 100644 --- a/shell/taskband/CMakeLists.txt +++ b/shell/taskband/CMakeLists.txt @@ -36,6 +36,7 @@ wintc_resolve_library(wintc-comgtk WINTC_COMGTK) wintc_resolve_library(wintc-exec WINTC_EXEC) wintc_resolve_library(wintc-shcommon WINTC_SHCOMMON) wintc_resolve_library(wintc-shelldpa WINTC_SHELLDPA) +wintc_resolve_library(wintc-shellext WINTC_SHELLEXT) wintc_resolve_library(wintc-shlang WINTC_SHLANG) wintc_resolve_library(wintc-sndapi WINTC_SNDAPI) @@ -47,11 +48,10 @@ set( TASKBAND_SOURCES src/application.c src/application.h + src/intapi.h src/main.c src/meta.h src/resources.c - src/toolbar.c - src/toolbar.h src/window.c src/window.h src/start/menumod.c @@ -65,10 +65,10 @@ set( src/start/toolbar.h src/start/util.c src/start/util.h - src/systray/behaviour.c - src/systray/behaviour.h src/systray/clock.c src/systray/clock.h + src/systray/icon.c + src/systray/icon.h src/systray/notifarea.c src/systray/notifarea.h src/systray/power.c @@ -123,6 +123,7 @@ target_include_directories( PRIVATE ${WINTC_EXEC_INCLUDE_DIRS} PRIVATE ${WINTC_SHCOMMON_INCLUDE_DIRS} PRIVATE ${WINTC_SHELLDPA_INCLUDE_DIRS} + PRIVATE ${WINTC_SHELLEXT_INCLUDE_DIRS} PRIVATE ${WINTC_SHLANG_INCLUDE_DIRS} PRIVATE ${WINTC_SNDAPI_INCLUDE_DIRS} ) @@ -142,6 +143,7 @@ target_link_directories( PRIVATE ${WINTC_EXEC_LIBRARY_DIRS} PRIVATE ${WINTC_SHCOMMON_LIBRARY_DIRS} PRIVATE ${WINTC_SHELLDPA_LIBRARY_DIRS} + PRIVATE ${WINTC_SHELLEXT_LIBRARY_DIRS} PRIVATE ${WINTC_SHLANG_LIBRARY_DIRS} PRIVATE ${WINTC_SNDAPI_LIBRARY_DIRS} ) @@ -161,6 +163,7 @@ target_link_libraries( PRIVATE ${WINTC_EXEC_LIBRARIES} PRIVATE ${WINTC_SHCOMMON_LIBRARIES} PRIVATE ${WINTC_SHELLDPA_LIBRARIES} + PRIVATE ${WINTC_SHELLEXT_LIBRARIES} PRIVATE ${WINTC_SHLANG_LIBRARIES} PRIVATE ${WINTC_SNDAPI_LIBRARIES} ) diff --git a/shell/taskband/deps b/shell/taskband/deps index b6eb267..2dddba0 100644 --- a/shell/taskband/deps +++ b/shell/taskband/deps @@ -12,5 +12,6 @@ bt,rt:wintc-comgtk bt,rt:wintc-exec bt,rt:wintc-shcommon bt,rt:wintc-shelldpa +bt,rt:wintc-shellext bt,rt:wintc-shlang bt,rt:wintc-sndapi diff --git a/shell/taskband/src/intapi.h b/shell/taskband/src/intapi.h new file mode 100644 index 0000000..27337c0 --- /dev/null +++ b/shell/taskband/src/intapi.h @@ -0,0 +1,16 @@ +#ifndef __INTAPI_H__ +#define __INTAPI_H__ + +// +// PUBLIC CONSTANTS +// + +// Taskband host API +// +#define WINTC_TASKBAND_HOSTEXT_TOOLBAR 1 + +// Notification area host API +// +#define WINTC_NOTIFAREA_HOSTEXT_ICON 1 + +#endif diff --git a/shell/taskband/src/start/personal.c b/shell/taskband/src/start/personal.c index 7f63f0d..fb03dee 100644 --- a/shell/taskband/src/start/personal.c +++ b/shell/taskband/src/start/personal.c @@ -11,7 +11,6 @@ #include #include -#include "../toolbar.h" #include "menumod.h" #include "personal.h" #include "progmenu.h" @@ -125,7 +124,6 @@ void create_personal_menu( ) { GtkBuilder* builder; - WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(toolbar_start); // Set default states // @@ -266,7 +264,10 @@ void create_personal_menu( // Transfer to popup // toolbar_start->personal.popup_menu = - wintc_dpa_create_popup(toolbar->widget_root, TRUE); + wintc_dpa_create_popup( + toolbar_start->start_button, + TRUE + ); wintc_widget_add_style_class( toolbar_start->personal.popup_menu, @@ -417,8 +418,6 @@ void open_personal_menu( WinTCToolbarStart* toolbar_start ) { - WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(toolbar_start); - // Reset should close flag, so that selection-done knows no item has // actually been 'activated' yet // @@ -431,7 +430,7 @@ void open_personal_menu( wintc_dpa_show_popup( toolbar_start->personal.popup_menu, - toolbar->widget_root + toolbar_start->start_button ); } @@ -1134,7 +1133,6 @@ static void on_personal_menu_hide( gpointer user_data ) { - WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(user_data); WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(user_data); // Track the last closed time, important for toggling the menu properly @@ -1146,7 +1144,7 @@ static void on_personal_menu_hide( // toolbar_start->sync_button = TRUE; gtk_toggle_button_set_active( - GTK_TOGGLE_BUTTON(toolbar->widget_root), + GTK_TOGGLE_BUTTON(toolbar_start->start_button), FALSE ); toolbar_start->sync_button = FALSE; diff --git a/shell/taskband/src/start/shared.h b/shell/taskband/src/start/shared.h index 925a50d..f7b8853 100644 --- a/shell/taskband/src/start/shared.h +++ b/shell/taskband/src/start/shared.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "progmenu.h" @@ -40,14 +41,13 @@ typedef struct _PersonalStartMenuData GArray* tuples_programs; } PersonalStartMenuData; -typedef struct _WinTCToolbarStartClass -{ - WinTCTaskbandToolbarClass __parent__; -} WinTCToolbarStartClass; - typedef struct _WinTCToolbarStart { - WinTCTaskbandToolbar __parent__; + WinTCShextUIController __parent__; + + // UI + // + GtkWidget* start_button; // Personal data struct // diff --git a/shell/taskband/src/start/toolbar.c b/shell/taskband/src/start/toolbar.c index 0e54ede..3450d41 100644 --- a/shell/taskband/src/start/toolbar.c +++ b/shell/taskband/src/start/toolbar.c @@ -2,9 +2,10 @@ #include #include #include +#include #include -#include "../toolbar.h" +#include "../intapi.h" #include "personal.h" #include "progmenu.h" #include "shared.h" @@ -13,6 +14,9 @@ // // FORWARD DECLARATIONS // +static void wintc_toolbar_start_constructed( + GObject* object +); static void wintc_toolbar_start_dispose( GObject* object ); @@ -28,7 +32,7 @@ static void on_start_button_toggled( G_DEFINE_TYPE( WinTCToolbarStart, wintc_toolbar_start, - WINTC_TYPE_TASKBAND_TOOLBAR + WINTC_TYPE_SHEXT_UI_CONTROLLER ) static void wintc_toolbar_start_class_init( @@ -37,16 +41,14 @@ static void wintc_toolbar_start_class_init( { GObjectClass* object_class = G_OBJECT_CLASS(klass); - object_class->dispose = wintc_toolbar_start_dispose; + object_class->constructed = wintc_toolbar_start_constructed; + object_class->dispose = wintc_toolbar_start_dispose; } static void wintc_toolbar_start_init( WinTCToolbarStart* self ) { - GtkBuilder* builder; - WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(self); - // Default states // self->sync_button = FALSE; @@ -70,22 +72,42 @@ static void wintc_toolbar_start_init( // Initialize progmenu // self->progmenu = wintc_toolbar_start_progmenu_new(); +} - // Create root widget (Start button) +// +// CLASS VIRTUAL METHODS +// +static void wintc_toolbar_start_constructed( + GObject* object +) +{ + (G_OBJECT_CLASS(wintc_toolbar_start_parent_class))->constructed(object); + + WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(object); + + // Create Start button as the toolbar // - builder = + GtkBuilder* builder = gtk_builder_new_from_resource( "/uk/oddmatics/wintc/taskband/start-button.ui" ); wintc_lc_builder_preprocess_widget_text(builder); - toolbar->widget_root = - GTK_WIDGET( - g_object_ref_sink( - gtk_builder_get_object(builder, "start-button") - ) - ); + wintc_builder_get_objects( + builder, + "start-button", &(toolbar_start->start_button), + NULL + ); + + wintc_ishext_ui_host_get_ext_widget( + wintc_shext_ui_controller_get_ui_host( + WINTC_SHEXT_UI_CONTROLLER(object) + ), + WINTC_TASKBAND_HOSTEXT_TOOLBAR, + GTK_TYPE_WIDGET, + toolbar_start->start_button + ); g_object_unref(G_OBJECT(builder)); @@ -93,32 +115,23 @@ static void wintc_toolbar_start_init( // FIXME: Hard coded to the personal menu for now, 'til DBus and stuff is // understood and we can support a 'Use classic menu' property // - create_personal_menu(self); + create_personal_menu(toolbar_start); // Attach signals for popup // g_signal_connect( - toolbar->widget_root, + toolbar_start->start_button, "toggled", G_CALLBACK(on_start_button_toggled), - self + toolbar_start ); } -// -// CLASS VIRTUAL METHODS -// static void wintc_toolbar_start_dispose( GObject* object ) { - WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(object); - WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(object); - - // Because we took a reference to the Start button from the builder, we - // must unref it now - // - g_object_unref(toolbar->widget_root); + WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(object); // FIXME: Only worrying about destroying the personal menu for now until // the classic menu is available @@ -139,9 +152,8 @@ void wintc_toolbar_start_toggle_menu( WinTCToolbarStart* toolbar_start ) { - WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(toolbar_start); - - GtkToggleButton* start_button = GTK_TOGGLE_BUTTON(toolbar->widget_root); + GtkToggleButton* start_button = + GTK_TOGGLE_BUTTON(toolbar_start->start_button); // Rate-limit toggling, prevents glitchy behaviour especially when launched // via cmdline/keyboard shortcut (so the menu loses focus then immediately diff --git a/shell/taskband/src/start/toolbar.h b/shell/taskband/src/start/toolbar.h index e6c8310..7dc0a2c 100644 --- a/shell/taskband/src/start/toolbar.h +++ b/shell/taskband/src/start/toolbar.h @@ -3,20 +3,22 @@ #include #include +#include #include "shared.h" // // GTK OOP BOILERPLATE // -#define WINTC_TYPE_TOOLBAR_START (wintc_toolbar_start_get_type()) -#define WINTC_TOOLBAR_START(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_TOOLBAR_START, WinTCToolbarStart)) -#define WINTC_TOOLBAR_START_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_TOOLBAR_START, WinTCToolbarStartClass)) -#define IS_WINTC_TOOLBAR_START(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_TOOLBAR_START)) -#define IS_WINTC_TOOLBAR_START_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_TOOLBAR_START)) -#define WINTC_TOOLBAR_START_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_TOOLBAR_START, WinTCToolbarStart)) +#define WINTC_TYPE_TOOLBAR_START (wintc_toolbar_start_get_type()) -GType wintc_toolbar_start_get_type(void) G_GNUC_CONST; +G_DECLARE_FINAL_TYPE( + WinTCToolbarStart, + wintc_toolbar_start, + WINTC, + TOOLBAR_START, + WinTCShextUIController +) // // PUBLIC FUNCTIONS diff --git a/shell/taskband/src/systray/behaviour.c b/shell/taskband/src/systray/behaviour.c deleted file mode 100644 index 00e17a6..0000000 --- a/shell/taskband/src/systray/behaviour.c +++ /dev/null @@ -1,190 +0,0 @@ -#include -#include - -#include "behaviour.h" - -// -// PRIVATE ENUMS -// -enum -{ - PROP_WIDGET_NOTIF = 1, - PROP_ICON_NAME -}; - -enum -{ - SIGNAL_ICON_CHANGED = 0, - N_SIGNALS -}; - -// -// STATIC DATA -// -static gint wintc_notification_behaviour_signals[N_SIGNALS] = { 0 }; - -// -// FORWARD DECLARATIONS -// -static void wintc_notification_behaviour_finalize( - GObject* object -); -static void wintc_notification_behaviour_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec -); -static void wintc_notification_behaviour_set_property( - GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec -); - -// -// GTK TYPE DEFINITIONS & CTORS -// -G_DEFINE_TYPE( - WinTCNotificationBehaviour, - wintc_notification_behaviour, - G_TYPE_OBJECT -) - -static void wintc_notification_behaviour_class_init( - WinTCNotificationBehaviourClass* klass -) -{ - GObjectClass* object_class = G_OBJECT_CLASS(klass); - - object_class->finalize = wintc_notification_behaviour_finalize; - object_class->get_property = wintc_notification_behaviour_get_property; - object_class->set_property = wintc_notification_behaviour_set_property; - - wintc_notification_behaviour_signals[SIGNAL_ICON_CHANGED] = - g_signal_new( - "icon-changed", - G_TYPE_FROM_CLASS(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0 - ); - - g_object_class_install_property( - object_class, - PROP_WIDGET_NOTIF, - g_param_spec_object( - "widget-notif", - "WidgetNotif", - "The GTK widget that hosts the notification icon.", - GTK_TYPE_WIDGET, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY - ) - ); - g_object_class_install_property( - object_class, - PROP_ICON_NAME, - g_param_spec_string( - "icon-name", - "IconName", - "The icon name to display in the notification area.", - NULL, - G_PARAM_WRITABLE - ) - ); -} - -static void wintc_notification_behaviour_init( - WinTCNotificationBehaviour* self -) -{ - self->icon_name = NULL; - self->widget_notif = NULL; -} - -// -// CLASS VIRTUAL METHODS -// -static void wintc_notification_behaviour_finalize( - GObject* object -) -{ - WinTCNotificationBehaviour* behaviour = - WINTC_NOTIFICATION_BEHAVIOUR(object); - - g_free(behaviour->icon_name); - - (G_OBJECT_CLASS(wintc_notification_behaviour_parent_class)) - ->finalize(object); -} - -static void wintc_notification_behaviour_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec -) -{ - WinTCNotificationBehaviour* behaviour = - WINTC_NOTIFICATION_BEHAVIOUR(object); - - switch (prop_id) - { - case PROP_ICON_NAME: - g_value_set_string(value, behaviour->icon_name); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void wintc_notification_behaviour_set_property( - GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec -) -{ - WinTCNotificationBehaviour* behaviour = - WINTC_NOTIFICATION_BEHAVIOUR(object); - - switch (prop_id) - { - case PROP_ICON_NAME: - g_free(behaviour->icon_name); - behaviour->icon_name = g_strdup(g_value_get_string(value)); - - g_signal_emit( - behaviour, - wintc_notification_behaviour_signals[SIGNAL_ICON_CHANGED], - 0 - ); - - break; - - case PROP_WIDGET_NOTIF: - behaviour->widget_notif = GTK_WIDGET(g_value_get_object(value)); - - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -// -// PUBLIC FUNCTIONS -// -const gchar* wintc_notification_behaviour_get_icon_name( - WinTCNotificationBehaviour* behaviour -) -{ - return behaviour->icon_name; -} diff --git a/shell/taskband/src/systray/behaviour.h b/shell/taskband/src/systray/behaviour.h deleted file mode 100644 index 995372d..0000000 --- a/shell/taskband/src/systray/behaviour.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef __BEHAVIOUR_H__ -#define __BEHAVIOUR_H__ - -#include -#include - -// -// GTK OOP BOILERPLATE -// -typedef struct _WinTCNotificationBehaviourClass -{ - GObjectClass __parent__; -} WinTCNotificationBehaviourClass; - -typedef struct _WinTCNotificationBehaviour -{ - GObject __parent__; - - gchar* icon_name; - GtkWidget* widget_notif; -} WinTCNotificationBehaviour; - -#define WINTC_TYPE_NOTIFICATION_BEHAVIOUR (wintc_notification_behaviour_get_type()) -#define WINTC_NOTIFICATION_BEHAVIOUR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_NOTIFICATION_BEHAVIOUR, WinTCNotificationBehaviour)) -#define WINTC_NOTIFICATION_BEHAVIOUR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_NOTIFICATION_BEHAVIOUR, WinTCNotificationBehaviourClass)) -#define IS_WINTC_NOTIFICATION_BEHAVIOUR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_NOTIFICATION_BEHAVIOUR)) -#define IS_WINTC_NOTIFICATION_BEHAVIOUR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_NOTIFICATION_BEHAVIOUR)) -#define WINTC_NOTIFICATION_BEHAVIOUR_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_NOTIFICATION_BEHAVIOUR, WinTCNotificationBehaviour)) - -GType wintc_notification_behaviour_get_type(void) G_GNUC_CONST; - -// -// PUBLIC FUNCTIONS -// -const gchar* wintc_notification_behaviour_get_icon_name( - WinTCNotificationBehaviour* behaviour -); - -#endif diff --git a/shell/taskband/src/systray/icon.c b/shell/taskband/src/systray/icon.c new file mode 100644 index 0000000..6a14264 --- /dev/null +++ b/shell/taskband/src/systray/icon.c @@ -0,0 +1,497 @@ +#include +#include +#include +#include +#include + +#include "icon.h" + +#define TRAY_ICON_SIZE 16 + +// +// PRIVATE ENUMS +// +enum +{ + PROP_NULL, + PROP_ICON_NAME, + N_PROPERTIES +}; + +// +// FORWARD DECLARATIONS +// +static void wintc_notif_area_icon_dispose( + GObject* object +); +static void wintc_notif_area_icon_finalize( + GObject* object +); +static void wintc_notif_area_icon_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec +); +static void wintc_notif_area_icon_set_property( + GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec +); + +static gboolean wintc_notif_area_icon_draw( + GtkWidget* widget, + cairo_t* cr +); +static void wintc_notif_area_icon_get_preferred_height( + GtkWidget* widget, + gint* minimum_height, + gint* natural_height +); +static void wintc_notif_area_icon_get_preferred_height_for_width( + GtkWidget* widget, + gint width, + gint* minimum_height, + gint* natural_height +); +static void wintc_notif_area_icon_get_preferred_width( + GtkWidget* widget, + gint* minimum_width, + gint* natural_width +); +static void wintc_notif_area_icon_get_preferred_width_for_height( + GtkWidget* widget, + gint height, + gint* minimum_width, + gint* natural_width +); +static void wintc_notif_area_icon_map( + GtkWidget* widget +); +static void wintc_notif_area_icon_realize( + GtkWidget* widget +); +static void wintc_notif_area_icon_size_allocate( + GtkWidget* widget, + GtkAllocation* allocation +); +static void wintc_notif_area_icon_unmap( + GtkWidget* widget +); +static void wintc_notif_area_icon_unrealize( + GtkWidget* widget +); + +// +// STATIC DATA +// +static GParamSpec* wintc_notif_area_icon_properties[N_PROPERTIES] = { 0 }; + +// +// GTK OOP CLASS/INSTANCE DEFINITIONS +// +struct _WinTCNotifAreaIcon +{ + GtkWidget __parent__; + + GdkWindow* hwnd; + gchar* icon_name; + GdkPixbuf* pixbuf_icon; + cairo_surface_t* surface_icon; +}; + +// +// GTK TYPE DEFINITIONS & CTORS +// +G_DEFINE_TYPE( + WinTCNotifAreaIcon, + wintc_notif_area_icon, + GTK_TYPE_WIDGET +) + +static void wintc_notif_area_icon_class_init( + WinTCNotifAreaIconClass* klass +) +{ + GObjectClass* object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); + + object_class->dispose = wintc_notif_area_icon_dispose; + object_class->finalize = wintc_notif_area_icon_finalize; + object_class->get_property = wintc_notif_area_icon_get_property; + object_class->set_property = wintc_notif_area_icon_set_property; + + widget_class->draw = wintc_notif_area_icon_draw; + widget_class->map = wintc_notif_area_icon_map; + widget_class->realize = wintc_notif_area_icon_realize; + widget_class->size_allocate = wintc_notif_area_icon_size_allocate; + widget_class->unmap = wintc_notif_area_icon_unmap; + widget_class->unrealize = wintc_notif_area_icon_unrealize; + + widget_class->get_preferred_height = + wintc_notif_area_icon_get_preferred_height; + widget_class->get_preferred_height_for_width = + wintc_notif_area_icon_get_preferred_height_for_width; + widget_class->get_preferred_width = + wintc_notif_area_icon_get_preferred_width; + widget_class->get_preferred_width_for_height = + wintc_notif_area_icon_get_preferred_width_for_height; + + wintc_notif_area_icon_properties[PROP_ICON_NAME] = + g_param_spec_string( + "icon-name", + "IconName", + "The XDG icon name to use.", + "image-missing", + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY + ); + + g_object_class_install_properties( + object_class, + N_PROPERTIES, + wintc_notif_area_icon_properties + ); +} + +static void wintc_notif_area_icon_init( + WinTCNotifAreaIcon* self +) +{ + gtk_widget_set_has_window(GTK_WIDGET(self), FALSE); +} + +// +// CLASS VIRTUAL METHODS +// +static void wintc_notif_area_icon_dispose( + GObject* object +) +{ + WinTCNotifAreaIcon* notif_icon = WINTC_NOTIF_AREA_ICON(object); + + if (notif_icon->pixbuf_icon) + { + cairo_surface_destroy(notif_icon->surface_icon); + g_clear_object(&(notif_icon->pixbuf_icon)); + } + + (G_OBJECT_CLASS(wintc_notif_area_icon_parent_class)) + ->dispose(object); +} + +static void wintc_notif_area_icon_finalize( + GObject* object +) +{ + WinTCNotifAreaIcon* notif_icon = WINTC_NOTIF_AREA_ICON(object); + + g_free(notif_icon->icon_name); + + (G_OBJECT_CLASS(wintc_notif_area_icon_parent_class)) + ->finalize(object); +} + +static void wintc_notif_area_icon_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec +) +{ + WinTCNotifAreaIcon* notif_icon = WINTC_NOTIF_AREA_ICON(object); + + switch (prop_id) + { + case PROP_ICON_NAME: + g_value_set_string(value, notif_icon->icon_name); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void wintc_notif_area_icon_set_property( + GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec +) +{ + WinTCNotifAreaIcon* notif_icon = WINTC_NOTIF_AREA_ICON(object); + + switch (prop_id) + { + case PROP_ICON_NAME: + wintc_notif_area_icon_set_icon_name( + notif_icon, + g_value_get_string(value) + ); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static gboolean wintc_notif_area_icon_draw( + GtkWidget* widget, + cairo_t* cr +) +{ + WinTCNotifAreaIcon* notif_icon = WINTC_NOTIF_AREA_ICON(widget); + + if (!(notif_icon->surface_icon)) + { + return FALSE; + } + + // We draw the icon centered vertically + // + gint height = gtk_widget_get_allocated_height(widget); + + cairo_save(cr); + + cairo_translate( + cr, + 0.0f, + (double) ((height / 2) - (TRAY_ICON_SIZE / 2)) + ); + + cairo_set_source_surface( + cr, + notif_icon->surface_icon, + 0.0f, + 0.0f + ); + cairo_pattern_set_extend( + cairo_get_source(cr), + CAIRO_EXTEND_NONE + ); + + cairo_paint(cr); + + cairo_restore(cr); + + return FALSE; +} + +static void wintc_notif_area_icon_get_preferred_height( + WINTC_UNUSED(GtkWidget* widget), + gint* minimum_height, + gint* natural_height +) +{ + *minimum_height = TRAY_ICON_SIZE; + *natural_height = TRAY_ICON_SIZE; +} + +static void wintc_notif_area_icon_get_preferred_height_for_width( + WINTC_UNUSED(GtkWidget* widget), + WINTC_UNUSED(gint width), + gint* minimum_height, + gint* natural_height +) +{ + *minimum_height = TRAY_ICON_SIZE; + *natural_height = TRAY_ICON_SIZE; +} + +static void wintc_notif_area_icon_get_preferred_width( + WINTC_UNUSED(GtkWidget* widget), + gint* minimum_width, + gint* natural_width +) +{ + *minimum_width = TRAY_ICON_SIZE; + *natural_width = TRAY_ICON_SIZE; +} + +static void wintc_notif_area_icon_get_preferred_width_for_height( + WINTC_UNUSED(GtkWidget* widget), + WINTC_UNUSED(gint height), + gint* minimum_width, + gint* natural_width +) +{ + *minimum_width = TRAY_ICON_SIZE; + *natural_width = TRAY_ICON_SIZE; +} + +static void wintc_notif_area_icon_map( + GtkWidget* widget +) +{ + WinTCNotifAreaIcon* notif_icon = WINTC_NOTIF_AREA_ICON(widget); + + if (notif_icon->hwnd) + { + gdk_window_show(notif_icon->hwnd); + } + + (GTK_WIDGET_CLASS(wintc_notif_area_icon_parent_class)) + ->map(widget); +} + +static void wintc_notif_area_icon_realize( + GtkWidget* widget +) +{ + (GTK_WIDGET_CLASS(wintc_notif_area_icon_parent_class)) + ->realize(widget); + + WinTCNotifAreaIcon* notif_icon = WINTC_NOTIF_AREA_ICON(widget); + + GtkAllocation allocation; + GdkWindowAttr attribs; + + gtk_widget_get_allocation(widget, &allocation); + + attribs.x = allocation.x; + attribs.y = allocation.y; + attribs.width = allocation.width; + attribs.height = allocation.height; + attribs.event_mask = GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK; + attribs.wclass = GDK_INPUT_ONLY; + attribs.window_type = GDK_WINDOW_CHILD; + + notif_icon->hwnd = + gdk_window_new( + gtk_widget_get_parent_window(widget), + &attribs, + GDK_WA_X | GDK_WA_Y + ); + + gtk_widget_register_window(widget, notif_icon->hwnd); +} + +static void wintc_notif_area_icon_size_allocate( + GtkWidget* widget, + GtkAllocation* allocation +) +{ + (GTK_WIDGET_CLASS(wintc_notif_area_icon_parent_class)) + ->size_allocate(widget, allocation); + + WinTCNotifAreaIcon* notif_icon = WINTC_NOTIF_AREA_ICON(widget); + + if (gtk_widget_get_realized(widget) && notif_icon->hwnd) + { + gdk_window_move_resize( + notif_icon->hwnd, + allocation->x, + allocation->y, + allocation->width, + allocation->height + ); + } +} + +static void wintc_notif_area_icon_unmap( + GtkWidget* widget +) +{ + WinTCNotifAreaIcon* notif_icon = WINTC_NOTIF_AREA_ICON(widget); + + if (notif_icon->hwnd) + { + gdk_window_hide(notif_icon->hwnd); + } + + (GTK_WIDGET_CLASS(wintc_notif_area_icon_parent_class)) + ->map(widget); +} + +static void wintc_notif_area_icon_unrealize( + GtkWidget* widget +) +{ + WinTCNotifAreaIcon* notif_icon = WINTC_NOTIF_AREA_ICON(widget); + + if (notif_icon->hwnd) + { + gtk_widget_unregister_window(widget, notif_icon->hwnd); + gdk_window_destroy(notif_icon->hwnd); + + notif_icon->hwnd = NULL; + } + + (GTK_WIDGET_CLASS(wintc_notif_area_icon_parent_class)) + ->unrealize(widget); +} + +// +// PUBLIC FUNCTIONS +// +GtkWidget* wintc_notif_area_icon_new(void) +{ + return GTK_WIDGET( + g_object_new( + WINTC_TYPE_NOTIF_AREA_ICON, + NULL + ) + ); +} + +const gchar* wintc_notif_area_icon_get_icon_name( + WinTCNotifAreaIcon* notif_icon +) +{ + return notif_icon->icon_name; +} + +void wintc_notif_area_icon_set_icon_name( + WinTCNotifAreaIcon* notif_icon, + const gchar* icon_name +) +{ + // Bin old icon + // + if (notif_icon->icon_name) + { + g_free(notif_icon->icon_name); + } + + if (notif_icon->pixbuf_icon) + { + cairo_surface_destroy(notif_icon->surface_icon); + g_clear_object(&(notif_icon->pixbuf_icon)); + } + + // Set new icon + // + notif_icon->icon_name = g_strdup(icon_name); + + notif_icon->pixbuf_icon = + gtk_icon_theme_load_icon( + gtk_icon_theme_get_default(), + notif_icon->icon_name, + 16, + GTK_ICON_LOOKUP_FORCE_SIZE, + NULL + ); + + if (notif_icon->pixbuf_icon) + { + notif_icon->surface_icon = + gdk_cairo_surface_create_from_pixbuf( + notif_icon->pixbuf_icon, + 1, + NULL + ); + } + + // Finish up + // + gtk_widget_queue_draw(GTK_WIDGET(notif_icon)); + + g_object_notify_by_pspec( + G_OBJECT(notif_icon), + wintc_notif_area_icon_properties[PROP_ICON_NAME] + ); +} diff --git a/shell/taskband/src/systray/icon.h b/shell/taskband/src/systray/icon.h new file mode 100644 index 0000000..ac46529 --- /dev/null +++ b/shell/taskband/src/systray/icon.h @@ -0,0 +1,33 @@ +#ifndef __SYSTRAY_ICON_H__ +#define __SYSTRAY_ICON_H__ + +#include +#include + +// +// GTK OOP BOILERPLATE +// +#define WINTC_TYPE_NOTIF_AREA_ICON (wintc_notif_area_icon_get_type()) + +G_DECLARE_FINAL_TYPE( + WinTCNotifAreaIcon, + wintc_notif_area_icon, + WINTC, + NOTIF_AREA_ICON, + GtkWidget +) + +// +// PUBLIC FUNCTIONS +// +GtkWidget* wintc_notif_area_icon_new(void); + +const gchar* wintc_notif_area_icon_get_icon_name( + WinTCNotifAreaIcon* notif_icon +); +void wintc_notif_area_icon_set_icon_name( + WinTCNotifAreaIcon* notif_icon, + const gchar* icon_name +); + +#endif diff --git a/shell/taskband/src/systray/network.c b/shell/taskband/src/systray/network.c index 10a9a2b..c212fa8 100644 --- a/shell/taskband/src/systray/network.c +++ b/shell/taskband/src/systray/network.c @@ -2,26 +2,27 @@ #include #include #include +#include -#include "behaviour.h" +#include "../intapi.h" +#include "icon.h" #include "network.h" // // STATIC DATA // -GtkWidget* s_menu_network = NULL; +GtkWidget* S_MENU_NETWORK = NULL; // // GTK OOP CLASS/INSTANCE DEFINITIONS // -struct _WinTCNotificationNetworkClass -{ - WinTCNotificationBehaviourClass __parent__; -}; - struct _WinTCNotificationNetwork { - WinTCNotificationBehaviour __parent__; + WinTCShextUIController __parent__; + + // UI + // + GtkWidget* notif_icon; // Network stuff // @@ -51,7 +52,7 @@ static void on_nm_client_notify_primary_connection( GParamSpec* pspec, gpointer user_data ); -static void on_widget_notif_button_press_event( +static void on_notif_icon_button_press_event( GtkWidget* self, GdkEventButton* event, gpointer user_data @@ -63,7 +64,7 @@ static void on_widget_notif_button_press_event( G_DEFINE_TYPE( WinTCNotificationNetwork, wintc_notification_network, - WINTC_TYPE_NOTIFICATION_BEHAVIOUR + WINTC_TYPE_SHEXT_UI_CONTROLLER ) static void wintc_notification_network_class_init( @@ -79,14 +80,14 @@ static void wintc_notification_network_init( WINTC_UNUSED(WinTCNotificationNetwork* self) ) { - if (!s_menu_network) + if (!S_MENU_NETWORK) { GtkBuilder* builder = gtk_builder_new_from_resource( "/uk/oddmatics/wintc/taskband/menu-tray-nm.ui" ); - s_menu_network = + S_MENU_NETWORK = GTK_WIDGET( g_object_ref(gtk_builder_get_object(builder, "menu")) ); @@ -102,15 +103,25 @@ static void wintc_notification_network_constructed( GObject* object ) { - WinTCNotificationBehaviour* behaviour = - WINTC_NOTIFICATION_BEHAVIOUR(object); - WinTCNotificationNetwork* network = + (G_OBJECT_CLASS(wintc_notification_network_parent_class)) + ->constructed(object); + + WinTCNotificationNetwork* network = WINTC_NOTIFICATION_NETWORK(object); - g_object_set( - network, - "icon-name", "network-offline", - NULL + network->notif_icon = + wintc_ishext_ui_host_get_ext_widget( + wintc_shext_ui_controller_get_ui_host( + WINTC_SHEXT_UI_CONTROLLER(object) + ), + WINTC_NOTIFAREA_HOSTEXT_ICON, + WINTC_TYPE_NOTIF_AREA_ICON, + object + ); + + wintc_notif_area_icon_set_icon_name( + WINTC_NOTIF_AREA_ICON(network->notif_icon), + "network-offline" ); // Connect to NetworkManager @@ -126,29 +137,13 @@ static void wintc_notification_network_constructed( // Hook up signals for widget // g_signal_connect( - behaviour->widget_notif, + network->notif_icon, "button-press-event", - G_CALLBACK(on_widget_notif_button_press_event), + G_CALLBACK(on_notif_icon_button_press_event), network ); } -// -// PUBLIC FUNCTIONS -// -WinTCNotificationNetwork* wintc_notification_network_new( - GtkWidget* widget_notif -) -{ - return WINTC_NOTIFICATION_NETWORK( - g_object_new( - WINTC_TYPE_NOTIFICATION_NETWORK, - "widget-notif", widget_notif, - NULL - ) - ); -} - // // PRIVATE FUNCTIONS // @@ -165,10 +160,9 @@ static void nm_update_primary_connection( if (!network->nm_primary_connection) { - g_object_set( - network, - "icon-name", "network-offline", - NULL + wintc_notif_area_icon_set_icon_name( + WINTC_NOTIF_AREA_ICON(network->notif_icon), + "network-offline" ); return; @@ -176,10 +170,9 @@ static void nm_update_primary_connection( // FIXME: Decide network type and stuff // - g_object_set( - network, - "icon-name", "network-idle", - NULL + wintc_notif_area_icon_set_icon_name( + WINTC_NOTIF_AREA_ICON(network->notif_icon), + "network-idle" ); } @@ -231,7 +224,7 @@ static void on_nm_client_ready( ); } -static void on_widget_notif_button_press_event( +static void on_notif_icon_button_press_event( WINTC_UNUSED(GtkWidget* self), GdkEventButton* event, WINTC_UNUSED(gpointer user_data) @@ -240,7 +233,7 @@ static void on_widget_notif_button_press_event( if (event->button == 3) { gtk_menu_popup_at_pointer( - GTK_MENU(s_menu_network), + GTK_MENU(S_MENU_NETWORK), (GdkEvent*) event ); } diff --git a/shell/taskband/src/systray/network.h b/shell/taskband/src/systray/network.h index 2430567..3af7de6 100644 --- a/shell/taskband/src/systray/network.h +++ b/shell/taskband/src/systray/network.h @@ -3,27 +3,19 @@ #include #include +#include // // GTK OOP BOILERPLATE // -typedef struct _WinTCNotificationNetworkClass WinTCNotificationNetworkClass; -typedef struct _WinTCNotificationNetwork WinTCNotificationNetwork; +#define WINTC_TYPE_NOTIFICATION_NETWORK (wintc_notification_network_get_type()) -#define WINTC_TYPE_NOTIFICATION_NETWORK (wintc_notification_network_get_type()) -#define WINTC_NOTIFICATION_NETWORK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_NOTIFICATION_NETWORK, WinTCNotificationNetwork)) -#define WINTC_NOTIFICATION_NETWORK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_NOTIFICATION_BEHAVIOUR, WinTCNotificationNetworkClass)) -#define IS_WINTC_NOTIFICATION_NETWORK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_NOTIFICATION_NETWORK)) -#define IS_WINTC_NOTIFICATION_NETWORK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_NOTIFICATION_NETWORK)) -#define WINTC_NOTIFICATION_NETWORK_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_NOTIFICATION_NETWORK, WinTCNotificationNetwork)) - -GType wintc_notification_network_get_type(void) G_GNUC_CONST; - -// -// PUBLIC FUNCTIONS -// -WinTCNotificationNetwork* wintc_notification_network_new( - GtkWidget* widget_notif -); +G_DECLARE_FINAL_TYPE( + WinTCNotificationNetwork, + wintc_notification_network, + WINTC, + NOTIFICATION_NETWORK, + WinTCShextUIController +) #endif diff --git a/shell/taskband/src/systray/notifarea.c b/shell/taskband/src/systray/notifarea.c index fbae9af..57595ba 100644 --- a/shell/taskband/src/systray/notifarea.c +++ b/shell/taskband/src/systray/notifarea.c @@ -1,9 +1,11 @@ #include #include #include +#include -#include "behaviour.h" +#include "../intapi.h" #include "clock.h" +#include "icon.h" #include "notifarea.h" #include "power.h" #include "volume.h" @@ -12,6 +14,24 @@ #include "network.h" #endif +// +// FORWARD DECLARATIONS +// +static void wintc_notification_area_ishext_ui_host_interface_init( + WinTCIShextUIHostInterface* iface +); + +static void wintc_notification_area_dispose( + GObject* object +); + +static GtkWidget* wintc_notification_area_get_ext_widget( + WinTCIShextUIHost* host, + guint ext_id, + GType expected_type, + gpointer ctx +); + // // GTK OOP CLASS/INSTANCE DEFINITIONS // @@ -29,46 +49,20 @@ struct _WinTCNotificationArea WinTCClockRunner* clock_runner; - GHashTable* map_widget_to_behaviour; + GSList* list_uictl_behaviours; }; -// -// FORWARD DECLARATIONS -// -static void wintc_notification_area_dispose( - GObject* object -); - -static void wintc_notification_area_append_component( - WinTCNotificationArea* notif_area, - GType component_type -); -static GtkWidget* wintc_notification_area_append_icon( - WinTCNotificationArea* notif_area -); -static void wintc_notification_area_map_widget( - WinTCNotificationArea* notif_area, - GtkWidget* widget_notif, - WinTCNotificationBehaviour* behaviour -); - -static void update_notification_icon( - GtkWidget* widget_notif, - WinTCNotificationBehaviour* behaviour -); - -static void on_behaviour_icon_changed( - WinTCNotificationBehaviour* behaviour, - gpointer user_data -); - // // GTK TYPE DEFINITION & CTORS // -G_DEFINE_TYPE( +G_DEFINE_TYPE_WITH_CODE( WinTCNotificationArea, wintc_notification_area, - GTK_TYPE_BIN + GTK_TYPE_BIN, + G_IMPLEMENT_INTERFACE( + WINTC_TYPE_ISHEXT_UI_HOST, + wintc_notification_area_ishext_ui_host_interface_init + ) ) static void wintc_notification_area_class_init( @@ -84,16 +78,6 @@ static void wintc_notification_area_init( WinTCNotificationArea* self ) { - // Create map for notification widgets --> behaviours - // - self->map_widget_to_behaviour = - g_hash_table_new_full( - g_direct_hash, - g_direct_equal, - NULL, - g_object_unref - ); - // Set up UI // self->box_container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); @@ -123,21 +107,28 @@ static void wintc_notification_area_init( // Create notification area icons // #ifndef WINTC_PKGMGR_BSDPKG - wintc_notification_area_append_component( - self, - WINTC_TYPE_NOTIFICATION_NETWORK + wintc_shext_ui_controller_new_from_type( + WINTC_TYPE_NOTIFICATION_NETWORK, + WINTC_ISHEXT_UI_HOST(self) ); #endif - wintc_notification_area_append_component( - self, - WINTC_TYPE_NOTIFICATION_POWER + wintc_shext_ui_controller_new_from_type( + WINTC_TYPE_NOTIFICATION_POWER, + WINTC_ISHEXT_UI_HOST(self) ); - wintc_notification_area_append_component( - self, - WINTC_TYPE_NOTIFICATION_VOLUME + wintc_shext_ui_controller_new_from_type( + WINTC_TYPE_NOTIFICATION_VOLUME, + WINTC_ISHEXT_UI_HOST(self) ); } +static void wintc_notification_area_ishext_ui_host_interface_init( + WinTCIShextUIHostInterface* iface +) +{ + iface->get_ext_widget = wintc_notification_area_get_ext_widget; +} + // // CLASS VIRTUAL METHODS // @@ -148,17 +139,65 @@ static void wintc_notification_area_dispose( WinTCNotificationArea* notif_area = WINTC_NOTIFICATION_AREA(object); g_clear_object(&(notif_area->clock_runner)); - - if (notif_area->map_widget_to_behaviour) - { - g_hash_table_unref( - g_steal_pointer(&(notif_area->map_widget_to_behaviour)) - ); - } + g_clear_slist( + &(notif_area->list_uictl_behaviours), + (GDestroyNotify) g_object_unref + ); (G_OBJECT_CLASS(wintc_notification_area_parent_class))->dispose(object); } +// +// INTERFACE METHODS (WinTCIShextUIHost) +// +static GtkWidget* wintc_notification_area_get_ext_widget( + WinTCIShextUIHost* host, + guint ext_id, + GType expected_type, + gpointer ctx +) +{ + WinTCNotificationArea* notif_area = WINTC_NOTIFICATION_AREA(host); + + if (ext_id != WINTC_NOTIFAREA_HOSTEXT_ICON) + { + g_critical("notifarea: unsupported ext widget type: %d", ext_id); + return NULL; + } + + if (expected_type != WINTC_TYPE_NOTIF_AREA_ICON) + { + g_critical("%s", "notifarea: invalid ext widget type"); + return NULL; + } + + if (!G_IS_OBJECT(ctx)) + { + g_critical("%s", "notifarea: expected a GObject for icon context"); + return NULL; + } + + // All good, create the icon + // + GtkWidget* notif_icon = wintc_notif_area_icon_new(); + + gtk_box_pack_start( + GTK_BOX(notif_area->box_container), + notif_icon, + FALSE, + FALSE, + 0 + ); + + notif_area->list_uictl_behaviours = + g_slist_append( + notif_area->list_uictl_behaviours, + ctx + ); + + return notif_icon; +} + // // PUBLIC FUNCTIONS // @@ -171,108 +210,3 @@ GtkWidget* notification_area_new(void) ) ); } - -// -// PRIVATE FUNCTIONS -// -static void wintc_notification_area_append_component( - WinTCNotificationArea* notif_area, - GType component_type -) -{ - GtkWidget* widget = wintc_notification_area_append_icon(notif_area); - - WinTCNotificationBehaviour* notif = - WINTC_NOTIFICATION_BEHAVIOUR( - g_object_new( - component_type, - "widget-notif", widget, - NULL - ) - ); - - wintc_notification_area_map_widget( - notif_area, - widget, - notif - ); -} - -static GtkWidget* wintc_notification_area_append_icon( - WinTCNotificationArea* notif_area -) -{ - GtkWidget* event_box = gtk_event_box_new(); - GtkWidget* image_icon = gtk_image_new(); - - gtk_widget_set_events(event_box, GDK_BUTTON_PRESS_MASK); - - gtk_container_add( - GTK_CONTAINER(event_box), - image_icon - ); - gtk_box_pack_start( - GTK_BOX(notif_area->box_container), - event_box, - FALSE, - FALSE, - 0 - ); - - return event_box; -} - -static void wintc_notification_area_map_widget( - WinTCNotificationArea* notif_area, - GtkWidget* widget_notif, - WinTCNotificationBehaviour* behaviour -) -{ - g_hash_table_insert( - notif_area->map_widget_to_behaviour, - widget_notif, - behaviour - ); - - // Connect up widget to behaviour - // - update_notification_icon( - widget_notif, - behaviour - ); - - g_signal_connect( - behaviour, - "icon-changed", - G_CALLBACK(on_behaviour_icon_changed), - widget_notif - ); -} - -static void update_notification_icon( - GtkWidget* widget_notif, - WinTCNotificationBehaviour* behaviour -) -{ - gtk_image_set_from_icon_name( - GTK_IMAGE(gtk_bin_get_child(GTK_BIN(widget_notif))), - wintc_notification_behaviour_get_icon_name(behaviour), - GTK_ICON_SIZE_SMALL_TOOLBAR - ); -} - -// -// CALLBACKS -// -static void on_behaviour_icon_changed( - WinTCNotificationBehaviour* behaviour, - gpointer user_data -) -{ - GtkWidget* widget_notif = GTK_WIDGET(user_data); - - update_notification_icon( - widget_notif, - behaviour - ); -} diff --git a/shell/taskband/src/systray/notifarea.h b/shell/taskband/src/systray/notifarea.h index 0c68e61..0e33cf8 100644 --- a/shell/taskband/src/systray/notifarea.h +++ b/shell/taskband/src/systray/notifarea.h @@ -7,15 +7,15 @@ // // GTK OOP BOILERPLATE // -typedef struct _WinTCNotificationAreaClass WinTCNotificationAreaClass; -typedef struct _WinTCNotificationArea WinTCNotificationArea; +#define WINTC_TYPE_NOTIFICATION_AREA (wintc_notification_area_get_type()) -#define WINTC_TYPE_NOTIFICATION_AREA (wintc_notification_area_get_type()) -#define WINTC_NOTIFICATION_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_NOTIFICATION_AREA, WinTCNotificationArea)) -#define WINTC_NOTIFICATION_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_NOTIFICATION_AREA, WinTCNotificationArea)) -#define IS_WINTC_NOTIFICATION_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_NOTIFICATION_AREA)) -#define IS_WINTC_NOTIFICATION_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_NOTIFICATION_AREA)) -#define WINTC_NOTIFICATION_AREA_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), WINTC_TYPE_NOTIFICATION_AREA)) +G_DECLARE_FINAL_TYPE( + WinTCNotificationArea, + wintc_notification_area, + WINTC, + NOTIFICATION_AREA, + GtkBin +) // // PUBLIC FUNCTIONS diff --git a/shell/taskband/src/systray/power.c b/shell/taskband/src/systray/power.c index a4f026a..9ca514b 100644 --- a/shell/taskband/src/systray/power.c +++ b/shell/taskband/src/systray/power.c @@ -2,8 +2,10 @@ #include #include #include +#include -#include "behaviour.h" +#include "../intapi.h" +#include "icon.h" #include "power.h" // @@ -51,14 +53,13 @@ static void on_up_device_battery_notify( // // GTK OOP CLASS/INSTANCE DEFINITIONS // -struct _WinTCNotificationPowerClass -{ - WinTCNotificationBehaviourClass __parent__; -}; - struct _WinTCNotificationPower { - WinTCNotificationBehaviour __parent__; + WinTCShextUIController __parent__; + + // UI + // + GtkWidget* notif_icon; // Power stuff // @@ -72,7 +73,7 @@ struct _WinTCNotificationPower G_DEFINE_TYPE( WinTCNotificationPower, wintc_notification_power, - WINTC_TYPE_NOTIFICATION_BEHAVIOUR + WINTC_TYPE_SHEXT_UI_CONTROLLER ) static void wintc_notification_power_class_init( @@ -101,6 +102,16 @@ static void wintc_notification_power_constructed( WinTCNotificationPower* power = WINTC_NOTIFICATION_POWER(object); + power->notif_icon = + wintc_ishext_ui_host_get_ext_widget( + wintc_shext_ui_controller_get_ui_host( + WINTC_SHEXT_UI_CONTROLLER(object) + ), + WINTC_NOTIFAREA_HOSTEXT_ICON, + WINTC_TYPE_NOTIF_AREA_ICON, + object + ); + // Connect to upower, enumerate existing devices and attach signals for // picking up new ones // @@ -149,22 +160,6 @@ static void wintc_notification_power_dispose( ->dispose(object); } -// -// PUBLIC FUNCTIONS -// -WinTCNotificationPower* wintc_notification_power_new( - GtkWidget* widget_notif -) -{ - return WINTC_NOTIFICATION_POWER( - g_object_new( - WINTC_TYPE_NOTIFICATION_POWER, - "widget-notif", widget_notif, - NULL - ) - ); -} - // // PRIVATE FUNCTIONS // @@ -264,18 +259,16 @@ static void wintc_notification_power_update_icon( { if (up_client_get_on_battery(power->up_client)) { - g_object_set( - power, - "icon-name", "battery-missing", - NULL + wintc_notif_area_icon_set_icon_name( + WINTC_NOTIF_AREA_ICON(power->notif_icon), + "battery-missing" ); } else { - g_object_set( - power, - "icon-name", "ac-adapter", - NULL + wintc_notif_area_icon_set_icon_name( + WINTC_NOTIF_AREA_ICON(power->notif_icon), + "ac-adapter" ); } @@ -337,10 +330,9 @@ static void wintc_notification_power_update_icon( break; } - g_object_set( - power, - "icon-name", icon_name, - NULL + wintc_notif_area_icon_set_icon_name( + WINTC_NOTIF_AREA_ICON(power->notif_icon), + icon_name ); } diff --git a/shell/taskband/src/systray/power.h b/shell/taskband/src/systray/power.h index 3d14230..e606cc4 100644 --- a/shell/taskband/src/systray/power.h +++ b/shell/taskband/src/systray/power.h @@ -3,27 +3,19 @@ #include #include +#include // // GTK OOP BOILERPLATE // -typedef struct _WinTCNotificationPowerClass WinTCNotificationPowerClass; -typedef struct _WinTCNotificationPower WinTCNotificationPower; +#define WINTC_TYPE_NOTIFICATION_POWER (wintc_notification_power_get_type()) -#define WINTC_TYPE_NOTIFICATION_POWER (wintc_notification_power_get_type()) -#define WINTC_NOTIFICATION_POWER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_NOTIFICATION_POWER, WinTCNotificationPower)) -#define WINTC_NOTIFICATION_POWER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_NOTIFICATION_BEHAVIOUR, WinTCNotificationPowerClass)) -#define IS_WINTC_NOTIFICATION_POWER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_NOTIFICATION_POWER)) -#define IS_WINTC_NOTIFICATION_POWER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_NOTIFICATION_POWER)) -#define WINTC_NOTIFICATION_POWER_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_NOTIFICATION_POWER, WinTCNotificationPower)) - -GType wintc_notification_power_get_type(void) G_GNUC_CONST; - -// -// PUBLIC FUNCTIONS -// -WinTCNotificationPower* wintc_notification_power_new( - GtkWidget* widget_notif -); +G_DECLARE_FINAL_TYPE( + WinTCNotificationPower, + wintc_notification_power, + WINTC, + NOTIFICATION_POWER, + WinTCShextUIController +) #endif diff --git a/shell/taskband/src/systray/toolbar.c b/shell/taskband/src/systray/toolbar.c index bd3037c..faaed74 100644 --- a/shell/taskband/src/systray/toolbar.c +++ b/shell/taskband/src/systray/toolbar.c @@ -1,22 +1,25 @@ #include #include #include +#include -#include "../toolbar.h" +#include "../intapi.h" #include "notifarea.h" #include "toolbar.h" +// +// FORWARD DECLARATIONS +// +static void wintc_toolbar_notif_area_constructed( + GObject* object +); + // // GTK OOP CLASS/INSTANCE DEFINITIONS // -struct _WinTCToolbarNotifAreaClass -{ - WinTCTaskbandToolbarClass __parent__; -}; - struct _WinTCToolbarNotifArea { - WinTCTaskbandToolbar __parent__; + WinTCShextUIController __parent__; }; // @@ -25,19 +28,38 @@ struct _WinTCToolbarNotifArea G_DEFINE_TYPE( WinTCToolbarNotifArea, wintc_toolbar_notif_area, - WINTC_TYPE_TASKBAND_TOOLBAR + WINTC_TYPE_SHEXT_UI_CONTROLLER ) static void wintc_toolbar_notif_area_class_init( - WINTC_UNUSED(WinTCToolbarNotifAreaClass* klass) -) {} - -static void wintc_toolbar_notif_area_init( - WinTCToolbarNotifArea* self + WinTCToolbarNotifAreaClass* klass ) { - WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(self); + GObjectClass* object_class = G_OBJECT_CLASS(klass); - toolbar->widget_root = notification_area_new(); + object_class->constructed = wintc_toolbar_notif_area_constructed; } +static void wintc_toolbar_notif_area_init( + WINTC_UNUSED(WinTCToolbarNotifArea* self) +) {} + +// +// CLASS VIRTUAL METHODS +// +static void wintc_toolbar_notif_area_constructed( + GObject* object +) +{ + (G_OBJECT_CLASS(wintc_toolbar_notif_area_parent_class)) + ->constructed(object); + + wintc_ishext_ui_host_get_ext_widget( + wintc_shext_ui_controller_get_ui_host( + WINTC_SHEXT_UI_CONTROLLER(object) + ), + WINTC_TASKBAND_HOSTEXT_TOOLBAR, + GTK_TYPE_WIDGET, + notification_area_new() + ); +} diff --git a/shell/taskband/src/systray/toolbar.h b/shell/taskband/src/systray/toolbar.h index 12455ca..f7cfcd4 100644 --- a/shell/taskband/src/systray/toolbar.h +++ b/shell/taskband/src/systray/toolbar.h @@ -3,21 +3,20 @@ #include #include +#include // // GTK OOP BOILERPLATE // -typedef struct _WinTCToolbarNotifAreaClass WinTCToolbarNotifAreaClass; -typedef struct _WinTCToolbarNotifArea WinTCToolbarNotifArea; +#define WINTC_TYPE_TOOLBAR_NOTIF_AREA (wintc_toolbar_notif_area_get_type()) -#define WINTC_TYPE_TOOLBAR_NOTIF_AREA (wintc_toolbar_notif_area_get_type()) -#define WINTC_TOOLBAR_NOTIF_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_TOOLBAR_NOTIF_AREA, WinTCToolbarNotifArea)) -#define WINTC_TOOLBAR_NOTIF_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_TOOLBAR_NOTIF_AREA, WinTCToolbarNotifAreaClass)) -#define IS_WINTC_TOOLBAR_NOTIF_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_TOOLBAR_NOTIF_AREA)) -#define IS_WINTC_TOOLBAR_NOTIF_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_TOOLBAR_NOTIF_AREA)) -#define WINTC_TOOLBAR_NOTIF_AREA_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_TOOLBAR_NOTIF_AREA, WinTCToolbarNotifArea)) - -GType wintc_toolbar_notif_area_get_type(void) G_GNUC_CONST; +G_DECLARE_FINAL_TYPE( + WinTCToolbarNotifArea, + wintc_toolbar_notif_area, + WINTC, + TOOLBAR_NOTIF_AREA, + WinTCShextUIController +) #endif diff --git a/shell/taskband/src/systray/volume.c b/shell/taskband/src/systray/volume.c index 355843f..3b78af8 100644 --- a/shell/taskband/src/systray/volume.c +++ b/shell/taskband/src/systray/volume.c @@ -4,22 +4,23 @@ #include #include #include +#include #include -#include "behaviour.h" +#include "../intapi.h" +#include "icon.h" #include "volume.h" // // GTK OOP CLASS/INSTANCE DEFINITIONS // -struct _WinTCNotificationVolumeClass -{ - WinTCNotificationBehaviourClass __parent__; -}; - struct _WinTCNotificationVolume { - WinTCNotificationBehaviour __parent__; + WinTCShextUIController __parent__; + + // UI + // + GtkWidget* notif_icon; GtkWidget* popup_volmgmt; @@ -66,7 +67,7 @@ static void on_snd_output_volume_changed( gpointer user_data ); -static gboolean on_widget_notif_button_press_event( +static gboolean on_notif_icon_button_press_event( GtkWidget* self, GdkEventButton* event, gpointer user_data @@ -92,7 +93,7 @@ static void on_scale_volume_value_changed( G_DEFINE_TYPE( WinTCNotificationVolume, wintc_notification_volume, - WINTC_TYPE_NOTIFICATION_BEHAVIOUR + WINTC_TYPE_SHEXT_UI_CONTROLLER ) static void wintc_notification_volume_class_init( @@ -143,15 +144,22 @@ static void wintc_notification_volume_constructed( GObject* object ) { - WinTCNotificationVolume* volume = - WINTC_NOTIFICATION_VOLUME(object); - WinTCNotificationBehaviour* behaviour = - WINTC_NOTIFICATION_BEHAVIOUR(volume); + WinTCNotificationVolume* volume = WINTC_NOTIFICATION_VOLUME(object); + + volume->notif_icon = + wintc_ishext_ui_host_get_ext_widget( + wintc_shext_ui_controller_get_ui_host( + WINTC_SHEXT_UI_CONTROLLER(object) + ), + WINTC_NOTIFAREA_HOSTEXT_ICON, + WINTC_TYPE_NOTIF_AREA_ICON, + object + ); // Connect up to the notification icon widget // volume->popup_volmgmt = - wintc_dpa_create_popup(behaviour->widget_notif, FALSE); + wintc_dpa_create_popup(volume->notif_icon, FALSE); volume->box_container = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); volume->check_mute = gtk_check_button_new_with_label("Mute"); @@ -215,9 +223,9 @@ static void wintc_notification_volume_constructed( ); g_signal_connect( - behaviour->widget_notif, + volume->notif_icon, "button-press-event", - G_CALLBACK(on_widget_notif_button_press_event), + G_CALLBACK(on_notif_icon_button_press_event), object ); @@ -251,22 +259,6 @@ static void wintc_notification_volume_constructed( ))->constructed(object); } -// -// PUBLIC FUNCTIONS -// -WinTCNotificationVolume* wintc_notification_volume_new( - GtkWidget* widget_notif -) -{ - return WINTC_NOTIFICATION_VOLUME( - g_object_new( - WINTC_TYPE_NOTIFICATION_VOLUME, - "widget-notif", widget_notif, - NULL - ) - ); -} - // // PRIVATE FUNCTIONS // @@ -279,10 +271,9 @@ static void wintc_notification_volume_set_have_device( if (!have_device) { - g_object_set( - volume, - "icon-name", "audio-volume-muted", - NULL + wintc_notif_area_icon_set_icon_name( + WINTC_NOTIF_AREA_ICON(volume->notif_icon), + "audio-volume_muted" ); } } @@ -365,10 +356,9 @@ static void on_snd_output_muted_changed( ); volume->syncing_state = FALSE; - g_object_set( - volume, - "icon-name", icon_name, - NULL + wintc_notif_area_icon_set_icon_name( + WINTC_NOTIF_AREA_ICON(volume->notif_icon), + icon_name ); } @@ -390,8 +380,8 @@ static void on_snd_output_volume_changed( volume->syncing_state = FALSE; } -static gboolean on_widget_notif_button_press_event( - GtkWidget* self, +static gboolean on_notif_icon_button_press_event( + WINTC_UNUSED(GtkWidget* self), WINTC_UNUSED(GdkEventButton* event), gpointer user_data ) @@ -401,7 +391,7 @@ static gboolean on_widget_notif_button_press_event( wintc_dpa_show_popup( volume->popup_volmgmt, - self + volume->notif_icon ); return TRUE; diff --git a/shell/taskband/src/systray/volume.h b/shell/taskband/src/systray/volume.h index a50fb3a..1133c00 100644 --- a/shell/taskband/src/systray/volume.h +++ b/shell/taskband/src/systray/volume.h @@ -3,27 +3,19 @@ #include #include +#include // // GTK OOP BOILERPLATE // -typedef struct _WinTCNotificationVolumeClass WinTCNotificationVolumeClass; -typedef struct _WinTCNotificationVolume WinTCNotificationVolume; +#define WINTC_TYPE_NOTIFICATION_VOLUME (wintc_notification_volume_get_type()) -#define WINTC_TYPE_NOTIFICATION_VOLUME (wintc_notification_volume_get_type()) -#define WINTC_NOTIFICATION_VOLUME(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_NOTIFICATION_VOLUME, WinTCNotificationVolume)) -#define WINTC_NOTIFICATION_VOLUME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_NOTIFICATION_BEHAVIOUR, WinTCNotificationVolumeClass)) -#define IS_WINTC_NOTIFICATION_VOLUME(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_NOTIFICATION_VOLUME)) -#define IS_WINTC_NOTIFICATION_VOLUME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_NOTIFICATION_VOLUME)) -#define WINTC_NOTIFICATION_VOLUME_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_NOTIFICATION_VOLUME, WinTCNotificationVolume)) - -GType wintc_notification_volume_get_type(void) G_GNUC_CONST; - -// -// PUBLIC FUNCTIONS -// -WinTCNotificationVolume* wintc_notification_volume_new( - GtkWidget* widget_notif -); +G_DECLARE_FINAL_TYPE( + WinTCNotificationVolume, + wintc_notification_volume, + WINTC, + NOTIFICATION_VOLUME, + WinTCShextUIController +) #endif diff --git a/shell/taskband/src/taskbuttons/taskbuttonbar.c b/shell/taskband/src/taskbuttons/taskbuttonbar.c index 7f38d10..be4721f 100644 --- a/shell/taskband/src/taskbuttons/taskbuttonbar.c +++ b/shell/taskband/src/taskbuttons/taskbuttonbar.c @@ -129,6 +129,7 @@ static void taskbutton_bar_init( window_monitor_init_management(GTK_CONTAINER(self)); gtk_widget_set_has_window(GTK_WIDGET(self), FALSE); + gtk_widget_set_hexpand(GTK_WIDGET(self), TRUE); wintc_widget_add_style_class(GTK_WIDGET(self), "wintc-taskbuttons"); diff --git a/shell/taskband/src/taskbuttons/toolbar.c b/shell/taskband/src/taskbuttons/toolbar.c index 7f2bb2d..b025fba 100644 --- a/shell/taskband/src/taskbuttons/toolbar.c +++ b/shell/taskband/src/taskbuttons/toolbar.c @@ -1,22 +1,25 @@ #include #include #include +#include -#include "../toolbar.h" +#include "../intapi.h" #include "taskbuttonbar.h" #include "toolbar.h" +// +// FORWARD DECLARATIONS +// +static void wintc_toolbar_task_buttons_constructed( + GObject* object +); + // // GTK OOP CLASS/INSTANCE DEFINITIONS // -struct _WinTCToolbarTaskButtonsClass -{ - WinTCTaskbandToolbarClass __parent__; -}; - struct _WinTCToolbarTaskButtons { - WinTCTaskbandToolbar __parent__; + WinTCShextUIController __parent__; }; // @@ -25,21 +28,38 @@ struct _WinTCToolbarTaskButtons G_DEFINE_TYPE( WinTCToolbarTaskButtons, wintc_toolbar_task_buttons, - WINTC_TYPE_TASKBAND_TOOLBAR + WINTC_TYPE_SHEXT_UI_CONTROLLER ) static void wintc_toolbar_task_buttons_class_init( - WINTC_UNUSED(WinTCToolbarTaskButtonsClass* klass) -) {} - -static void wintc_toolbar_task_buttons_init( - WinTCToolbarTaskButtons* self + WinTCToolbarTaskButtonsClass* klass ) { - WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(self); + GObjectClass* object_class = G_OBJECT_CLASS(klass); - // Create root widget - // - toolbar->widget_root = taskbutton_bar_new(); + object_class->constructed = wintc_toolbar_task_buttons_constructed; } +static void wintc_toolbar_task_buttons_init( + WINTC_UNUSED(WinTCToolbarTaskButtons* self) +) {} + +// +// CLASS VIRTUAL METHODS +// +static void wintc_toolbar_task_buttons_constructed( + GObject* object +) +{ + (G_OBJECT_CLASS(wintc_toolbar_task_buttons_parent_class)) + ->constructed(object); + + wintc_ishext_ui_host_get_ext_widget( + wintc_shext_ui_controller_get_ui_host( + WINTC_SHEXT_UI_CONTROLLER(object) + ), + WINTC_TASKBAND_HOSTEXT_TOOLBAR, + GTK_TYPE_WIDGET, + taskbutton_bar_new() + ); +} diff --git a/shell/taskband/src/taskbuttons/toolbar.h b/shell/taskband/src/taskbuttons/toolbar.h index 854718b..529a71d 100644 --- a/shell/taskband/src/taskbuttons/toolbar.h +++ b/shell/taskband/src/taskbuttons/toolbar.h @@ -3,21 +3,20 @@ #include #include +#include // // GTK OOP BOILERPLATE // -typedef struct _WinTCToolbarTaskButtonsClass WinTCToolbarTaskButtonsClass; -typedef struct _WinTCToolbarTaskButtons WinTCToolbarTaskButtons; +#define WINTC_TYPE_TOOLBAR_TASK_BUTTONS (wintc_toolbar_task_buttons_get_type()) -#define WINTC_TYPE_TOOLBAR_TASK_BUTTONS (wintc_toolbar_task_buttons_get_type()) -#define WINTC_TOOLBAR_TASK_BUTTONS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_TOOLBAR_TASK_BUTTONS, WinTCToolbarTaskButtons)) -#define WINTC_TOOLBAR_TASK_BUTTONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_TOOLBAR_TASK_BUTTONS, WinTCToolbarTaskButtonsClass)) -#define IS_WINTC_TOOLBAR_TASK_BUTTONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_TOOLBAR_TASK_BUTTONS)) -#define IS_WINTC_TOOLBAR_TASK_BUTTONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_TOOLBAR_TASK_BUTTONS)) -#define WINTC_TOOLBAR_TASK_BUTTONS_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_TOOLBAR_TASK_BUTTONS, WinTCToolbarTaskButtons)) - -GType wintc_toolbar_task_buttons_get_type(void) G_GNUC_CONST; +G_DECLARE_FINAL_TYPE( + WinTCToolbarTaskButtons, + wintc_toolbar_task_buttons, + WINTC, + TOOLBAR_TASK_BUTTONS, + WinTCShextUIController +) #endif diff --git a/shell/taskband/src/toolbar.c b/shell/taskband/src/toolbar.c deleted file mode 100644 index f8415d0..0000000 --- a/shell/taskband/src/toolbar.c +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include - -#include "toolbar.h" - -// -// PRIVATE ENUMS -// -enum -{ - PROP_ROOT_WIDGET = 1 -}; - -// -// FORWARD DECLARATIONS -// -static void wintc_taskband_toolbar_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec -); - -// -// GTK TYPE DEFINITIONS & CTORS -// -G_DEFINE_TYPE( - WinTCTaskbandToolbar, - wintc_taskband_toolbar, - G_TYPE_OBJECT -) - -static void wintc_taskband_toolbar_class_init( - WinTCTaskbandToolbarClass* klass -) -{ - GObjectClass* object_class = G_OBJECT_CLASS(klass); - - object_class->get_property = wintc_taskband_toolbar_get_property; - - g_object_class_install_property( - object_class, - PROP_ROOT_WIDGET, - g_param_spec_object( - "root-widget", - "RootWidget", - "The GtkWidget that is the root of the toolbar.", - GTK_TYPE_WIDGET, - G_PARAM_READABLE - ) - ); -} - -static void wintc_taskband_toolbar_init( - WinTCTaskbandToolbar* self -) -{ - self->widget_root = NULL; -} - -// -// PRIVATE FUNCTIONS -// -GtkWidget* wintc_taskband_toolbar_get_root_widget( - WinTCTaskbandToolbar* toolbar -) -{ - return toolbar->widget_root; -} - -// -// CLASS VIRTUAL METHODS -// -static void wintc_taskband_toolbar_get_property( - GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec -) -{ - WinTCTaskbandToolbar* toolbar = - WINTC_TASKBAND_TOOLBAR(object); - - switch (prop_id) - { - case PROP_ROOT_WIDGET: - g_value_set_object(value, toolbar->widget_root); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} diff --git a/shell/taskband/src/toolbar.h b/shell/taskband/src/toolbar.h deleted file mode 100644 index 26766c9..0000000 --- a/shell/taskband/src/toolbar.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __TOOLBAR_H__ -#define __TOOLBAR_H__ - -#include -#include - -// -// GTK OOP BOILERPLATE -// -typedef struct _WinTCTaskbandToolbarClass -{ - GObjectClass __parent__; -} WinTCTaskbandToolbarClass; - -typedef struct _WinTCTaskbandToolbar -{ - GObject __parent__; - - GtkWidget* widget_root; -} WinTCTaskbandToolbar; - -#define WINTC_TYPE_TASKBAND_TOOLBAR (wintc_taskband_toolbar_get_type()) -#define WINTC_TASKBAND_TOOLBAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_TASKBAND_TOOLBAR, WinTCTaskbandToolbar)) -#define WINTC_TASKBAND_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_TASKBAND_TOOLBAR, WinTCTaskbandToolbarClass)) -#define IS_WINTC_TASKBAND_TOOLBAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_TASKBAND_TOOLBAR)) -#define IS_WINTC_TASKBAND_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_TASKBAND_TOOLBAR)) -#define WINTC_TASKBAND_TOOLBAR_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_TASKBAND_TOOLBAR, WinTCTaskbandToolbar)) - -GType wintc_taskband_toolbar_get_type(void) G_GNUC_CONST; - -// -// PUBLIC FUNCTIONS -// -GtkWidget* wintc_taskband_toolbar_get_root_widget( - WinTCTaskbandToolbar* toolbar -); - -#endif diff --git a/shell/taskband/src/window.c b/shell/taskband/src/window.c index dfdcd8a..e1d9c7d 100644 --- a/shell/taskband/src/window.c +++ b/shell/taskband/src/window.c @@ -3,9 +3,10 @@ #include #include #include +#include #include "application.h" -#include "toolbar.h" +#include "intapi.h" #include "window.h" #include "start/toolbar.h" #include "systray/toolbar.h" @@ -29,14 +30,19 @@ typedef enum // // FORWARD DECLARATIONS // +static void wintc_taskband_window_ishext_ui_host_interface_init( + WinTCIShextUIHostInterface* iface +); + static void wintc_taskband_window_dispose( GObject* object ); -static WinTCTaskbandToolbar* wintc_taskband_window_create_toolbar( - WinTCTaskbandWindow* taskband, - GType toolbar_type, - gboolean expand +static GtkWidget* wintc_taskband_window_get_ext_widget( + WinTCIShextUIHost* host, + guint ext_id, + GType expected_type, + gpointer ctx ); static gboolean on_window_map_event( @@ -48,7 +54,7 @@ static gboolean on_window_map_event( // // STATIC DATA // -static const WinTCTaskbandToolbarId s_layout[] = { +static const WinTCTaskbandToolbarId S_LAYOUT[] = { WINTC_TASKBAND_TOOLBAR_START, WINTC_TASKBAND_TOOLBAR_QUICK_ACCESS, WINTC_TASKBAND_TOOLBAR_PRE_BUTTONS, @@ -75,18 +81,22 @@ struct _WinTCTaskbandWindow GSList* toolbars; - WinTCTaskbandToolbar* toolbar_notifarea; - WinTCTaskbandToolbar* toolbar_start; - WinTCTaskbandToolbar* toolbar_taskbuttons; + WinTCShextUIController* uictl_notifarea; + WinTCShextUIController* uictl_start; + WinTCShextUIController* uictl_taskbuttons; }; // // GTK TYPE DEFINITION & CTORS // -G_DEFINE_TYPE( +G_DEFINE_TYPE_WITH_CODE( WinTCTaskbandWindow, wintc_taskband_window, - GTK_TYPE_APPLICATION_WINDOW + GTK_TYPE_APPLICATION_WINDOW, + G_IMPLEMENT_INTERFACE( + WINTC_TYPE_ISHEXT_UI_HOST, + wintc_taskband_window_ishext_ui_host_interface_init + ) ) static void wintc_taskband_window_class_init( @@ -134,20 +144,82 @@ static void wintc_taskband_window_init( ); } +static void wintc_taskband_window_ishext_ui_host_interface_init( + WinTCIShextUIHostInterface* iface +) +{ + iface->get_ext_widget = wintc_taskband_window_get_ext_widget; +} + // -// FORWARD DECLARATIONS +// CLASS VIRTUAL METHODS // static void wintc_taskband_window_dispose( GObject* object ) { - WinTCTaskbandWindow* wnd = WINTC_TASKBAND_WINDOW(object); + WinTCTaskbandWindow* taskband = WINTC_TASKBAND_WINDOW(object); - g_clear_slist(&(wnd->toolbars), g_object_unref); + g_clear_slist(&(taskband->toolbars), g_object_unref); (G_OBJECT_CLASS(wintc_taskband_window_parent_class))->dispose(object); } +// +// INTERFACE METHODS (WinTCIShextUIHost) +// +static GtkWidget* wintc_taskband_window_get_ext_widget( + WinTCIShextUIHost* host, + guint ext_id, + GType expected_type, + gpointer ctx +) +{ + WinTCTaskbandWindow* taskband = WINTC_TASKBAND_WINDOW(host); + + // Only toolbars are supported + // + if (ext_id != WINTC_TASKBAND_HOSTEXT_TOOLBAR) + { + g_critical("taskband: unsupported ext widget type: %d", ext_id); + return NULL; + } + + // No special type expected, we host any kind of widget as a 'toolbar' + // + if (expected_type != GTK_TYPE_WIDGET || !GTK_IS_WIDGET(ctx)) + { + g_critical("%s", "taskband: invalid ext widget type"); + return NULL; + } + + // Go ahead and import the widget + // + // FIXME: We expand based on hexpand... this isn't SUPER intuitive when + // vertical taskbar support is implemented, but it'll do + // + GtkWidget* toolbar = GTK_WIDGET(ctx); + gboolean expand = gtk_widget_get_hexpand(toolbar); + + taskband->toolbars = + g_slist_append( + taskband->toolbars, + toolbar + ); + + gtk_box_pack_start( + GTK_BOX(taskband->main_box), + toolbar, + expand, + expand, + 0 + ); + + gtk_widget_show_all(toolbar); + + return ctx; +} + // // PUBLIC FUNCTIONS // @@ -173,43 +245,10 @@ void wintc_taskband_window_toggle_start_menu( ) { wintc_toolbar_start_toggle_menu( - WINTC_TOOLBAR_START(taskband->toolbar_start) + WINTC_TOOLBAR_START(taskband->uictl_start) ); } -// -// PRIVATE FUNCTIONS -// -static WinTCTaskbandToolbar* wintc_taskband_window_create_toolbar( - WinTCTaskbandWindow* taskband, - GType toolbar_type, - gboolean expand -) -{ - WinTCTaskbandToolbar* toolbar = g_object_new(toolbar_type, NULL); - GtkWidget* root = wintc_taskband_toolbar_get_root_widget( - toolbar - ); - - taskband->toolbars = - g_slist_append( - taskband->toolbars, - toolbar - ); - - gtk_box_pack_start( - GTK_BOX(taskband->main_box), - root, - expand, - expand, - 0 - ); - - gtk_widget_show_all(root); - - return toolbar; -} - // // CALLBACKS // @@ -223,41 +262,41 @@ static gboolean on_window_map_event( // Spawn toolbars // - for (guint i = 0; i < G_N_ELEMENTS(s_layout); i++) + for (guint i = 0; i < G_N_ELEMENTS(S_LAYOUT); i++) { - switch (s_layout[i]) + switch (S_LAYOUT[i]) { case WINTC_TASKBAND_TOOLBAR_START: - taskband->toolbar_start = - wintc_taskband_window_create_toolbar( - taskband, + taskband->uictl_start = + wintc_shext_ui_controller_new_from_type( WINTC_TYPE_TOOLBAR_START, - FALSE + WINTC_ISHEXT_UI_HOST(taskband) ); + break; case WINTC_TASKBAND_TOOLBAR_BUTTONS: - taskband->toolbar_taskbuttons = - wintc_taskband_window_create_toolbar( - taskband, + taskband->uictl_taskbuttons = + wintc_shext_ui_controller_new_from_type( WINTC_TYPE_TOOLBAR_TASK_BUTTONS, - TRUE + WINTC_ISHEXT_UI_HOST(taskband) ); + break; case WINTC_TASKBAND_TOOLBAR_NOTIFICATION_AREA: - taskband->toolbar_notifarea = - wintc_taskband_window_create_toolbar( - taskband, + taskband->uictl_notifarea = + wintc_shext_ui_controller_new_from_type( WINTC_TYPE_TOOLBAR_NOTIF_AREA, - FALSE + WINTC_ISHEXT_UI_HOST(taskband) ); + break; case WINTC_TASKBAND_TOOLBAR_QUICK_ACCESS: case WINTC_TASKBAND_TOOLBAR_PRE_BUTTONS: case WINTC_TASKBAND_TOOLBAR_POST_BUTTONS: - WINTC_LOG_DEBUG("Not implemented toolbar: %d", s_layout[i]); + WINTC_LOG_DEBUG("Not implemented toolbar: %d", S_LAYOUT[i]); break; } }