Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
1 change: 1 addition & 0 deletions lib/Constants.vala
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace Gala {
MULTITASKING_VIEW,
DOCK,
ZOOM,
CLOSE_WINDOW,
N_ACTIONS
}

Expand Down
21 changes: 17 additions & 4 deletions src/Gestures/ScrollBackend.vala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 elementary, Inc (https://elementary.io)
* Copyright 2021-2025 elementary, Inc (https://elementary.io)
* 2021 José Expósito <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -49,21 +49,22 @@ public class Gala.ScrollBackend : Object, GestureBackend {
Object (actor: actor, orientation: orientation, settings: settings);

actor.scroll_event.connect (on_scroll_event);
actor.leave_event.connect (on_leave_event);
// When the actor is turned invisible, we don't receive a scroll finish event which would cause
// us to ignore the first new scroll event if we're currently ignoring.
actor.notify["visible"].connect (() => ignoring = false);
}

private bool on_scroll_event (Clutter.Event event) {
if (!can_handle_event (event)) {
return false;
return Clutter.EVENT_PROPAGATE;
}

if (ignoring) {
if (event.get_scroll_finish_flags () != NONE) {
ignoring = false;
}
return false;
return Clutter.EVENT_PROPAGATE;
}

var time = event.get_time ();
Expand Down Expand Up @@ -104,7 +105,19 @@ public class Gala.ScrollBackend : Object, GestureBackend {
}
}

return true;
return Clutter.EVENT_PROPAGATE;
}

private bool on_leave_event (Clutter.Event event) requires (event.get_type () == LEAVE) {
if (!started) {
return Clutter.EVENT_PROPAGATE;
}

double delta = calculate_delta (delta_x, delta_y, direction);
on_end (delta, event.get_time ());
reset ();

return Clutter.EVENT_PROPAGATE;
}

private static bool can_handle_event (Clutter.Event event) {
Expand Down
13 changes: 9 additions & 4 deletions src/Widgets/MultitaskingView/MonitorClone.vala
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,26 @@
public class Gala.MonitorClone : ActorTarget {
public signal void window_selected (Meta.Window window);

public Meta.Display display { get; construct; }
public WindowManager wm { get; construct; }
public int monitor { get; construct; }

private WindowCloneContainer window_container;
private BackgroundManager background;

public MonitorClone (Meta.Display display, int monitor) {
Object (display: display, monitor: monitor);
public MonitorClone (WindowManager wm, int monitor) {
Object (wm: wm, monitor: monitor);
}

construct {
reactive = true;

unowned var display = wm.get_display ();

background = new BackgroundManager (display, monitor, false);

var scale = display.get_monitor_scale (monitor);

window_container = new WindowCloneContainer (display, scale);
window_container = new WindowCloneContainer (wm, scale);
window_container.window_selected.connect ((w) => { window_selected (w); });

display.window_entered_monitor.connect (window_entered);
Expand All @@ -58,6 +60,7 @@ public class Gala.MonitorClone : ActorTarget {
}

~MonitorClone () {
unowned var display = wm.get_display ();
display.window_entered_monitor.disconnect (window_entered);
display.window_left_monitor.disconnect (window_left);
}
Expand All @@ -66,6 +69,8 @@ public class Gala.MonitorClone : ActorTarget {
* Make sure the MonitorClone is at the location of the monitor on the stage
*/
public void update_allocation () {
unowned var display = wm.get_display ();

var monitor_geometry = display.get_monitor_geometry (monitor);

set_position (monitor_geometry.x, monitor_geometry.y);
Expand Down
4 changes: 2 additions & 2 deletions src/Widgets/MultitaskingView/MultitaskingView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public class Gala.MultitaskingView : ActorTarget, ActivatableComponent {
continue;
}

var monitor_clone = new MonitorClone (display, monitor);
var monitor_clone = new MonitorClone (wm, monitor);
monitor_clone.window_selected.connect (window_selected);
monitor_clone.visible = opened;

Expand Down Expand Up @@ -351,7 +351,7 @@ public class Gala.MultitaskingView : ActorTarget, ActivatableComponent {
unowned var manager = display.get_workspace_manager ();
var scale = display.get_monitor_scale (display.get_primary_monitor ());

var workspace = new WorkspaceClone (manager.get_workspace_by_index (num), scale);
var workspace = new WorkspaceClone (wm, manager.get_workspace_by_index (num), scale);
workspaces.insert_child_at_index (workspace, num);
icon_groups.add_group (workspace.icon_group);

Expand Down
132 changes: 95 additions & 37 deletions src/Widgets/MultitaskingView/WindowClone.vala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2022-2023 elementary, Inc. (https://elementary.io)
* SPDX-FileCopyrightText: 2022-2025 elementary, Inc. (https://elementary.io)
* 2014 Tom Beckmann
*/

Expand All @@ -13,6 +13,7 @@ public class Gala.WindowClone : ActorTarget {
private const int ACTIVE_SHAPE_SIZE = 12;
private const int FADE_ANIMATION_DURATION = 200;
private const int TITLE_MAX_WIDTH_MARGIN = 60;
private const int CLOSE_TRANSLATION = 600;

/**
* The window was selected. The MultitaskingView should consider activating
Expand All @@ -26,8 +27,7 @@ public class Gala.WindowClone : ActorTarget {
*/
public signal void request_reposition ();

public Meta.Display display { get; construct; }

public WindowManager wm { get; construct; }
public Meta.Window window { get; construct; }

/**
Expand Down Expand Up @@ -84,14 +84,17 @@ public class Gala.WindowClone : ActorTarget {
private ulong check_confirm_dialog_cb = 0;
private bool in_slot_animation = false;

private Clutter.Actor clone_container;
private Gala.CloseButton close_button;
private ActiveShape active_shape;
private Clutter.Actor window_icon;
private Tooltip window_title;

public WindowClone (Meta.Display display, Meta.Window window, float scale, bool overview_mode = false) {
private GestureController gesture_controller;

public WindowClone (WindowManager wm, Meta.Window window, float scale, bool overview_mode = false) {
Object (
display: display,
wm: wm,
window: window,
monitor_scale_factor: scale,
overview_mode: overview_mode
Expand All @@ -101,6 +104,9 @@ public class Gala.WindowClone : ActorTarget {
construct {
reactive = true;

gesture_controller = new GestureController (CLOSE_WINDOW, this, wm);
gesture_controller.enable_scroll (this, VERTICAL);

window.unmanaged.connect (unmanaged);
window.notify["fullscreen"].connect (check_shadow_requirements);
window.notify["maximized-horizontally"].connect (check_shadow_requirements);
Expand All @@ -126,13 +132,18 @@ public class Gala.WindowClone : ActorTarget {
add_action (drag_action);
}

window_title = new Tooltip ();
window_title.opacity = 0;

active_shape = new ActiveShape ();
active_shape.opacity = 0;

clone_container = new Clutter.Actor () {
pivot_point = { 0.5f, 0.5f }
};

window_title = new Tooltip ();
window_title.opacity = 0;

add_child (active_shape);
add_child (clone_container);
add_child (window_title);

reallocate ();
Expand Down Expand Up @@ -183,13 +194,7 @@ public class Gala.WindowClone : ActorTarget {
}

clone = new Clutter.Clone (actor);
clone.set_content_scaling_filters (TRILINEAR, TRILINEAR);
add_child (clone);

set_child_below_sibling (active_shape, clone);
set_child_above_sibling (close_button, clone);
set_child_above_sibling (window_icon, clone);
set_child_above_sibling (window_title, clone);
clone_container.add_child (clone);

check_shadow_requirements ();
}
Expand Down Expand Up @@ -266,34 +271,83 @@ public class Gala.WindowClone : ActorTarget {
}

public override void start_progress (GestureAction action) {
update_hover_widgets (true);
if (action == MULTITASKING_VIEW) {
update_hover_widgets (true);
}
}

public override void update_progress (Gala.GestureAction action, double progress) {
if (action != CLOSE_WINDOW || !Meta.Prefs.get_gnome_animations ()) {
return;
}

var target_translation_y = (float) (-CLOSE_TRANSLATION * monitor_scale_factor * progress);
var target_opacity = (uint) (255 * (1 - progress));

clone_container.translation_y = target_translation_y;
clone_container.opacity = target_opacity;

window_icon.translation_y = target_translation_y;
window_icon.opacity = target_opacity;

window_title.translation_y = target_translation_y;
window_title.opacity = target_opacity;

close_button.translation_y = target_translation_y;
close_button.opacity = target_opacity;

if (progress == 1.0 && get_current_commit (CLOSE_WINDOW) == 1.0) {
close_window (Meta.CURRENT_TIME);
}
}

public override void commit_progress (Gala.GestureAction action, double to) {
if (action != CLOSE_WINDOW || !Meta.Prefs.get_gnome_animations ()) {
return;
}

if (to == 1.0 && get_current_progress (SWITCH_WORKSPACE) != 0) {
Idle.add (() => {
gesture_controller.goto (0.0);
return Source.REMOVE;
});
} else if (get_current_progress (CLOSE_WINDOW) == 1.0 && to == 1.0) {
close_window (Meta.CURRENT_TIME);
}
}

public override void end_progress (GestureAction action) {
update_hover_widgets (false);
if (action == MULTITASKING_VIEW) {
update_hover_widgets (false);
}
}

public override void allocate (Clutter.ActorBox box) {
base.allocate (box);

var input_rect = window.get_buffer_rect ();
var outer_rect = window.get_frame_rect ();
var clone_scale_factor = width / outer_rect.width;

// Compensate for invisible borders of the texture
float clone_x = (input_rect.x - outer_rect.x) * clone_scale_factor;
float clone_y = (input_rect.y - outer_rect.y) * clone_scale_factor;

var clone_container_alloc = InternalUtils.actor_box_from_rect (clone_x, clone_y, input_rect.width * clone_scale_factor, input_rect.height * clone_scale_factor);
clone_container.allocate (clone_container_alloc);

if (clone == null || (drag_action != null && drag_action.dragging)) {
return;
}

var input_rect = window.get_buffer_rect ();
var outer_rect = window.get_frame_rect ();
var clone_scale_factor = width / outer_rect.width;
unowned var display = wm.get_display ();

clone.set_scale (clone_scale_factor, clone_scale_factor);

float clone_width, clone_height;
clone.get_preferred_size (null, null, out clone_width, out clone_height);

// Compensate for invisible borders of the texture
float clone_x = (input_rect.x - outer_rect.x) * clone_scale_factor;
float clone_y = (input_rect.y - outer_rect.y) * clone_scale_factor;

var clone_alloc = InternalUtils.actor_box_from_rect (clone_x, clone_y, clone_width, clone_height);
var clone_alloc = InternalUtils.actor_box_from_rect (0, 0, clone_width, clone_height);
clone.allocate (clone_alloc);

Clutter.ActorBox shape_alloc = {
Expand Down Expand Up @@ -380,15 +434,17 @@ public class Gala.WindowClone : ActorTarget {
}

private void check_confirm_dialog (int monitor, Meta.Window new_window) {
if (new_window.get_transient_for () == window) {
Idle.add (() => {
Idle.add (() => {
if (new_window.get_transient_for () == window) {
gesture_controller.goto (0.0);
selected ();
return Source.REMOVE;
});

SignalHandler.disconnect (window.get_display (), check_confirm_dialog_cb);
check_confirm_dialog_cb = 0;
}
SignalHandler.disconnect (window.get_display (), check_confirm_dialog_cb);
check_confirm_dialog_cb = 0;
}

return Source.REMOVE;
});
}

/**
Expand Down Expand Up @@ -419,7 +475,7 @@ public class Gala.WindowClone : ActorTarget {
selected ();
break;
case Clutter.Button.MIDDLE:
close_window (display.get_current_time ());
close_window (wm.get_display ().get_current_time ());
break;
}
}
Expand Down Expand Up @@ -479,7 +535,7 @@ public class Gala.WindowClone : ActorTarget {
close_button.opacity = 0;
window_title.opacity = 0;

display.set_cursor (Meta.Cursor.DND_IN_DRAG);
wm.get_display ().set_cursor (Meta.Cursor.DND_IN_DRAG);

return this;
}
Expand Down Expand Up @@ -532,7 +588,7 @@ public class Gala.WindowClone : ActorTarget {
}
}

display.set_cursor (hovered ? Meta.Cursor.DND_MOVE: Meta.Cursor.DND_IN_DRAG);
wm.get_display ().set_cursor (hovered ? Meta.Cursor.DND_MOVE: Meta.Cursor.DND_IN_DRAG);
}

/**
Expand All @@ -541,8 +597,10 @@ public class Gala.WindowClone : ActorTarget {
* otherwise we cancel the drag and animate back to our old place.
*/
private void drag_end (Clutter.Actor destination) {
unowned var display = wm.get_display ();

Meta.Workspace workspace = null;
var primary = window.get_display ().get_primary_monitor ();
var primary = display.get_primary_monitor ();

active_shape.show ();

Expand Down Expand Up @@ -631,7 +689,7 @@ public class Gala.WindowClone : ActorTarget {

request_reposition ();

display.set_cursor (Meta.Cursor.DEFAULT);
wm.get_display ().set_cursor (Meta.Cursor.DEFAULT);

if (duration > 0) {
ulong handler = 0;
Expand Down
Loading