From 59dff93fc59ebf498a0e22a9908eda440850403a Mon Sep 17 00:00:00 2001 From: Rory Fewell Date: Sun, 25 Feb 2024 21:20:12 +0000 Subject: [PATCH] Enhancement: Refactor Start menu, removes some hacks, fixes some bugs --- shared/comgtk/CMakeLists.txt | 2 + shared/comgtk/public/wintc-comgtk.h.in | 7 + shared/comgtk/src/container.c | 24 + shared/comgtk/src/container.h | 13 + shared/shelldpa/public/wintc-shelldpa.h | 3 +- shared/shelldpa/src/api.c | 41 +- shared/shelldpa/src/api.h | 3 +- shared/shelldpa/src/impl-x11.c | 28 +- shell/taskband/CMakeLists.txt | 25 +- shell/taskband/src/res/personal-menu.ui | 852 +++++++++++++ shell/taskband/src/res/resources.xml | 2 + shell/taskband/src/res/start-button.ui | 67 ++ shell/taskband/src/res/start-menu.css | 24 +- shell/taskband/src/start/action.c | 39 - shell/taskband/src/start/action.h | 15 - shell/taskband/src/start/menumod.c | 186 +++ shell/taskband/src/start/menumod.h | 22 + shell/taskband/src/start/personal.c | 1071 +++++++++++++++++ shell/taskband/src/start/personal.h | 25 + shell/taskband/src/start/placeslist.c | 175 --- shell/taskband/src/start/placeslist.h | 26 - shell/taskband/src/start/programslist.c | 283 ----- shell/taskband/src/start/programslist.h | 33 - shell/taskband/src/start/shared.h | 54 + shell/taskband/src/start/startbutton.c | 173 --- shell/taskband/src/start/startbutton.h | 34 - shell/taskband/src/start/startmenu.c | 592 --------- shell/taskband/src/start/startmenu.h | 31 - shell/taskband/src/start/startmenuitem.c | 478 -------- shell/taskband/src/start/startmenuitem.h | 51 - shell/taskband/src/start/toolbar.c | 152 +++ shell/taskband/src/start/toolbar.h | 20 + shell/taskband/src/systray/toolbar.c | 43 + shell/taskband/src/systray/toolbar.h | 23 + shell/taskband/src/systray/volume.c | 2 +- shell/taskband/src/taskbuttons/toolbar.c | 45 + shell/taskband/src/taskbuttons/toolbar.h | 23 + shell/taskband/src/toolbar.c | 94 ++ shell/taskband/src/toolbar.h | 38 + shell/taskband/src/window.c | 216 ++-- shell/taskband/src/window.h | 2 +- .../override/xp-start-plugin.scss | 30 +- .../gtk-3.0-base/styling/start-menu.scss | 5 +- .../luna/blue/gtk-3.0/styling/start-menu.scss | 5 +- themes/professional/Resources/start_flag.png | Bin 1152 -> 1147 bytes .../gtk-3.0/styling/start-menu.scss | 3 +- 46 files changed, 3005 insertions(+), 2075 deletions(-) create mode 100644 shared/comgtk/src/container.c create mode 100644 shared/comgtk/src/container.h create mode 100644 shell/taskband/src/res/personal-menu.ui create mode 100644 shell/taskband/src/res/start-button.ui delete mode 100644 shell/taskband/src/start/action.c delete mode 100644 shell/taskband/src/start/action.h create mode 100644 shell/taskband/src/start/menumod.c create mode 100644 shell/taskband/src/start/menumod.h create mode 100644 shell/taskband/src/start/personal.c create mode 100644 shell/taskband/src/start/personal.h delete mode 100644 shell/taskband/src/start/placeslist.c delete mode 100644 shell/taskband/src/start/placeslist.h delete mode 100644 shell/taskband/src/start/programslist.c delete mode 100644 shell/taskband/src/start/programslist.h create mode 100644 shell/taskband/src/start/shared.h delete mode 100644 shell/taskband/src/start/startbutton.c delete mode 100644 shell/taskband/src/start/startbutton.h delete mode 100644 shell/taskband/src/start/startmenu.c delete mode 100644 shell/taskband/src/start/startmenu.h delete mode 100644 shell/taskband/src/start/startmenuitem.c delete mode 100644 shell/taskband/src/start/startmenuitem.h create mode 100644 shell/taskband/src/start/toolbar.c create mode 100644 shell/taskband/src/start/toolbar.h create mode 100644 shell/taskband/src/systray/toolbar.c create mode 100644 shell/taskband/src/systray/toolbar.h create mode 100644 shell/taskband/src/taskbuttons/toolbar.c create mode 100644 shell/taskband/src/taskbuttons/toolbar.h create mode 100644 shell/taskband/src/toolbar.c create mode 100644 shell/taskband/src/toolbar.h diff --git a/shared/comgtk/CMakeLists.txt b/shared/comgtk/CMakeLists.txt index 47df866..0389795 100644 --- a/shared/comgtk/CMakeLists.txt +++ b/shared/comgtk/CMakeLists.txt @@ -35,6 +35,8 @@ add_library( libwintc-comgtk src/assets.h src/debug.h + src/container.c + src/container.h src/defprocs.c src/defprocs.h src/errors.c diff --git a/shared/comgtk/public/wintc-comgtk.h.in b/shared/comgtk/public/wintc-comgtk.h.in index 112c06b..21c3394 100644 --- a/shared/comgtk/public/wintc-comgtk.h.in +++ b/shared/comgtk/public/wintc-comgtk.h.in @@ -9,6 +9,13 @@ // #define WINTC_ASSETS_DIR "@CMAKE_INSTALL_PREFIX@/@WINTC_ASSETS_INSTALL_DIR@" +// +// Container-related +// +void wintc_gtk_container_clear( + GtkContainer* container +); + // // Debugging // diff --git a/shared/comgtk/src/container.c b/shared/comgtk/src/container.c new file mode 100644 index 0000000..1db0e2e --- /dev/null +++ b/shared/comgtk/src/container.c @@ -0,0 +1,24 @@ +#include +#include + +#include "container.h" + +// +// PUBLIC FUNCTIONS +// +void wintc_gtk_container_clear( + GtkContainer* container +) +{ + GList* children = gtk_container_get_children(container); + GList* iter = children; + + while (iter) + { + gtk_widget_destroy(GTK_WIDGET(iter->data)); + + iter = iter->next; + } + + g_list_free(children); +} diff --git a/shared/comgtk/src/container.h b/shared/comgtk/src/container.h new file mode 100644 index 0000000..0e74c10 --- /dev/null +++ b/shared/comgtk/src/container.h @@ -0,0 +1,13 @@ +#ifndef __CONTAINER_H__ +#define __CONTAINER_H__ + +#include + +// +// PUBLIC FUNCTIONS +// +void wintc_gtk_container_clear( + GtkContainer* container +); + +#endif diff --git a/shared/shelldpa/public/wintc-shelldpa.h b/shared/shelldpa/public/wintc-shelldpa.h index 480dd5d..d2579ed 100644 --- a/shared/shelldpa/public/wintc-shelldpa.h +++ b/shared/shelldpa/public/wintc-shelldpa.h @@ -20,7 +20,8 @@ typedef enum // PUBLIC FUNCTIONS // GtkWidget* wintc_dpa_create_popup( - GtkWidget* owner + GtkWidget* owner, + gboolean enable_composition ); void wintc_dpa_show_popup( GtkWidget* popup, diff --git a/shared/shelldpa/src/api.c b/shared/shelldpa/src/api.c index b9556de..3e9254b 100644 --- a/shared/shelldpa/src/api.c +++ b/shared/shelldpa/src/api.c @@ -64,7 +64,8 @@ static gboolean on_popup_window_focus_out( // PUBLIC FUNCTIONS // GtkWidget* wintc_dpa_create_popup( - GtkWidget* owner + GtkWidget* owner, + gboolean enable_composition ) { GtkWidget* popup; @@ -77,10 +78,6 @@ GtkWidget* wintc_dpa_create_popup( { popup = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_decorated( - GTK_WINDOW(popup), - FALSE - ); gtk_window_set_type_hint( GTK_WINDOW(popup), GDK_WINDOW_TYPE_HINT_POPUP_MENU @@ -106,6 +103,34 @@ GtkWidget* wintc_dpa_create_popup( GDK_FOCUS_CHANGE_MASK ); + // If the application wants composition (eg. for shadows) we fake out + // CSD here + // + if (enable_composition) + { + GtkWidget* fake_titlebar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + + // HACK: Apply CSS to force the fake titlebar to not show up as + // Adwaita has a min-height on titlebar boxes! Blah! + // + wintc_widget_add_css( + fake_titlebar, + "* { min-height: 0px; }" + ); + + gtk_window_set_titlebar( + GTK_WINDOW(popup), + fake_titlebar + ); + } + else + { + gtk_window_set_decorated( + GTK_WINDOW(popup), + FALSE + ); + } + // Connect signals // g_signal_connect( @@ -144,7 +169,11 @@ void wintc_dpa_show_popup( ); gtk_widget_show_all(popup); - height = gtk_widget_get_allocated_height(popup); + gtk_window_get_size( + GTK_WINDOW(popup), + NULL, + &height + ); gdk_window_get_origin( gtk_widget_get_window(owner), diff --git a/shared/shelldpa/src/api.h b/shared/shelldpa/src/api.h index 5e9fe49..124d49e 100644 --- a/shared/shelldpa/src/api.h +++ b/shared/shelldpa/src/api.h @@ -24,7 +24,8 @@ typedef enum // PUBLIC FUNCTIONS // GtkWidget* wintc_dpa_create_popup( - GtkWidget* owner + GtkWidget* owner, + gboolean enable_composition ); void wintc_dpa_show_popup( GtkWidget* popup, diff --git a/shared/shelldpa/src/impl-x11.c b/shared/shelldpa/src/impl-x11.c index 368bb4b..0310e82 100644 --- a/shared/shelldpa/src/impl-x11.c +++ b/shared/shelldpa/src/impl-x11.c @@ -6,9 +6,6 @@ #include "api.h" #include "impl-x11.h" -// FIXME: Remove this before release -#define TASKBAND_ROW_HEIGHT 30 - // // STRUCTURE DEFINITIONS // @@ -127,12 +124,13 @@ static void on_taskband_realized( ) { GdkAtom cardinal_atom; - GdkDisplay* display = gdk_display_get_default(); + GdkDisplay* display = gdk_display_get_default(); GdkRectangle geometry; - GdkMonitor* monitor = NULL; - int monitor_count = gdk_display_get_n_monitors(display); + gint height_request = 0; + GdkMonitor* monitor = NULL; + int monitor_count = gdk_display_get_n_monitors(display); GdkAtom net_wm_strut_partial_atom; - int screen_bottom = 0; + int screen_bottom = 0; cardinal_atom = gdk_atom_intern_static_string("CARDINAL"); @@ -165,19 +163,25 @@ static void on_taskband_realized( gdk_monitor_get_geometry(monitor, &geometry); - gtk_window_set_default_size( - GTK_WINDOW(self), + gtk_widget_get_size_request( + self, + NULL, + &height_request + ); + + gtk_widget_set_size_request( + self, geometry.width, - TASKBAND_ROW_HEIGHT + height_request ); gtk_window_move( GTK_WINDOW(self), geometry.x, - geometry.y + geometry.height - TASKBAND_ROW_HEIGHT + geometry.y + geometry.height - height_request ); struts.bottom = - screen_bottom - (geometry.y + geometry.height) + TASKBAND_ROW_HEIGHT; + screen_bottom - (geometry.y + geometry.height) + height_request; struts.bottom_start_x = geometry.x; struts.bottom_end_x = geometry.x + geometry.width; diff --git a/shell/taskband/CMakeLists.txt b/shell/taskband/CMakeLists.txt index 6d249a9..1b7b5d8 100644 --- a/shell/taskband/CMakeLists.txt +++ b/shell/taskband/CMakeLists.txt @@ -42,20 +42,17 @@ add_executable( src/main.c src/meta.h src/resources.c + src/toolbar.c + src/toolbar.h src/window.c src/window.h - src/start/action.c - src/start/action.h - src/start/placeslist.c - src/start/placeslist.h - src/start/programslist.c - src/start/programslist.h - src/start/startbutton.c - src/start/startbutton.h - src/start/startmenu.c - src/start/startmenu.h - src/start/startmenuitem.c - src/start/startmenuitem.h + src/start/menumod.c + src/start/menumod.h + src/start/personal.c + src/start/personal.h + src/start/shared.h + src/start/toolbar.c + src/start/toolbar.h src/start/util.c src/start/util.h src/systray/behaviour.c @@ -64,10 +61,14 @@ add_executable( src/systray/clock.h src/systray/notifarea.c src/systray/notifarea.h + src/systray/toolbar.c + src/systray/toolbar.h src/systray/volume.c src/systray/volume.h src/taskbuttons/taskbuttonbar.c src/taskbuttons/taskbuttonbar.h + src/taskbuttons/toolbar.c + src/taskbuttons/toolbar.h src/taskbuttons/windowmonitor.c src/taskbuttons/windowmonitor.h ) diff --git a/shell/taskband/src/res/personal-menu.ui b/shell/taskband/src/res/personal-menu.ui new file mode 100644 index 0000000..822245c --- /dev/null +++ b/shell/taskband/src/res/personal-menu.ui @@ -0,0 +1,852 @@ + + + + + True + False + vertical + + + True + False + + + True + False + vertical + + + True + False + + + + + + True + True + 0 + + + + + False + True + 0 + + + + + True + False + + + False + True + 1 + + + + + + False + True + 0 + + + + + True + False + + + True + False + vertical + + + True + False + 90 + + + False + True + end + 0 + + + + + + False + True + 0 + + + + + True + False + vertical + + + True + False + ttb + + + True + False + end + True + + + + + True + False + + + True + False + center + horizontal + + + True + False + All Programs + + + False + False + 1 + + + + + True + False + horizontal + + + + False + False + 2 + + + + + + + + + + True + True + 0 + + + + + + True + True + 1 + + + + + True + False + vertical + + + True + False + ttb + + + True + False + + + True + False + horizontal + + + True + False + folder-documents + 3 + + + False + False + 1 + + + + + True + False + %PLACE_DOCUMENTS% + 24 + Opens the My Documents folder, where you can store letters, reports, notes, and other kinds of documents. + True + 0.0 + + + True + True + 2 + + + + + + + + + + True + False + + + True + False + horizontal + + + True + False + document-open-recent + 3 + + + False + False + 1 + + + + + True + False + %PLACE_RECENTS% + 24 + Displays recently opened documents and folders. + True + 0.0 + + + True + True + 2 + + + + + + + + + + True + False + + + True + False + horizontal + + + True + False + folder-pictures + 3 + + + False + False + 1 + + + + + True + False + %PLACE_PICTURES% + 24 + Opens the My Pictures folder, where you can store digital photos, images, and graphics files. + True + 0.0 + + + True + True + 2 + + + + + + + + + + True + False + + + True + False + horizontal + + + True + False + folder-music + 3 + + + False + False + 1 + + + + + True + False + %PLACE_MUSIC% + 24 + Opens the My Music folder, where you can store music and other audio files. + True + 0.0 + + + True + True + 2 + + + + + + + + + + True + False + + + True + False + horizontal + + + True + False + computer + 3 + + + False + False + 1 + + + + + True + False + %PLACE_DRIVES% + 24 + Gives access to, and information about, the disk drives, cameras, scanners, and other hardware connected to your computer. + True + 0.0 + + + True + True + 2 + + + + + + + + + + True + False + + + + + True + False + + + True + False + horizontal + + + True + False + preferences-other + 3 + + + False + False + 1 + + + + + True + False + %PLACE_CONTROLPANEL% + 24 + Provides options for you to customize the appearance and functionality of your computer, add or remove programs, and set up network connections and user accounts. + True + 0.0 + + + True + True + 2 + + + + + + + + + True + False + + + True + False + horizontal + + + True + False + preferences-desktop-default-applications + 3 + + + False + False + 1 + + + + + True + False + Set Program Access and Defaults + 24 + Chooses default programs for certain activities, such as Web browsing or sending e-mail, and specifies which programs are accessible from the Start menu, desktop, and other locations. + True + 0.0 + + + True + True + 2 + + + + + + + + + True + False + + + True + False + horizontal + + + True + False + preferences-system-network + 3 + + + False + False + 1 + + + + + True + False + Connect To... + 24 + Connects to other computers, networks, and the Internet. + True + 0.0 + + + True + True + 2 + + + + + + + + + True + False + + + True + False + horizontal + + + True + False + printer + 3 + + + False + False + 1 + + + + + True + False + %PLACE_PRINTERS% + 24 + Shows installed printers and fax printers and helps you add new ones. + True + 0.0 + + + True + True + 2 + + + + + + + + + True + False + + + + + True + False + + + True + False + horizontal + + + True + False + help-browser + 3 + + + False + False + 1 + + + + + True + False + Help and Support + 24 + Opens a central location for Help topics, tutorials, troubleshooting, and other support services. + True + 0.0 + + + True + True + 2 + + + + + + + + + True + False + + + True + False + horizontal + + + True + False + system-search + 3 + + + False + False + 1 + + + + + True + False + Search + 24 + Opens a window where you can pick search options and work with search results. + True + 0.0 + + + True + True + 2 + + + + + + + + + True + False + + + True + False + horizontal + + + True + False + system-run + 3 + + + False + False + 1 + + + + + True + False + Run... + 24 + Opens a program, folder, document, or Web site. + True + 0.0 + + + True + True + 2 + + + + + + + + + False + True + 0 + + + + + + False + True + 2 + + + + + + True + True + 1 + + + + + True + False + + + True + True + True + + + True + False + + + True + False + + + + + + + False + True + 0 + + + + + True + False + Turn Off Computer + Provides options for turning off or restarting your computer, or for activating Stand By or Hibernate modes. + + + False + True + 1 + + + + + + + False + True + end + 0 + + + + + True + True + True + + + True + False + + + True + False + vertical + + + + + + + False + True + 0 + + + + + True + False + Log Off + Provides options for closing your programs and logging off, or for leaving your programs running and switching to another user. + + + False + True + 1 + + + + + + + False + True + end + 1 + + + + + + False + True + 2 + + + + diff --git a/shell/taskband/src/res/resources.xml b/shell/taskband/src/res/resources.xml index cf38afc..e5c83eb 100644 --- a/shell/taskband/src/res/resources.xml +++ b/shell/taskband/src/res/resources.xml @@ -1,6 +1,8 @@ + personal-menu.ui + start-button.ui start-menu.css volume-popup.css diff --git a/shell/taskband/src/res/start-button.ui b/shell/taskband/src/res/start-button.ui new file mode 100644 index 0000000..02dbfa2 --- /dev/null +++ b/shell/taskband/src/res/start-button.ui @@ -0,0 +1,67 @@ + + + + + + True + False + False + Click here to begin + + + True + False + + + True + False + + + + + + + False + True + 0 + + + + + True + False + start + + + + False + True + 1 + + + + + True + False + Start + + + + False + True + 2 + + + + + + + diff --git a/shell/taskband/src/res/start-menu.css b/shell/taskband/src/res/start-menu.css index b32f112..3fb2a37 100644 --- a/shell/taskband/src/res/start-menu.css +++ b/shell/taskband/src/res/start-menu.css @@ -1,4 +1,4 @@ -.xp-start-button .lower +.wintc-start-button .lower { font-size: 0pt; } @@ -13,32 +13,22 @@ box > menubar > separator margin: 4px 0px; } -menuitem.xp-start-all-programs +menuitem.start-all-programs > box { min-height: 32px; } -menuitem.xp-start-all-programs > box -{ - font-weight: bold; -} - -separator.xp-start-all-programs -{ - margin-top: 40px; -} - -.xp-start-logoffpane button +.start-logoffpane button { margin: 8px 3px; } -.xp-start-logoffpane button:last-child +.start-logoffpane button:last-child { margin-right: 8px; } -.xp-start-userpane box +.start-userpane box { background-size: 100% 100%; box-shadow: 0px 0px 2px 0px rgba(0,0,0,0.75); @@ -47,12 +37,12 @@ separator.xp-start-all-programs min-width: 48px; } -.xp-start-userpane label +.start-userpane label { font-size: 16pt; } -.xp-start-vuserpane label +.start-vuserpane label { font-size: 0pt; } diff --git a/shell/taskband/src/start/action.c b/shell/taskband/src/start/action.c deleted file mode 100644 index d02c91a..0000000 --- a/shell/taskband/src/start/action.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include -#include - -#include "action.h" - -// -// PUBLIC FUNCTIONS -// -void launch_action( - WinTCAction action_id -) -{ - GError* error = NULL; - - if (!wintc_launch_action(action_id, &error)) - { - wintc_nice_error_and_clear(&error); - } -} - -void launch_command( - const gchar* command -) -{ - if (command == NULL) - { - g_error("No command specified."); - return; - } - - GError* error = NULL; - - if (!wintc_launch_command(command, &error)) - { - wintc_nice_error_and_clear(&error); - } -} diff --git a/shell/taskband/src/start/action.h b/shell/taskband/src/start/action.h deleted file mode 100644 index f445341..0000000 --- a/shell/taskband/src/start/action.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __ACTION_H__ -#define __ACTION_H__ - -#include -#include - -void launch_action( - WinTCAction action_id -); - -void launch_command( - const gchar* command -); - -#endif diff --git a/shell/taskband/src/start/menumod.c b/shell/taskband/src/start/menumod.c new file mode 100644 index 0000000..a9936c6 --- /dev/null +++ b/shell/taskband/src/start/menumod.c @@ -0,0 +1,186 @@ +#include +#include +#include + +#include "menumod.h" + +// +// FORWARD DECLARATIONS +// +static void wintc_menu_modded_size_allocate( + GtkWidget* widget, + GtkAllocation* allocation +); + +// +// GTK OOP CLASS/INSTANCE DEFINITIONS +// +struct _WinTCMenuModdedClass +{ + GtkMenuBarClass __parent__; +}; + +struct _WinTCMenuModded +{ + GtkMenuBar __parent__; +}; + +// +// GTK TYPE DEFINITION & CTORS +// +G_DEFINE_TYPE( + WinTCMenuModded, + wintc_menu_modded, + GTK_TYPE_MENU_BAR +) + +static void wintc_menu_modded_class_init( + WinTCMenuModdedClass* klass +) +{ + GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); + + widget_class->size_allocate = wintc_menu_modded_size_allocate; +} + +static void wintc_menu_modded_init( + WINTC_UNUSED(WinTCMenuModded* self) +) {} + +// +// CLASS VIRTUAL METHODS +// +static void wintc_menu_modded_size_allocate( + GtkWidget* widget, + GtkAllocation* allocation +) +{ + // Omega giga ultra hax! There's some GTK gadget fancy pants stuff in the + // menu bar's allocate function what we don't have access to, so we chain + // up early for it to handle all that jazz... + // + (GTK_WIDGET_CLASS(wintc_menu_modded_parent_class)) + ->size_allocate(widget, allocation); + + // ...and then assuming that it took care of all the CSS box model business + // for the menu bar itself, we retrieve the allocation that was set, and + // use that to layout the children a *second* time in the way *we* want + // + GtkAllocation menu_allocation; + GtkAllocation remaining_space; + + gtk_widget_get_allocation(widget, &menu_allocation); + remaining_space = menu_allocation; + remaining_space.x = 0; + remaining_space.y = 0; + + if ( + gtk_menu_bar_get_pack_direction(GTK_MENU_BAR(widget)) + != GTK_PACK_DIRECTION_TTB + ) + { + // I'm only implementing TTB for now since that's all the Start menu + // needs + // + g_critical("%s", "Modded menu class only supports TTB packing!"); + return; + } + + // Calculate children's size allocations + // + GArray* allocations; + GtkWidget* child; + GList* children = gtk_container_get_children(GTK_CONTAINER(widget)); + GList* li; + gint n_expanders = 0; + gint share_space = 0; + + allocations = + g_array_new( + FALSE, + TRUE, + sizeof(GtkRequestedSize) + ); + + for (li = children; li; li = li->next) + { + GtkRequestedSize request; + gint toggle_size; + + child = li->data; + + if (!gtk_widget_get_visible(child)) + { + continue; + } + + if (gtk_widget_get_vexpand(child)) + { + n_expanders++; + } + + request.data = child; + + gtk_widget_get_preferred_height_for_width( + child, + menu_allocation.width, + &(request.minimum_size), + &(request.natural_size) + ); + gtk_menu_item_toggle_size_request( + GTK_MENU_ITEM(child), + &toggle_size + ); + + request.minimum_size += toggle_size; + request.natural_size += toggle_size; + + gtk_menu_item_toggle_size_allocate( + GTK_MENU_ITEM(child), + toggle_size + ); + + g_array_append_val(allocations, request); + + remaining_space.height -= request.minimum_size; + } + + remaining_space.height = + gtk_distribute_natural_allocation( + remaining_space.height, + allocations->len, + (GtkRequestedSize*) allocations->data + ); + + if (n_expanders > 0) + { + share_space = remaining_space.height / n_expanders; + } + + for (guint i = 0; i < allocations->len; i++) + { + GtkAllocation child_alloc = remaining_space; + GtkRequestedSize* request = &g_array_index( + allocations, + GtkRequestedSize, + i + ); + + child_alloc.height = request->minimum_size; + + if (gtk_widget_get_vexpand(request->data)) + { + child_alloc.height += share_space; + } + + remaining_space.y += child_alloc.height; + + gtk_widget_size_allocate( + request->data, + &child_alloc + ); + } + + g_list_free(children); + g_array_unref(allocations); +} diff --git a/shell/taskband/src/start/menumod.h b/shell/taskband/src/start/menumod.h new file mode 100644 index 0000000..12c3e99 --- /dev/null +++ b/shell/taskband/src/start/menumod.h @@ -0,0 +1,22 @@ +#ifndef __MENUMOD_H__ +#define __MENUMOD_H__ + +#include +#include + +// +// GTK OOP BOILERPLATE +// +typedef struct _WinTCMenuModdedClass WinTCMenuModdedClass; +typedef struct _WinTCMenuModded WinTCMenuModded; + +#define TYPE_WINTC_MENU_MODDED (wintc_menu_modded_get_type()) +#define WINTC_MENU_MODDED(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_MENU_MODDED, WinTCMenuModded)) +#define WINTC_MENU_MODDED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_MENU_MODDED, WinTCMenuModdedClass)) +#define IS_WINTC_MENU_MODDED(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_MENU_MODDED)) +#define IS_WINTC_MENU_MODDED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_MENU_MODDED)) +#define WINTC_MENU_MODDED_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_WINTC_MENU_MODDED, WinTCMenuModded)) + +GType wintc_menu_modded_get_type(void) G_GNUC_CONST; + +#endif diff --git a/shell/taskband/src/start/personal.c b/shell/taskband/src/start/personal.c new file mode 100644 index 0000000..07cfd7c --- /dev/null +++ b/shell/taskband/src/start/personal.c @@ -0,0 +1,1071 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../toolbar.h" +#include "menumod.h" +#include "personal.h" +#include "shared.h" +#include "toolbar.h" +#include "util.h" + +#define DEFAULT_ITEM_COUNT 2 +#define MAX_MFU_ITEM_COUNT 6 +#define TOTAL_PROGRAMS_ITEM_COUNT (DEFAULT_ITEM_COUNT + MAX_MFU_ITEM_COUNT) + +#define PLACE_ICON_SIZE 24 +#define PROGRAM_ICON_SIZE 32 + +// +// PRIVATE STRUCTS +// +typedef struct _StartSignalTuple +{ + WinTCToolbarStart* toolbar_start; + gboolean is_action; + gpointer user_data; +} StartSignalTuple; + +// +// FORWARD DECLARATIONS +// +static void connect_menu_shell_signals( + GtkMenuShell* menu_shell, + WinTCToolbarStart* toolbar_start +); +static GtkWidget* create_personal_menu_item( + GtkMenuShell* menu_shell, + const gchar* icon_name, + const gchar* program_name, + const gchar* comment, + const gchar* generic_name +); +static GtkWidget* create_personal_menu_item_from_desktop_entry( + GDesktopAppInfo* entry, + StartSignalTuple* signal_tuple, + const gchar* comment, + const gchar* generic_name +); +static GtkWidget* create_personal_menu_item_from_garcon_item( + GarconMenuItem* garcon_item, + StartSignalTuple* signal_tuple +); +static void refresh_personal_menu( + WinTCToolbarStart* toolbar_start +); +static void refresh_userpic( + WinTCToolbarStart* toolbar_start +); + +static void clear_signal_tuple( + StartSignalTuple* tuple +); + +static gboolean recent_filter_exclude_directories( + const GtkRecentFilterInfo* filter_info, + gpointer user_data +); + +static void on_button_power_clicked( + GtkButton* button, + gpointer user_data +); +static void on_event_box_userpic_clicked( + GtkWidget* widget, + GdkEventButton* event, + gpointer user_data +); +static void on_menu_item_launcher_activate( + GtkMenuItem* self, + gpointer user_data +); +static void on_menu_item_recent_activated( + GtkRecentChooser* self, + gpointer user_data +); +static void on_menu_item_with_submenu_deselect( + GtkMenuItem* self, + gpointer user_data +); +static void on_menu_shell_selection_done( + GtkMenuShell* self, + gpointer user_data +); +static void on_menu_shell_submenu_selection_done( + GtkMenuShell* self, + gpointer user_data +); +static void on_personal_menu_hide( + GtkWidget* self, + gpointer user_data +); + +// +// INTERNAL FUNCTIONS +// +void close_personal_menu( + WinTCToolbarStart* toolbar_start +) +{ + gtk_widget_hide(toolbar_start->personal.popup_menu); +} + +void create_personal_menu( + WinTCToolbarStart* toolbar_start +) +{ + GtkBuilder* builder; + WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(toolbar_start); + + // Set default states + // + toolbar_start->personal.sync_menu_refresh = TRUE; + + // Init GArrays for signal tuples + // + toolbar_start->personal.tuples_places = g_array_new( + FALSE, + TRUE, + sizeof(StartSignalTuple) + ); + toolbar_start->personal.tuples_programs = g_array_new( + FALSE, + TRUE, + sizeof(StartSignalTuple) + ); + + g_array_set_clear_func( + toolbar_start->personal.tuples_programs, + (GDestroyNotify) clear_signal_tuple + ); + + // Ensure our modded menu type is known to GObject + // + g_type_ensure(TYPE_WINTC_MENU_MODDED); + + // Construct menu from XML + // + builder = + gtk_builder_new_from_resource( + "/uk/oddmatics/wintc/taskband/personal-menu.ui" + ); + + wintc_preprocess_builder_widget_text(builder); + + // Pull UI elements we store for later usage + // + toolbar_start->personal.button_logoff = + GTK_WIDGET(gtk_builder_get_object(builder, "button-logoff")); + toolbar_start->personal.button_shutdown = + GTK_WIDGET(gtk_builder_get_object(builder, "button-shutdown")); + toolbar_start->personal.eventbox_userpic = + GTK_WIDGET(gtk_builder_get_object(builder, "eventbox-userpic")); + toolbar_start->personal.menubar_places = + GTK_WIDGET(gtk_builder_get_object(builder, "menubar-places")); + toolbar_start->personal.menubar_programs = + GTK_WIDGET(gtk_builder_get_object(builder, "menubar-programs")); + toolbar_start->personal.menuitem_all_programs = + GTK_WIDGET(gtk_builder_get_object(builder, "menuitem-all-programs")); + toolbar_start->personal.separator_all_programs = + GTK_WIDGET(gtk_builder_get_object(builder, "separator-all-programs")); + + // Sort out user pic + // + toolbar_start->personal.style_userpic = + GTK_STYLE_PROVIDER(gtk_css_provider_new()); + + gtk_style_context_add_provider( + gtk_widget_get_style_context( + gtk_widget_get_parent(toolbar_start->personal.eventbox_userpic) + ), + toolbar_start->personal.style_userpic, + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + ); + + gtk_widget_set_events( + toolbar_start->personal.eventbox_userpic, + GDK_BUTTON_PRESS_MASK + ); + + g_signal_connect( + toolbar_start->personal.eventbox_userpic, + "button-press-event", + G_CALLBACK(on_event_box_userpic_clicked), + NULL + ); + + refresh_userpic(toolbar_start); + + // Set username labels + // + struct passwd* user_pwd = getpwuid(getuid()); + + gtk_label_set_text( + GTK_LABEL(gtk_builder_get_object(builder, "label-username-horz")), + user_pwd->pw_name + ); + gtk_label_set_text( + GTK_LABEL(gtk_builder_get_object(builder, "label-username-vert")), + user_pwd->pw_name + ); + + // Attach Recent Documents submenu + // + GtkWidget* menu_recents = gtk_recent_chooser_menu_new(); + GtkRecentFilter* recent_filter = gtk_recent_filter_new(); + + gtk_recent_filter_add_custom( + recent_filter, + GTK_RECENT_FILTER_MIME_TYPE, + (GtkRecentFilterFunc) recent_filter_exclude_directories, + NULL, + NULL + ); + + gtk_recent_chooser_set_filter( + GTK_RECENT_CHOOSER(menu_recents), + recent_filter + ); + gtk_recent_chooser_set_sort_type( + GTK_RECENT_CHOOSER(menu_recents), + GTK_RECENT_SORT_MRU + ); + + gtk_menu_item_set_submenu( + GTK_MENU_ITEM(gtk_builder_get_object(builder, "menuitem-recent-docs")), + menu_recents + ); + + g_signal_connect( + menu_recents, + "item-activated", + G_CALLBACK(on_menu_item_recent_activated), + toolbar_start + ); + + // Attach All Programs submenu + // + GarconMenu* programs_menu = garcon_menu_new_for_path( + WINTC_ASSETS_DIR + "/shell-res/start-menu.menu" + ); + GtkWidget* programs_submenu = garcon_gtk_menu_new(programs_menu); + + gtk_menu_item_set_submenu( + GTK_MENU_ITEM(toolbar_start->personal.menuitem_all_programs), + programs_submenu + ); + + // Transfer to popup + // + toolbar_start->personal.popup_menu = + wintc_dpa_create_popup(toolbar->widget_root, TRUE); + + wintc_widget_add_style_class( + toolbar_start->personal.popup_menu, + "wintc-personal-menu" + ); + + gtk_container_add( + GTK_CONTAINER(toolbar_start->personal.popup_menu), + GTK_WIDGET(gtk_builder_get_object(builder, "main-box")) + ); + + g_object_unref(G_OBJECT(builder)); + + g_signal_connect( + toolbar_start->personal.popup_menu, + "hide", + G_CALLBACK(on_personal_menu_hide), + toolbar_start + ); + + // Take extra references to All Programs items, so we can safely take + // them out of the menu bar whilst refreshing without them being disposed + // + g_object_ref(toolbar_start->personal.menuitem_all_programs); + g_object_ref(toolbar_start->personal.separator_all_programs); + + // Attach signals + // + connect_menu_shell_signals( + GTK_MENU_SHELL(toolbar_start->personal.menubar_places), + toolbar_start + ); + connect_menu_shell_signals( + GTK_MENU_SHELL(toolbar_start->personal.menubar_programs), + toolbar_start + ); + + // Attach actions for places - the order of WinTCAction is the same as + // these Start menu items + // + StartSignalTuple* tuple; + GList* elements; + GList* li; + gint i = 0; + + elements = + gtk_container_get_children( + GTK_CONTAINER(toolbar_start->personal.menubar_places) + ); + li = elements; + + g_array_set_size( + toolbar_start->personal.tuples_places, + g_list_length(elements) + ); + + while (li) + { + GtkMenuItem* menu_item = GTK_MENU_ITEM(li->data); + + // Skip separators + // + if (!GTK_IS_SEPARATOR_MENU_ITEM(menu_item)) + { + // Only connect activation for items without submenus + // + if (!gtk_menu_item_get_submenu(menu_item)) + { + tuple = + &g_array_index( + toolbar_start->personal.tuples_places, + StartSignalTuple, + i + ); + + tuple->is_action = TRUE; + tuple->toolbar_start = toolbar_start; + tuple->user_data = GINT_TO_POINTER(i); + + g_signal_connect( + menu_item, + "activate", + G_CALLBACK(on_menu_item_launcher_activate), + tuple + ); + } + + i++; + } + + li = li->next; + } + + g_list_free(elements); + + // Attach power button signals + // + g_signal_connect( + toolbar_start->personal.button_logoff, + "clicked", + G_CALLBACK(on_button_power_clicked), + GINT_TO_POINTER(WINTC_ACTION_LOGOFF) + ); + g_signal_connect( + toolbar_start->personal.button_shutdown, + "clicked", + G_CALLBACK(on_button_power_clicked), + GINT_TO_POINTER(WINTC_ACTION_SHUTDOWN) + ); +} + +void destroy_personal_menu( + WinTCToolbarStart* toolbar_start +) +{ + // Unref extra references on all programs items + // + g_object_unref( + g_steal_pointer(&(toolbar_start->personal.menuitem_all_programs)) + ); + g_object_unref( + g_steal_pointer(&(toolbar_start->personal.separator_all_programs)) + ); + + // Clear signal tuple data + // + g_array_unref( + g_steal_pointer(&(toolbar_start->personal.tuples_places)) + ); + g_array_unref( + g_steal_pointer(&(toolbar_start->personal.tuples_programs)) + ); + + // Destroy popup + // + gtk_widget_destroy( + g_steal_pointer(&(toolbar_start->personal.popup_menu)) + ); +} + +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 + // + toolbar_start->sync_menu_should_close = FALSE; + + if (toolbar_start->personal.sync_menu_refresh) + { + refresh_personal_menu(toolbar_start); + } + + wintc_dpa_show_popup( + toolbar_start->personal.popup_menu, + toolbar->widget_root + ); +} + +// +// PRIVATE FUNCTIONS +// +static void connect_menu_shell_signals( + GtkMenuShell* menu_shell, + WinTCToolbarStart* toolbar_start +) +{ + GtkWidget* child; + GList* children = gtk_container_get_children( + GTK_CONTAINER(menu_shell) + ); + GList* li = children; + + while (li) + { + child = li->data; + + // Connect enter/leave events for auto-focusing the menu shell + // + g_signal_connect( + child, + "enter-notify-event", + G_CALLBACK(wintc_menu_shell_select_on_enter), + menu_shell + ); + g_signal_connect( + child, + "leave-notify-event", + G_CALLBACK(wintc_menu_shell_deselect_on_leave), + menu_shell + ); + + // If the item has a sub-menu, apply a hacks to deal with the funny + // pop-up menu behaviour (if we deselect the menu ourselves, it avoids + // the issue of the submenu somehow 'detaching' itself) + // + if (gtk_menu_item_get_submenu(GTK_MENU_ITEM(child))) + { + g_signal_connect( + child, + "deselect", + G_CALLBACK(on_menu_item_with_submenu_deselect), + NULL + ); + g_signal_connect( + gtk_menu_item_get_submenu(GTK_MENU_ITEM(child)), + "selection-done", + G_CALLBACK(on_menu_shell_submenu_selection_done), + toolbar_start + ); + } + + li = li->next; + } + + g_list_free(g_steal_pointer(&children)); + + g_signal_connect( + menu_shell, + "selection-done", + G_CALLBACK(on_menu_shell_selection_done), + toolbar_start + ); +} + +static GtkWidget* create_personal_menu_item( + GtkMenuShell* menu_shell, + const gchar* icon_name, + const gchar* program_name, + const gchar* comment, + const gchar* generic_name +) +{ + GtkWidget* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + GtkWidget* image_icon = gtk_image_new_from_icon_name( + icon_name, + GTK_ICON_SIZE_MENU + ); + GtkWidget* label_program = gtk_label_new(program_name); + GtkWidget* menu_item = gtk_menu_item_new(); + + gtk_image_set_pixel_size( + GTK_IMAGE(image_icon), + PROGRAM_ICON_SIZE + ); + + gtk_label_set_line_wrap( + GTK_LABEL(label_program), + TRUE + ); + gtk_label_set_max_width_chars( + GTK_LABEL(label_program), + 24 + ); + gtk_label_set_xalign( + GTK_LABEL(label_program), + 0.0 + ); + + // Pack icon first... + // + gtk_box_pack_start( + GTK_BOX(box), + image_icon, + FALSE, + FALSE, + 0 + ); + + // ...then pack the program name/heading... + // + if (generic_name) + { + GtkWidget* inner_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + GtkWidget* label_generic = gtk_label_new(generic_name); + + wintc_widget_add_style_class( + menu_item, + "start-default-item" + ); + + gtk_label_set_xalign( + GTK_LABEL(label_generic), + 0.0 + ); + gtk_widget_set_valign(inner_box, GTK_ALIGN_CENTER); + + gtk_box_pack_start( + GTK_BOX(inner_box), + label_generic, + TRUE, + TRUE, + 0 + ); + gtk_box_pack_start( + GTK_BOX(inner_box), + label_program, + TRUE, + TRUE, + 0 + ); + + gtk_box_pack_start( + GTK_BOX(box), + inner_box, + TRUE, + TRUE, + 0 + ); + } + else + { + gtk_box_pack_start( + GTK_BOX(box), + label_program, + FALSE, + FALSE, + 0 + ); + } + + gtk_container_add( + GTK_CONTAINER(menu_item), + box + ); + + // ...finally add the comment to the menu item tooltip + // + if (comment) + { + gchar* real_comment = wintc_str_set_suffix(comment, "."); + + gtk_widget_set_tooltip_text(menu_item, real_comment); + + g_free(real_comment); + } + + // Add enter/leave signals for auto-selecting menushell + // + g_signal_connect( + menu_item, + "enter-notify-event", + G_CALLBACK(wintc_menu_shell_select_on_enter), + menu_shell + ); + g_signal_connect( + menu_item, + "leave-notify-event", + G_CALLBACK(wintc_menu_shell_deselect_on_leave), + menu_shell + ); + + return menu_item; +} + +static GtkWidget* create_personal_menu_item_from_desktop_entry( + GDesktopAppInfo* entry, + StartSignalTuple* signal_tuple, + const gchar* comment, + const gchar* generic_name +) +{ + GtkWidget* menu_item; + + if (entry) + { + GAppInfo* app_info = G_APP_INFO(entry); + gchar* icon_name = g_path_get_basename( + g_app_info_get_executable(app_info) + ); + + menu_item = + create_personal_menu_item( + GTK_MENU_SHELL( + signal_tuple->toolbar_start->personal.menubar_programs + ), + icon_name, + g_app_info_get_name(app_info), + comment, + generic_name + ); + + signal_tuple->is_action = FALSE; + signal_tuple->user_data = wintc_desktop_app_info_get_command(entry); + + g_signal_connect( + menu_item, + "activate", + G_CALLBACK(on_menu_item_launcher_activate), + signal_tuple + ); + + g_free(icon_name); + } + else + { + menu_item = + create_personal_menu_item( + GTK_MENU_SHELL( + signal_tuple->toolbar_start->personal.menubar_programs + ), + "dialog-warning", + _("Click to specify a default"), + comment, + generic_name + ); + + signal_tuple->is_action = TRUE; + signal_tuple->user_data = GINT_TO_POINTER(WINTC_ACTION_MIMEMGMT); + + g_signal_connect( + menu_item, + "activate", + G_CALLBACK(on_menu_item_launcher_activate), + signal_tuple + ); + } + + return menu_item; +} + +static GtkWidget* create_personal_menu_item_from_garcon_item( + GarconMenuItem* garcon_item, + StartSignalTuple* signal_tuple +) +{ + GtkWidget* menu_item = + create_personal_menu_item( + GTK_MENU_SHELL( + signal_tuple->toolbar_start->personal.menubar_programs + ), + garcon_menu_item_get_icon_name(garcon_item), + garcon_menu_item_get_name(garcon_item), + garcon_menu_item_get_comment(garcon_item), + NULL + ); + + signal_tuple->is_action = FALSE; + signal_tuple->user_data = + garcon_menu_item_get_command_expanded(garcon_item); + + g_signal_connect( + menu_item, + "activate", + G_CALLBACK(on_menu_item_launcher_activate), + signal_tuple + ); + + return menu_item; +} + +static void refresh_personal_menu( + WinTCToolbarStart* toolbar_start +) +{ + // Temporarily remove All Programs items from meubar (safe because we + // took extra references to them already) + // + gtk_container_remove( + GTK_CONTAINER(toolbar_start->personal.menubar_programs), + toolbar_start->personal.menuitem_all_programs + ); + gtk_container_remove( + GTK_CONTAINER(toolbar_start->personal.menubar_programs), + toolbar_start->personal.separator_all_programs + ); + + // Clear existing items + // + wintc_gtk_container_clear( + GTK_CONTAINER(toolbar_start->personal.menubar_programs) + ); + + // Set up signal tuple array + // + g_array_remove_range( + toolbar_start->personal.tuples_programs, + 0, + toolbar_start->personal.tuples_programs->len + ); + + g_array_set_size( + toolbar_start->personal.tuples_programs, + TOTAL_PROGRAMS_ITEM_COUNT + ); + + // Add default items + // + GDesktopAppInfo* entry_internet = wintc_query_mime_handler( + "x-scheme-handler/http", + NULL + ); + GDesktopAppInfo* entry_email = wintc_query_mime_handler( + "x-scheme-handler/mailto", + NULL + ); + StartSignalTuple* tuple; + + tuple = + &g_array_index( + toolbar_start->personal.tuples_programs, + StartSignalTuple, + 0 + ); + tuple->toolbar_start = toolbar_start; + + gtk_menu_shell_append( + GTK_MENU_SHELL(toolbar_start->personal.menubar_programs), + create_personal_menu_item_from_desktop_entry( + entry_internet, + tuple, + _("Opens your Internet browser."), + _("Internet") + ) + ); + + tuple = + &g_array_index( + toolbar_start->personal.tuples_programs, + StartSignalTuple, + 1 + ); + tuple->toolbar_start = toolbar_start; + + gtk_menu_shell_append( + GTK_MENU_SHELL(toolbar_start->personal.menubar_programs), + create_personal_menu_item_from_desktop_entry( + entry_email, + tuple, + _("Opens your e-mail program so you can send or read a message."), + _("E-mail") + ) + ); + + // Add separator between defaults & MFU + // + gtk_menu_shell_append( + GTK_MENU_SHELL(toolbar_start->personal.menubar_programs), + gtk_separator_menu_item_new() + ); + + // Add MFU items + // FIXME: In future we will need some >>>algorithm<<< to come up with a + // 'top' programs list to display here, and also reserve the last + // slot for the latest newly added program, if any + // + // For now we simply grab the first items that are pulled in via the + // all.menu file + // + GarconMenu* all_entries = garcon_menu_new_for_path( + WINTC_ASSETS_DIR "/shell-res/all.menu" + ); + GError* error = NULL; + + if (!garcon_menu_load(all_entries, NULL, &error)) + { + wintc_display_error_and_clear(&error); + return; + } + + // Loop over to add the items + // + GList* elements = garcon_menu_get_elements(all_entries); + GList* li = elements; + gint i = 0; + + while (i < MAX_MFU_ITEM_COUNT && li != NULL) + { + tuple = + &g_array_index( + toolbar_start->personal.tuples_programs, + StartSignalTuple, + DEFAULT_ITEM_COUNT + i + ); + tuple->toolbar_start = toolbar_start; + + gtk_menu_shell_append( + GTK_MENU_SHELL(toolbar_start->personal.menubar_programs), + create_personal_menu_item_from_garcon_item( + GARCON_MENU_ITEM(li->data), + tuple + ) + ); + + i++; + li = li->next; + } + + g_list_free(g_steal_pointer(&elements)); + + // Re-append All Programs items + // + gtk_menu_shell_append( + GTK_MENU_SHELL(toolbar_start->personal.menubar_programs), + toolbar_start->personal.separator_all_programs + ); + gtk_menu_shell_append( + GTK_MENU_SHELL(toolbar_start->personal.menubar_programs), + toolbar_start->personal.menuitem_all_programs + ); + + // Successfully refreshed the menu + // + toolbar_start->personal.sync_menu_refresh = FALSE; +} + +static void refresh_userpic( + WinTCToolbarStart* toolbar_start +) +{ + // TODO: Read from AccountsService or whatever on DBus? Default to the + // flower pic -- for now we're just displaying the FPO image + // + static const gchar* css = + "* { background-image: url('" + WINTC_ASSETS_DIR "/shell-res/fpo-userpic.png" + "'); }"; + + // Give GTK a bump that we want to update the pic + // + gtk_css_provider_load_from_data( + GTK_CSS_PROVIDER(toolbar_start->personal.style_userpic), + css, + -1, + NULL + ); +} + +// +// CALLBACKS +// +static void clear_signal_tuple( + StartSignalTuple* tuple +) +{ + if (!(tuple->is_action)) + { + g_clear_pointer(&(tuple->user_data), g_free); + } +} + +static gboolean recent_filter_exclude_directories( + const GtkRecentFilterInfo* filter_info, + WINTC_UNUSED(gpointer user_data) +) +{ + return g_strcmp0(filter_info->mime_type, "inode/directory") != 0; +} + +static void on_button_power_clicked( + WINTC_UNUSED(GtkButton* button), + gpointer user_data +) +{ + GError* error = NULL; + + if (!wintc_launch_action(GPOINTER_TO_INT(user_data), &error)) + { + wintc_nice_error_and_clear(&error); + } +} + +static void on_event_box_userpic_clicked( + WINTC_UNUSED(GtkWidget* widget), + GdkEventButton* event, + WINTC_UNUSED(gpointer user_data) +) +{ + // + // TODO: Implement this when the user pic cpl is done! + // + if (event->button > 1) + { + return; + } + + GError* error = NULL; + + g_set_error( + &error, + WINTC_GENERAL_ERROR, + WINTC_GENERAL_ERROR_NOTIMPL, + "Cannot edit user pic yet!" + ); + + wintc_nice_error_and_clear(&error); +} + +static void on_menu_item_launcher_activate( + WINTC_UNUSED(GtkMenuItem* self), + gpointer user_data +) +{ + StartSignalTuple* tuple = (StartSignalTuple*) user_data; + + // Raise flag to let Start menu know to close, and launch the action + // + tuple->toolbar_start->sync_menu_should_close = TRUE; + + // Launch either the associated action or cmdline depending on what's in + // the tuple + // + GError* error = NULL; + + if (tuple->is_action) + { + wintc_launch_action(GPOINTER_TO_INT(tuple->user_data), &error); + } + else + { + wintc_launch_command(tuple->user_data, &error); + } + + if (error) + { + wintc_nice_error_and_clear(&error); + } +} + +static void on_menu_item_recent_activated( + GtkRecentChooser* self, + gpointer user_data +) +{ + WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(user_data); + + toolbar_start->sync_menu_should_close = TRUE; + + // Launch the specified URI + // + GError* error = NULL; + gchar* uri = gtk_recent_chooser_get_current_uri(self); + + wintc_launch_command(uri, &error); + + g_free(uri); +} + +static void on_menu_item_with_submenu_deselect( + GtkMenuItem* self, + WINTC_UNUSED(gpointer user_data) +) +{ + // HACK: I suppose infighting with select-on-enter... we popdown the menu + // ourselves when the item is deselected, otherwise for some asinine + // reason the menu has a chance to get stuck open, in a detached + // state + // + // This is still a bit glitchy if someone spam clicks the submenu + // item, but it's better than the alternative + // + gtk_menu_popdown( + GTK_MENU(gtk_menu_item_get_submenu(self)) + ); +} + +static void on_menu_shell_selection_done( + WINTC_UNUSED(GtkMenuShell* self), + gpointer user_data +) +{ + WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(user_data); + + if (!toolbar_start->sync_menu_should_close) + { + return; + } + + gtk_widget_hide( + toolbar_start->personal.popup_menu + ); +} + +static void on_menu_shell_submenu_selection_done( + WINTC_UNUSED(GtkMenuShell* self), + gpointer user_data +) +{ + WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(user_data); + + toolbar_start->sync_menu_should_close = TRUE; +} + +static void on_personal_menu_hide( + WINTC_UNUSED(GtkWidget* self), + gpointer user_data +) +{ + WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(user_data); + WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(user_data); + + toolbar_start->sync_button = TRUE; + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(toolbar->widget_root), + FALSE + ); + toolbar_start->sync_button = FALSE; +} diff --git a/shell/taskband/src/start/personal.h b/shell/taskband/src/start/personal.h new file mode 100644 index 0000000..8e8b6df --- /dev/null +++ b/shell/taskband/src/start/personal.h @@ -0,0 +1,25 @@ +#ifndef __PERSONAL_START_H__ +#define __PERSONAL_START_H__ + +#include +#include + +#include "shared.h" + +// +// INTERNAL FUNCTIONS +// +void close_personal_menu( + WinTCToolbarStart* toolbar_start +); +void create_personal_menu( + WinTCToolbarStart* toolbar_start +); +void destroy_personal_menu( + WinTCToolbarStart* toolbar_start +); +void open_personal_menu( + WinTCToolbarStart* toolbar_start +); + +#endif diff --git a/shell/taskband/src/start/placeslist.c b/shell/taskband/src/start/placeslist.c deleted file mode 100644 index 7ec55f5..0000000 --- a/shell/taskband/src/start/placeslist.c +++ /dev/null @@ -1,175 +0,0 @@ -#include -#include -#include -#include - -#include "startmenuitem.h" -#include "placeslist.h" -#include "util.h" - -// -// GTK OOP CLASS/INSTANCE DEFINITIONS -// -struct _PlacesListClass -{ - GtkMenuBarClass __parent__; -}; - -struct _PlacesList -{ - GtkMenuBar __parent__; -}; - -// -// FORWARD DECLARATIONS -// -static void places_list_finalize( - GObject* object -); - -static void places_list_append_item( - PlacesList* places_list, - WinTCAction action_id, - gboolean significant -); - -static void places_list_append_separator( - PlacesList* places_list -); - -// -// GTK TYPE DEFINITION & CTORS -// -G_DEFINE_TYPE(PlacesList, places_list, GTK_TYPE_MENU_BAR) - -static void places_list_class_init( - PlacesListClass* klass -) -{ - GObjectClass* gclass = G_OBJECT_CLASS(klass); - - gclass->finalize = places_list_finalize; -} - -static void places_list_init( - PlacesList* self -) -{ - // Set up structure - // - gtk_menu_bar_set_pack_direction( - GTK_MENU_BAR(self), - GTK_PACK_DIRECTION_TTB - ); - - places_list_append_item( - self, - WINTC_ACTION_MYDOCS, - TRUE - ); - places_list_append_item( - self, - WINTC_ACTION_MYRECENTS, - TRUE - ); - places_list_append_item( - self, - WINTC_ACTION_MYPICS, - TRUE - ); - places_list_append_item( - self, - WINTC_ACTION_MYMUSIC, - TRUE - ); - places_list_append_item( - self, - WINTC_ACTION_MYCOMP, - TRUE - ); - - places_list_append_separator(self); - - places_list_append_item( - self, - WINTC_ACTION_CONTROL, - FALSE - ); - places_list_append_item( - self, - WINTC_ACTION_MIMEMGMT, - FALSE - ); - places_list_append_item( - self, - WINTC_ACTION_CONNECTTO, - FALSE - ); - places_list_append_item( - self, - WINTC_ACTION_PRINTERS, - FALSE - ); - - places_list_append_separator(self); - - places_list_append_item( - self, - WINTC_ACTION_HELP, - FALSE - ); - places_list_append_item( - self, - WINTC_ACTION_SEARCH, - FALSE - ); - places_list_append_item( - self, - WINTC_ACTION_RUN, - FALSE - ); -} - -// -// FINALIZE -// -static void places_list_finalize( - GObject* object -) -{ - (*G_OBJECT_CLASS(places_list_parent_class)->finalize) (object); -} - -// -// PRIVATE FUNCTIONS -// -static void places_list_append_item( - PlacesList* places_list, - WinTCAction action_id, - gboolean significant -) -{ - GtkWidget* item = start_menu_item_new_from_action(action_id); - - // If the item is significant, add the style - // - if (significant) - { - wintc_widget_add_style_class(item, "significant"); - } - - // FIXME: Shift 24 size to constant - // - start_menu_item_set_icon_size(START_MENU_ITEM(item), 24); - - gtk_menu_shell_append(GTK_MENU_SHELL(places_list), item); -} - -static void places_list_append_separator( - PlacesList* places_list -) -{ - GtkWidget* separator = gtk_separator_menu_item_new(); - - gtk_menu_shell_append(GTK_MENU_SHELL(places_list), separator); -} diff --git a/shell/taskband/src/start/placeslist.h b/shell/taskband/src/start/placeslist.h deleted file mode 100644 index 776e5c6..0000000 --- a/shell/taskband/src/start/placeslist.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __PLACESLIST_H__ -#define __PLACESLIST_H__ - -#include -#include - -G_BEGIN_DECLS - -// -// GTK OOP BOILERPLATE -// -typedef struct _PlacesListClass PlacesListClass; -typedef struct _PlacesList PlacesList; - -#define TYPE_PLACES_LIST (places_list_get_type()) -#define PLACES_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_PLACES_LIST, PlacesList)) -#define PLACES_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_PLACES_LIST, PlacesListClass)) -#define IS_PLACES_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_PLACES_LIST)) -#define IS_PLACES_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_PLACES_LIST)) -#define PLACES_LIST_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_PLACES_LIST, PlacesListClass)) - -GType places_list_get_type(void) G_GNUC_CONST; - -G_END_DECLS - -#endif diff --git a/shell/taskband/src/start/programslist.c b/shell/taskband/src/start/programslist.c deleted file mode 100644 index d1ca1b8..0000000 --- a/shell/taskband/src/start/programslist.c +++ /dev/null @@ -1,283 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../meta.h" -#include "programslist.h" -#include "startmenuitem.h" -#include "util.h" - -// -// GTK OOP CLASS/INSTANCE DEFINITIONS -// -struct _ProgramsListClass -{ - GtkMenuBarClass __parent__; -}; - -struct _ProgramsList -{ - GtkMenuBar __parent__; -}; - -// -// FORWARD DECLARATIONS -// -static void programs_list_finalize( - GObject* object -); - -static void programs_list_append_all_programs_item( - ProgramsList* programs_list -); -static void programs_list_append_default_items( - ProgramsList* programs_list -); -static void programs_list_append_separator( - ProgramsList* programs_list, - const gchar* style_class -); -static void programs_list_append_top_items( - ProgramsList* programs_list, - gint count -); - -// -// GTK TYPE DEFINITION & CTORS -// -G_DEFINE_TYPE(ProgramsList, programs_list, GTK_TYPE_MENU_BAR) - -static void programs_list_class_init( - ProgramsListClass* klass -) -{ - GObjectClass* gclass = G_OBJECT_CLASS(klass); - - gclass->finalize = programs_list_finalize; -} - -static void programs_list_init( - ProgramsList* self -) -{ - // Set up structure - // - gtk_menu_bar_set_pack_direction( - GTK_MENU_BAR(self), - GTK_PACK_DIRECTION_TTB - ); - - programs_list_refresh(self); -} - -// -// PUBLIC FUNCTIONS -// -void programs_list_refresh( - ProgramsList* programs_list -) -{ - programs_list_append_default_items(programs_list); - - programs_list_append_separator(programs_list, NULL); - - programs_list_append_top_items(programs_list, 6); - - programs_list_append_separator(programs_list, "xp-start-all-programs"); - - programs_list_append_all_programs_item(programs_list); -} - -// -// FINALIZE -// -static void programs_list_finalize( - GObject* object -) -{ - (*G_OBJECT_CLASS(programs_list_parent_class)->finalize) (object); -} - -// -// PRIVATE FUNCTIONS -// -static void programs_list_append_all_programs_item( - ProgramsList* programs_list -) -{ - GtkWidget* item = gtk_menu_item_new(); - - // - // The layout of the item contents is such that we can have the text and - // arrow centered - // - // We have an outer box, which contains the label and a box that represents - // the arrow (should the theme decide to style one) - // - - // Outer box - // - GtkWidget* outer_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - gtk_widget_set_halign(outer_box, GTK_ALIGN_CENTER); - - // All programs text - // - GtkWidget* all_programs_label = gtk_label_new(_("All Programs")); - - // 'Arrow' box - // - GtkWidget* arrow_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - // Set garcon menu - // - GarconMenu* programs_menu = garcon_menu_new_for_path( - WINTC_ASSETS_DIR "/shell-res/start-menu.menu" - ); - GtkWidget* programs_submenu = garcon_gtk_menu_new(programs_menu); - - gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), programs_submenu); - - // Set style - // - wintc_widget_add_style_class(item, "xp-start-all-programs"); - wintc_widget_add_style_class(arrow_box, "arrow"); - - // Box up - // - gtk_box_pack_start(GTK_BOX(outer_box), all_programs_label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(outer_box), arrow_box, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(item), outer_box); - gtk_menu_shell_append(GTK_MENU_SHELL(programs_list), item); -} - -static void programs_list_append_default_items( - ProgramsList* programs_list -) -{ - const gchar* imsg = _("Opens your Internet browser."); - const gchar* emsg = _("Opens your e-mail program so you can send or read a message."); - - // Load desktop entries and create menu items - // - GDesktopAppInfo* internet_entry = wintc_query_mime_handler( - "x-scheme-handler/http", - NULL - ); - GDesktopAppInfo* email_entry = wintc_query_mime_handler( - "x-scheme-handler/mailto", - NULL - ); - - // - // FIXME: Handle NULL entries here! ATM there is a bodge in startmenuitem.c, which - // isn't really the right place for it (since in future, the desktop entry - // constructor could be used for pinned items!) - // - // (Also we throw away the error, it should be handled as well ofc, I'm too - // lazy to do that this evening) - // - - GtkWidget* internet_item = start_menu_item_new_from_desktop_entry( - internet_entry, - _("Internet"), - imsg - ); - GtkWidget* email_item = start_menu_item_new_from_desktop_entry( - email_entry, - _("E-mail"), - emsg - ); - - // FIXME: Shift 32 size to constant - // - start_menu_item_set_icon_size(START_MENU_ITEM(internet_item), 32); - start_menu_item_set_icon_size(START_MENU_ITEM(email_item), 32); - - g_clear_object(&internet_entry); - g_clear_object(&email_entry); - - gtk_menu_shell_append(GTK_MENU_SHELL(programs_list), internet_item); - gtk_menu_shell_append(GTK_MENU_SHELL(programs_list), email_item); -} - -static void programs_list_append_separator( - ProgramsList* programs_list, - const gchar* style_class -) -{ - GtkWidget* separator = gtk_separator_menu_item_new(); - - if (style_class != NULL) - { - wintc_widget_add_style_class(separator, style_class); - } - - gtk_menu_shell_append(GTK_MENU_SHELL(programs_list), separator); -} - -static void programs_list_append_top_items( - ProgramsList* programs_list, - gint count -) -{ - GarconMenu* all_entries = garcon_menu_new_for_path( - WINTC_ASSETS_DIR "/shell-res/all.menu" - ); - GError* load_error = NULL; - - if (!garcon_menu_load(all_entries, NULL, &load_error)) - { - wintc_log_error_and_clear(&load_error); - return; - } - - // FIXME: In future we will need some >>>algorithm<<< to come up with a 'top' - // programs list to display here, and also reserve the last slot for the - // latest newly added program, if any - // - // For now we simply grab the first items that are pulled in via the - // all.menu file - // - GList* elements = garcon_menu_get_elements(all_entries); - GList* li = elements; - gint i = 0; - - GtkWidget* menu_item; - - while (i < count && li != NULL) - { - if ( - GARCON_IS_MENU_ITEM(li->data) && - !garcon_menu_item_get_no_display(li->data) - ) - { - menu_item = - start_menu_item_new_from_garcon_item( - GARCON_MENU_ITEM(li->data), - NULL, - NULL - ); - - // FIXME: Shift 32 size to constant - // - start_menu_item_set_icon_size(START_MENU_ITEM(menu_item), 32); - - gtk_menu_shell_append(GTK_MENU_SHELL(programs_list), menu_item); - - // We only count items we actually added to the increment - // - i++; - } - - li = li->next; - } - - g_list_free(g_steal_pointer(&elements)); - g_clear_object(&all_entries); -} diff --git a/shell/taskband/src/start/programslist.h b/shell/taskband/src/start/programslist.h deleted file mode 100644 index 7772785..0000000 --- a/shell/taskband/src/start/programslist.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __PROGRAMSLIST_H__ -#define __PROGRAMSLIST_H__ - -#include -#include - -G_BEGIN_DECLS - -// -// GTK OOP BOILERPLATE -// -typedef struct _ProgramsListClass ProgramsListClass; -typedef struct _ProgramsList ProgramsList; - -#define TYPE_PROGRAMS_LIST (programs_list_get_type()) -#define PROGRAMS_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_PROGRAMS_LIST, ProgramsList)) -#define PROGRAMS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_PROGRAMS_LIST, ProgramsListClass)) -#define IS_PROGRAMS_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_PROGRAMS_LIST)) -#define IS_PROGRAMS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_PROGRAMS_LIST)) -#define PROGRAMS_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_PROGRAMS_LIST, ProgramsListClass)) - -GType programs_list_get_type(void) G_GNUC_CONST; - -// -// PUBLIC FUNCTIONS -// -void programs_list_refresh( - ProgramsList* programs_list -); - -G_END_DECLS - -#endif diff --git a/shell/taskband/src/start/shared.h b/shell/taskband/src/start/shared.h new file mode 100644 index 0000000..ba4027f --- /dev/null +++ b/shell/taskband/src/start/shared.h @@ -0,0 +1,54 @@ +#ifndef __SHARED_START_H__ +#define __SHARED_START_H__ + +// +// INTERNAL STRUCTS +// +typedef struct _PersonalStartMenuData +{ + // UI + // + GtkWidget* popup_menu; + + GtkWidget* button_logoff; + GtkWidget* button_shutdown; + GtkWidget* eventbox_userpic; + GtkWidget* menubar_places; + GtkWidget* menubar_programs; + GtkWidget* menuitem_all_programs; + GtkWidget* separator_all_programs; + + // UI state + // + gboolean sync_menu_refresh; + + // Custom style contexts + // + GtkStyleProvider* style_userpic; + + // Signal tuples + // + GArray* tuples_places; + GArray* tuples_programs; +} PersonalStartMenuData; + +typedef struct _WinTCToolbarStartClass +{ + WinTCTaskbandToolbarClass __parent__; +} WinTCToolbarStartClass; + +typedef struct _WinTCToolbarStart +{ + WinTCTaskbandToolbar __parent__; + + // Personal data struct + // + PersonalStartMenuData personal; + + // UI state + // + gboolean sync_button; + gboolean sync_menu_should_close; +} WinTCToolbarStart; + +#endif diff --git a/shell/taskband/src/start/startbutton.c b/shell/taskband/src/start/startbutton.c deleted file mode 100644 index e220be1..0000000 --- a/shell/taskband/src/start/startbutton.c +++ /dev/null @@ -1,173 +0,0 @@ -#include -#include -#include -#include - -#include "../meta.h" -#include "startbutton.h" -#include "startmenu.h" -#include "util.h" - -// -// GTK OOP CLASS/INSTANCE DEFINITIONS -// -struct _StartButtonPrivate -{ - StartMenu* menu; - - gboolean synchronizing; -}; - -struct _StartButtonClass -{ - GtkToggleButtonClass __parent__; -}; - -struct _StartButton -{ - GtkToggleButton __parent__; - - StartButtonPrivate* priv; -}; - -// -// FORWARD DECLARATIONS -// -static void on_clicked( - GtkButton* button, - gpointer user_data -); - -static void on_start_menu_hidden( - GtkWidget* widget, - gpointer user_data -); - -// -// GTK TYPE DEFINITION & CTORS -// -G_DEFINE_TYPE_WITH_CODE( - StartButton, - start_button, - GTK_TYPE_TOGGLE_BUTTON, - G_ADD_PRIVATE(StartButton) -) - -static void start_button_class_init( - WINTC_UNUSED(StartButtonClass* klass) -) {} - -static void start_button_init( - StartButton* self -) -{ - self->priv = start_button_get_instance_private(self); - - self->priv->synchronizing = FALSE; - - // - // The layout here - we use a box to represent the icon next to the 'start' text - // so that themes can apply their own icon here (important because the Plex style - // has a white Windows flag instead of the coloured one in Luna and other XP - // styles) - // - - // Outer box - // - GtkWidget* outer_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - // 'Flag icon' box - // - GtkWidget* icon_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - // Start text - // - // NOTE: We add two labels for uppercase and lowercase 'start' text, this is so - // that themes can hide one or the other via font-size: 0pt - // - GtkWidget* start_label_l = gtk_label_new(_("start")); - GtkWidget* start_label_u = gtk_label_new(_("Start")); - - gtk_box_pack_start(GTK_BOX(outer_box), icon_box, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(outer_box), start_label_l, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(outer_box), start_label_u, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(self), outer_box); - - gtk_widget_set_tooltip_text(GTK_WIDGET(self), _("Click here to begin")); - - // Add style class - // - wintc_widget_add_style_class(GTK_WIDGET(self), "xp-start-button"); - wintc_widget_add_style_class(icon_box, "xp-flag"); - wintc_widget_add_style_class(start_label_l, "lower"); - wintc_widget_add_style_class(start_label_u, "upper"); - - // Create menu - // - self->priv->menu = start_menu_new(GTK_WIDGET(self)); - - g_signal_connect( - G_OBJECT(self), - "clicked", - G_CALLBACK(on_clicked), - NULL - ); - - connect_start_menu_closed_signal( - self->priv->menu, - G_CALLBACK(on_start_menu_hidden) - ); -} - -// -// PUBLIC FUNCTIONS -// -GtkWidget* start_button_new(void) -{ - return GTK_WIDGET( - g_object_new(TYPE_START_BUTTON, NULL) - ); -} - -// -// CALLBACKS -// -static void on_clicked( - GtkButton* button, - WINTC_UNUSED(gpointer user_data) -) -{ - StartButton* start_button = START_BUTTON(button); - - if (start_button->priv->synchronizing) - { - return; - } - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) - { - start_menu_present(start_button->priv->menu); - } - else - { - start_menu_close(start_button->priv->menu); - } -} - -static void on_start_menu_hidden( - WINTC_UNUSED(GtkWidget* widget), - gpointer user_data -) -{ - StartButton* start_button = START_BUTTON(user_data); - - start_button->priv->synchronizing = TRUE; - - gtk_toggle_button_set_active( - GTK_TOGGLE_BUTTON(start_button), - FALSE - ); - - start_button->priv->synchronizing = FALSE; -} diff --git a/shell/taskband/src/start/startbutton.h b/shell/taskband/src/start/startbutton.h deleted file mode 100644 index 21eeee6..0000000 --- a/shell/taskband/src/start/startbutton.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __STARTBUTTON_H__ -#define __STARTBUTTON_H__ - -#include -#include - -#include "startmenu.h" - -G_BEGIN_DECLS - -// -// GTK OOP BOILERPLATE -// -typedef struct _StartButtonPrivate StartButtonPrivate; -typedef struct _StartButtonClass StartButtonClass; -typedef struct _StartButton StartButton; - -#define TYPE_START_BUTTON (start_button_get_type()) -#define START_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_START_BUTTON, StartButton)) -#define START_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_START_BUTTON, StartButtonClass)) -#define IS_START_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_START_BUTTON)) -#define IS_START_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_START_BUTTON)) -#define START_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_START_BUTTON, StartButtonClass)) - -GType start_button_get_type(void) G_GNUC_CONST; - -// -// PUBLIC FUNCTIONS -// -GtkWidget* start_button_new(void); - -G_END_DECLS - -#endif diff --git a/shell/taskband/src/start/startmenu.c b/shell/taskband/src/start/startmenu.c deleted file mode 100644 index eec2d4a..0000000 --- a/shell/taskband/src/start/startmenu.c +++ /dev/null @@ -1,592 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../meta.h" -#include "action.h" -#include "placeslist.h" -#include "programslist.h" -#include "startmenu.h" -#include "util.h" - -// -// STRUCTURE DEFINITIONS -// -struct _StartMenu -{ - GtkWidget* menu; - - GtkWidget* main_box; - GtkWidget* start_button; - GtkStyleProvider* userpic_style_provider; -}; - -// -// FORWARD DECLARATIONS -// -static void create_logoffpane_structure( - StartMenu* start_menu, - GtkBox* box -); -static void create_places_structure( - StartMenu* start_menu, - GtkBox* box -); -static void create_programs_structure( - StartMenu* start_menu, - GtkBox* box -); -static void create_taskcolumns_structure( - StartMenu* start_menu, - GtkBox* box -); -static void create_userpane_structure( - StartMenu* start_menu, - GtkBox* box -); -static void create_vertical_userpane_structure( - StartMenu* start_menu, - GtkBox* box -); -static void update_userpic( - StartMenu* start_menu -); - -static void on_action_button_clicked( - GtkButton* button, - gpointer user_data -); -static gboolean on_focus_out( - GtkWidget* widget, - GdkEvent* event, - gpointer user_data -); -static void on_selection_done( - GtkWidget* widget, - StartMenu* start_menu -); -static void on_userpic_clicked( - GtkWidget* userpic, - GdkEventButton* event -); - -// -// PUBLIC FUNCTIONS -// -void connect_start_menu_closed_signal( - StartMenu* start_menu, - GCallback callback -) -{ - g_signal_connect( - start_menu->menu, - "hide", - callback, - start_menu->start_button - ); -} - -void start_menu_close( - StartMenu* start_menu -) -{ - gtk_widget_hide(start_menu->menu); -} - -StartMenu* start_menu_new( - GtkWidget* start_button -) -{ - StartMenu* start_menu = g_new(StartMenu, 1); - - // On X11, we must use a GtkWindow, on Wayland we use a GtkPopover - the - // reason for this is because popovers cannot exist outside the bounds of - // the parent window on X11 - // - // We use a GtkWindow instead on X11 to work around that, using - // gtk_window_move() -- which obviously doesn't work on Wayland - // - // So... GtkWindow on X11, GtkPopover on Wayland :) - // - if (wintc_get_display_protocol_in_use() == WINTC_DISPPROTO_X11) - { - start_menu->menu = gtk_window_new(GTK_WINDOW_TOPLEVEL); - - // Set up hints - // - gtk_window_set_type_hint( - GTK_WINDOW(start_menu->menu), - GDK_WINDOW_TYPE_HINT_POPUP_MENU - ); - gtk_window_set_resizable( - GTK_WINDOW(start_menu->menu), - FALSE - ); - gtk_window_set_keep_above( - GTK_WINDOW(start_menu->menu), - TRUE - ); - gtk_window_stick(GTK_WINDOW(start_menu->menu)); - gtk_window_set_skip_taskbar_hint( - GTK_WINDOW(start_menu->menu), - TRUE - ); - gtk_window_set_title( - GTK_WINDOW(start_menu->menu), - "Start menu" - ); - gtk_widget_set_events( - GTK_WIDGET(start_menu->menu), - GDK_FOCUS_CHANGE_MASK - ); - - // Set up signals - // - g_signal_connect( - start_menu->menu, - "delete-event", - G_CALLBACK(gtk_widget_hide_on_delete), - NULL - ); - g_signal_connect( - start_menu->menu, - "focus-out-event", - G_CALLBACK(on_focus_out), - NULL - ); - - // Set titlebar to the fake titlebar box - // - GtkWidget* fake_titlebar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - gtk_window_set_titlebar( - GTK_WINDOW(start_menu->menu), - fake_titlebar - ); - } - else if (wintc_get_display_protocol_in_use() == WINTC_DISPPROTO_WAYLAND) - { - start_menu->menu = gtk_popover_new(start_button); - } - - // Set up structure - // - start_menu->main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - - create_userpane_structure(start_menu, GTK_BOX(start_menu->main_box)); - create_taskcolumns_structure(start_menu, GTK_BOX(start_menu->main_box)); - create_logoffpane_structure(start_menu, GTK_BOX(start_menu->main_box)); - - gtk_container_add(GTK_CONTAINER(start_menu->menu), start_menu->main_box); - - // Add style class - // - wintc_widget_add_style_class(GTK_WIDGET(start_menu->menu), "xp-start-menu"); - - gtk_widget_show_all(start_menu->main_box); - - // Attach button - // - start_menu->start_button = start_button; - - return start_menu; -} - -void start_menu_present( - StartMenu* start_menu -) -{ - gint height; - gint x; - gint y; - - if (wintc_get_display_protocol_in_use() == WINTC_DISPPROTO_X11) - { - gtk_window_present_with_time( - GTK_WINDOW(start_menu->menu), - GDK_CURRENT_TIME - ); - - height = gtk_widget_get_allocated_height(start_menu->main_box); - - gdk_window_get_origin( - gtk_widget_get_window(start_menu->start_button), - &x, - &y - ); - - gtk_window_move( - GTK_WINDOW(start_menu->menu), - x, - y - height - ); - } - else - { - gtk_widget_show(start_menu->menu); - } -} - -// -// PRIVATE FUNCTIONS -// -static void create_logoffpane_structure( - WINTC_UNUSED(StartMenu* start_menu), - GtkBox* box -) -{ - GtkWidget* logoffpane_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - // - // These are a couple ordinary buttons, except we have an extra box before the - // label so that themes can add an icon - // - // The reason for not using the gtk-icon-theme here is because the themes need - // to be able to override the image, AND they need to provide a 'hot' graphic for - // when the buttons are hovered - // - - // Log off button - // - GtkWidget* logoff_button = gtk_button_new(); - GtkWidget* logoff_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget* logoff_icon_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget* logoff_label = gtk_label_new(_("Log Off")); - - gtk_box_pack_start(GTK_BOX(logoff_box), logoff_icon_box, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(logoff_box), logoff_label, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(logoff_button), logoff_box); - - g_signal_connect( - G_OBJECT(logoff_button), - "clicked", - G_CALLBACK(on_action_button_clicked), - GINT_TO_POINTER(WINTC_ACTION_LOGOFF) - ); - - gtk_widget_set_tooltip_text( - logoff_button, - _("Provides options for closing your programs and logging off, or for leaving your programs running and switching to another user.") - ); - - wintc_widget_add_style_class(logoff_icon_box, "logoff-icon"); - - // Shut down button - // - GtkWidget* shutdown_button = gtk_button_new(); - GtkWidget* shutdown_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget* shutdown_icon_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget* shutdown_label = gtk_label_new(_("Turn Off Computer")); - - gtk_box_pack_start(GTK_BOX(shutdown_box), shutdown_icon_box, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(shutdown_box), shutdown_label, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(shutdown_button), shutdown_box); - - g_signal_connect( - G_OBJECT(shutdown_button), - "clicked", - G_CALLBACK(on_action_button_clicked), - GINT_TO_POINTER(WINTC_ACTION_SHUTDOWN) - ); - - gtk_widget_set_tooltip_text( - shutdown_button, - _("Provides options for turning off or restarting your computer, or for activating Stand By or Hibernate modes.") - ); - - wintc_widget_add_style_class(shutdown_icon_box, "shutdown-icon"); - - // Pack box - // - gtk_box_pack_end(GTK_BOX(logoffpane_box), shutdown_button, FALSE, FALSE, 0); - gtk_box_pack_end(GTK_BOX(logoffpane_box), logoff_button, FALSE, FALSE, 0); - gtk_box_pack_start(box, logoffpane_box, FALSE, FALSE, 0); - - // Add style class - // - wintc_widget_add_style_class(GTK_WIDGET(logoffpane_box), "xp-start-logoffpane"); -} - -static void create_places_structure( - StartMenu* start_menu, - GtkBox* box -) -{ - GtkWidget* places_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - - // Create menu - // - GtkWidget* places_list = GTK_WIDGET(g_object_new(TYPE_PLACES_LIST, NULL)); - - // Pack box - // - gtk_box_pack_start(GTK_BOX(places_box), places_list, TRUE, TRUE, 0); - gtk_box_pack_start(box, places_box, TRUE, TRUE, 0); - - // Set up signals - // - GList* menu_children = - gtk_container_get_children( - GTK_CONTAINER(places_list) - ); - - wintc_signal_connect_list( - menu_children, - "enter-notify-event", - G_CALLBACK(wintc_menu_shell_select_on_enter), - places_list - ); - wintc_signal_connect_list( - menu_children, - "leave-notify-event", - G_CALLBACK(wintc_menu_shell_deselect_on_leave), - places_list - ); - - g_list_free(g_steal_pointer(&menu_children)); - - g_signal_connect( - places_list, - "selection-done", - G_CALLBACK(on_selection_done), - start_menu - ); - - // Add style class - // - wintc_widget_add_style_class(GTK_WIDGET(places_box), "xp-start-places-column"); -} - -static void create_programs_structure( - StartMenu* start_menu, - GtkBox* box -) -{ - GtkWidget* programs_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - - // Create menu - // - GtkWidget* programs_list = GTK_WIDGET(g_object_new(TYPE_PROGRAMS_LIST, NULL)); - - // Pack box - // - gtk_box_pack_start(GTK_BOX(programs_box), programs_list, TRUE, TRUE, 0); - gtk_box_pack_start(box, programs_box, TRUE, TRUE, 0); - - // Set up signals - // - GList* menu_children = - gtk_container_get_children( - GTK_CONTAINER(programs_list) - ); - - wintc_signal_connect_list( - menu_children, - "enter-notify-event", - G_CALLBACK(wintc_menu_shell_select_on_enter), - programs_list - ); - wintc_signal_connect_list( - menu_children, - "leave-notify-event", - G_CALLBACK(wintc_menu_shell_deselect_on_leave), - programs_list - ); - - g_list_free(g_steal_pointer(&menu_children)); - - g_signal_connect( - programs_list, - "selection-done", - G_CALLBACK(on_selection_done), - start_menu - ); - - // Add style class - // - wintc_widget_add_style_class(GTK_WIDGET(programs_box), "xp-start-programs-column"); -} - -static void create_taskcolumns_structure( - StartMenu* start_menu, - GtkBox* box -) -{ - // Create structure - // - GtkWidget* columns_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - create_vertical_userpane_structure(start_menu, GTK_BOX(columns_box)); - create_programs_structure(start_menu, GTK_BOX(columns_box)); - create_places_structure(start_menu, GTK_BOX(columns_box)); - - gtk_box_pack_start(box, columns_box, TRUE, TRUE, 0); - - // Add style class - // - wintc_widget_add_style_class(GTK_WIDGET(columns_box), "xp-start-columns"); -} - -static void create_userpane_structure( - StartMenu* start_menu, - GtkBox* box -) -{ - GtkWidget* userpane_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - // User profile picture - // - GtkStyleContext* context; - GtkWidget* pic_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget* pic_event_box = gtk_event_box_new(); - - start_menu->userpic_style_provider = - GTK_STYLE_PROVIDER(gtk_css_provider_new()); - - context = gtk_widget_get_style_context(pic_box); - - gtk_style_context_add_provider( - context, - start_menu->userpic_style_provider, - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION - ); - - update_userpic(start_menu); - - gtk_widget_set_events(pic_event_box, GDK_BUTTON_PRESS_MASK); - gtk_box_pack_start(GTK_BOX(pic_box), pic_event_box, TRUE, TRUE, 0); - - g_signal_connect( - pic_event_box, - "button-press-event", - G_CALLBACK(on_userpic_clicked), - NULL - ); - - // Username display - // - struct passwd* user_pwd = getpwuid(getuid()); - - GtkWidget* username_label = gtk_label_new(user_pwd->pw_name); - - // Construct box - // - gtk_box_pack_start(GTK_BOX(userpane_box), pic_box, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(userpane_box), username_label, FALSE, FALSE, 0); - - gtk_box_pack_start(box, userpane_box, FALSE, FALSE, 0); - - // Add style class - // - wintc_widget_add_style_class(userpane_box, "xp-start-userpane"); -} - -static void create_vertical_userpane_structure( - WINTC_UNUSED(StartMenu* start_menu), - GtkBox* box -) -{ - GtkWidget* userpane_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - - // Username display - // - struct passwd* user_pwd = getpwuid(getuid()); - - GtkWidget* username_label = gtk_label_new(user_pwd->pw_name); - - gtk_label_set_angle(GTK_LABEL(username_label), 90); - - // Construct box - // - gtk_box_pack_end(GTK_BOX(userpane_box), username_label, FALSE, FALSE, 0); - - gtk_box_pack_start(box, userpane_box, FALSE, FALSE, 0); - - // Add style class - // - wintc_widget_add_style_class(userpane_box, "xp-start-vuserpane"); -} - -static void update_userpic( - StartMenu* start_menu -) -{ - static gchar* css = NULL; - - if (css == NULL) - { - // FIXME: This should read from whatever the XDG path is, probably needs a - // g_strdup_printf for the username - // - css = "* { background-image: url('" WINTC_ASSETS_DIR "/shell-res/fpo-userpic.png'); }"; - } - - // Give GTK a bump that we want to update the pic - // - gtk_css_provider_load_from_data( - GTK_CSS_PROVIDER(start_menu->userpic_style_provider), - css, - -1, - NULL - ); -} - -// -// CALLBACKS -// -static void on_action_button_clicked( - WINTC_UNUSED(GtkButton* button), - gpointer user_data -) -{ - launch_action(GPOINTER_TO_INT(user_data)); -} - -static gboolean on_focus_out( - GtkWidget* widget, - WINTC_UNUSED(GdkEvent* event), - WINTC_UNUSED(gpointer user_data) -) -{ - gtk_widget_hide(widget); - return TRUE; -} - -static void on_selection_done( - WINTC_UNUSED(GtkWidget* widget), - StartMenu* start_menu -) -{ - gtk_widget_hide(GTK_WIDGET(start_menu->menu)); -} - -static void on_userpic_clicked( - WINTC_UNUSED(GtkWidget* userpic), - GdkEventButton* event -) -{ - // - // FIXME: Implement this when the user pic cpl is done! - // - if (event->button > 1) - { - return; - } - - GError* error = NULL; - - g_set_error( - &error, - WINTC_GENERAL_ERROR, - WINTC_GENERAL_ERROR_NOTIMPL, - "Cannot edit user pic yet!" - ); - - wintc_nice_error_and_clear(&error); -} diff --git a/shell/taskband/src/start/startmenu.h b/shell/taskband/src/start/startmenu.h deleted file mode 100644 index b272360..0000000 --- a/shell/taskband/src/start/startmenu.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __STARTMENU_H__ -#define __STARTMENU_H__ - -#include - -// -// STRUCTURE DEFINITIONS -// -typedef struct _StartMenu StartMenu; - -// -// PUBLIC FUNCTIONS -// -void connect_start_menu_closed_signal( - StartMenu* start_menu, - GCallback callback -); - -void start_menu_close( - StartMenu* start_menu -); - -StartMenu* start_menu_new( - GtkWidget* start_button -); - -void start_menu_present( - StartMenu* start_menu -); - -#endif diff --git a/shell/taskband/src/start/startmenuitem.c b/shell/taskband/src/start/startmenuitem.c deleted file mode 100644 index 32b1377..0000000 --- a/shell/taskband/src/start/startmenuitem.c +++ /dev/null @@ -1,478 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../meta.h" -#include "action.h" -#include "startmenuitem.h" -#include "util.h" - -// -// GTK OOP CLASS/INSTANCE DEFINITIONS -// -struct _StartMenuItemPrivate -{ - StartMenuItem* menuitem; - - WinTCAction action; - gchar* cmdline; - gboolean is_action; - - GtkWidget* icon; - GtkWidget* label; - GtkWidget* label_generic; -}; - -struct _StartMenuItemClass -{ - GtkMenuItemClass __parent__; -}; - -struct _StartMenuItem -{ - GtkMenuItem __parent__; - - StartMenuItemPrivate* priv; -}; - -// -// FORWARD DECLARATIONS -// -static void start_menu_item_finalize( - GObject* object -); - -static GtkWidget* start_menu_item_new_manual( - const gchar* icon_name, - const gchar* program_name, - const gchar* comment, - const gchar* generic_name -); - -static void on_menu_item_activate( - GtkWidget* widget, - gpointer user_data -); - -// -// GTK TYPE DEFINITIONS & CTORS -// -G_DEFINE_TYPE_WITH_CODE( - StartMenuItem, - start_menu_item, - GTK_TYPE_MENU_ITEM, - G_ADD_PRIVATE(StartMenuItem) -) - -static void start_menu_item_class_init( - StartMenuItemClass* klass -) -{ - GObjectClass* gclass = G_OBJECT_CLASS(klass); - - gclass->finalize = start_menu_item_finalize; -} - -static void start_menu_item_init( - StartMenuItem* self -) -{ - self->priv = start_menu_item_get_instance_private(self); - - g_signal_connect( - G_OBJECT(self), - "activate", - G_CALLBACK(on_menu_item_activate), - NULL - ); -} - -// -// FINALIZE -// -static void start_menu_item_finalize( - GObject* object -) -{ - StartMenuItem* start_menu_item = START_MENU_ITEM(object); - - if (start_menu_item->priv->cmdline != NULL) - { - g_free(start_menu_item->priv->cmdline); - } - - (*G_OBJECT_CLASS(start_menu_item_parent_class)->finalize) (object); -} - -// -// PUBLIC FUNCTIONS -// -GtkWidget* start_menu_item_new_from_action( - WinTCAction action -) -{ - const gchar* comment; - const gchar* icon_name; - const gchar* name; - GtkWidget* start_menu_item; - - switch (action) - { - case WINTC_ACTION_MYDOCS: - comment = _("Opens the My Documents folder, where you can store letters, reports, notes, and other kinds of documents."); - icon_name = "folder-documents"; - name = wintc_get_place_name(WINTC_PLACE_DOCUMENTS); - break; - - case WINTC_ACTION_MYRECENTS: - comment = _("Displays recently opened documents and folders."); - icon_name = "document-open-recent"; - name = wintc_get_place_name(WINTC_PLACE_RECENTS); - break; - - case WINTC_ACTION_MYPICS: - comment = _("Opens the My Pictures folder, where you can store digital photos, images, and graphics files."); - icon_name = "folder-pictures"; - name = wintc_get_place_name(WINTC_PLACE_PICTURES); - break; - - case WINTC_ACTION_MYMUSIC: - comment = _("Opens the My Music folder, where you can store music and other audio files."); - icon_name = "folder-music"; - name = wintc_get_place_name(WINTC_PLACE_MUSIC); - break; - - case WINTC_ACTION_MYCOMP: - comment = _("Gives access to, and information about, the disk drives, cameras, scanners, and other hardware connected to your computer."); - icon_name = "computer"; - name = wintc_get_place_name(WINTC_PLACE_DRIVES); - break; - - case WINTC_ACTION_CONTROL: - comment = _("Provides options for you to customize the appearance and functionality of your computer, add or remove programs, and set up network connections and user accounts."); - icon_name = "preferences-other"; - name = wintc_get_place_name(WINTC_PLACE_CONTROLPANEL); - break; - - case WINTC_ACTION_MIMEMGMT: - comment = _("Chooses default programs for certain activities, such as Web browsing or sending e-mail, and specifies which programs are accessible from the Start menu, desktop, and other locations."); - icon_name = "preferences-desktop-default-applications"; - name = _("Set Program Access and Defaults"); - break; - - case WINTC_ACTION_CONNECTTO: - comment = _("Connects to other computers, networks, and the Internet."); - icon_name = "preferences-system-network"; - name = _("Connect To"); - break; - - case WINTC_ACTION_PRINTERS: - comment = _("Shows installed printers and fax printers and helps you add new ones."); - icon_name = "printer"; - name = wintc_get_place_name(WINTC_PLACE_PRINTERS); - break; - - case WINTC_ACTION_HELP: - comment = _("Opens a central location for Help topics, tutorials, troubleshooting, and other support services."); - icon_name = "help-browser"; - name = _("Help and Support"); - break; - - case WINTC_ACTION_SEARCH: - comment = _("Opens a window where you can pick search options and work with search results."); - icon_name = "system-search"; - name = _("Search"); - break; - - case WINTC_ACTION_RUN: - comment = _("Opens a program, folder, document, or Web site."); - icon_name = "system-run"; - name = _("Run..."); - break; - - default: - comment = "Unknown action."; - icon_name = "dialog-error"; - name = "Unknown"; - break; - } - - - start_menu_item = - start_menu_item_new_manual( - icon_name, - name, - comment, - NULL - ); - - // Add action state - // - (START_MENU_ITEM(start_menu_item))->priv->action = action; - (START_MENU_ITEM(start_menu_item))->priv->is_action = TRUE; - - return start_menu_item; -} - -GtkWidget* start_menu_item_new_from_desktop_entry( - GDesktopAppInfo* entry, - const gchar* generic_name, - const gchar* comment -) -{ - // FIXME: Temp bodge for handling NULL desktop entry (handle properly in - // programslist.c) - // - // (We just insert a default item to open the MIME management action) - // - if (entry == NULL) - { - GtkWidget* null_menu_item = - start_menu_item_new_manual( - "important", - "Click to specify a default", - comment != NULL ? comment : "No default program could be identified.", - generic_name - ); - - (START_MENU_ITEM(null_menu_item))->priv->action = WINTC_ACTION_MIMEMGMT; - (START_MENU_ITEM(null_menu_item))->priv->is_action = TRUE; - - return null_menu_item; - } - - // Normal code - desktop entry actually exists! Wahey! - // - GAppInfo* app_info = G_APP_INFO(entry); - - const gchar* app_desc = g_app_info_get_description(app_info); - const gchar* exe_path = g_app_info_get_executable(app_info); - const gchar* name = g_app_info_get_name(app_info); - - gchar* exe_name = g_path_get_basename(exe_path); - - GtkWidget* start_menu_item = - start_menu_item_new_manual( - exe_name, - name, - comment != NULL ? comment : app_desc, - generic_name - ); - - (START_MENU_ITEM(start_menu_item))->priv->cmdline = - wintc_desktop_app_info_get_command(entry); - - g_free(exe_name); - - return start_menu_item; -} - -GtkWidget* start_menu_item_new_from_garcon_item( - GarconMenuItem* item, - const gchar* generic_name, - const gchar* comment -) -{ - GtkWidget* start_menu_item = - start_menu_item_new_manual( - garcon_menu_item_get_icon_name(item), - garcon_menu_item_get_name(item), - comment != NULL ? - comment : - garcon_menu_item_get_comment(item), - generic_name - ); - - (START_MENU_ITEM(start_menu_item))->priv->cmdline = - garcon_menu_item_get_command_expanded(item); - - return start_menu_item; -} - -void start_menu_item_set_icon_size( - StartMenuItem* item, - gint size -) -{ - g_assert(item->priv->icon != NULL); - - gtk_image_set_pixel_size( - GTK_IMAGE(item->priv->icon), - size - ); -} - -// -// PRIVATE FUNCTIONS -// -static GtkWidget* start_menu_item_new_manual( - const gchar* icon_name, - const gchar* program_name, - const gchar* comment, - const gchar* generic_name -) -{ - StartMenuItem* start_menu_item = - START_MENU_ITEM(g_object_new(TYPE_START_MENU_ITEM, NULL)); - - // Application icon - // - start_menu_item->priv->icon = - gtk_image_new_from_icon_name( - icon_name, - GTK_ICON_SIZE_MENU - ); - - // Depending on if a generic name is specified, we create either a normal item or - // a 'default' item (the kind that go at the top of the Start menu) - // - if (generic_name == NULL) // Normal item - { - // Program name - // - start_menu_item->priv->label = - gtk_label_new(program_name); - - // Set up structure - // - GtkWidget* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - gtk_box_pack_start( - GTK_BOX(box), - start_menu_item->priv->icon, - FALSE, - FALSE, - 0 - ); - gtk_box_pack_start( - GTK_BOX(box), - start_menu_item->priv->label, - FALSE, - FALSE, - 0 - ); - - gtk_container_add(GTK_CONTAINER(start_menu_item), box); - } - else // Default item - { - // Add style class to distinguish this menu item - // - wintc_widget_add_style_class( - GTK_WIDGET(start_menu_item), - "xp-start-default-item" - ); - - // Generic program type - // - start_menu_item->priv->label_generic = - gtk_label_new(generic_name); - - gtk_widget_set_halign( - start_menu_item->priv->label_generic, - GTK_ALIGN_START - ); - - // Program name - // - start_menu_item->priv->label = - gtk_label_new(program_name); - - // Set up structure - // - GtkWidget* outer_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget* label_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - - gtk_widget_set_valign(label_box, GTK_ALIGN_CENTER); - - gtk_box_pack_start( - GTK_BOX(label_box), - start_menu_item->priv->label_generic, - FALSE, - FALSE, - 0 - ); - gtk_box_pack_start( - GTK_BOX(label_box), - start_menu_item->priv->label, - FALSE, - FALSE, - 0 - ); - - gtk_box_pack_start( - GTK_BOX(outer_box), - start_menu_item->priv->icon, - FALSE, - FALSE, - 0 - ); - gtk_box_pack_start( - GTK_BOX(outer_box), - label_box, - FALSE, - FALSE, - 0 - ); - - gtk_container_add(GTK_CONTAINER(start_menu_item), outer_box); - } - - // Set program name line wrapping - // - gtk_label_set_line_wrap( - GTK_LABEL(start_menu_item->priv->label), - TRUE - ); - gtk_label_set_max_width_chars( - GTK_LABEL(start_menu_item->priv->label), - 24 - ); - gtk_label_set_xalign( - GTK_LABEL(start_menu_item->priv->label), - 0.0 - ); - - // Add program comment - // - if (comment != NULL) - { - gchar* real_comment = wintc_str_set_suffix(comment, "."); - - gtk_widget_set_tooltip_text( - GTK_WIDGET(start_menu_item), - real_comment - ); - - g_free(real_comment); - } - - return GTK_WIDGET(start_menu_item); -} - -// -// CALLBACKS -// -static void on_menu_item_activate( - GtkWidget* widget, - WINTC_UNUSED(gpointer user_data) -) -{ - StartMenuItem* start_menu_item = START_MENU_ITEM(widget); - - if (start_menu_item->priv->is_action) - { - launch_action(start_menu_item->priv->action); - } - else - { - launch_command(start_menu_item->priv->cmdline); - } -} diff --git a/shell/taskband/src/start/startmenuitem.h b/shell/taskband/src/start/startmenuitem.h deleted file mode 100644 index 26a6f52..0000000 --- a/shell/taskband/src/start/startmenuitem.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __STARTMENUITEM_H__ -#define __STARTMENUITEM_H__ - -#include -#include -#include -#include -#include - -G_BEGIN_DECLS - -// -// GTK OOP BOILERPLATE -// -typedef struct _StartMenuItemPrivate StartMenuItemPrivate; -typedef struct _StartMenuItemClass StartMenuItemClass; -typedef struct _StartMenuItem StartMenuItem; - -#define TYPE_START_MENU_ITEM (start_menu_item_get_type()) -#define START_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_START_MENU_ITEM, StartMenuItem)) -#define START_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_START_MENU_ITEM, StartMenuItemClass)) -#define IS_START_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_START_MENU_ITEM)) -#define IS_START_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_START_MENU_ITEM)) -#define START_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_START_MENU_ITEM, StartMenuItemClass)) - -GType start_menu_item_get_type(void) G_GNUC_CONST; - -// -// PUBLIC FUNCTIONS -// -GtkWidget* start_menu_item_new_from_action( - WinTCAction action -); -GtkWidget* start_menu_item_new_from_desktop_entry( - GDesktopAppInfo* entry, - const gchar* generic_name, - const gchar* comment -); -GtkWidget* start_menu_item_new_from_garcon_item( - GarconMenuItem* item, - const gchar* generic_name, - const gchar* comment -); -void start_menu_item_set_icon_size( - StartMenuItem* item, - gint size -); - -G_END_DECLS - -#endif diff --git a/shell/taskband/src/start/toolbar.c b/shell/taskband/src/start/toolbar.c new file mode 100644 index 0000000..503263d --- /dev/null +++ b/shell/taskband/src/start/toolbar.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include + +#include "../toolbar.h" +#include "personal.h" +#include "shared.h" +#include "toolbar.h" + +// +// FORWARD DECLARATIONS +// +static void wintc_toolbar_start_dispose( + GObject* object +); + +static void on_start_button_toggled( + GtkToggleButton* self, + gpointer user_data +); + +// +// GTK TYPE DEFINITION & CTORS +// +G_DEFINE_TYPE( + WinTCToolbarStart, + wintc_toolbar_start, + TYPE_WINTC_TASKBAND_TOOLBAR +) + +static void wintc_toolbar_start_class_init( + WinTCToolbarStartClass* klass +) +{ + GObjectClass* object_class = G_OBJECT_CLASS(klass); + + 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; + self->sync_menu_should_close = FALSE; + + // Apply stylesheet for this toolbar + // + GtkCssProvider* css = gtk_css_provider_new(); + + gtk_css_provider_load_from_resource( + css, + "/uk/oddmatics/wintc/taskband/start-menu.css" + ); + + gtk_style_context_add_provider_for_screen( + gdk_screen_get_default(), + GTK_STYLE_PROVIDER(css), + GTK_STYLE_PROVIDER_PRIORITY_FALLBACK + ); + + // Create root widget (Start button) + // + builder = + gtk_builder_new_from_resource( + "/uk/oddmatics/wintc/taskband/start-button.ui" + ); + + wintc_preprocess_builder_widget_text(builder); + + toolbar->widget_root = + GTK_WIDGET( + g_object_ref_sink( + gtk_builder_get_object(builder, "start-button") + ) + ); + + g_object_unref(G_OBJECT(builder)); + + // Create Start menu widget + // 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); + + // Attach signals for popup + // + g_signal_connect( + toolbar->widget_root, + "toggled", + G_CALLBACK(on_start_button_toggled), + self + ); +} + +// +// 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); + + // FIXME: Only worrying about destroying the personal menu for now until + // the classic menu is available + // + destroy_personal_menu(toolbar_start); + + (G_OBJECT_CLASS(wintc_toolbar_start_parent_class))->dispose(object); +} + +// +// CALLBACKS +// +static void on_start_button_toggled( + GtkToggleButton* self, + gpointer user_data +) +{ + WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(user_data); + + if (toolbar_start->sync_button) + { + return; + } + + // FIXME: Only dealing with personal menu here until class menu exists + // + if (gtk_toggle_button_get_active(self)) + { + open_personal_menu(toolbar_start); + } + else + { + close_personal_menu(toolbar_start); + } +} + diff --git a/shell/taskband/src/start/toolbar.h b/shell/taskband/src/start/toolbar.h new file mode 100644 index 0000000..557d5a2 --- /dev/null +++ b/shell/taskband/src/start/toolbar.h @@ -0,0 +1,20 @@ +#ifndef __TOOLBAR_START_H__ +#define __TOOLBAR_START_H__ + +#include +#include + +// +// GTK OOP BOILERPLATE +// +#define TYPE_WINTC_TOOLBAR_START (wintc_toolbar_start_get_type()) +#define WINTC_TOOLBAR_START(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_TOOLBAR_START, WinTCToolbarStart)) +#define WINTC_TOOLBAR_START_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_TOOLBAR_START, WinTCToolbarStartClass)) +#define IS_WINTC_TOOLBAR_START(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_TOOLBAR_START)) +#define IS_WINTC_TOOLBAR_START_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_TOOLBAR_START)) +#define WINTC_TOOLBAR_START_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_WINTC_TOOLBAR_START, WinTCToolbarStart)) + +GType wintc_toolbar_start_get_type(void) G_GNUC_CONST; + +#endif + diff --git a/shell/taskband/src/systray/toolbar.c b/shell/taskband/src/systray/toolbar.c new file mode 100644 index 0000000..596c3bb --- /dev/null +++ b/shell/taskband/src/systray/toolbar.c @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "../toolbar.h" +#include "notifarea.h" +#include "toolbar.h" + +// +// GTK OOP CLASS/INSTANCE DEFINITIONS +// +struct _WinTCToolbarNotifAreaClass +{ + WinTCTaskbandToolbarClass __parent__; +}; + +struct _WinTCToolbarNotifArea +{ + WinTCTaskbandToolbar __parent__; +}; + +// +// GTK TYPE DEFINITION & CTORS +// +G_DEFINE_TYPE( + WinTCToolbarNotifArea, + wintc_toolbar_notif_area, + TYPE_WINTC_TASKBAND_TOOLBAR +) + +static void wintc_toolbar_notif_area_class_init( + WINTC_UNUSED(WinTCToolbarNotifAreaClass* klass) +) {} + +static void wintc_toolbar_notif_area_init( + WinTCToolbarNotifArea* self +) +{ + WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(self); + + toolbar->widget_root = notification_area_new(); +} + diff --git a/shell/taskband/src/systray/toolbar.h b/shell/taskband/src/systray/toolbar.h new file mode 100644 index 0000000..5d573ca --- /dev/null +++ b/shell/taskband/src/systray/toolbar.h @@ -0,0 +1,23 @@ +#ifndef __TOOLBAR_NOTIF_AREA_H__ +#define __TOOLBAR_NOTIF_AREA_H__ + +#include +#include + +// +// GTK OOP BOILERPLATE +// +typedef struct _WinTCToolbarNotifAreaClass WinTCToolbarNotifAreaClass; +typedef struct _WinTCToolbarNotifArea WinTCToolbarNotifArea; + +#define TYPE_WINTC_TOOLBAR_NOTIF_AREA (wintc_toolbar_notif_area_get_type()) +#define WINTC_TOOLBAR_NOTIF_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_TOOLBAR_NOTIF_AREA, WinTCToolbarNotifArea)) +#define WINTC_TOOLBAR_NOTIF_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_TOOLBAR_NOTIF_AREA, WinTCToolbarNotifAreaClass)) +#define IS_WINTC_TOOLBAR_NOTIF_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_TOOLBAR_NOTIF_AREA)) +#define IS_WINTC_TOOLBAR_NOTIF_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_TOOLBAR_NOTIF_AREA)) +#define WINTC_TOOLBAR_NOTIF_AREA_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_WINTC_TOOLBAR_NOTIF_AREA, WinTCToolbarNotifArea)) + +GType wintc_toolbar_notif_area_get_type(void) G_GNUC_CONST; + +#endif + diff --git a/shell/taskband/src/systray/volume.c b/shell/taskband/src/systray/volume.c index ff71ddf..99298d5 100644 --- a/shell/taskband/src/systray/volume.c +++ b/shell/taskband/src/systray/volume.c @@ -144,7 +144,7 @@ static void wintc_notification_volume_constructed( // Connect up to the notification icon widget // volume->popup_volmgmt = - wintc_dpa_create_popup(behaviour->widget_notif); + wintc_dpa_create_popup(behaviour->widget_notif, FALSE); volume->box_container = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); volume->check_mute = gtk_check_button_new_with_label("Mute"); diff --git a/shell/taskband/src/taskbuttons/toolbar.c b/shell/taskband/src/taskbuttons/toolbar.c new file mode 100644 index 0000000..8e70bbd --- /dev/null +++ b/shell/taskband/src/taskbuttons/toolbar.c @@ -0,0 +1,45 @@ +#include +#include +#include + +#include "../toolbar.h" +#include "taskbuttonbar.h" +#include "toolbar.h" + +// +// GTK OOP CLASS/INSTANCE DEFINITIONS +// +struct _WinTCToolbarTaskButtonsClass +{ + WinTCTaskbandToolbarClass __parent__; +}; + +struct _WinTCToolbarTaskButtons +{ + WinTCTaskbandToolbar __parent__; +}; + +// +// GTK TYPE DEFINITION & CTORS +// +G_DEFINE_TYPE( + WinTCToolbarTaskButtons, + wintc_toolbar_task_buttons, + TYPE_WINTC_TASKBAND_TOOLBAR +) + +static void wintc_toolbar_task_buttons_class_init( + WINTC_UNUSED(WinTCToolbarTaskButtonsClass* klass) +) {} + +static void wintc_toolbar_task_buttons_init( + WinTCToolbarTaskButtons* self +) +{ + WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(self); + + // Create root widget + // + toolbar->widget_root = taskbutton_bar_new(); +} + diff --git a/shell/taskband/src/taskbuttons/toolbar.h b/shell/taskband/src/taskbuttons/toolbar.h new file mode 100644 index 0000000..3106cad --- /dev/null +++ b/shell/taskband/src/taskbuttons/toolbar.h @@ -0,0 +1,23 @@ +#ifndef __TOOLBAR_TASK_BUTTONS_H__ +#define __TOOLBAR_TASK_BUTTONS_H__ + +#include +#include + +// +// GTK OOP BOILERPLATE +// +typedef struct _WinTCToolbarTaskButtonsClass WinTCToolbarTaskButtonsClass; +typedef struct _WinTCToolbarTaskButtons WinTCToolbarTaskButtons; + +#define TYPE_WINTC_TOOLBAR_TASK_BUTTONS (wintc_toolbar_task_buttons_get_type()) +#define WINTC_TOOLBAR_TASK_BUTTONS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_TOOLBAR_TASK_BUTTONS, WinTCToolbarTaskButtons)) +#define WINTC_TOOLBAR_TASK_BUTTONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_TOOLBAR_TASK_BUTTONS, WinTCToolbarTaskButtonsClass)) +#define IS_WINTC_TOOLBAR_TASK_BUTTONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_TOOLBAR_TASK_BUTTONS)) +#define IS_WINTC_TOOLBAR_TASK_BUTTONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_TOOLBAR_TASK_BUTTONS)) +#define WINTC_TOOLBAR_TASK_BUTTONS_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_WINTC_TOOLBAR_TASK_BUTTONS, WinTCToolbarTaskButtons)) + +GType wintc_toolbar_task_buttons_get_type(void) G_GNUC_CONST; + +#endif + diff --git a/shell/taskband/src/toolbar.c b/shell/taskband/src/toolbar.c new file mode 100644 index 0000000..f8415d0 --- /dev/null +++ b/shell/taskband/src/toolbar.c @@ -0,0 +1,94 @@ +#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 new file mode 100644 index 0000000..c606e07 --- /dev/null +++ b/shell/taskband/src/toolbar.h @@ -0,0 +1,38 @@ +#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 TYPE_WINTC_TASKBAND_TOOLBAR (wintc_taskband_toolbar_get_type()) +#define WINTC_TASKBAND_TOOLBAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_TASKBAND_TOOLBAR, WinTCTaskbandToolbar)) +#define WINTC_TASKBAND_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_TASKBAND_TOOLBAR, WinTCTaskbandToolbarClass)) +#define IS_WINTC_TASKBAND_TOOLBAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_TASKBAND_TOOLBAR)) +#define IS_WINTC_TASKBAND_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_TASKBAND_TOOLBAR)) +#define WINTC_TASKBAND_TOOLBAR_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_WINTC_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 5b63c9d..ccd9e8c 100644 --- a/shell/taskband/src/window.c +++ b/shell/taskband/src/window.c @@ -5,24 +5,57 @@ #include #include "application.h" +#include "toolbar.h" #include "window.h" -#include "start/startbutton.h" -#include "systray/notifarea.h" -#include "taskbuttons/taskbuttonbar.h" -#include "taskbuttons/windowmonitor.h" +#include "start/toolbar.h" +#include "systray/toolbar.h" +#include "taskbuttons/toolbar.h" + +#define TASKBAND_HEIGHT 30 + +// +// PRIVATE ENUMS +// +typedef enum +{ + WINTC_TASKBAND_TOOLBAR_START, + WINTC_TASKBAND_TOOLBAR_QUICK_ACCESS, + WINTC_TASKBAND_TOOLBAR_PRE_BUTTONS, + WINTC_TASKBAND_TOOLBAR_BUTTONS, + WINTC_TASKBAND_TOOLBAR_POST_BUTTONS, + WINTC_TASKBAND_TOOLBAR_NOTIFICATION_AREA +} WinTCTaskbandToolbarId; + +// +// FORWARD DECLARATIONS +// +static void wintc_taskband_window_create_toolbar( + WinTCTaskbandWindow* taskband, + GType toolbar_type, + gboolean expand +); + +static gboolean on_window_map_event( + GtkWidget* self, + GdkEventAny* event, + gpointer user_data +); + +// +// STATIC DATA +// +static const WinTCTaskbandToolbarId s_layout[] = { + WINTC_TASKBAND_TOOLBAR_START, + WINTC_TASKBAND_TOOLBAR_QUICK_ACCESS, + WINTC_TASKBAND_TOOLBAR_PRE_BUTTONS, + WINTC_TASKBAND_TOOLBAR_BUTTONS, + WINTC_TASKBAND_TOOLBAR_POST_BUTTONS, + WINTC_TASKBAND_TOOLBAR_NOTIFICATION_AREA +}; // // GTK OOP CLASS/INSTANCE DEFINITIONS // -struct _WinTCTaskbandWindowPrivate -{ - GtkWidget* main_box; - - GtkWidget* notification_area; - GtkWidget* start_button; - GtkWidget* taskbuttons; -}; - struct _WinTCTaskbandWindowClass { GtkApplicationWindowClass __parent__; @@ -32,17 +65,20 @@ struct _WinTCTaskbandWindow { GtkApplicationWindow __parent__; - WinTCTaskbandWindowPrivate* priv; + GtkWidget* main_box; + + GtkWidget* notification_area; + GtkWidget* start_button; + GtkWidget* taskbuttons; }; // // GTK TYPE DEFINITION & CTORS // -G_DEFINE_TYPE_WITH_CODE( +G_DEFINE_TYPE( WinTCTaskbandWindow, wintc_taskband_window, - GTK_TYPE_APPLICATION_WINDOW, - G_ADD_PRIVATE(WinTCTaskbandWindow) + GTK_TYPE_APPLICATION_WINDOW ) static void wintc_taskband_window_class_init( @@ -53,8 +89,6 @@ static void wintc_taskband_window_init( WinTCTaskbandWindow* self ) { - self->priv = wintc_taskband_window_get_instance_private(self); - // // WINDOW SETUP // @@ -63,71 +97,27 @@ static void wintc_taskband_window_init( "wintc-taskband" ); + // FIXME: This is obviously hard coded rubbish! + // + gtk_widget_set_size_request(GTK_WIDGET(self), -1, TASKBAND_HEIGHT); wintc_anchor_taskband_to_bottom(GTK_WINDOW(self)); - // - // SET UP CHILDREN IN HERE - // FIXME: Tidy all this stuff up big time! Taskband shouldn't know about - // how stuff is built, just ask for a Start button, a taskbar, and - // systray -- no implementation details!! - // - // Create main container box // - self->priv->main_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + self->main_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_add( GTK_CONTAINER(self), - self->priv->main_box + self->main_box ); - // Create Start button and menu + // Connect to map-event signal to spawn toolbars once the window opens // - GtkCssProvider* css_start = gtk_css_provider_new(); - - gtk_css_provider_load_from_resource( - css_start, - "/uk/oddmatics/wintc/taskband/start-menu.css" - ); - - gtk_style_context_add_provider_for_screen( - gdk_screen_get_default(), - GTK_STYLE_PROVIDER(css_start), - GTK_STYLE_PROVIDER_PRIORITY_FALLBACK - ); - - self->priv->start_button = start_button_new(); - - gtk_box_pack_start( - GTK_BOX(self->priv->main_box), - self->priv->start_button, - FALSE, - FALSE, - 0 - ); - - // Create task buttons - // - self->priv->taskbuttons = taskbutton_bar_new(); - - gtk_box_pack_start( - GTK_BOX(self->priv->main_box), - self->priv->taskbuttons, - TRUE, - TRUE, - 0 - ); - - // Create notification area - // - self->priv->notification_area = notification_area_new(); - - gtk_box_pack_end( - GTK_BOX(self->priv->main_box), - self->priv->notification_area, - FALSE, - FALSE, - 0 + g_signal_connect( + self, + "map-event", + G_CALLBACK(on_window_map_event), + NULL ); } @@ -150,3 +140,81 @@ GtkWidget* wintc_taskband_window_new( ) ); } + +// +// PRIVATE FUNCTIONS +// +static void 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 + ); + + gtk_box_pack_start( + GTK_BOX(taskband->main_box), + root, + expand, + expand, + 0 + ); + + gtk_widget_show_all(root); +} + +// +// CALLBACKS +// +static gboolean on_window_map_event( + GtkWidget* self, + WINTC_UNUSED(GdkEventAny* event), + WINTC_UNUSED(gpointer user_data) +) +{ + WinTCTaskbandWindow* taskband = WINTC_TASKBAND_WINDOW(self); + + // Spawn toolbars + // + for (guint i = 0; i < G_N_ELEMENTS(s_layout); i++) + { + switch (s_layout[i]) + { + case WINTC_TASKBAND_TOOLBAR_START: + wintc_taskband_window_create_toolbar( + taskband, + TYPE_WINTC_TOOLBAR_START, + FALSE + ); + break; + + case WINTC_TASKBAND_TOOLBAR_BUTTONS: + wintc_taskband_window_create_toolbar( + taskband, + TYPE_WINTC_TOOLBAR_TASK_BUTTONS, + TRUE + ); + break; + + case WINTC_TASKBAND_TOOLBAR_NOTIFICATION_AREA: + wintc_taskband_window_create_toolbar( + taskband, + TYPE_WINTC_TOOLBAR_NOTIF_AREA, + FALSE + ); + 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]); + break; + } + } + + return TRUE; +} + diff --git a/shell/taskband/src/window.h b/shell/taskband/src/window.h index a319e97..7d6ea5a 100644 --- a/shell/taskband/src/window.h +++ b/shell/taskband/src/window.h @@ -9,7 +9,6 @@ // // GTK OOP BOILERPLATE // -typedef struct _WinTCTaskbandWindowPrivate WinTCTaskbandWindowPrivate; typedef struct _WinTCTaskbandWindowClass WinTCTaskbandWindowClass; typedef struct _WinTCTaskbandWindow WinTCTaskbandWindow; @@ -30,3 +29,4 @@ GtkWidget* wintc_taskband_window_new( ); #endif + diff --git a/themes/build-common/gtk-3.0-base/override/xp-start-plugin.scss b/themes/build-common/gtk-3.0-base/override/xp-start-plugin.scss index f771a7f..7e70945 100644 --- a/themes/build-common/gtk-3.0-base/override/xp-start-plugin.scss +++ b/themes/build-common/gtk-3.0-base/override/xp-start-plugin.scss @@ -10,7 +10,7 @@ // // START BUTTON // -button.xp-start-button +button.wintc-start-button { // HACK: Slight hack going on here - in Windows XP, the window buttons has a margin // either side of it, however it doesn't seem like the custom widget in XFCE @@ -50,7 +50,7 @@ button.xp-start-button @include __wintc_apply_props($start_button_press_styles); } - @at-root .xp-flag + @at-root .wintc-flag { @include __wintc_apply_props_excluding( $start_flag_styles, @@ -58,8 +58,8 @@ button.xp-start-button "min-width" ); - min-height: $start_flag_size; - min-width: $start_flag_size; + min-height: $start_flag_height; + min-width: $start_flag_width; } // The Start button contains both 'Start' and 'start' labels, so that themes can @@ -95,7 +95,7 @@ button.xp-start-button // // START MENU // -window.csd.xp-start-menu // Specificity hack -_- +window.csd.wintc-personal-menu // Specificity hack -_- { @include __wintc_apply_props($start_menu_styles); @@ -174,7 +174,7 @@ window.csd.xp-start-menu // Specificity hack -_- } } - @at-root .xp-start-userpane + @at-root .start-userpane { @include __wintc_apply_props($start_menu_horz_userpane_styles); @@ -201,7 +201,7 @@ window.csd.xp-start-menu // Specificity hack -_- } } - @at-root .xp-start-vuserpane + @at-root .start-vuserpane { @include __wintc_apply_props($start_menu_vert_userpane_styles); @@ -211,7 +211,7 @@ window.csd.xp-start-menu // Specificity hack -_- } } - @at-root .xp-start-programs-column + @at-root .start-programs-column { @include __wintc_apply_props($start_menu_programs_column_styles); @@ -274,7 +274,7 @@ window.csd.xp-start-menu // Specificity hack -_- ); } - @at-root .xp-start-default-item + @at-root .start-default-item { @include __wintc_apply_props( $start_menu_programs_menuitem_mime_styles @@ -328,21 +328,21 @@ window.csd.xp-start-menu // Specificity hack -_- margin: 0px; } - menuitem.xp-start-all-programs + menuitem.start-all-programs { @include __wintc_apply_props_not_in_category( $start_menu_allprograms_menuitem_styles, font ); - min-height: $start_menu_allprograms_height; - > box { @include __wintc_apply_props_for_category( $start_menu_allprograms_menuitem_styles, font ); + + min-height: $start_menu_allprograms_height; } .arrow @@ -374,7 +374,7 @@ window.csd.xp-start-menu // Specificity hack -_- } } - @at-root .xp-start-places-column + @at-root .start-places-column { @include __wintc_apply_props($start_menu_places_column_styles); @@ -393,7 +393,7 @@ window.csd.xp-start-menu // Specificity hack -_- ); } - &.significant + &.significant > box label { @include __wintc_apply_props($start_menu_places_menuitem_top_styles); } @@ -411,7 +411,7 @@ window.csd.xp-start-menu // Specificity hack -_- } } - @at-root .xp-start-logoffpane + @at-root .start-logoffpane { @include __wintc_apply_props($start_menu_logoff_pane_styles); diff --git a/themes/build-common/gtk-3.0-base/styling/start-menu.scss b/themes/build-common/gtk-3.0-base/styling/start-menu.scss index 67fb348..23e3cd0 100644 --- a/themes/build-common/gtk-3.0-base/styling/start-menu.scss +++ b/themes/build-common/gtk-3.0-base/styling/start-menu.scss @@ -7,7 +7,8 @@ * Author(s): Rory Fewell */ -$start_flag_size: 16px !default; +$start_flag_height: 16px !default; +$start_flag_width: 16px !default; $start_text_case: upper !default; $start_menu_allprograms_height: 30px !default; @@ -360,7 +361,7 @@ $start_menu_allprograms_separator_styles: $start_menu_allprograms_separator_styles, true, margin, - 20, + 4, undefined, undefined, undefined diff --git a/themes/luna/blue/gtk-3.0/styling/start-menu.scss b/themes/luna/blue/gtk-3.0/styling/start-menu.scss index 1721ef8..70dd7f8 100644 --- a/themes/luna/blue/gtk-3.0/styling/start-menu.scss +++ b/themes/luna/blue/gtk-3.0/styling/start-menu.scss @@ -7,7 +7,8 @@ * Author(s): Rory Fewell */ -$start_flag_size: 20px; +$start_flag_height: 20px; +$start_flag_width: 20px; $start_text_case: lower; $start_menu_allprograms_height: 24px; @@ -478,7 +479,7 @@ $start_menu_places_column_styles: padding, 2, 2, - undefined, + 5, 5 ); $start_menu_places_column_styles: diff --git a/themes/professional/Resources/start_flag.png b/themes/professional/Resources/start_flag.png index 1a1a3996d3f10216880104c1f39c512da45bfb89..9c4e2fbbfbade1ccd7914d7e62fe7b0ff7c5b22d 100644 GIT binary patch delta 1120 zcmV-m1fTnW3Hu0;7k?561^@s6v=Wsr0004QX+uL$X=7sm04R}lk-bYoQ5eR5YGRZj zR76CBgGEC@6h&j%;36Srkkz6$KLS54_bMT+K}&H%_KvnyJr)LP1)t z?+0wE-jAtXt?xBmo$Cox16#ZBw5A&cVVQ>DWgv^*ocJZ!LE9GQwbobzo+1MhO1oNpO>6wzCcW0gx1W5BtkrJCagFMxyjsIZyEFxPly$_Qc*S`YCorNWOoq?WLDQaE?%9(q~BlBzPy~o zMO?{{N`^-u#A09P*HBxUhg0cwRDb#N(cq1GgIf#N zvAi!Uu!a(vpN3FYS%`_p3y3^Qs0F;vkP5bSJkMz-KC`O;!7?x6Buqa1jyNm}Cz#L{ zUA0vTp;)MGr|ufINA+22{LT`sB#sl$vwF~yvT#7+gQe@4v|;i#o60ls3b!vRX(Rb0 zl(Va1%VE6j3!dZBLx191Y&sp#w|wJN*D19?8%zpmwyeJxOxX6uLo(^nOV-g3l6VS- zFEwDa=MLkz%9Z$dfaic>wo1=!1Xy@xc`+K>D|x1iNJLB-TP-D(a#jelwF|z_8c_bp z`*953T)?ZlK}FcwZ4ZqZIMxij>;a;&Rov*ECZXyv(#Q66wVJU;lpe3o3Jeae2Zpg`WB-~p*F+bx_q5$%=T%o zgU%3P{S73wx=lM^%?xG6b!mbPf0T<~bm&J#tB{w=Pssl-{cVJtzcwkwkv}#5dqysH m&e_p_d5g6KA=9s!%KZi;denjYXOu5*2(kn>7z1*(|#oB-jcz76A*<##iA#&{nWj5ClaKvGND_ zYDCsMSs@}i%k2F)Gv_jM27IZaUb35GP%<1VolHdL<`*J?Cx85O5++Va(`|EnYAVIQ zwX-#?&l%+@8Qg7_{)-0{7v*)L+jgv&^nx)H?+()oNhq(ovB$`UGmHH z<#OMf|CUuk=T2DY_CfCv)_VzwZ`R{EZT{@bGD*hcPX0fQM+$*`5IRC zk;BTmBP{jZ2a*MD)00cFuu zQ>74!`8&3&p%HV|fS%=dj%X)woOqhogSNDeebV1wwU!HqHQr{RI@eEe`=XLIT1rAW zI}ck<<87a_9hDIh-(b^ifxhmVpt^3U1=>(jNb_a=Da?RruWTff5tXu$zK_JyIC!BM zV|};Sj~lT{7Z30Z;9zU$xqk^S3s0+dprx~xXS#$$M3cF7Qc`IvLy)am@B{jw;UB*n z$I$gfytwT%2-|zjsj)DQv;xojfM{$L*ZOBjXpDsAW2dU!#3qZd%}`}-`wkI7S~JcQ zjR&mUGIJb4tRx7Tdd=1^>lnYT_z4Xb*C( */ -$start_flag_size: 21px; +$start_flag_height: 18px; +$start_flag_width: 21px; $start_menu_allprograms_arrow_width: 24px;