diff options
Diffstat (limited to 'applets/wncklet')
| -rw-r--r-- | applets/wncklet/Makefile.am | 28 | ||||
| -rw-r--r-- | applets/wncklet/org.mate.panel.Wncklet.mate-panel-applet.desktop.in.in | 2 | ||||
| -rw-r--r-- | applets/wncklet/showdesktop.c | 75 | ||||
| -rw-r--r-- | applets/wncklet/wayland-backend.c | 411 | ||||
| -rw-r--r-- | applets/wncklet/wayland-backend.h | 1 | ||||
| -rw-r--r-- | applets/wncklet/window-list.c | 146 | ||||
| -rw-r--r-- | applets/wncklet/window-list.ui | 1 | ||||
| -rw-r--r-- | applets/wncklet/window-menu.c | 13 | ||||
| -rw-r--r-- | applets/wncklet/wncklet.c | 27 | ||||
| -rw-r--r-- | applets/wncklet/wncklet.h | 7 | ||||
| -rw-r--r-- | applets/wncklet/workspace-switcher.c | 171 |
11 files changed, 726 insertions, 156 deletions
diff --git a/applets/wncklet/Makefile.am b/applets/wncklet/Makefile.am index ed442671..a59b1192 100644 --- a/applets/wncklet/Makefile.am +++ b/applets/wncklet/Makefile.am @@ -19,12 +19,18 @@ WNCKLET_SOURCES = \ window-menu.h \ window-list.c \ window-list.h \ - workspace-switcher.c \ - workspace-switcher.h \ showdesktop.c \ showdesktop.h \ $(BUILT_SOURCES) +if ENABLE_X11 +WNCKLET_SOURCES += \ + workspace-switcher.c \ + workspace-switcher.h +endif + + + WNCKLET_LDADD = \ ../../libmate-panel-applet/libmate-panel-applet-4.la \ $(WNCKLET_LIBS) \ @@ -78,9 +84,9 @@ $(applet_in_files): $(applet_in_files).in Makefile $(applet_DATA): $(applet_in_files) $(AM_V_GEN) $(MSGFMT) --desktop --keyword= --keyword=Name --keyword=Description --template $< -d $(top_srcdir)/po -o $@ +service_in_files = org.mate.panel.applet.WnckletFactory.service.in if !WNCKLET_INPROCESS servicedir = $(datadir)/dbus-1/services -service_in_files = org.mate.panel.applet.WnckletFactory.service.in service_DATA = $(service_in_files:.service.in=.service) org.mate.panel.applet.WnckletFactory.service: $(service_in_files) @@ -93,10 +99,18 @@ ui_FILES = \ showdesktop-menu.xml \ window-list-menu.xml \ window-list.ui \ - window-menu-menu.xml \ + window-menu-menu.xml + +if ENABLE_X11 +ui_FILES += \ workspace-switcher-menu.xml \ workspace-switcher.ui +endif + + + + wncklet-resources.c: wncklet.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/wncklet.gresource.xml) $(AM_V_GEN)$(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate --c-name wncklet $< @@ -107,16 +121,10 @@ BUILT_SOURCES = \ wncklet-resources.c \ wncklet-resources.h -if HAVE_WINDOW_PREVIEWS wncklet_gschemas_in = \ org.mate.panel.applet.window-list.gschema.xml.in \ org.mate.panel.applet.window-list-previews.gschema.xml.in \ org.mate.panel.applet.workspace-switcher.gschema.xml.in -else -wncklet_gschemas_in = \ - org.mate.panel.applet.window-list.gschema.xml.in \ - org.mate.panel.applet.workspace-switcher.gschema.xml.in -endif gsettings_SCHEMAS = $(wncklet_gschemas_in:.xml.in=.xml) @GSETTINGS_RULES@ diff --git a/applets/wncklet/org.mate.panel.Wncklet.mate-panel-applet.desktop.in.in b/applets/wncklet/org.mate.panel.Wncklet.mate-panel-applet.desktop.in.in index 99e7815c..ec53ade3 100644 --- a/applets/wncklet/org.mate.panel.Wncklet.mate-panel-applet.desktop.in.in +++ b/applets/wncklet/org.mate.panel.Wncklet.mate-panel-applet.desktop.in.in @@ -50,7 +50,7 @@ Description=Hide application windows and show the desktop # Translators: Do NOT translate or transliterate this text (this is an icon file name)! Icon=user-desktop MateComponentId=OAFIID:MATE_ShowDesktopApplet; -Platforms=X11; +Platforms=X11;Wayland; X-MATE-Bugzilla-Bugzilla=MATE X-MATE-Bugzilla-Product=mate-panel X-MATE-Bugzilla-Component=Show Desktop Button diff --git a/applets/wncklet/showdesktop.c b/applets/wncklet/showdesktop.c index 190077f1..882e55d6 100644 --- a/applets/wncklet/showdesktop.c +++ b/applets/wncklet/showdesktop.c @@ -35,11 +35,21 @@ #include <libwnck/libwnck.h> #endif +#ifndef HAVE_X11 +#include <gdk/gdkwayland.h> +#define GDK_IS_X11_DISPLAY(object) !(G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_DISPLAY)) +#endif + #include "wncklet.h" #include "showdesktop.h" #include <string.h> +#ifdef HAVE_WAYLAND +#include "wayland-protocol/wlr-foreign-toplevel-management-unstable-v1-client.h" +#include "wayland-backend.h" +#include <gdk/gdkwayland.h> +#endif #define TIMEOUT_ACTIVATE_SECONDS 1 #define SHOW_DESKTOP_ICON "user-desktop" @@ -52,6 +62,9 @@ typedef struct { GtkOrientation orient; int size; +#ifdef HAVE_X11 + WnckHandle* wnck_handle; +#endif WnckScreen* wnck_screen; guint showing_desktop: 1; @@ -72,6 +85,11 @@ static void theme_changed_callback(GtkIconTheme* icon_theme, ShowDesktopData* sd static void button_toggled_callback(GtkWidget* button, ShowDesktopData* sdd); static void show_desktop_changed_callback(WnckScreen* screen, ShowDesktopData* sdd); +#ifdef HAVE_WAYLAND +GtkWidget* tasklist; +gboolean desktop_showing; +#endif + /* this is when the panel orientation changes */ static void applet_change_orient(MatePanelApplet* applet, MatePanelAppletOrient orient, ShowDesktopData* sdd) @@ -308,6 +326,10 @@ static void applet_destroyed(GtkWidget* applet, ShowDesktopData* sdd) sdd->icon_theme = NULL; } +#ifdef HAVE_X11 + g_clear_object(&sdd->wnck_handle); +#endif + g_free (sdd); } @@ -371,7 +393,7 @@ static void show_desktop_applet_realized(MatePanelApplet* applet, gpointer data) #ifdef HAVE_X11 if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) { - sdd->wnck_screen = wnck_screen_get (gdk_x11_screen_get_screen_number (screen)); + sdd->wnck_screen = wncklet_get_screen (sdd->wnck_handle, sdd->applet); if (sdd->wnck_screen != NULL) wncklet_connect_while_alive (sdd->wnck_screen, "showing_desktop_changed", @@ -382,7 +404,14 @@ static void show_desktop_applet_realized(MatePanelApplet* applet, gpointer data) g_warning ("Could not get WnckScreen!"); } #endif /* HAVE_X11 */ - +#ifdef HAVE_WAYLAND +if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) +{ + /*/initialize wayland show desktop applet*/ + tasklist = wayland_tasklist_new(); + desktop_showing = FALSE; +} +#endif show_desktop_changed_callback (sdd->wnck_screen, sdd); sdd->icon_theme = gtk_icon_theme_get_for_screen (screen); @@ -426,6 +455,13 @@ gboolean show_desktop_applet_fill(MatePanelApplet* applet) sdd->size = mate_panel_applet_get_size(MATE_PANEL_APPLET(sdd->applet)); +#ifdef HAVE_X11 + if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) + { + sdd->wnck_handle = wnck_handle_new(WNCK_CLIENT_TYPE_PAGER); + } +#endif + g_signal_connect (sdd->applet, "realize", G_CALLBACK (show_desktop_applet_realized), sdd); @@ -545,9 +581,39 @@ static void button_toggled_callback(GtkWidget* button, ShowDesktopData* sdd) gdk_atom_intern("_NET_SHOWING_DESKTOP", FALSE)); } - else +#ifdef HAVE_WAYLAND + else if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) +#endif #endif - { /* not using X11 */ +#ifdef HAVE_WAYLAND +#ifndef HAVE_X11 + if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) +#endif + { + static GtkWidget* outer_box; + GList *children1, *children2; + if (desktop_showing == FALSE) + desktop_showing = TRUE; + + else + desktop_showing = FALSE; + + can_show_desktop = TRUE; + children1 = gtk_container_get_children (GTK_CONTAINER (tasklist)); + outer_box = g_list_first(children1)->data; + children2 = gtk_container_get_children (GTK_CONTAINER (outer_box)); + while (children2 != NULL) + { + button = GTK_WIDGET (children2->data); + toggle_show_desktop (button, desktop_showing); + children2 = children2->next; + } + } +#endif + +else + + { /* not using X11 or wayland */ can_show_desktop = FALSE; } @@ -588,6 +654,7 @@ static void button_toggled_callback(GtkWidget* button, ShowDesktopData* sdd) wnck_screen_toggle_showing_desktop(sdd->wnck_screen, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))); #endif /* HAVE_X11 */ + update_button_display (sdd); } diff --git a/applets/wncklet/wayland-backend.c b/applets/wncklet/wayland-backend.c index f82b7fee..30469894 100644 --- a/applets/wncklet/wayland-backend.c +++ b/applets/wncklet/wayland-backend.c @@ -26,27 +26,50 @@ #endif #include <gdk/gdkwayland.h> +#include <gio/gdesktopappinfo.h> #include "wayland-backend.h" #include "wayland-protocol/wlr-foreign-toplevel-management-unstable-v1-client.h" -static const int window_button_width = 140; +/*shorter than wnck-tasklist due to common use of larger fonts*/ +#define TASKLIST_TEXT_MAX_WIDTH 16 + +/*In the future this could be changable from the panel-prefs dialog*/ +static const int max_button_width = 180; +static const int icon_size = 16; +int full_button_width; + +typedef struct +{ + GtkWidget *menu; + GtkWidget *maximize; + GtkWidget *minimize; + GtkWidget *on_top; + GtkWidget *close; +} ContextMenu; typedef struct { GtkWidget *list; GtkWidget *outer_box; + ContextMenu *context_menu; struct zwlr_foreign_toplevel_manager_v1 *manager; } TasklistManager; typedef struct { GtkWidget *button; + GtkWidget *icon; GtkWidget *label; struct zwlr_foreign_toplevel_handle_v1 *toplevel; gboolean active; + gboolean maximized; + gboolean minimized; + gboolean fullscreen; } ToplevelTask; +static int tasklist_invocations = 0; + static const char *tasklist_manager_key = "tasklist_manager"; static const char *toplevel_task_key = "toplevel_task"; @@ -57,6 +80,10 @@ static uint32_t foreign_toplevel_manager_global_version = 0; static ToplevelTask *toplevel_task_new (TasklistManager *tasklist, struct zwlr_foreign_toplevel_handle_v1 *handle); +guint buttons, tasklist_width; + +gboolean window_hidden; + static void wl_registry_handle_global (void *_data, struct wl_registry *registry, @@ -119,7 +146,7 @@ foreign_toplevel_manager_handle_toplevel (void *data, { TasklistManager *tasklist = data; ToplevelTask *task = toplevel_task_new (tasklist, toplevel); - gtk_box_pack_start (GTK_BOX (tasklist->list), task->button, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (tasklist->list), task->button, TRUE, TRUE, 0); } static void @@ -161,6 +188,74 @@ tasklist_manager_disconnected_from_widget (TasklistManager *tasklist) if (tasklist->manager) zwlr_foreign_toplevel_manager_v1_stop (tasklist->manager); + + if (tasklist->context_menu) + { + gtk_widget_destroy (tasklist->context_menu->menu); + g_free (tasklist->context_menu); + tasklist->context_menu = NULL; + } +} + +static void +menu_on_maximize (GtkMenuItem *item, gpointer user_data) +{ + ToplevelTask *task = g_object_get_data (G_OBJECT (item), toplevel_task_key); + if (task->toplevel) { + if (task->maximized) { + zwlr_foreign_toplevel_handle_v1_unset_maximized (task->toplevel); + } else { + zwlr_foreign_toplevel_handle_v1_set_maximized (task->toplevel); + } + } +} + +static void +menu_on_minimize (GtkMenuItem *item, gpointer user_data) +{ + ToplevelTask *task = g_object_get_data (G_OBJECT (item), toplevel_task_key); + if (task->toplevel) { + if (task->minimized) { + zwlr_foreign_toplevel_handle_v1_unset_minimized (task->toplevel); + } else { + zwlr_foreign_toplevel_handle_v1_set_minimized (task->toplevel); + } + } +} + +static void +menu_on_close (GtkMenuItem *item, gpointer user_data) +{ + ToplevelTask *task = g_object_get_data (G_OBJECT (item), toplevel_task_key); + if (task->toplevel) { + zwlr_foreign_toplevel_handle_v1_close (task->toplevel); + } +} + +static ContextMenu * +context_menu_new () +{ + ContextMenu *menu = g_new0 (ContextMenu, 1); + menu->menu = gtk_menu_new (); + menu->maximize = gtk_menu_item_new (); + menu->minimize = gtk_menu_item_new (); + menu->on_top = gtk_check_menu_item_new_with_label ("Always On Top"); + menu->close = gtk_menu_item_new_with_label ("Close"); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), menu->maximize); + gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), menu->minimize); + gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), gtk_separator_menu_item_new ()); + gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), menu->on_top); + gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), gtk_separator_menu_item_new ()); + gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), menu->close); + + gtk_widget_show_all (menu->menu); + + g_signal_connect (menu->maximize, "activate", G_CALLBACK (menu_on_maximize), NULL); + g_signal_connect (menu->minimize, "activate", G_CALLBACK (menu_on_minimize), NULL); + g_signal_connect (menu->close, "activate", G_CALLBACK (menu_on_close), NULL); + gtk_widget_set_sensitive (menu->on_top, FALSE); + return menu; } static TasklistManager * @@ -170,7 +265,7 @@ tasklist_manager_new (void) return NULL; TasklistManager *tasklist = g_new0 (TasklistManager, 1); - tasklist->list = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); + tasklist->list = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_set_homogeneous (GTK_BOX (tasklist->list), TRUE); tasklist->outer_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (tasklist->outer_box), tasklist->list, FALSE, FALSE, 0); @@ -186,6 +281,7 @@ tasklist_manager_new (void) tasklist_manager_key, tasklist, (GDestroyNotify)tasklist_manager_disconnected_from_widget); + tasklist->context_menu = context_menu_new (); return tasklist; } @@ -207,7 +303,27 @@ foreign_toplevel_handle_app_id (void *data, struct zwlr_foreign_toplevel_handle_v1 *toplevel, const char *app_id) { - /* ignore */ + ToplevelTask *task = data; + + gchar *app_id_lower = g_utf8_strdown (app_id, -1); + gchar *desktop_app_id = g_strdup_printf ("%s.desktop", app_id_lower); + GDesktopAppInfo *app_info = g_desktop_app_info_new (desktop_app_id); + + if (app_info) { + GIcon *icon = g_app_info_get_icon (G_APP_INFO (app_info)); + if (icon) { + gtk_image_set_from_gicon (GTK_IMAGE (task->icon), icon, GTK_ICON_SIZE_MENU); + goto cleanup; + } + } + gtk_image_set_from_icon_name (GTK_IMAGE (task->icon), app_id_lower, GTK_ICON_SIZE_MENU); + +cleanup: + if (app_info) { + g_object_unref (G_OBJECT (app_info)); + } + g_free (app_id_lower); + g_free (desktop_app_id); } static void @@ -234,6 +350,9 @@ foreign_toplevel_handle_state (void *data, ToplevelTask *task = data; task->active = FALSE; + task->maximized = FALSE; + task->minimized = FALSE; + task->fullscreen = FALSE; enum zwlr_foreign_toplevel_handle_v1_state *i; wl_array_for_each (i, state) @@ -243,7 +362,15 @@ foreign_toplevel_handle_state (void *data, case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED: task->active = TRUE; break; - + case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED: + task->maximized = TRUE; + break; + case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED: + task->minimized = TRUE; + break; + case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN: + task->fullscreen = TRUE; + break; default: break; } @@ -260,12 +387,143 @@ foreign_toplevel_handle_done (void *data, } static void +adjust_buttons (GtkContainer *outer_box, int button_space, int real_buttons, ToplevelTask *task) +{ + GtkWidget *widget, *button, *box; + + /*catch the case of an added button that can be missed + *Note that button space can come up zero on a first button + */ + if (real_buttons < 2) + { + if(task) + { + gtk_widget_set_size_request (task->button, full_button_width, -1); + } + } + + if ((task) && (button_space > 0) && (button_space < icon_size * 3)) + { + gtk_widget_hide (task->icon); + } + else if (task) + { + gtk_widget_show (task->icon); + } + + if ((task) && (button_space > 0) && (button_space < icon_size)) + { + gtk_widget_hide (task->label); + } + else if (task) + { + gtk_widget_show (task->label); + } + + GList* children = gtk_container_get_children (GTK_CONTAINER (outer_box)); + + while (children != NULL) + { + button = GTK_WIDGET (children->data); + box = gtk_bin_get_child (GTK_BIN (button)); + + if ((real_buttons < 2) || (real_buttons * full_button_width < tasklist_width * 0.75)) + { + gtk_widget_set_size_request (button, full_button_width, -1); + gtk_widget_show_all (button); + return; + } + else + { + gtk_widget_set_size_request (button, MIN(button_space, full_button_width), -1); + } + + /* if the number of buttons forces width to less than 3x the icon size, hide the icons + * if the number of buttons forces width to less than the icon size, hide the labels too. + * This is roughy the same behavior as on x11 + * To find the icon and label we must iterate through the children of the box we packed + * into the button, there are two of them + */ + + GList* contents = gtk_container_get_children (GTK_CONTAINER (box)); + while (contents != NULL) + { + widget = GTK_WIDGET (contents->data); + /*Show or hide the icon*/ + if (GTK_IS_IMAGE (widget)) + { + if ((button_space < icon_size * 3) && (button_space > 1)) + gtk_widget_hide (widget); + + else + gtk_widget_show (widget); + + } + + /*Show or hide the label*/ + if (GTK_IS_LABEL (widget)) + { + if ((button_space < icon_size) && (button_space > 1)) + { + gtk_widget_hide (widget); + /*We can go a little wider for empty buttons*/ + gtk_widget_set_size_request (button, tasklist_width / real_buttons * 0.9, -1); + if (task) + gtk_widget_hide (task->label); + + } + else + { + gtk_widget_show (widget); + } + } + contents = contents->next; + } + children = children->next; + } + return; +} + +static void foreign_toplevel_handle_closed (void *data, struct zwlr_foreign_toplevel_handle_v1 *toplevel) { ToplevelTask *task = data; + if (task->button) + { + GtkOrientation orient; + GtkWidget *outer_box, *parent_box; + int real_buttons, button_space; + + outer_box = gtk_widget_get_parent (GTK_WIDGET (task->button)); gtk_widget_destroy (task->button); + buttons = buttons -1; + + if (tasklist_invocations > 1) + real_buttons = buttons / 2; + + else + real_buttons = buttons; + + if (real_buttons == 0) + return; + + /* We don't need to modify button size on a vertical panel*/ + orient = gtk_orientable_get_orientation (GTK_ORIENTABLE (outer_box)); + if (orient == GTK_ORIENTATION_VERTICAL) + return; + + /*Get the box the tasklist outer box sits in + *and leave a little space so the buttons don't push other applets off the panel + */ + + parent_box = gtk_widget_get_ancestor ((outer_box), GTK_TYPE_BOX); + tasklist_width = MAX(gtk_widget_get_allocated_width (parent_box), tasklist_width) ; + button_space = (tasklist_width / real_buttons) * 0.75; + button_space = MIN(button_space, full_button_width); + adjust_buttons (GTK_CONTAINER(outer_box), button_space, real_buttons, NULL); + } } static const struct zwlr_foreign_toplevel_handle_v1_listener foreign_toplevel_handle_listener = { @@ -284,6 +542,7 @@ toplevel_task_disconnected_from_widget (ToplevelTask *task) struct zwlr_foreign_toplevel_handle_v1 *toplevel = task->toplevel; task->button = NULL; + task->icon = NULL; task->label = NULL; task->toplevel = NULL; @@ -293,6 +552,34 @@ toplevel_task_disconnected_from_widget (ToplevelTask *task) g_free (task); } +/*We have to use the "activate" signal here + *as only signals valid for GtkButton work, + *"clicked" is taken, and we need to separate + *showing the desktop from mouse clicks on window buttons + */ +void +toggle_show_desktop(GtkWidget *button, gboolean desktop_showing) +{ + window_hidden = desktop_showing; + g_signal_emit_by_name (button, "activate"); +} + +static void +toggle_window(GtkButton *button, ToplevelTask *task) +{ + if (task->toplevel) + { + if (window_hidden) + { + zwlr_foreign_toplevel_handle_v1_set_minimized (task->toplevel); + } + else + { + zwlr_foreign_toplevel_handle_v1_unset_minimized (task->toplevel); + } + } +} + static void toplevel_task_handle_clicked (GtkButton *button, ToplevelTask *task) { @@ -312,13 +599,25 @@ toplevel_task_handle_clicked (GtkButton *button, ToplevelTask *task) } } -static gboolean on_toplevel_button_press (GtkWidget *widget, GdkEvent *event, gpointer user_data) +static gboolean on_toplevel_button_press (GtkWidget *button, GdkEvent *event, TasklistManager *tasklist) { /* Assume event is a button press */ if (((GdkEventButton*)event)->button == GDK_BUTTON_SECONDARY) { - /* Returning true for secondary clicks suppresses the applet's default context menu, - * which we do not want to show up for task buttons */ + ContextMenu *menu = tasklist->context_menu; + ToplevelTask *task = g_object_get_data (G_OBJECT (button), toplevel_task_key); + + g_object_set_data (G_OBJECT (menu->maximize), toplevel_task_key, task); + g_object_set_data (G_OBJECT (menu->minimize), toplevel_task_key, task); + g_object_set_data (G_OBJECT (menu->close), toplevel_task_key, task); + + gtk_menu_item_set_label (GTK_MENU_ITEM (menu->minimize), + task->minimized ? "Unminimize" : "Minimize"); + gtk_menu_item_set_label (GTK_MENU_ITEM (menu->maximize), + task->maximized ? "Unmaximize" : "Maximize"); + + gtk_menu_popup_at_widget (GTK_MENU (menu->menu), button, + GDK_GRAVITY_NORTH_WEST, GDK_GRAVITY_SOUTH_WEST, event); return TRUE; } else @@ -331,16 +630,29 @@ static ToplevelTask * toplevel_task_new (TasklistManager *tasklist, struct zwlr_foreign_toplevel_handle_v1 *toplevel) { ToplevelTask *task = g_new0 (ToplevelTask, 1); + GtkOrientation orient; + GtkWidget *whole_panel_box, *parent_box; + int real_buttons, button_space, panel_width; + buttons = buttons + 1; + orient = gtk_orientable_get_orientation (GTK_ORIENTABLE (tasklist->outer_box)); task->button = gtk_button_new (); g_signal_connect (task->button, "clicked", G_CALLBACK (toplevel_task_handle_clicked), task); + g_signal_connect (task->button, "activate", G_CALLBACK (toggle_window), task); + + task->icon = gtk_image_new_from_icon_name ("unknown", icon_size); task->label = gtk_label_new (""); - gtk_label_set_max_width_chars (GTK_LABEL (task->label), 1); - gtk_widget_set_size_request (task->label, window_button_width, -1); + gtk_label_set_max_width_chars (GTK_LABEL (task->label), TASKLIST_TEXT_MAX_WIDTH); gtk_label_set_ellipsize (GTK_LABEL (task->label), PANGO_ELLIPSIZE_END); - gtk_container_add (GTK_CONTAINER(task->button), task->label); + gtk_label_set_xalign (GTK_LABEL (task->label), 0.0); + + GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start (GTK_BOX (box), task->icon, FALSE, FALSE, 6); + gtk_box_pack_start (GTK_BOX (box), task->label, TRUE, TRUE, 2); + gtk_container_add (GTK_CONTAINER (task->button), box); + gtk_widget_set_name (task->button , "tasklist-button"); gtk_widget_show_all (task->button); task->toplevel = toplevel; @@ -354,8 +666,81 @@ toplevel_task_new (TasklistManager *tasklist, struct zwlr_foreign_toplevel_handl g_signal_connect (task->button, "button-press-event", G_CALLBACK (on_toplevel_button_press), - task); + tasklist); + + /* Buttons on a vertical panel are not affected by how many are needed + * GTK handles compressing contents as needed as the window width tells + * GTK how much space to allocate the label and icon. Buttons will use + * the full width of a vertical panel without any special attention + * so break out here instead of breaking the vertical panel case + */ + + if (orient == GTK_ORIENTATION_VERTICAL) + return task; + + /* On horizontal panels, GTK does not by default limit the width of the tasklist + * as it does not run out of space in the window until the entire panel is used, + * leaving buttons at full width until then and overflowing all other applets + * + * Thus we must get the tasklist's allocated width when extra space remains, + * which will be most of the distance between the handle and the next applet + * From there, we can expand buttons and/or hide elements as needed + * For some reason this function always gets called twice, so use half the value of buttons + * but do not attempt to adjust the global value as it would get adjusted twice + * Since we are adding a button here the true value cannot be zero + */ + whole_panel_box = gtk_widget_get_toplevel(GTK_WIDGET (tasklist->outer_box)); + parent_box = gtk_widget_get_ancestor(GTK_WIDGET (tasklist->outer_box), GTK_TYPE_BOX); + if (gtk_widget_get_allocated_width (parent_box) > 1) + { + tasklist_width = gtk_widget_get_allocated_width (parent_box); + } + else + { + tasklist_width = MAX(gtk_widget_get_allocated_width (parent_box), tasklist_width); + } + + panel_width = gtk_widget_get_allocated_width (whole_panel_box); + /*on startup we get an allocated with of zero, so start with 1/3 the panel width + *as a sane default + *This may overflow on very crowded panels where the tasklist is less than 1/3ed the + *panel witth but will self-correct on opening or closing a few windows + */ + + if (tasklist_width <= 2) + tasklist_width = panel_width / 3; + + if (tasklist_invocations > 1) + real_buttons = MAX ((buttons / 2), 1); + + else + real_buttons = MAX ((buttons), 1); + + /*always allow at least three buttons to fit without adjustment + *so short window lists don't overflow + */ + if (tasklist_width > 0) + { + full_button_width = MIN(max_button_width, tasklist_width / 3); + } + + /*Leave a little space so the buttons don't push other applets off the panel*/ + button_space = (tasklist_width / real_buttons) * 0.75; + button_space = MIN(button_space, full_button_width); + + /* iterate over all the buttons*/ + adjust_buttons (GTK_CONTAINER (tasklist->list), button_space, real_buttons, task); + + /*Reset the tasklist width after button adjustments*/ + if (gtk_widget_get_allocated_width (parent_box) > 1) + { + tasklist_width = gtk_widget_get_allocated_width (parent_box); + } + else + { + tasklist_width = MAX(gtk_widget_get_allocated_width (parent_box), tasklist_width); + } return task; } @@ -364,6 +749,8 @@ wayland_tasklist_new () { wayland_tasklist_init_if_needed (); TasklistManager *tasklist = tasklist_manager_new (); + + tasklist_invocations = tasklist_invocations + 1; if (!tasklist) return gtk_label_new ("Shell does not support WLR Foreign Toplevel Control"); return tasklist->outer_box; diff --git a/applets/wncklet/wayland-backend.h b/applets/wncklet/wayland-backend.h index e2402236..0bff2b5f 100644 --- a/applets/wncklet/wayland-backend.h +++ b/applets/wncklet/wayland-backend.h @@ -35,6 +35,7 @@ extern "C" { #endif +void toggle_show_desktop(GtkWidget *button, gboolean desktop_showing); GtkWidget* wayland_tasklist_new (void); void wayland_tasklist_set_orientation (GtkWidget* tasklist_widget, GtkOrientation orient); diff --git a/applets/wncklet/window-list.c b/applets/wncklet/window-list.c index 85c305d4..17821cdd 100644 --- a/applets/wncklet/window-list.c +++ b/applets/wncklet/window-list.c @@ -25,6 +25,11 @@ #include <libwnck/libwnck.h> #endif /* HAVE_X11 */ +#ifndef HAVE_X11 +#include <gdk/gdkwayland.h> +#define GDK_IS_X11_DISPLAY(object) !(G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_DISPLAY)) +#endif + #ifdef HAVE_WAYLAND #include <gdk/gdkwayland.h> #include "wayland-backend.h" @@ -39,9 +44,7 @@ #define WINDOW_LIST_ICON "mate-panel-window-list" #define WINDOW_LIST_SCHEMA "org.mate.panel.applet.window-list" -#ifdef HAVE_WINDOW_PREVIEWS #define WINDOW_LIST_PREVIEW_SCHEMA "org.mate.panel.applet.window-list-previews" -#endif /* HAVE_WINDOW_PREVIEWS */ typedef enum { TASKLIST_NEVER_GROUP, @@ -52,17 +55,20 @@ typedef enum { typedef struct { GtkWidget* applet; GtkWidget* tasklist; -#ifdef HAVE_WINDOW_PREVIEWS GtkWidget* preview; +#ifdef HAVE_X11 + WnckHandle* wnck_handle; +#endif + gboolean show_window_thumbnails; gint thumbnail_size; -#endif gboolean include_all_workspaces; TasklistGroupingType grouping; gboolean move_unminimized_windows; gboolean scroll_enable; + gboolean middle_click_close; GtkOrientation orientation; int size; @@ -70,33 +76,28 @@ typedef struct { gboolean needs_hints; #endif - GtkIconTheme* icon_theme; - /* Properties: */ GtkWidget* properties_dialog; GtkWidget* wayland_info_label; GtkWidget* show_current_radio; GtkWidget* show_all_radio; -#ifdef HAVE_WINDOW_PREVIEWS GtkWidget* window_thumbnail_box; GtkWidget* show_thumbnails_check; GtkWidget* thumbnail_size_label; GtkWidget* thumbnail_size_spin; -#endif GtkWidget* never_group_radio; GtkWidget* auto_group_radio; GtkWidget* always_group_radio; GtkWidget* move_minimized_radio; GtkWidget* mouse_scroll_check; + GtkWidget* middle_click_close_check; GtkWidget* change_workspace_radio; GtkWidget* minimized_windows_box; GtkWidget* window_grouping_box; GtkWidget* window_list_content_box; GSettings* settings; -#ifdef HAVE_WINDOW_PREVIEWS GSettings* preview_settings; -#endif } TasklistData; static void call_system_monitor(GtkAction* action, TasklistData* tasklist); @@ -138,6 +139,7 @@ static void tasklist_update(TasklistData* tasklist) wnck_tasklist_set_include_all_workspaces(WNCK_TASKLIST(tasklist->tasklist), tasklist->include_all_workspaces); wnck_tasklist_set_switch_workspace_on_unminimize(WNCK_TASKLIST(tasklist->tasklist), tasklist->move_unminimized_windows); wnck_tasklist_set_scroll_enabled (WNCK_TASKLIST(tasklist->tasklist), tasklist->scroll_enable); + wnck_tasklist_set_middle_click_close (WNCK_TASKLIST (tasklist->tasklist), tasklist->middle_click_close); } #endif /* HAVE_X11 */ @@ -202,11 +204,6 @@ static void response_cb(GtkWidget* widget, int id, TasklistData* tasklist) } } -static void applet_realized(MatePanelApplet* applet, TasklistData* tasklist) -{ - tasklist->icon_theme = gtk_icon_theme_get_for_screen(gtk_widget_get_screen(tasklist->applet)); -} - static void applet_change_orient(MatePanelApplet* applet, MatePanelAppletOrient orient, TasklistData* tasklist) { GtkOrientation new_orient; @@ -246,7 +243,6 @@ static void applet_change_background(MatePanelApplet* applet, MatePanelAppletBac } #ifdef HAVE_X11 -#ifdef HAVE_WINDOW_PREVIEWS static cairo_surface_t* preview_window_thumbnail (WnckWindow *wnck_window, TasklistData *tasklist, @@ -371,14 +367,14 @@ preview_window_reposition (WnckTasklist *tl, x_pos = monitor_geom.width + monitor_geom.x - width - tasklist->size - PREVIEW_PADDING; break; case MATE_PANEL_APPLET_ORIENT_RIGHT: - x_pos = tasklist->size + PREVIEW_PADDING; + x_pos = monitor_geom.x + tasklist->size + PREVIEW_PADDING; break; case MATE_PANEL_APPLET_ORIENT_UP: y_pos = monitor_geom.height + monitor_geom.y - height - tasklist->size - PREVIEW_PADDING; break; case MATE_PANEL_APPLET_ORIENT_DOWN: default: - y_pos = tasklist->size + PREVIEW_PADDING; + y_pos = monitor_geom.y + tasklist->size + PREVIEW_PADDING; break; } @@ -477,7 +473,7 @@ static gboolean applet_enter_notify_event (WnckTasklist *tl, GList *wnck_windows /* Do not show preview if window is not visible nor in current workspace */ if (!wnck_window_is_visible_on_workspace (wnck_window, - wnck_screen_get_active_workspace (wnck_screen_get_default ()))) + wnck_screen_get_active_workspace (wncklet_get_screen (tasklist->wnck_handle, tasklist->applet)))) return FALSE; thumbnail = preview_window_thumbnail (wnck_window, tasklist, &thumbnail_width, &thumbnail_height, &thumbnail_scale); @@ -513,7 +509,6 @@ static gboolean applet_leave_notify_event (WnckTasklist *tl, GList *wnck_windows return FALSE; } -#endif /* HAVE_WINDOW_PREVIEWS */ #endif /* HAVE_X11 */ static void applet_change_pixel_size(MatePanelApplet* applet, gint size, TasklistData* tasklist) @@ -602,7 +597,6 @@ static void display_all_workspaces_changed(GSettings* settings, gchar* key, Task tasklist_properties_update_content_radio(tasklist); } -#ifdef HAVE_WINDOW_PREVIEWS static void tasklist_update_thumbnail_size_spin(TasklistData* tasklist) { GtkWidget* button; @@ -625,7 +619,6 @@ static void thumbnail_size_changed(GSettings *settings, gchar* key, TasklistData tasklist->thumbnail_size = g_settings_get_int(settings, key); tasklist_update_thumbnail_size_spin(tasklist); } -#endif static GtkWidget* get_grouping_button(TasklistData* tasklist, TasklistGroupingType type) { @@ -700,6 +693,12 @@ static void scroll_enabled_changed (GSettings* settings, gchar* key, TasklistDat tasklist_update(tasklist); } +static void middle_click_close_changed (GSettings* settings, gchar* key, TasklistData* tasklist) +{ + tasklist->middle_click_close = g_settings_get_boolean (settings, key); + tasklist_update(tasklist); +} + static void setup_gsettings(TasklistData* tasklist) { tasklist->settings = mate_panel_applet_settings_new (MATE_PANEL_APPLET (tasklist->applet), WINDOW_LIST_SCHEMA); @@ -709,7 +708,6 @@ static void setup_gsettings(TasklistData* tasklist) G_CALLBACK (display_all_workspaces_changed), tasklist); -#ifdef HAVE_WINDOW_PREVIEWS tasklist->preview_settings = mate_panel_applet_settings_new (MATE_PANEL_APPLET (tasklist->applet), WINDOW_LIST_PREVIEW_SCHEMA); g_signal_connect (tasklist->preview_settings, @@ -721,7 +719,6 @@ static void setup_gsettings(TasklistData* tasklist) "changed::thumbnail-window-size", G_CALLBACK (thumbnail_size_changed), tasklist); -#endif g_signal_connect (tasklist->settings, "changed::group-windows", G_CALLBACK (group_windows_changed), @@ -734,6 +731,10 @@ static void setup_gsettings(TasklistData* tasklist) "changed::scroll-enabled", G_CALLBACK (scroll_enabled_changed), tasklist); + g_signal_connect (tasklist->settings, + "changed::middle-click-close", + G_CALLBACK (middle_click_close_changed), + tasklist); } static void applet_size_allocate(GtkWidget *widget, GtkAllocation *allocation, TasklistData *tasklist) @@ -768,77 +769,26 @@ static void applet_size_allocate(GtkWidget *widget, GtkAllocation *allocation, T mate_panel_applet_set_size_hints(MATE_PANEL_APPLET(tasklist->applet), size_hints, len, 0); } -#ifdef HAVE_X11 -/* Currently only used on X11, but should work on Wayland as well when needed */ -static GdkPixbuf* icon_loader_func(const char* icon, int size, unsigned int flags, void* data) -{ - TasklistData* tasklist; - GdkPixbuf* retval; - char* icon_no_extension; - char* p; - - tasklist = data; - - if (icon == NULL || strcmp(icon, "") == 0) - return NULL; - - if (g_path_is_absolute(icon)) - { - if (g_file_test(icon, G_FILE_TEST_EXISTS)) - { - return gdk_pixbuf_new_from_file_at_size(icon, size, size, NULL); - } - else - { - char* basename; - - basename = g_path_get_basename(icon); - retval = icon_loader_func(basename, size, flags, data); - g_free(basename); - - return retval; - } - } - - /* This is needed because some .desktop files have an icon name *and* - * an extension as icon */ - icon_no_extension = g_strdup(icon); - p = strrchr(icon_no_extension, '.'); - - if (p && (strcmp(p, ".png") == 0 || strcmp(p, ".xpm") == 0 || strcmp(p, ".svg") == 0)) - { - *p = 0; - } - - retval = gtk_icon_theme_load_icon(tasklist->icon_theme, icon_no_extension, size, 0, NULL); - g_free(icon_no_extension); - - return retval; -} -#endif /* HAVE_X11 */ - gboolean window_list_applet_fill(MatePanelApplet* applet) { TasklistData* tasklist; GtkActionGroup* action_group; GtkCssProvider *provider; - GdkScreen *screen; tasklist = g_new0(TasklistData, 1); tasklist->applet = GTK_WIDGET(applet); provider = gtk_css_provider_new (); - screen = gdk_screen_get_default (); gtk_css_provider_load_from_data (provider, ".mate-panel-menu-bar button,\n" " #tasklist-button {\n" " padding: 0px;\n" " margin: 0px;\n }", -1, NULL); - gtk_style_context_add_provider_for_screen (screen, - GTK_STYLE_PROVIDER (provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + gtk_style_context_add_provider_for_screen (gtk_widget_get_screen (tasklist->applet), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); g_object_unref (provider); mate_panel_applet_set_flags(MATE_PANEL_APPLET(tasklist->applet), MATE_PANEL_APPLET_EXPAND_MAJOR | MATE_PANEL_APPLET_EXPAND_MINOR | MATE_PANEL_APPLET_HAS_HANDLE); @@ -847,11 +797,9 @@ gboolean window_list_applet_fill(MatePanelApplet* applet) tasklist->include_all_workspaces = g_settings_get_boolean (tasklist->settings, "display-all-workspaces"); -#ifdef HAVE_WINDOW_PREVIEWS tasklist->show_window_thumbnails = g_settings_get_boolean (tasklist->preview_settings, "show-window-thumbnails"); tasklist->thumbnail_size = g_settings_get_int (tasklist->preview_settings, "thumbnail-window-size"); -#endif tasklist->grouping = g_settings_get_enum (tasklist->settings, "group-windows"); @@ -859,6 +807,8 @@ gboolean window_list_applet_fill(MatePanelApplet* applet) tasklist->scroll_enable = g_settings_get_boolean (tasklist->settings, "scroll-enabled"); + tasklist->middle_click_close = g_settings_get_boolean (tasklist->settings, "middle-click-close"); + tasklist->size = mate_panel_applet_get_size(applet); #if !defined(WNCKLET_INPROCESS) && !GTK_CHECK_VERSION (3, 23, 0) @@ -881,19 +831,15 @@ gboolean window_list_applet_fill(MatePanelApplet* applet) #ifdef HAVE_X11 if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) { - tasklist->tasklist = wnck_tasklist_new(); + tasklist->wnck_handle = wnck_handle_new(WNCK_CLIENT_TYPE_PAGER); + tasklist->tasklist = wnck_tasklist_new_with_handle(tasklist->wnck_handle); - wnck_tasklist_set_middle_click_close (WNCK_TASKLIST (tasklist->tasklist), TRUE); - wnck_tasklist_set_icon_loader(WNCK_TASKLIST(tasklist->tasklist), icon_loader_func, tasklist, NULL); - -#ifdef HAVE_WINDOW_PREVIEWS g_signal_connect (tasklist->tasklist, "task-enter-notify", G_CALLBACK (applet_enter_notify_event), tasklist); g_signal_connect (tasklist->tasklist, "task-leave-notify", G_CALLBACK (applet_leave_notify_event), tasklist); -#endif /* HAVE_WINDOW_PREVIEWS */ } else #endif /* HAVE_X11 */ @@ -921,9 +867,6 @@ gboolean window_list_applet_fill(MatePanelApplet* applet) gtk_container_add(GTK_CONTAINER(tasklist->applet), tasklist->tasklist); - g_signal_connect (tasklist->applet, "realize", - G_CALLBACK (applet_realized), - tasklist); g_signal_connect (tasklist->applet, "change-orient", G_CALLBACK (applet_change_orient), tasklist); @@ -1051,12 +994,10 @@ static void group_windows_toggled(GtkToggleButton* button, TasklistData* tasklis } } -#ifdef HAVE_WINDOW_PREVIEWS static void thumbnail_size_spin_changed(GtkSpinButton* button, TasklistData* tasklist) { g_settings_set_int(tasklist->preview_settings, "thumbnail-window-size", gtk_spin_button_get_value_as_int(button)); } -#endif static void move_minimized_toggled(GtkToggleButton* button, TasklistData* tasklist) { @@ -1107,9 +1048,7 @@ static void setup_dialog_wayland(TasklistData* tasklist) gtk_widget_set_sensitive(tasklist->window_grouping_box, FALSE); gtk_widget_set_sensitive(tasklist->minimized_windows_box, FALSE); -#ifdef HAVE_WINDOW_PREVIEWS gtk_widget_set_sensitive(tasklist->window_thumbnail_box, FALSE); -#endif /* HAVE_WINDOW_PREVIEWS */ } #endif /* HAVE_WAYLAND */ @@ -1129,7 +1068,6 @@ static void setup_dialog(GtkBuilder* builder, TasklistData* tasklist) setup_sensitivity(tasklist, builder, "never_group_radio", "auto_group_radio", "always_group_radio", "group-windows" /* key */); -#ifdef HAVE_WINDOW_PREVIEWS tasklist->window_thumbnail_box = WID("window_thumbnail_box"); tasklist->show_thumbnails_check = WID("show_thumbnails_check"); tasklist->thumbnail_size_label = WID("thumbnail_size_label"); @@ -1146,13 +1084,10 @@ static void setup_dialog(GtkBuilder* builder, TasklistData* tasklist) g_object_bind_property(tasklist->show_thumbnails_check, "active", tasklist->thumbnail_size_label, "sensitive", G_BINDING_DEFAULT); g_object_bind_property(tasklist->show_thumbnails_check, "active", tasklist->thumbnail_size_spin, "sensitive", G_BINDING_DEFAULT); -#else - gtk_widget_hide(WID("window_thumbnail_box")); -#endif - tasklist->move_minimized_radio = WID("move_minimized_radio"); tasklist->change_workspace_radio = WID("change_workspace_radio"); tasklist->mouse_scroll_check = WID("mouse_scroll_check"); + tasklist->middle_click_close_check = WID("middle_click_close_check"); tasklist->minimized_windows_box = WID("minimized_windows_box"); tasklist->window_grouping_box = WID("window_grouping_box"); tasklist->window_list_content_box = WID("window_list_content_box"); @@ -1183,13 +1118,18 @@ static void setup_dialog(GtkBuilder* builder, TasklistData* tasklist) "active", G_SETTINGS_BIND_DEFAULT); -#ifdef HAVE_WINDOW_PREVIEWS + /* Middle mouse click to close window: */ + g_settings_bind (tasklist->settings, + "middle-click-close", + tasklist->middle_click_close_check, + "active", + G_SETTINGS_BIND_DEFAULT); + /* change thumbnail size: */ tasklist_update_thumbnail_size_spin(tasklist); g_signal_connect (tasklist->thumbnail_size_spin, "value-changed", (GCallback) thumbnail_size_spin_changed, tasklist); -#endif /* move window when unminimizing: */ tasklist_update_unminimization_radio(tasklist); @@ -1247,11 +1187,9 @@ static void destroy_tasklist(GtkWidget* widget, TasklistData* tasklist) { g_signal_handlers_disconnect_by_data (G_OBJECT (tasklist->applet), tasklist); -#ifdef HAVE_WINDOW_PREVIEWS g_signal_handlers_disconnect_by_data (G_OBJECT (tasklist->tasklist), tasklist); g_signal_handlers_disconnect_by_data (tasklist->preview_settings, tasklist); g_object_unref(tasklist->preview_settings); -#endif g_signal_handlers_disconnect_by_data (tasklist->settings, tasklist); @@ -1260,9 +1198,11 @@ static void destroy_tasklist(GtkWidget* widget, TasklistData* tasklist) if (tasklist->properties_dialog) gtk_widget_destroy(tasklist->properties_dialog); -#ifdef HAVE_WINDOW_PREVIEWS if (tasklist->preview) gtk_widget_destroy(tasklist->preview); + +#ifdef HAVE_X11 + g_clear_object(&tasklist->wnck_handle); #endif g_free(tasklist); diff --git a/applets/wncklet/window-list.ui b/applets/wncklet/window-list.ui index 4cc49f9c..2ed06c0e 100644 --- a/applets/wncklet/window-list.ui +++ b/applets/wncklet/window-list.ui @@ -76,6 +76,7 @@ <object class="GtkNotebook"> <property name="visible">True</property> <property name="can-focus">True</property> + <property name="border_width">5</property> <child> <object class="GtkBox" id="behaviour_vbox"> <property name="visible">True</property> diff --git a/applets/wncklet/window-menu.c b/applets/wncklet/window-menu.c index 4b4e48dc..18f33f19 100644 --- a/applets/wncklet/window-menu.c +++ b/applets/wncklet/window-menu.c @@ -45,6 +45,10 @@ #include <gdk/gdkwayland.h> #endif /* HAVE_WAYLAND */ +#ifndef HAVE_X11 +#define GDK_IS_X11_DISPLAY(object) !(G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_DISPLAY)) +#endif + #include "wncklet.h" #include "window-menu.h" @@ -53,6 +57,9 @@ typedef struct { GtkWidget* applet; GtkWidget* selector; +#ifdef HAVE_X11 + WnckHandle* wnck_handle; +#endif int size; MatePanelAppletOrient orient; } WindowMenu; @@ -119,6 +126,9 @@ static const GtkActionEntry window_menu_actions[] = { static void window_menu_destroy(GtkWidget* widget, WindowMenu* window_menu) { +#ifdef HAVE_X11 + g_clear_object(&window_menu->wnck_handle); +#endif g_free(window_menu); } @@ -252,7 +262,8 @@ gboolean window_menu_applet_fill(MatePanelApplet* applet) #ifdef HAVE_X11 if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) { - window_menu->selector = wnck_selector_new(); + window_menu->wnck_handle = wnck_handle_new(WNCK_CLIENT_TYPE_PAGER); + window_menu->selector = wnck_selector_new_with_handle(window_menu->wnck_handle); } else #endif /* HAVE_X11 */ diff --git a/applets/wncklet/wncklet.c b/applets/wncklet/wncklet.c index 3b185910..1ced4507 100644 --- a/applets/wncklet/wncklet.c +++ b/applets/wncklet/wncklet.c @@ -35,11 +35,15 @@ #include <gdk/gdkx.h> #define WNCK_I_KNOW_THIS_IS_UNSTABLE #include <libwnck/libwnck.h> +#include "workspace-switcher.h" +#endif +#ifndef HAVE_X11 +#include <gdk/gdkwayland.h> +#define GDK_IS_X11_DISPLAY(object) !(G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_DISPLAY)) #endif #include "wncklet.h" #include "window-menu.h" -#include "workspace-switcher.h" #include "window-list.h" #include "showdesktop.h" @@ -96,18 +100,19 @@ void wncklet_display_help(GtkWidget* widget, const char* doc_id, const char* lin } #ifdef HAVE_X11 -WnckScreen* wncklet_get_screen(GtkWidget* applet) +WnckScreen* wncklet_get_screen(WnckHandle* handle, GtkWidget* applet) { + g_return_val_if_fail (WNCK_IS_HANDLE (handle), NULL); g_return_val_if_fail (GDK_IS_X11_DISPLAY (gdk_display_get_default ()), NULL); int screen_num; if (!gtk_widget_has_screen(applet)) - return wnck_screen_get_default(); + return wnck_handle_get_default_screen(handle); screen_num = gdk_x11_screen_get_screen_number(gtk_widget_get_screen(applet)); - return wnck_screen_get(screen_num); + return wnck_handle_get_screen(handle, screen_num); } #endif /* HAVE_X11 */ @@ -124,22 +129,12 @@ static gboolean wncklet_factory(MatePanelApplet* applet, const char* iid, gpoint { gboolean retval = FALSE; -#ifdef HAVE_X11 - if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) - { - static gboolean type_registered = FALSE; - if (!type_registered) - { - wnck_set_client_type(WNCK_CLIENT_TYPE_PAGER); - type_registered = TRUE; - } - } -#endif /* HAVE_X11 */ - if (!strcmp(iid, "WindowMenuApplet")) retval = window_menu_applet_fill(applet); +#ifdef HAVE_X11 else if (!strcmp(iid, "WorkspaceSwitcherApplet") || !strcmp(iid, "PagerApplet")) retval = workspace_switcher_applet_fill(applet); +#endif else if (!strcmp(iid, "WindowListApplet") || !strcmp(iid, "TasklistApplet")) retval = window_list_applet_fill(applet); else if (!strcmp(iid, "ShowDesktopApplet")) diff --git a/applets/wncklet/wncklet.h b/applets/wncklet/wncklet.h index 145cbce3..4b1dccea 100644 --- a/applets/wncklet/wncklet.h +++ b/applets/wncklet/wncklet.h @@ -28,17 +28,18 @@ #include <gtk/gtk.h> #include <mate-panel-applet.h> +#define WNCK_I_KNOW_THIS_IS_UNSTABLE +#include <libwnck/libwnck.h> + #define WNCKLET_RESOURCE_PATH "/org/mate/panel/applet/wncklet/" #ifdef __cplusplus extern "C" { #endif -typedef struct _WnckScreen WnckScreen; - void wncklet_display_help(GtkWidget* widget, const char* doc_id, const char* link_id, const char* icon_name); -WnckScreen* wncklet_get_screen(GtkWidget* applet); +WnckScreen* wncklet_get_screen(WnckHandle* handle, GtkWidget* applet); void wncklet_connect_while_alive(gpointer object, const char* signal, GCallback func, gpointer func_data, gpointer alive_object); diff --git a/applets/wncklet/workspace-switcher.c b/applets/wncklet/workspace-switcher.c index 065e951a..cba0ecbd 100644 --- a/applets/wncklet/workspace-switcher.c +++ b/applets/wncklet/workspace-switcher.c @@ -53,6 +53,153 @@ #define WORKSPACE_SWITCHER_ICON "mate-panel-workspace-switcher" +/* Container for the WnckPager to work around the sizing issues we have in the + * panel. See + * https://github.com/mate-desktop/mate-panel/issues/1230#issuecomment-1046235088 */ + +typedef struct _PagerContainer PagerContainer; +typedef GtkBinClass PagerContainerClass; + +static GType pager_container_get_type (void); + +#define PAGER_CONTAINER_TYPE (pager_container_get_type ()) +#define PAGER_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PAGER_CONTAINER_TYPE, PagerContainer)) + +struct _PagerContainer +{ + GtkBin parent; + GtkOrientation orientation; + int size; +}; + +G_DEFINE_TYPE (PagerContainer, pager_container, GTK_TYPE_BIN) + +static gboolean +queue_resize_idle_cb (gpointer user_data) +{ + gtk_widget_queue_resize (GTK_WIDGET (user_data)); + return G_SOURCE_REMOVE; +} + +static void +pager_container_get_preferred_width (GtkWidget *widget, + int *minimum_width, + int *natural_width) +{ + PagerContainer *self; + + self = PAGER_CONTAINER (widget); + + if (self->orientation == GTK_ORIENTATION_VERTICAL) + { + /* self->size is panel width */ + *minimum_width = *natural_width = self->size; + } + else + { + /* self->size is panel size/height, that will get allocated to pager, request width for this size */ + gtk_widget_get_preferred_width_for_height (gtk_bin_get_child (GTK_BIN (self)), + self->size, + minimum_width, + natural_width); + } +} + +static void +pager_container_get_preferred_height (GtkWidget *widget, + int *minimum_height, + int *natural_height) +{ + PagerContainer *self; + + self = PAGER_CONTAINER (widget); + + if (self->orientation == GTK_ORIENTATION_VERTICAL) + { + /* self->size is panel size/width that will get allocated to pager, request height for this size */ + gtk_widget_get_preferred_height_for_width (gtk_bin_get_child (GTK_BIN (self)), + self->size, + minimum_height, + natural_height); + } + else + { + /* self->size is panel height */ + *minimum_height = *natural_height = self->size; + } +} + +static void +pager_container_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + PagerContainer *self; + int size; + + self = PAGER_CONTAINER (widget); + + if (self->orientation == GTK_ORIENTATION_VERTICAL) + size = allocation->width; + else + size = allocation->height; + + size = MAX (size, 1); + + if (self->size != size) + { + self->size = size; + g_idle_add (queue_resize_idle_cb, self); + return; + } + + GTK_WIDGET_CLASS (pager_container_parent_class)->size_allocate (widget, + allocation); +} + +static void +pager_container_class_init (PagerContainerClass *self_class) +{ + GtkWidgetClass *widget_class; + + widget_class = GTK_WIDGET_CLASS (self_class); + + widget_class->get_preferred_width = pager_container_get_preferred_width; + widget_class->get_preferred_height = pager_container_get_preferred_height; + widget_class->size_allocate = pager_container_size_allocate; +} + +static void +pager_container_init (PagerContainer *self) +{ +} + +static GtkWidget * +pager_container_new (GtkWidget *child, + GtkOrientation orientation) +{ + PagerContainer *self; + + self = g_object_new (PAGER_CONTAINER_TYPE, "child", child, NULL); + + self->orientation = orientation; + + return GTK_WIDGET (self); +} + +static void +pager_container_set_orientation (PagerContainer *self, + GtkOrientation orientation) +{ + if (self->orientation == orientation) + return; + + self->orientation = orientation; + + gtk_widget_queue_resize (GTK_WIDGET (self)); +} + +/* Pager applet itself */ + typedef enum { PAGER_WM_MARCO, PAGER_WM_METACITY, @@ -65,8 +212,12 @@ typedef enum { typedef struct { GtkWidget* applet; + GtkWidget* pager_container; GtkWidget* pager; +#ifdef HAVE_X11 + WnckHandle* wnck_handle; +#endif WnckScreen* screen; PagerWM wm; @@ -251,7 +402,7 @@ static void applet_realized(MatePanelApplet* applet, PagerData* pager) #ifdef HAVE_X11 if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) { - pager->screen = wncklet_get_screen(GTK_WIDGET(applet)); + pager->screen = wncklet_get_screen(pager->wnck_handle, GTK_WIDGET(applet)); wncklet_connect_while_alive(pager->screen, "window_manager_changed", G_CALLBACK(window_manager_changed), pager, pager->applet); } #endif /* HAVE_X11 */ @@ -290,6 +441,8 @@ static void applet_change_orient(MatePanelApplet* applet, MatePanelAppletOrient pager->orientation = new_orient; pager_update(pager); + pager_container_set_orientation(PAGER_CONTAINER(pager->pager_container), pager->orientation); + if (pager->label_row_col) gtk_label_set_text(GTK_LABEL(pager->label_row_col), pager->orientation == GTK_ORIENTATION_HORIZONTAL ? _("rows") : _("columns")); } @@ -522,9 +675,7 @@ static void display_workspace_names_changed(GSettings* settings, gchar* key, Pag static void all_workspaces_changed(GSettings* settings, gchar* key, PagerData* pager) { - gboolean value = TRUE; /* Default value */ - - value = g_settings_get_boolean (settings, key); + gboolean value = g_settings_get_boolean (settings, key); pager->display_all = value; pager_update(pager); @@ -624,7 +775,8 @@ gboolean workspace_switcher_applet_fill(MatePanelApplet* applet) #ifdef HAVE_X11 if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) { - pager->pager = wnck_pager_new(); + pager->wnck_handle = wnck_handle_new(WNCK_CLIENT_TYPE_PAGER); + pager->pager = wnck_pager_new_with_handle(pager->wnck_handle); wnck_pager_set_shadow_type(WNCK_PAGER(pager->pager), GTK_SHADOW_IN); } else @@ -659,7 +811,8 @@ gboolean workspace_switcher_applet_fill(MatePanelApplet* applet) G_CALLBACK (applet_scroll), pager); - gtk_container_add(GTK_CONTAINER(pager->applet), pager->pager); + pager->pager_container = pager_container_new(pager->pager, pager->orientation); + gtk_container_add(GTK_CONTAINER(pager->applet), pager->pager_container); g_signal_connect (pager->applet, "realize", G_CALLBACK (applet_realized), @@ -678,6 +831,7 @@ gboolean workspace_switcher_applet_fill(MatePanelApplet* applet) context); gtk_widget_show (pager->pager); + gtk_widget_show (pager->pager_container); gtk_widget_show (pager->applet); action_group = gtk_action_group_new("WorkspaceSwitcher Applet Actions"); @@ -1138,5 +1292,10 @@ static void destroy_pager(GtkWidget* widget, PagerData* pager) if (pager->properties_dialog) gtk_widget_destroy(pager->properties_dialog); + +#ifdef HAVE_X11 + g_clear_object(&pager->wnck_handle); +#endif + g_free(pager); } |
