From 4e36020f42a84a28d7c12a1a2ee1ce874cc7499d Mon Sep 17 00:00:00 2001 From: lenemter Date: Wed, 29 Jul 2026 08:31:45 +0200 Subject: [PATCH 1/2] Avoid duplicate background app entries --- src/AppSystem/Background/BackgroundMonitor.vala | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/AppSystem/Background/BackgroundMonitor.vala b/src/AppSystem/Background/BackgroundMonitor.vala index ca2faeca..edc6e99c 100644 --- a/src/AppSystem/Background/BackgroundMonitor.vala +++ b/src/AppSystem/Background/BackgroundMonitor.vala @@ -40,12 +40,21 @@ public class Dock.BackgroundMonitor : Object { } private void update_background_apps () { + var app_id_set = new GLib.GenericSet (GLib.str_hash, GLib.str_equal, null); BackgroundApp[] apps = {}; foreach (var table in proxy.background_apps) { DesktopAppInfo? app_info = null; if ("app_id" in table) { - app_info = new DesktopAppInfo ((string) table["app_id"] + ".desktop"); + unowned var app_id = table["app_id"].get_string (); + + if (app_id in app_id_set) { + // avoid duplicate entries + continue; + } + + app_info = new DesktopAppInfo (app_id + ".desktop"); + app_id_set.add (app_id); } if (app_info == null) { From 4a636027388b8c634a181bbfcf8b3216c3633fb3 Mon Sep 17 00:00:00 2001 From: flodavid Date: Wed, 11 Mar 2026 18:55:05 +0100 Subject: [PATCH 2/2] Separate launcher and worskpace docks --- data/Application.css | 4 ++ src/HorizontalMargin.vala | 30 +++++++++++++++ src/ItemManager.vala | 27 +------------ src/MainWindow.vala | 81 ++++++++++++++++++++++++++++++--------- src/WorkspaceManager.vala | 69 +++++++++++++++++++++++++++++++++ src/meson.build | 2 + 6 files changed, 170 insertions(+), 43 deletions(-) create mode 100644 src/HorizontalMargin.vala create mode 100644 src/WorkspaceManager.vala diff --git a/data/Application.css b/data/Application.css index bfd5c8a1..3b6fba5c 100644 --- a/data/Application.css +++ b/data/Application.css @@ -40,6 +40,10 @@ bottom-margin { min-height: 9px; } +horizontal-margin { + min-width: 9px; +} + launcher { padding: 6px; padding-bottom: 0px; diff --git a/src/HorizontalMargin.vala b/src/HorizontalMargin.vala new file mode 100644 index 00000000..c94e2358 --- /dev/null +++ b/src/HorizontalMargin.vala @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * SPDX-FileCopyrightText: 2026 elementary, Inc. (https://elementary.io) + */ + +public class HorizontalMargin : Gtk.Widget { + private static GLib.List instances = new GLib.List (); + + class construct { + set_css_name ("horizontal-margin"); + } + + construct { + instances.append (this); + } + + ~HorizontalMargin () { + instances.remove (this); + } + + public new static int get_size () { + foreach (var instance in instances) { + if (instance.get_realized ()) { + return instance.get_width (); + } + } + + return 0; + } +} diff --git a/src/ItemManager.vala b/src/ItemManager.vala index 56408603..72610b68 100644 --- a/src/ItemManager.vala +++ b/src/ItemManager.vala @@ -10,10 +10,6 @@ private DynamicWorkspaceIcon dynamic_workspace_item; -#if WORKSPACE_SWITCHER - private Gtk.Separator separator; -#endif - static construct { settings = new Settings ("io.elementary.dock"); } @@ -24,23 +20,9 @@ var background_item = new BackgroundItem (); var background_group = new ItemGroup (background_item.group_model, (obj) => (BackgroundItem) obj); -#if WORKSPACE_SWITCHER - dynamic_workspace_item = new DynamicWorkspaceIcon (); - - separator = new Gtk.Separator (VERTICAL) { - valign = START, - margin_top = Launcher.PADDING, - }; - settings.bind ("icon-size", separator, "height-request", GET); -#endif - append (app_group); append (background_group); -#if WORKSPACE_SWITCHER - append (separator); - append (new ItemGroup (WorkspaceSystem.get_default ().workspaces, (obj) => new WorkspaceIconGroup ((Workspace) obj))); - append (dynamic_workspace_item); -#endif + overflow = VISIBLE; var drop_target_file = new Gtk.DropTarget (typeof (File), COPY) { @@ -143,19 +125,14 @@ map.connect (() => { AppSystem.get_default ().load.begin (); background_item.load (); -#if WORKSPACE_SWITCHER - WorkspaceSystem.get_default ().load.begin (); -#endif }); } public void move_launcher_after (BaseItem source, int target_index) { if (source is Launcher) { AppSystem.get_default ().reorder_app (source.app, target_index); - } else if (source is WorkspaceIconGroup) { - WorkspaceSystem.get_default ().reorder_workspace (source.workspace, target_index); } else { - warning ("Tried to move neither launcher nor icon group"); + info ("Tried to move not a launcher"); } } } diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 6642a679..13e48eed 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -24,8 +24,11 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { private Pantheon.Desktop.Panel? panel; private ItemManager item_manager; + private WorkspaceManager workspace_manager; private WindowDragManager window_drag_manager; private bool initialized_blur = false; + private bool realized_item_manager = false; + private bool realized_workspace_manager = false; private int border_radius = 0; class construct { @@ -36,24 +39,49 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { overflow = VISIBLE; resizable = false; titlebar = new Gtk.Label ("") { visible = false }; + item_manager = new ItemManager (); + workspace_manager = new WorkspaceManager (); - var dock_box = new Gtk.Box (VERTICAL, 0); - dock_box.append (new Container ()); - dock_box.append (new BottomMargin ()); + /* Launchers */ - item_manager = new ItemManager (); + var launcher_container = new Gtk.Box (VERTICAL, 0); + launcher_container.append (new Container ()); + launcher_container.append (new BottomMargin ()); + + // // Don't clip launchers to dock background https://github.com/elementary/dock/issues/275 + var launcher_overlay = new Gtk.Overlay () { + child = launcher_container + }; + launcher_overlay.add_overlay (item_manager); + + var launcher_size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.BOTH); + launcher_size_group.add_widget (launcher_container); + launcher_size_group.add_widget (item_manager); + + /* Workspaces */ + + var workspace_container = new Gtk.Box (VERTICAL, 0); + workspace_container.append (new Container ()); + workspace_container.append (new BottomMargin ()); - // Don't clip launchers to dock background https://github.com/elementary/dock/issues/275 - var overlay = new Gtk.Overlay () { - child = dock_box + var workspace_overlay = new Gtk.Overlay () { + child = workspace_container }; - overlay.add_overlay (item_manager); + workspace_overlay.add_overlay (workspace_manager); - var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.BOTH); - size_group.add_widget (dock_box); - size_group.add_widget (item_manager); + var workspace_size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.BOTH); + workspace_size_group.add_widget (workspace_container); + workspace_size_group.add_widget (workspace_manager); - child = overlay; + /* Full dock */ + + var docks_box = new Gtk.Box (HORIZONTAL, 0); + docks_box.append (launcher_overlay); + docks_box.append (new HorizontalMargin ()); + docks_box.append (workspace_overlay); + + // child = launcher_overlay; + child = docks_box; remove_css_class ("background"); @@ -61,7 +89,14 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { var drop_target_launcher = new Gtk.DropTarget (typeof (Launcher), MOVE); item_manager.add_controller (drop_target_launcher); - item_manager.realize.connect (init_panel); + item_manager.realize.connect (() => { + realized_item_manager = true; + try_init_panel (); + }); + workspace_manager.realize.connect (() => { + realized_workspace_manager = true; + try_init_panel (); + }); settings.changed["autohide-mode"].connect (() => { if (panel != null) { @@ -86,7 +121,6 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { remove_css_class ("reduce-transparency"); } else { add_css_class ("reduce-transparency"); - } } @@ -107,14 +141,22 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { } private static Wl.RegistryListener registry_listener; - private void init_panel () { + private void try_init_panel () { + // Wait for both parts of the dock to be realized to setup the surface + if (!realized_item_manager || !realized_workspace_manager) { + return; + } + unowned var surface = (Gdk.Toplevel) get_surface (); surface.compute_size.connect ((surface, size) => { // manually set shadow width since the additional margin we add to avoid icons clipping when // bouncing isn't added by default and instead counts to the frame var item_manager_width = item_manager.get_width (); - var shadow_size = (surface.width - item_manager_width) / 2; + var hztl_margin_width = HorizontalMargin.get_size (); + var workspace_manager_width = workspace_manager.get_width (); + // var shadow_size = (surface.width - item_manager_width) / 2; + var shadow_size = (surface.width - item_manager_width - hztl_margin_width - workspace_manager_width) / 2; var top_margin = TOP_MARGIN + shadow_size - 1; size.set_shadow_width (shadow_size, shadow_size, top_margin, shadow_size); }); @@ -123,12 +165,15 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { // manually set input region since container's shadow are is the content of the window // and it still gets window events var item_manager_width = item_manager.get_width (); - var shadow_size = (width - item_manager_width) / 2; + var hztl_margin_width = HorizontalMargin.get_size (); + var workspace_manager_width = workspace_manager.get_width (); + // var shadow_size = (width - item_manager_width) / 2; + var shadow_size = (width - item_manager_width - hztl_margin_width - workspace_manager_width) / 2; var top_margin = TOP_MARGIN + shadow_size; surface.set_input_region (new Cairo.Region.rectangle ({ shadow_size, top_margin, - item_manager_width, + item_manager_width + workspace_manager_width, height - top_margin })); diff --git a/src/WorkspaceManager.vala b/src/WorkspaceManager.vala new file mode 100644 index 00000000..93c7b8e0 --- /dev/null +++ b/src/WorkspaceManager.vala @@ -0,0 +1,69 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * SPDX-FileCopyrightText: 2026 elementary, Inc. (https://elementary.io) + */ + + public class Dock.WorkspaceManager : Gtk.Box { + private static Settings settings; + + private DynamicWorkspaceIcon dynamic_workspace_item; + + static construct { + settings = new Settings ("io.elementary.dock"); + } + + construct { + dynamic_workspace_item = new DynamicWorkspaceIcon (); + + append (new ItemGroup (WorkspaceSystem.get_default ().workspaces, (obj) => new WorkspaceIconGroup ((Workspace) obj))); + append (dynamic_workspace_item); + + overflow = VISIBLE; + + var drop_target_file = new Gtk.DropTarget (typeof (File), COPY) { + preload = true + }; + add_controller (drop_target_file); + + double drop_x, drop_y; + drop_target_file.enter.connect ((x, y) => { + drop_x = x; + drop_y = y; + return COPY; + }); + + drop_target_file.notify["value"].connect (() => { + if (drop_target_file.get_value () == null) { + return; + } + + if (drop_target_file.get_value ().get_object () == null) { + return; + } + + if (!(drop_target_file.get_value ().get_object () is File)) { + return; + } + + var file = (File) drop_target_file.get_value ().get_object (); + var app_info = new DesktopAppInfo.from_filename (file.get_path ()); + + if (app_info == null) { + return; + } + }); + + map.connect (() => { + WorkspaceSystem.get_default ().load.begin (); + }); + } + + public void move_launcher_after (BaseItem source, int target_index) { + if (source is WorkspaceIconGroup) { + WorkspaceSystem.get_default ().reorder_workspace (source.workspace, target_index); + } else { + info ("Tried to move not an icon group"); + return; + } + } +} diff --git a/src/meson.build b/src/meson.build index 4e860dee..29379d9b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -3,9 +3,11 @@ sources = [ 'BaseIconGroup.vala', 'BaseItem.vala', 'BottomMargin.vala', + 'HorizontalMargin.vala', 'ContainerItem.vala', 'ItemGroup.vala', 'ItemManager.vala', + 'WorkspaceManager.vala', 'MainWindow.vala', 'RenderNodeWalker.vala', 'AppSystem' / 'App.vala',