Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
1cfd418
WIP: POF workspace switcher
lenemter Feb 12, 2025
bbd8aed
Fix bugs
lenemter Feb 12, 2025
95e19dc
Add support for switching workspaces
lenemter Feb 12, 2025
e34fc23
Use existing DesktopIntegration API
lenemter Feb 13, 2025
aca71f9
Fix crash. Make WorkspaceSystem handle the workspace indexes
lenemter Feb 13, 2025
28c1149
Introduce WindowSystem
lenemter Feb 13, 2025
a42d660
Fix edge cases
lenemter Feb 13, 2025
116acd5
Restructure the project
lenemter Feb 13, 2025
2326695
LauncherManager -> ItemManager
lenemter Feb 13, 2025
a0a3c29
Add support for custom dynamic workspace styling
lenemter Feb 13, 2025
0ef83b8
IconGroup: respect icon-size setting
lenemter Feb 13, 2025
c0fca29
Prepare support for active workspace indicator
lenemter Feb 13, 2025
eaf00ec
Don't reload application windows when switching workspace
lenemter Feb 13, 2025
072bfbd
Add active workspace indicator
lenemter Feb 13, 2025
2d467ff
A
lenemter Feb 13, 2025
fdd29b1
Fix lint
lenemter Feb 13, 2025
982b778
Add new line
lenemter Feb 13, 2025
1866d64
CSS: add workspace switcher styles (#364)
danirabbit Feb 13, 2025
0b7d384
Merge branch 'main' into lenemter/workspace-switcher-pof
lenemter Feb 13, 2025
72597c9
Fix crash
lenemter Feb 13, 2025
cf1e40d
Improve high contrast styles (#365)
danirabbit Feb 13, 2025
67d7c46
Add separate button for new workspace
lenemter Feb 13, 2025
89bacb7
DynamicWorkspaceItem: scale icon with dock icon size (#369)
danirabbit Feb 13, 2025
c6177c3
Update icon sizes in IconGroup for better scaling (#368)
alainm23 Feb 14, 2025
ad28f33
Dynamically compute grid spacing
lenemter Feb 14, 2025
6d0d7e7
Fix alignment
lenemter Feb 14, 2025
8619d9c
Fix crash
lenemter Feb 14, 2025
1203631
Merge branch 'main' into lenemter/workspace-switcher-pof
lenemter Feb 14, 2025
c740899
Fix merge and update POTFILES
lenemter Feb 14, 2025
4599581
Add a nice pop up animation
lenemter Feb 14, 2025
d7351d1
Remove TODO
lenemter Feb 14, 2025
1ee32c0
Introduce DockSettings
lenemter Feb 14, 2025
04ddbd8
Move launchers here as well
lenemter Feb 14, 2025
712dceb
Fix lint
lenemter Feb 14, 2025
d26c39b
Create base class 'DockItem'
lenemter Feb 14, 2025
5071d4c
Remove DockSettings
lenemter Feb 14, 2025
19614cd
Remove extra new line
lenemter Feb 14, 2025
a48b91c
Merge branch 'main' into lenemter/workspace-switcher-pof
lenemter Feb 14, 2025
63da719
AppSystem: Revert changes to active workspace handling
lenemter Feb 15, 2025
b05dd1f
Reduce diff
lenemter Feb 15, 2025
1d2adac
Add default icon
lenemter Feb 15, 2025
08ed668
Make DynamicWorkspaceIcon a subclass of DockItem
lenemter Feb 15, 2025
05869b7
DockItem -> BaseItem
lenemter Feb 15, 2025
82d87df
Merge branch 'main' into lenemter/workspace-switcher-pof
lenemter Feb 15, 2025
fdff8a9
Don't query active workspace on windows update
lenemter Feb 15, 2025
c383eb1
Remove setup_item_removed
lenemter Feb 15, 2025
f2f0e1a
Add pop up animation for dynamic workspace
lenemter Feb 15, 2025
52104d0
Merge branch 'main' into lenemter/workspace-switcher-pof
lenemter Feb 16, 2025
204b1da
remove_item_finish -> remove_finish
lenemter Feb 16, 2025
247c872
A
lenemter Feb 16, 2025
1c60d30
Better track of removed workspaces
lenemter Feb 16, 2025
f0707b0
Revert "Better track of removed workspaces"
lenemter Feb 17, 2025
b5e81f5
Fix removing workspaces
lenemter Feb 17, 2025
12d63b5
Fix warnings
lenemter Feb 17, 2025
8399ecb
Remove duplicate files from meson
lenemter Feb 17, 2025
7da3132
Sort files
lenemter Feb 17, 2025
d4e4198
Merge branch 'main' into lenemter/workspace-switcher-pof
lenemter Feb 17, 2025
30f6eeb
Simplify reposition_items
lenemter Feb 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions data/Application.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,38 @@ launcher progressbar progress {
min-width: 0;
}

icongroup {
padding: 6px;
padding-bottom: 0;
}

icongroup box {
background: alpha(@base_color, 0.4);
box-shadow:
inset 0 -1px 0 0 alpha(@highlight_color, 0.2),
inset 0 1px 0 0 alpha(@highlight_color, 0.3),
inset 1px 0 0 0 alpha(@highlight_color, 0.07),
inset -1px 0 0 0 alpha(@highlight_color, 0.07),
0 0 0 1px alpha(@borders, 0.3),
0 1px 1px alpha(@borders, 0.2),
0 1px 4px alpha(@borders, 0.4);
border-radius: 6px;
border-spacing: 3px;
}

.reduce-transparency icongroup box {
background: @base_color;
}

icongroup .add-image {
color: alpha(@selected_fg_color, 0.75);
-gtk-icon-shadow: 0 1px 0 alpha(@highlight_color, 0.2);
}

.reduce-transparency .add-image {
color: @selected_fg_color;
}

.running-indicator {
color: @selected_fg_color;
-gtk-icon-size: 9px;
Expand Down
4 changes: 4 additions & 0 deletions po/POTFILES
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ src/DBus/Unity.vala
src/WindowSystem/DesktopIntegration.vala
src/WindowSystem/Window.vala
src/WindowSystem/WindowSystem.vala
src/WorkspaceSystem/DynamicWorkspaceItem.vala
src/WorkspaceSystem/IconGroup.vala
src/WorkspaceSystem/Workspace.vala
src/WorkspaceSystem/WorkspaceSystem.vala
50 changes: 39 additions & 11 deletions src/ItemManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,22 @@

private Adw.TimedAnimation resize_animation;
private List<Launcher> launchers; // Only used to keep track of launcher indices
private List<IconGroup> icon_groups; // Only used to keep track of icon group indices
private DynamicWorkspaceIcon dynamic_workspace_item;

static construct {
settings = new Settings ("io.elementary.dock");
}

construct {
launchers = new List<Launcher> ();
icon_groups = new List<IconGroup> ();

// Idle is used here to because DynamicWorkspaceIcon depends on ItemManager
Idle.add_once (() => {
dynamic_workspace_item = new DynamicWorkspaceIcon ();
add_item (dynamic_workspace_item);
});

overflow = VISIBLE;

Expand Down Expand Up @@ -110,25 +119,40 @@
add_item (launcher);
});

map.connect (AppSystem.get_default ().load);
WorkspaceSystem.get_default ().workspace_added.connect ((workspace) => {
add_item (new IconGroup (workspace));
});

map.connect (() => {
AppSystem.get_default ().load.begin ();
WorkspaceSystem.get_default ().load.begin ();
});
}

private void reposition_items () {
var launcher_size = get_launcher_size ();

int index = 0;
foreach (var launcher in launchers) {
var position = index * launcher_size;
position_item (launcher, ref index);
}

if (launcher.parent != this) {
put (launcher, position, 0);
launcher.current_pos = position;
} else {
launcher.animate_move (position);
}
foreach (var icon_group in icon_groups) {
position_item (icon_group, ref index);
}

position_item (dynamic_workspace_item, ref index);
}

private void position_item (BaseItem item, ref int index) {
var position = get_launcher_size () * index;

index++;
if (item.parent != this) {
put (item, position, 0);
item.current_pos = position;
} else {
item.animate_move (position);
}

index++;
}

private void add_launcher_via_dnd (Launcher launcher, int index) {
Expand All @@ -144,6 +168,8 @@

if (item is Launcher) {
launchers.append ((Launcher) item);
} else if (item is IconGroup) {
icon_groups.append ((IconGroup) item);
}

resize_animation.easing = EASE_OUT_BACK;
Expand All @@ -163,6 +189,8 @@
private void remove_item (BaseItem item) {
if (item is Launcher) {
launchers.remove ((Launcher) item);
} else if (item is IconGroup) {
icon_groups.remove ((IconGroup) item);
}

item.set_revealed (false);
Expand Down
5 changes: 5 additions & 0 deletions src/WindowSystem/DesktopIntegration.vala
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ public interface Dock.DesktopIntegration : GLib.Object {

public signal void running_applications_changed ();
public signal void windows_changed ();
public signal void active_workspace_changed ();
public signal void workspace_removed (int index);

public abstract async RunningApplication[] get_running_applications () throws GLib.DBusError, GLib.IOError;
public abstract async Window[] get_windows () throws GLib.DBusError, GLib.IOError;
public abstract async void show_windows_for (string app_id) throws GLib.DBusError, GLib.IOError;
public abstract async void focus_window (uint64 uid) throws GLib.DBusError, GLib.IOError;
public abstract async void activate_workspace (int index) throws GLib.DBusError, GLib.IOError;
public abstract async int get_n_workspaces () throws GLib.DBusError, GLib.IOError;
public abstract async int get_active_workspace () throws GLib.DBusError, GLib.IOError;
}
15 changes: 15 additions & 0 deletions src/WindowSystem/Window.vala
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ public class Dock.Window : GLib.Object {

public string app_id { get; private set; default = ""; }
public bool has_focus { get; private set; default = false; }
public int workspace_index { get; private set; default = 0; }
public bool on_active_workspace { get; private set; default = false; }

public GLib.Icon icon { get; private set; default = new GLib.ThemedIcon ("application-default-icon"); }

public Window (uint64 uid) {
Object (uid: uid);
}
Expand All @@ -24,8 +27,20 @@ public class Dock.Window : GLib.Object {
has_focus = (bool) properties["has-focus"];
}

if ("workspace-index" in properties) {
workspace_index = (int) properties["workspace-index"];
}

if ("on-active-workspace" in properties) {
on_active_workspace = (bool) properties["on-active-workspace"];
}

var app_info = new GLib.DesktopAppInfo (app_id);
if (app_info != null) {
var icon = app_info.get_icon ();
if (icon != null && Gtk.IconTheme.get_for_display (Gdk.Display.get_default ()).has_gicon (icon)) {
this.icon = icon;
}
}
}
}
14 changes: 14 additions & 0 deletions src/WindowSystem/WindowSystem.vala
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
return instance.once (() => { return new WindowSystem (); });
}

public signal void workspace_removed (int index);

public DesktopIntegration? desktop_integration { get; private set; }
public Gee.List<Window> windows { get; private owned set; }
public int active_workspace { get; private set; default = 0; }

private WindowSystem () {}

Expand All @@ -28,8 +31,11 @@
);

yield sync_windows ();
yield sync_active_workspace ();

desktop_integration.windows_changed.connect (sync_windows);
desktop_integration.active_workspace_changed.connect (sync_active_workspace);
desktop_integration.workspace_removed.connect ((index) => workspace_removed (index));
} catch (Error e) {
critical ("Failed to get desktop integration: %s", e.message);
}
Expand Down Expand Up @@ -64,4 +70,12 @@

windows = new_windows;
}

private async void sync_active_workspace () requires (desktop_integration != null) {
try {
active_workspace = yield desktop_integration.get_active_workspace ();
} catch (Error e) {
critical (e.message);
}
}
}
67 changes: 67 additions & 0 deletions src/WorkspaceSystem/DynamicWorkspaceItem.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* SPDX-License-Identifier: GPL-3.0
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
*/

public class Dock.DynamicWorkspaceIcon : BaseItem {
class construct {
set_css_name ("icongroup");
}

public DynamicWorkspaceIcon () {
Object ();
}

construct {
var add_image = new Gtk.Image.from_icon_name ("list-add-symbolic") {
hexpand = true,
vexpand = true
};
add_image.add_css_class ("add-image");

// Gtk.Box is used here to keep css nodes consistent with IconGroup
var box = new Gtk.Box (VERTICAL, 0);
box.append (add_image);

overlay.child = box;

WorkspaceSystem.get_default ().workspace_added.connect (update_running_indicator_visibility);
WorkspaceSystem.get_default ().workspace_removed.connect (update_running_indicator_visibility);
WindowSystem.get_default ().notify["active-workspace"].connect (update_running_indicator_visibility);

dock_settings.bind ("icon-size", box, "width-request", DEFAULT);
dock_settings.bind ("icon-size", box, "height-request", DEFAULT);

dock_settings.bind_with_mapping (
"icon-size", add_image, "pixel_size", DEFAULT | GET,
(value, variant, user_data) => {
var icon_size = variant.get_int32 ();
value.set_int (icon_size / 2);
return true;
},
(value, expected_type, user_data) => {
return new Variant.maybe (null, null);
},
null, null
);

gesture_click.button = Gdk.BUTTON_PRIMARY;
gesture_click.released.connect (switch_to_new_workspace);
}

private void update_running_indicator_visibility () {
unowned var workspace_system = WorkspaceSystem.get_default ();
unowned var window_system = WindowSystem.get_default ();
running_revealer.reveal_child = workspace_system.workspaces.size == window_system.active_workspace;
}

private async void switch_to_new_workspace () {
var n_workspaces = WorkspaceSystem.get_default ().workspaces.size;

try {
yield WindowSystem.get_default ().desktop_integration.activate_workspace (n_workspaces);
} catch (Error e) {
warning ("Couldn't switch to new workspace: %s", e.message);
}
}
}
Loading