From ba0ae305bd99eedd5a38396fea60c67d83733b7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 24 Apr 2026 10:52:56 -0700 Subject: [PATCH] Create ExtendedBehaviorWindow --- .../ShellClients/ExtendedBehaviorWindow.vala | 27 ++++++++ compositor/ShellClients/PanelWindow.vala | 51 ++++++++++++-- compositor/ShellClients/PositionedWindow.vala | 69 ++----------------- .../ShellClients/ShellClientsManager.vala | 9 +-- compositor/ShellClients/ShellWindow.vala | 36 +--------- compositor/meson.build | 1 + 6 files changed, 86 insertions(+), 107 deletions(-) create mode 100644 compositor/ShellClients/ExtendedBehaviorWindow.vala diff --git a/compositor/ShellClients/ExtendedBehaviorWindow.vala b/compositor/ShellClients/ExtendedBehaviorWindow.vala new file mode 100644 index 00000000..5a714d69 --- /dev/null +++ b/compositor/ShellClients/ExtendedBehaviorWindow.vala @@ -0,0 +1,27 @@ +/* + * Copyright 2025 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Authored by: Leonhard Kargl + */ + +public class GreeterCompositor.ExtendedBehaviorWindow : ShellWindow { + public bool modal { get; private set; default = false; } + public bool dim { get; private set; default = false; } + + public ExtendedBehaviorWindow (Meta.Window window) { + Object (window: window); + } + + public void make_modal (bool dim) { + modal = true; + this.dim = dim; + } + + protected override void get_window_position (Mtk.Rectangle window_rect, out int x, out int y) { + var monitor_rect = window.display.get_monitor_geometry (window.get_monitor ()); + + x = monitor_rect.x + (monitor_rect.width - window_rect.width) / 2; + y = monitor_rect.y + (monitor_rect.height - window_rect.height) / 2; + } +} diff --git a/compositor/ShellClients/PanelWindow.vala b/compositor/ShellClients/PanelWindow.vala index 5897cafc..3127168a 100644 --- a/compositor/ShellClients/PanelWindow.vala +++ b/compositor/ShellClients/PanelWindow.vala @@ -15,19 +15,17 @@ public class GreeterCompositor.PanelWindow : ShellWindow { private int height = -1; public PanelWindow (WindowManager wm, Meta.Window window, Pantheon.Desktop.Anchor anchor) { - Object (wm: wm, anchor: anchor, window: window, position: Position.from_anchor (anchor)); + Object (wm: wm, window: window, anchor: anchor); } construct { - update_strut (); - window.unmanaging.connect (() => { if (window_struts.remove (window)) { update_struts (); } }); - notify["anchor"].connect (() => position = Position.from_anchor (anchor)); + notify["anchor"].connect (position_window); unowned var workspace_manager = window.display.get_workspace_manager (); workspace_manager.workspace_added.connect (update_strut); @@ -35,6 +33,15 @@ public class GreeterCompositor.PanelWindow : ShellWindow { window.size_changed.connect (update_strut); window.position_changed.connect (update_strut); + notify["width"].connect (update_strut); + notify["height"].connect (update_strut); + + var window_actor = (Meta.WindowActor) window.get_compositor_private (); + + window_actor.notify["width"].connect (update_clip); + window_actor.notify["height"].connect (update_clip); + window_actor.notify["translation-y"].connect (update_clip); + notify["anchor"].connect (update_clip); } public Mtk.Rectangle get_custom_window_rect () { @@ -103,4 +110,40 @@ public class GreeterCompositor.PanelWindow : ShellWindow { return TOP; } } + + protected override void get_window_position (Mtk.Rectangle window_rect, out int x, out int y) { + var monitor_rect = window.display.get_monitor_geometry (window.display.get_primary_monitor ()); + switch (anchor) { + case TOP: + x = monitor_rect.x + (monitor_rect.width - window_rect.width) / 2; + y = monitor_rect.y; + break; + + case BOTTOM: + x = monitor_rect.x + (monitor_rect.width - window_rect.width) / 2; + y = monitor_rect.y + monitor_rect.height - window_rect.height; + break; + + default: + warning ("Unsupported anchor %s for PanelWindow", anchor.to_string ()); + x = 0; + y = 0; + break; + } + } + + private void update_clip () { + var monitor_geom = window.display.get_monitor_geometry (window.get_monitor ()); + var window_actor = (Meta.WindowActor) window.get_compositor_private (); + + var y = window_actor.y + window_actor.translation_y; + + if (y + window_actor.height > monitor_geom.y + monitor_geom.height) { + window_actor.set_clip (0, 0, window_actor.width, monitor_geom.y + monitor_geom.height - y); + } else if (y < monitor_geom.y) { + window_actor.set_clip (0, monitor_geom.y - y, window_actor.width, window_actor.height); + } else { + window_actor.remove_clip (); + } + } } diff --git a/compositor/ShellClients/PositionedWindow.vala b/compositor/ShellClients/PositionedWindow.vala index 645d211d..e12b07cf 100644 --- a/compositor/ShellClients/PositionedWindow.vala +++ b/compositor/ShellClients/PositionedWindow.vala @@ -5,37 +5,11 @@ * Authored by: Leonhard Kargl */ -public class GreeterCompositor.PositionedWindow : Object { - public enum Position { - TOP, - BOTTOM, - CENTER, - FULLSCREEN; - - public static Position from_anchor (Pantheon.Desktop.Anchor anchor) { - if (anchor > 1) { - warning ("Position %s not supported yet", anchor.to_string ()); - return CENTER; - } - - return (Position) anchor; - } - } - +public abstract class GreeterCompositor.PositionedWindow : Object { public Meta.Window window { get; construct; } - /** - * This may only be set after the window was shown. - * The initial position should only be given in the constructor. - */ - public Position position { get; construct set; } - public Variant? position_data { get; construct set; } private ulong position_changed_id; - public PositionedWindow (Meta.Window window, Position position, Variant? position_data = null) { - Object (window: window, position: position, position_data: position_data); - } - construct { window.stick (); @@ -46,47 +20,18 @@ public class GreeterCompositor.PositionedWindow : Object { unowned var monitor_manager = window.display.get_context ().get_backend ().get_monitor_manager (); monitor_manager.monitors_changed.connect (position_window); monitor_manager.monitors_changed_internal.connect (position_window); - - notify["position"].connect (position_window); - notify["position-data"].connect (position_window); } - private void position_window () { - int x = 0, y = 0; + protected void position_window () { var window_rect = window.get_frame_rect (); - int width = window_rect.width, height = window_rect.height; - unowned var display = window.display; - - switch (position) { - case CENTER: - var monitor_geom = display.get_monitor_geometry (display.get_primary_monitor ()); - x = monitor_geom.x + (monitor_geom.width - window_rect.width) / 2; - y = monitor_geom.y + (monitor_geom.height - window_rect.height) / 2; - break; - - case TOP: - var monitor_geom = display.get_monitor_geometry (display.get_primary_monitor ()); - x = monitor_geom.x + (monitor_geom.width - window_rect.width) / 2; - y = monitor_geom.y; - break; - case BOTTOM: - var monitor_geom = display.get_monitor_geometry (display.get_primary_monitor ()); - x = monitor_geom.x + (monitor_geom.width - window_rect.width) / 2; - y = monitor_geom.y + monitor_geom.height - window_rect.height; - break; - - case FULLSCREEN: - var monitor_geom = display.get_monitor_geometry (display.get_primary_monitor ()); - x = monitor_geom.x; - y = monitor_geom.y; - width = monitor_geom.width; - height = monitor_geom.height; - break; - } + int x = 0, y = 0; + get_window_position (window_rect, out x, out y); SignalHandler.block (window, position_changed_id); - window.move_resize_frame (false, x, y, width, height); + window.move_frame (false, x, y); SignalHandler.unblock (window, position_changed_id); } + + protected abstract void get_window_position (Mtk.Rectangle window_rect, out int x, out int y); } diff --git a/compositor/ShellClients/ShellClientsManager.vala b/compositor/ShellClients/ShellClientsManager.vala index fe8ce2c3..e1633037 100644 --- a/compositor/ShellClients/ShellClientsManager.vala +++ b/compositor/ShellClients/ShellClientsManager.vala @@ -20,15 +20,13 @@ public class GreeterCompositor.ShellClientsManager : Object { return instance; } - public Clutter.Actor? actor { get { return wm.stage; } } - public WindowManager wm { get; construct; } private NotificationsClient notifications_client; private ManagedClient[] protocol_clients = {}; private GLib.HashTable panel_windows = new GLib.HashTable (null, null); - private GLib.HashTable positioned_windows = new GLib.HashTable (null, null); + private GLib.HashTable positioned_windows = new GLib.HashTable (null, null); private ShellClientsManager (WindowManager wm) { Object (wm: wm); @@ -95,7 +93,6 @@ public class GreeterCompositor.ShellClientsManager : Object { } #endif - public void make_desktop (Meta.Window window) { #if HAS_MUTTER49 window.set_type (Meta.WindowType.DESKTOP); @@ -176,14 +173,14 @@ public class GreeterCompositor.ShellClientsManager : Object { public void init_greeter (Meta.Window window) { make_desktop (window); - positioned_windows[window] = new ShellWindow (window, FULLSCREEN); + positioned_windows[window] = new ExtendedBehaviorWindow (window); // connect_after so we make sure that any queued move is unqueued window.unmanaging.connect_after ((_window) => positioned_windows.remove (_window)); } public void make_centered (Meta.Window window) requires (!is_itself_shell_window (window)) { - positioned_windows[window] = new ShellWindow (window, CENTER); + positioned_windows[window] = new ExtendedBehaviorWindow (window); // connect_after so we make sure that any queued move is unqueued window.unmanaging.connect_after ((_window) => positioned_windows.remove (_window)); diff --git a/compositor/ShellClients/ShellWindow.vala b/compositor/ShellClients/ShellWindow.vala index 99555ffb..3a8f6baf 100644 --- a/compositor/ShellClients/ShellWindow.vala +++ b/compositor/ShellClients/ShellWindow.vala @@ -5,40 +5,6 @@ * Authored by: Leonhard Kargl */ -public class GreeterCompositor.ShellWindow : PositionedWindow { - public Clutter.Actor? actor { get { return window_actor; } } +public abstract class GreeterCompositor.ShellWindow : PositionedWindow { - private Meta.WindowActor window_actor; - - public ShellWindow (Meta.Window window, Position position, Variant? position_data = null) { - base (window, position, position_data); - } - - construct { - window_actor = (Meta.WindowActor) window.get_compositor_private (); - - window_actor.notify["width"].connect (update_clip); - window_actor.notify["height"].connect (update_clip); - window_actor.notify["translation-y"].connect (update_clip); - notify["position"].connect (update_clip); - } - - private void update_clip () { - if (position != TOP && position != BOTTOM) { - window_actor.remove_clip (); - return; - } - - var monitor_geom = window.display.get_monitor_geometry (window.get_monitor ()); - - var y = window_actor.y + window_actor.translation_y; - - if (y + window_actor.height > monitor_geom.y + monitor_geom.height) { - window_actor.set_clip (0, 0, window_actor.width, monitor_geom.y + monitor_geom.height - y); - } else if (y < monitor_geom.y) { - window_actor.set_clip (0, monitor_geom.y - y, window_actor.width, window_actor.height); - } else { - window_actor.remove_clip (); - } - } } diff --git a/compositor/meson.build b/compositor/meson.build index e8453310..49f74fb4 100644 --- a/compositor/meson.build +++ b/compositor/meson.build @@ -101,6 +101,7 @@ compositor_files = files( 'Background/SystemBackground.vala', 'PantheonShell.vala', 'ShellClients/CenteredWindow.vala', + 'ShellClients/ExtendedBehaviorWindow.vala', 'ShellClients/ManagedClient.vala', 'ShellClients/NotificationsClient.vala', 'ShellClients/PanelWindow.vala',