From bba30e0998a6990ccd296ce3021a520989445931 Mon Sep 17 00:00:00 2001 From: lenemter Date: Wed, 14 Feb 2024 18:44:00 +0900 Subject: [PATCH] Implement FocusManager --- .../DBusWingpanelManager.vala | 21 ++- compositor/WingpanelManager/FocusManager.vala | 142 ++++++++++++++++++ compositor/meson.build | 1 + 3 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 compositor/WingpanelManager/FocusManager.vala diff --git a/compositor/WingpanelManager/DBusWingpanelManager.vala b/compositor/WingpanelManager/DBusWingpanelManager.vala index a7326cdc5..4e7024985 100644 --- a/compositor/WingpanelManager/DBusWingpanelManager.vala +++ b/compositor/WingpanelManager/DBusWingpanelManager.vala @@ -19,9 +19,11 @@ [DBus (name = "org.pantheon.gala.WingpanelInterface")] public class GreeterCompositor.DBusWingpanelManager : Object { - private WingpanelManager background_manager; private static DBusWingpanelManager? instance; - static WindowManager wm; + private static WindowManager wm; + + private WingpanelManager background_manager; + private FocusManager focus_manager; [DBus (visible = false)] public static void init (WindowManager _wm) { @@ -50,12 +52,19 @@ public class GreeterCompositor.DBusWingpanelManager : Object { background_manager.state_changed.connect ((state, animation_duration) => { state_changed (state, animation_duration); }); + + focus_manager = new FocusManager (wm.get_display ()); } public bool begin_grab_focused_window (int x, int y, int button, uint time, uint state) throws GLib.Error { - return false; + return focus_manager.begin_grab_focused_window (x, y, button, time, state); } - public void remember_focused_window () throws GLib.Error {} - public void restore_focused_window () throws GLib.Error {} - } + public void remember_focused_window () throws GLib.Error { + focus_manager.remember_focused_window (); + } + + public void restore_focused_window () throws GLib.Error { + focus_manager.restore_focused_window (); + } +} diff --git a/compositor/WingpanelManager/FocusManager.vala b/compositor/WingpanelManager/FocusManager.vala new file mode 100644 index 000000000..7fabfb2fc --- /dev/null +++ b/compositor/WingpanelManager/FocusManager.vala @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011-2015 Wingpanel Developers (http://launchpad.net/wingpanel) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + + public class GreeterCompositor.FocusManager : GLib.Object { + private unowned Meta.Display display; + private unowned Meta.Workspace? current_workspace = null; + private unowned Meta.Window? last_focused_window = null; + private unowned Meta.Window? last_focused_dialog_window = null; + + public FocusManager (Meta.Display _display) { + display = _display; + + unowned Meta.WorkspaceManager manager = display.get_workspace_manager (); + manager.workspace_switched.connect (() => { + update_current_workspace (); + }); + + update_current_workspace (); + } + + public void remember_focused_window () { + var windows = current_workspace.list_windows (); + foreach (unowned Meta.Window window in windows) { + window_created (window); + if (window.has_focus ()) { + last_focused_window = window; + } + } + + display.window_created.connect (window_created); + } + + public void restore_focused_window () { + // when a dialog was opened give it focus + if (last_focused_dialog_window != null) { + last_focused_dialog_window.focus (display.get_current_time ()); + // if dialog is closed pass focus to last focussed window + last_focused_dialog_window.unmanaged.connect (() => { + last_focused_dialog_window = null; + restore_focused_window (); + }); + } else if (last_focused_window != null) { + last_focused_window.focus (display.get_current_time ()); + } + + var windows = current_workspace.list_windows (); + foreach (unowned Meta.Window window in windows) { + window.focused.disconnect (window_focused); + window.unmanaged.disconnect (window_unmanaged); + } + + display.window_created.disconnect (window_created); + } + + void window_created (Meta.Window window) { + window.focused.connect (window_focused); + window.unmanaged.connect (window_unmanaged); + } + + void window_focused (Meta.Window window) { + // make sure we keep the last_focused_window when a dialog is started from wingpanel + if (window.window_type == Meta.WindowType.DIALOG) { + last_focused_dialog_window = window; + } else if (window.window_type != Meta.WindowType.DOCK) { // ignore focus to wingpanel + last_focused_window = window; + } + } + + void window_unmanaged (Meta.Window window) { + window.focused.disconnect (window_focused); + window.unmanaged.disconnect (window_unmanaged); + } + + public bool begin_grab_focused_window (int x, int y, int button, uint time, uint state) { + unowned var window = display.get_focus_window (); + if (window == null || !get_can_grab_window (window, x, y)) { + unowned Meta.Workspace workspace = display.get_workspace_manager ().get_active_workspace (); + List? windows = workspace.list_windows (); + if (windows == null) { + return false; + } + + window = null; + List copy = windows.copy (); + copy.reverse (); + copy.@foreach ((win) => { + if (window != null) { + return; + } + + if (get_can_grab_window (win, x, y)) { + window = win; + } + }); + } + + if (window != null) { +#if HAS_MUTTER44 + window.begin_grab_op (Meta.GrabOp.MOVING, null, null, time); +#else + display.begin_grab_op (window, Meta.GrabOp.MOVING, false, true, button, state, time, x, y); +#endif + return true; + } + + return false; + } + + private static bool get_can_grab_window (Meta.Window window, int x, int y) { + var frame = window.get_frame_rect (); + return !window.minimized && window.maximized_vertically && x >= frame.x && x <= frame.x + frame.width; + } + + private void update_current_workspace () { + unowned Meta.WorkspaceManager manager = display.get_workspace_manager (); + unowned var workspace = manager.get_workspace_by_index (manager.get_active_workspace_index ()); + + if (workspace == null) { + warning ("Cannot get active workspace"); + + return; + } + + current_workspace = workspace; + } +} diff --git a/compositor/meson.build b/compositor/meson.build index 6008a2c9a..d80167cdc 100644 --- a/compositor/meson.build +++ b/compositor/meson.build @@ -75,6 +75,7 @@ compositor_files = files( 'Background/SystemBackground.vala', 'WingpanelManager/WingpanelManager.vala', 'WingpanelManager/DBusWingpanelManager.vala', + 'WingpanelManager/FocusManager.vala', 'WingpanelManager/BackgroundUtils.vala', 'DBus.vala', 'DBusAccelerator.vala',