Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions protocol/pantheon-desktop-shell-v1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@

<arg name="hide_mode" type="uint" enum="hide_mode" summary="hide mode"/>
</request>

<request name="request_visible_in_multitasking_view">
<description summary="request visible in multitasking view">
Tell the shell that the panel would like to be visible in the multitasking view.
</description>
</request>
</interface>

<interface name="io_elementary_pantheon_widget_v1" version="1">
Expand Down
1 change: 1 addition & 0 deletions protocol/pantheon-desktop-shell.vapi
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace Pantheon.Desktop {
public void focus ();
public void set_size (int width, int height);
public void set_hide_mode (Pantheon.Desktop.HideMode hide_mode);
public void request_visible_in_multitasking_view ();
}

[CCode (cheader_filename = "pantheon-desktop-shell-client-protocol.h", cname = "struct io_elementary_pantheon_widget_v1", cprefix = "io_elementary_pantheon_widget_v1_")]
Expand Down
103 changes: 103 additions & 0 deletions src/DBus/WindowDragManager.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* SPDX-License-Identifier: GPL-3.0
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
*/

public class Dock.WindowDragManager : Object {
[DBus (name = "io.elementary.desktop.wm.WindowDragProvider")]
private interface WindowDragProvider : Object {
public signal void enter (uint64 window_id);
public signal void motion (int x, int y);
public signal void leave ();
public signal void dropped ();
}

public Gtk.Window dock_window { get; construct; }

private Window? current_window = null;
private WorkspaceIconGroup? current_icon_group = null;

private WindowDragProvider provider;

public WindowDragManager (Gtk.Window dock_window) {
Object (dock_window: dock_window);
}

construct {
connect_to_dbus.begin ();
}

private async void connect_to_dbus () {
try {
provider = yield Bus.get_proxy (SESSION, "io.elementary.gala", "/io/elementary/gala");
provider.enter.connect (on_enter);
provider.motion.connect (on_motion);
provider.leave.connect (on_leave);
provider.dropped.connect (on_dropped);
} catch (Error e) {
warning ("Failed to connect to WindowDragProvider DBus interface: %s", e.message);
}
}

private void on_enter (uint64 window_id) {
current_window = WindowSystem.get_default ().find_window (window_id);
}

private void on_motion (int x, int y) {
if (current_window == null) {
return;
}

var icon_group = find_icon_group (x, y);

if (icon_group == current_icon_group) {
return;
}

if (current_icon_group != null) {
current_icon_group.window_left ();
}

current_icon_group = icon_group;

if (current_icon_group != null) {
current_icon_group.window_entered (current_window);
}
}

private WorkspaceIconGroup? find_icon_group (int x, int y) {
double root_x, root_y;
dock_window.get_surface_transform (out root_x, out root_y);

var widget = dock_window.pick (x - root_x, y - root_y, DEFAULT);

while (!(widget is WorkspaceIconGroup) && widget != null) {
widget = widget.get_parent ();
}

if (widget is WorkspaceIconGroup) {
return (WorkspaceIconGroup) widget;
}

return null;
}

private void on_leave () {
if (current_icon_group != null) {
current_icon_group.window_left ();
current_icon_group = null;
}

current_window = null;
}

private void on_dropped () {
if (current_icon_group != null && current_window != null &&
current_icon_group.workspace.index != current_window.workspace_index
) {
WindowSystem.get_default ().move_window_to_workspace.begin (
current_window.uid, current_icon_group.workspace.index
);
}
}
}
7 changes: 6 additions & 1 deletion src/MainWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class Dock.MainWindow : Gtk.ApplicationWindow {

private Gtk.Box main_box;

private WindowDragManager window_drag_manager;

class construct {
set_css_name ("dock-window");
}
Expand Down Expand Up @@ -75,6 +77,8 @@ public class Dock.MainWindow : Gtk.ApplicationWindow {
transparency_settings.changed["use-transparency"].connect (update_transparency);
update_transparency ();
}

window_drag_manager = new WindowDragManager (this);
}

private void update_transparency () {
Expand All @@ -95,6 +99,7 @@ public class Dock.MainWindow : Gtk.ApplicationWindow {
panel = desktop_shell.get_panel (wl_surface);
panel.set_anchor (BOTTOM);
panel.set_hide_mode (settings.get_enum ("autohide-mode"));
panel.request_visible_in_multitasking_view ();
}
}
}
Expand Down Expand Up @@ -153,7 +158,7 @@ public class Dock.MainWindow : Gtk.ApplicationWindow {

var prop = xdisplay.intern_atom ("_MUTTER_HINTS", false);

var value = "anchor=8:hide-mode=%d:restore-previous-region=1".printf (settings.get_enum ("autohide-mode"));
var value = "anchor=8:hide-mode=%d:restore-previous-region=1:visible-in-multitasking-view=1".printf (settings.get_enum ("autohide-mode"));

xdisplay.change_property (window, prop, X.XA_STRING, 8, 0, (uchar[]) value, value.length);
}
Expand Down
1 change: 1 addition & 0 deletions src/WindowSystem/DesktopIntegration.vala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public interface Dock.DesktopIntegration : GLib.Object {
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 move_window_to_workspace (uint64 window, int workspace) 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;
Expand Down
12 changes: 10 additions & 2 deletions src/WindowSystem/WindowSystem.vala
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@
}
}

private Window? find_window (uint64 uid) {
public Window? find_window (uint64 uid) {
uint index;
if (windows.find_custom (uid, (win, uid) => {
return win.uid == uid;
return win.uid == (uint64) uid;
}, out index)) {
return windows[index];
}
Expand Down Expand Up @@ -83,4 +83,12 @@
critical (e.message);
}
}

public async void move_window_to_workspace (uint64 window, int workspace) requires (desktop_integration != null) {
try {
yield desktop_integration.move_window_to_workspace (window, workspace);
} catch (Error e) {
critical ("Failed to move window to workspace: %s", e.message);
}
}
}
31 changes: 28 additions & 3 deletions src/WorkspaceSystem/IconGroup.vala
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,25 @@
public class Dock.WorkspaceIconGroup : BaseIconGroup {
public Workspace workspace { get; construct; }

public GLib.ListStore additional_icons { private get; construct; }

public WorkspaceIconGroup (Workspace workspace) {
var additional_icons = new GLib.ListStore (typeof (GLib.Icon));

var workspace_icons = new Gtk.MapListModel (workspace.windows, (window) => {
return ((Window) window).icon;
});

var icon_sources_list_store = new GLib.ListStore (typeof (GLib.ListModel));
icon_sources_list_store.append (additional_icons);
icon_sources_list_store.append (workspace_icons);

var flatten_model = new Gtk.FlattenListModel (icon_sources_list_store);

Object (
workspace: workspace,
icons: new Gtk.MapListModel (workspace.windows, (window) => {
return ((Window) window).icon;
}),
additional_icons: additional_icons,
icons: flatten_model,
group: Group.WORKSPACE
);
}
Expand All @@ -36,4 +49,16 @@ public class Dock.WorkspaceIconGroup : BaseIconGroup {
workspace.reorder (ItemManager.get_default ().get_index_for_launcher (this));
}
}

public void window_entered (Window window) {
if (window.workspace_index == workspace.index) {
return;
}

additional_icons.append (window.icon);
}

public void window_left () {
additional_icons.remove_all ();
}
}
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ sources = [
'DBus' / 'ShellKeyGrabber.vala',
'DBus' / 'SwitcherooControl.vala',
'DBus' / 'Unity.vala',
'DBus' / 'WindowDragManager.vala',
'WindowSystem' / 'DesktopIntegration.vala',
'WindowSystem' / 'Window.vala',
'WindowSystem' / 'WindowSystem.vala',
Expand Down