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
20 changes: 20 additions & 0 deletions src/ShellClients/ExtendedBehaviorWindow.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2025 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Authored by: Leonhard Kargl <[email protected]>
*/

public class Gala.ExtendedBehaviorWindow : ShellWindow {
public ExtendedBehaviorWindow (Meta.Window window) {
var target = new PropertyTarget (CUSTOM, window.get_compositor_private (), "opacity", typeof (uint), 255u, 0u);
Object (window: window, hide_target: target);
}

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;
}
}
90 changes: 83 additions & 7 deletions src/ShellClients/PanelWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ public class Gala.PanelWindow : ShellWindow, RootTarget {
private GestureController workspace_gesture_controller;
private WorkspaceHideTracker workspace_hide_tracker;

private int width = -1;
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 {
Expand All @@ -46,7 +49,7 @@ public class Gala.PanelWindow : ShellWindow, RootTarget {
}
});

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);
Expand All @@ -71,20 +74,50 @@ public class Gala.PanelWindow : ShellWindow, RootTarget {
workspace_hide_tracker.switching_workspace_progress_updated.connect ((value) => workspace_gesture_controller.progress = value);
workspace_hide_tracker.window_state_changed_progress_updated.connect (workspace_gesture_controller.goto);

window.size_changed.connect (update_target);
notify["anchor"].connect (update_target);
update_target ();

add_gesture_controller (user_gesture_controller);
add_gesture_controller (workspace_gesture_controller);

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 () {
var window_rect = window.get_frame_rect ();

if (width > 0) {
window_rect.width = width;
}

if (height > 0) {
window_rect.height = height;

if (anchor == BOTTOM) {
var geom = window.display.get_monitor_geometry (window.get_monitor ());
window_rect.y = geom.y + geom.height - height;
}
}

return window_rect;
}

public void set_size (int width, int height) {
this.width = width;
this.height = height;
}

public void request_visible_in_multitasking_view () {
visible_in_multitasking_view = true;
actor.add_action (new DragDropAction (DESTINATION, "multitaskingview-window"));
}

protected override void update_target () {
base.update_target ();
workspace_hide_tracker.recalculate_all_workspaces ();
}

protected override double get_hidden_progress () {
var user_workspace_hidden_progress = double.min (
user_gesture_controller.progress,
Expand Down Expand Up @@ -214,4 +247,47 @@ public class Gala.PanelWindow : ShellWindow, RootTarget {
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_target () {
var to_value = anchor == TOP ? -get_custom_window_rect ().height : get_custom_window_rect ().height;
hide_target = new PropertyTarget (CUSTOM, actor, "translation-y", typeof (float), 0f, (float) to_value);

workspace_hide_tracker.recalculate_all_workspaces ();
}

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 ();
}
}
}
82 changes: 5 additions & 77 deletions src/ShellClients/PositionedWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,11 @@
* Authored by: Leonhard Kargl <[email protected]>
*/

public class Gala.PositionedWindow : Object {
public enum Position {
TOP,
BOTTOM,
CENTER;

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 Gala.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 int width = -1;
private int height = -1;

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 ();

Expand All @@ -48,62 +20,18 @@ public class Gala.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);
}

public Mtk.Rectangle get_custom_window_rect () {
protected void position_window () {
var window_rect = window.get_frame_rect ();

if (width > 0) {
window_rect.width = width;
}

if (height > 0) {
window_rect.height = height;

if (position == BOTTOM) {
var geom = window.display.get_monitor_geometry (window.get_monitor ());
window_rect.y = geom.y + geom.height - height;
}
}

return window_rect;
}

public void set_size (int width, int height) {
this.width = width;
this.height = height;
}

private void position_window () {
int x = 0, y = 0;
var window_rect = window.get_frame_rect ();
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;
}
get_window_position (window_rect, out x, out y);

SignalHandler.block (window, position_changed_id);
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);
}
2 changes: 1 addition & 1 deletion src/ShellClients/ShellClientsManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public class Gala.ShellClientsManager : Object, GestureTarget {
}

public void make_centered (Meta.Window window) requires (!is_itself_positioned (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));
Expand Down
98 changes: 12 additions & 86 deletions src/ShellClients/ShellWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,18 @@
* Authored by: Leonhard Kargl <[email protected]>
*/

public class Gala.ShellWindow : PositionedWindow, GestureTarget {
public abstract class Gala.ShellWindow : PositionedWindow, GestureTarget {
public bool restore_previous_x11_region { private get; set; default = false; }

private Meta.WindowActor window_actor;
/**
* A gesture target that will receive a CUSTOM update every time a gesture
* is propagated, with the progress gotten via {@link get_hidden_progress()}
*/
public GestureTarget hide_target { get; construct set; }

private double multitasking_view_progress = 0;
private int animations_ongoing = 0;

private PropertyTarget property_target;

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);

window.size_changed.connect (update_target);
notify["position"].connect (update_target);
update_target ();
}

protected virtual void update_target () {
property_target = new PropertyTarget (
CUSTOM, window_actor,
get_animation_property (),
get_property_type (),
calculate_value (false),
calculate_value (true)
);
}

public virtual void propagate (UpdateType update_type, GestureAction action, double progress) {
switch (update_type) {
case START:
Expand All @@ -53,7 +29,7 @@ public class Gala.ShellWindow : PositionedWindow, GestureTarget {
multitasking_view_progress = progress;
}

property_target.propagate (UPDATE, CUSTOM, get_hidden_progress ());
hide_target.propagate (UPDATE, CUSTOM, get_hidden_progress ());
break;

case END:
Expand All @@ -71,6 +47,8 @@ public class Gala.ShellWindow : PositionedWindow, GestureTarget {
}

private void update_visibility () {
unowned var window_actor = (Meta.WindowActor) window.get_compositor_private ();

var visible = get_hidden_progress () < 0.1;
var animating = animations_ongoing > 0;

Expand Down Expand Up @@ -104,63 +82,11 @@ public class Gala.ShellWindow : PositionedWindow, GestureTarget {
return true;
}

unowned var window_actor = (Meta.WindowActor) transient.get_compositor_private ();
unowned var transient_window_actor = (Meta.WindowActor) transient.get_compositor_private ();

window_actor.visible = visible && !animating;
transient_window_actor.visible = visible && !animating;

return true;
});
}

private string get_animation_property () {
switch (position) {
case TOP:
case BOTTOM:
return "translation-y";
default:
return "opacity";
}
}

private Type get_property_type () {
switch (position) {
case TOP:
case BOTTOM:
return typeof (float);
default:
return typeof (uint);
}
}

private Value calculate_value (bool hidden) {
var custom_rect = get_custom_window_rect ();

switch (position) {
case TOP:
return hidden ? -custom_rect.height : 0f;
case BOTTOM:
return hidden ? custom_rect.height : 0f;
default:
return hidden ? 0u : 255u;
}
}

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 ();
}
}
}
Loading