Fix memory consumption issue on window resize, update cursor cloning approach, fix ability to drag windows between workspaces on the launcher view
This commit is contained in:
parent
9dad741cc8
commit
4d85db204b
|
|
@ -6,8 +6,7 @@ import Globals from './globals.js';
|
|||
|
||||
// Taken from https://github.com/jkitching/soft-brightness-plus
|
||||
export class CursorManager {
|
||||
constructor(mainActor, targetMonitors, refreshRate) {
|
||||
this._mainActor = mainActor;
|
||||
constructor(targetMonitors, refreshRate) {
|
||||
this._targetMonitors = targetMonitors;
|
||||
this._refreshRate = refreshRate;
|
||||
|
||||
|
|
@ -111,7 +110,6 @@ export class CursorManager {
|
|||
// prereqs: setup in _enableCloningMouse
|
||||
_startCloningMouse() {
|
||||
Globals.logger.log_debug('CursorManager _startCloningMouse');
|
||||
this._mainActor.add_child(this._cursorRoot);
|
||||
|
||||
this._updateMouseSprite();
|
||||
this._cursorTracker.connectObject('cursor-changed', this._updateMouseSprite.bind(this), this);
|
||||
|
|
@ -122,10 +120,6 @@ export class CursorManager {
|
|||
|
||||
this._cursorWatch = PointerWatcher.getPointerWatcher().addWatch(interval, this._updateMousePosition.bind(this));
|
||||
this._updateMousePosition();
|
||||
|
||||
const [xMouse, yMouse] = global.get_pointer();
|
||||
|
||||
if (this._targetMonitors.some(monitor => this._isWithinMonitorBounds(xMouse, yMouse, monitor))) this._hideSystemCursor();
|
||||
}
|
||||
|
||||
// After this:
|
||||
|
|
@ -145,7 +139,6 @@ export class CursorManager {
|
|||
if (this._mouseSprite?.content?.texture) this._mouseSprite.content.texture = null;
|
||||
Meta.enable_unredirect_for_display(global.display);
|
||||
|
||||
if (this._cursorRoot) this._mainActor.remove_child(this._cursorRoot);
|
||||
if (!this._systemCursorShown) this._showSystemCursor();
|
||||
}
|
||||
|
||||
|
|
@ -169,23 +162,54 @@ export class CursorManager {
|
|||
|
||||
_updateMousePosition(...args) {
|
||||
const [xMouse, yMouse] = args.length ? args : global.get_pointer();
|
||||
const inBounds = this._targetMonitors.some(monitor => this._isWithinMonitorBounds(xMouse, yMouse, monitor));
|
||||
let onMonitorIndex;
|
||||
let xRel;
|
||||
let yRel;
|
||||
|
||||
if (xMouse === this.xMouse && yMouse === this.yMouse)
|
||||
return;
|
||||
const inBoundsCheck = (monitorObj, index) => {
|
||||
const inBoundsCoordinates = this._getInBoundsCoordinates(xMouse, yMouse, monitorObj.monitor);
|
||||
if (inBoundsCoordinates) {
|
||||
onMonitorIndex = index;
|
||||
xRel = inBoundsCoordinates.xRel;
|
||||
yRel = inBoundsCoordinates.yRel;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inBounds) {
|
||||
if (this._cursorRoot && this._mainActor.get_last_child() !== this._cursorRoot)
|
||||
this._mainActor.set_child_above_sibling(this._cursorRoot, null);
|
||||
// check the previously in-bounds monitor first to avoid iterating over the whole list in the likely case that the cursor
|
||||
// is still on the same monitor
|
||||
if (this.onMonitorIndex === undefined || !inBoundsCheck(this._targetMonitors[this.onMonitorIndex], this.onMonitorIndex)) {
|
||||
for (let i = 0; i < this._targetMonitors.length; i++) {
|
||||
if (this.onMonitorIndex === i) continue;
|
||||
if (inBoundsCheck(this._targetMonitors[i], i)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.onMonitorIndex !== onMonitorIndex) {
|
||||
try {
|
||||
if (this.onMonitorIndex !== undefined) this._targetMonitors[this.onMonitorIndex].actor.remove_child(this._cursorRoot);
|
||||
|
||||
this.onMonitorIndex = onMonitorIndex;
|
||||
if (this.onMonitorIndex !== undefined) {
|
||||
const actor = this._targetMonitors[this.onMonitorIndex].actor;
|
||||
actor.add_child(this._cursorRoot);
|
||||
actor.set_child_above_sibling(this._cursorRoot, null);
|
||||
}
|
||||
} catch (e) {
|
||||
Globals.logger.log_debug(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.onMonitorIndex !== undefined) {
|
||||
if (this._systemCursorShown) this._hideSystemCursor();
|
||||
this._cursorRoot.set_position(xMouse, yMouse);
|
||||
} else if (!this._systemCursorShown && !inBounds) {
|
||||
this._cursorRoot.set_position(xRel, yRel);
|
||||
} else if (!this._systemCursorShown) {
|
||||
this._showSystemCursor();
|
||||
}
|
||||
|
||||
this.xMouse = xMouse;
|
||||
this.yMouse = yMouse;
|
||||
this.xRel = xRel;
|
||||
this.xRel = xRel;
|
||||
|
||||
const seat = Clutter.get_default_backend().get_default_seat();
|
||||
if (this._cursorUnfocusInhibited && !seat.is_unfocus_inhibited()) {
|
||||
|
|
@ -214,8 +238,16 @@ export class CursorManager {
|
|||
}
|
||||
}
|
||||
|
||||
_isWithinMonitorBounds(x, y, monitor) {
|
||||
return x >= monitor.x && x < monitor.x + monitor.width &&
|
||||
y >= monitor.y && y < monitor.y + monitor.height;
|
||||
_getInBoundsCoordinates(x, y, monitor) {
|
||||
const xRel = x - monitor.x;
|
||||
const yRel = y - monitor.y;
|
||||
if (xRel >= 0 && xRel < monitor.width && yRel >= 0 && yRel < monitor.height) {
|
||||
return {
|
||||
xRel,
|
||||
yRel,
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -250,9 +250,6 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
const virtualMonitors = this._find_virtual_monitors();
|
||||
const refreshRate = targetMonitor.refreshRate ?? 60;
|
||||
|
||||
this._cursor_manager = new CursorManager(Main.layoutManager.uiGroup, [targetMonitor, ...virtualMonitors], refreshRate);
|
||||
this._cursor_manager.enable();
|
||||
|
||||
// use rgba(255, 4, 144, 1) for chroma key background
|
||||
this._overlay = new St.Bin({ style: 'background-color: rgba(0, 0, 0, 1);', clip_to_allocation: true });
|
||||
this._overlay.opacity = 255;
|
||||
|
|
@ -285,16 +282,15 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
Shell.util_set_hidden_from_pick(this._overlay, true);
|
||||
global.stage.add_child(this._overlay);
|
||||
|
||||
// In GS 45, use of "actor" was renamed to "child".
|
||||
const clutterContainer = Clutter.Container !== undefined;
|
||||
this._actor_added_connection = global.stage.connect(
|
||||
clutterContainer ? 'actor-added' : 'child-added',
|
||||
this._handle_sibling_update.bind(this),
|
||||
);
|
||||
this._actor_removed_connection = global.stage.connect(
|
||||
clutterContainer ? 'actor-removed' : 'child-removed',
|
||||
this._handle_sibling_update.bind(this),
|
||||
);
|
||||
const cursor_manager_monitor_objs = this._overlay_content.monitor_actors.map(monitor => {
|
||||
return {
|
||||
monitor: monitor.monitorDetails,
|
||||
actor: monitor.containerActor
|
||||
};
|
||||
});
|
||||
|
||||
this._cursor_manager = new CursorManager(cursor_manager_monitor_objs, refreshRate);
|
||||
this._cursor_manager.enable();
|
||||
|
||||
this._update_follow_threshold(this.settings);
|
||||
|
||||
|
|
@ -342,11 +338,6 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
}
|
||||
}
|
||||
|
||||
_handle_sibling_update() {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _handle_sibling_update()');
|
||||
global.stage.set_child_above_sibling(this._overlay, null);
|
||||
}
|
||||
|
||||
_add_settings_keybinding(settings_key, bind_to_function) {
|
||||
try {
|
||||
Main.wm.addKeybinding(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import GLib from 'gi://GLib';
|
|||
import GObject from 'gi://GObject';
|
||||
import Mtk from 'gi://Mtk';
|
||||
import Shell from 'gi://Shell';
|
||||
import St from 'gi://St';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
import Globals from './globals.js';
|
||||
|
|
@ -339,6 +340,12 @@ export const VirtualMonitorEffect = GObject.registerClass({
|
|||
'Target and virtual monitor placement details, as relevant to rendering',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'target-monitor': GObject.ParamSpec.jsobject(
|
||||
'target-monitor',
|
||||
'Target Monitor',
|
||||
'Details about the monitor being used as a viewport',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'imu-snapshots': GObject.ParamSpec.jsobject(
|
||||
'imu-snapshots',
|
||||
'IMU Snapshots',
|
||||
|
|
@ -631,7 +638,11 @@ export const VirtualMonitorEffect = GObject.registerClass({
|
|||
float cogl_position_width = cogl_position_mystery_factor * aspect_ratio / u_actor_to_display_ratios.y;
|
||||
float cogl_position_height = cogl_position_width / aspect_ratio;
|
||||
|
||||
vec3 pos_factors = vec3(cogl_position_width / u_display_resolution.x, cogl_position_height / u_display_resolution.y, cogl_position_mystery_factor / u_display_resolution.x);
|
||||
vec3 pos_factors = vec3(
|
||||
cogl_position_width / u_display_resolution.x,
|
||||
cogl_position_height / u_display_resolution.y,
|
||||
cogl_position_mystery_factor / u_display_resolution.x
|
||||
);
|
||||
world_pos.x -= u_display_position.x * pos_factors.x;
|
||||
world_pos.y -= u_display_position.y * pos_factors.y;
|
||||
world_pos.z = u_display_position.z * pos_factors.z;
|
||||
|
|
@ -697,7 +708,7 @@ export const VirtualMonitorEffect = GObject.registerClass({
|
|||
);
|
||||
this.set_uniform_matrix(this.get_uniform_location("u_projection_matrix"), false, 4, projection_matrix);
|
||||
this.set_uniform_float(this.get_uniform_location("u_fov_vertical_radians"), 1, [fovVerticalRadians]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_display_resolution"), 2, [this.get_actor().width, this.get_actor().height]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_display_resolution"), 2, [this.target_monitor.width, this.target_monitor.height]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_look_ahead_cfg"), 4, Globals.data_stream.device_data.lookAheadCfg);
|
||||
this.set_uniform_float(this.get_uniform_location("u_actor_to_display_ratios"), 2, this.actor_to_display_ratios);
|
||||
this.set_uniform_float(this.get_uniform_location("u_actor_to_display_offsets"), 2, this.actor_to_display_offsets);
|
||||
|
|
@ -771,6 +782,12 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
'Target and virtual monitor placement details, as relevant to rendering',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'monitor-actors': GObject.ParamSpec.jsobject(
|
||||
'monitor-actors',
|
||||
'Monitor Actors',
|
||||
'Tracking actors and details for each monitor',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'imu-snapshots': GObject.ParamSpec.jsobject(
|
||||
'imu-snapshots',
|
||||
'IMU Snapshots',
|
||||
|
|
@ -910,13 +927,14 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
);
|
||||
this.bannerActor.set_content(this.custom_banner_enabled ? this.customBannerContent : this.bannerContent);
|
||||
this.bannerActor.hide();
|
||||
|
||||
this.monitor_actors = [];
|
||||
}
|
||||
|
||||
renderMonitors() {
|
||||
// collect bindings and connections to clean up on dispose
|
||||
this._property_bindings = [];
|
||||
this._property_connections = [];
|
||||
this._monitor_actors = [];
|
||||
|
||||
const notifyToFunction = ((property, fn) => {
|
||||
this._property_connections.push(this.connect(`notify::${property}`, fn.bind(this)));
|
||||
|
|
@ -956,17 +974,21 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
Globals.logger.log_debug(`\t\t\tMonitor ${index}: ${monitor.x}, ${monitor.y}, ${monitor.width}, ${monitor.height}`);
|
||||
|
||||
const containerActor = new Clutter.Actor({
|
||||
width: this.target_monitor.width,
|
||||
height: this.target_monitor.height
|
||||
clip_to_allocation: true
|
||||
});
|
||||
const viewport = new St.Bin({
|
||||
child: containerActor,
|
||||
width: monitor.width,
|
||||
height: monitor.height
|
||||
});
|
||||
|
||||
// Create a clone of the stage content for this monitor
|
||||
const monitorClone = new Clutter.Clone({
|
||||
source: Main.layoutManager.uiGroup,
|
||||
clip_to_allocation: true,
|
||||
x: -monitor.x,
|
||||
y: -monitor.y
|
||||
});
|
||||
monitorClone.set_clip(monitor.x, monitor.y, monitor.width, monitor.height);
|
||||
|
||||
// Add the monitor actor to the scene
|
||||
containerActor.add_child(monitorClone);
|
||||
|
|
@ -975,6 +997,7 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
imu_snapshots: this.imu_snapshots,
|
||||
monitor_index: index,
|
||||
monitor_placements: this.monitor_placements,
|
||||
target_monitor: this.target_monitor,
|
||||
display_distance: this.display_distance,
|
||||
display_distance_default: this._display_distance_default(),
|
||||
actor_to_display_ratios: actorToDisplayRatios,
|
||||
|
|
@ -982,17 +1005,20 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
lens_vector: this.lens_vector,
|
||||
show_banner: this.show_banner
|
||||
});
|
||||
containerActor.add_effect_with_name('viewport-effect', effect);
|
||||
this.add_child(containerActor);
|
||||
viewport.add_effect_with_name('viewport-effect', effect);
|
||||
this.add_child(viewport);
|
||||
Shell.util_set_hidden_from_pick(viewport, true);
|
||||
|
||||
this._monitor_actors.push({
|
||||
this.monitor_actors.push({
|
||||
viewport,
|
||||
containerActor,
|
||||
monitorClone,
|
||||
effect
|
||||
effect,
|
||||
monitorDetails: monitor
|
||||
});
|
||||
|
||||
// do this so the primary monitor is always on top at first, before the focused monitor logic comes into play
|
||||
this.set_child_below_sibling(containerActor, null);
|
||||
this.set_child_below_sibling(viewport, null);
|
||||
|
||||
[
|
||||
'monitor-placements',
|
||||
|
|
@ -1018,7 +1044,7 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
// in addition to rendering distance properly in the shader, the parent actor determines overlap based on child ordering
|
||||
effect.connect('notify::is-closest', ((actor, _pspec) => {
|
||||
if (!this._is_disposed && actor.is_closest) {
|
||||
this.set_child_above_sibling(containerActor, null);
|
||||
this.set_child_above_sibling(viewport, null);
|
||||
if (this.show_banner) this.set_child_above_sibling(this.bannerActor, null);
|
||||
}
|
||||
}).bind(this));
|
||||
|
|
@ -1063,7 +1089,7 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
|
||||
Globals.data_stream.refresh_data();
|
||||
this.imu_snapshots = Globals.data_stream.imu_snapshots;
|
||||
this.queue_redraw();
|
||||
this.monitor_actors.forEach(({ monitorClone }) => monitorClone.queue_redraw());
|
||||
this._last_redraw = Date.now();
|
||||
}).bind(this));
|
||||
this._redraw_timeline.set_repeat_count(-1);
|
||||
|
|
@ -1080,7 +1106,7 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
const fovVerticalRadians = Math.atan(Math.tan(fovVerticalRadiansInitial) / this._display_distance_default());
|
||||
|
||||
// distance needed for the FOV-sized monitor to fill up the screen
|
||||
const fullScreenDistance = this.target_monitor.height / 2 / Math.sin(fovVerticalRadians / 2);
|
||||
const fullScreenDistance = this.target_monitor.height / 2 / Math.tan(fovVerticalRadians / 2);
|
||||
|
||||
return {
|
||||
widthPixels: this.target_monitor.width,
|
||||
|
|
@ -1172,12 +1198,13 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
this._redraw_timeline = null;
|
||||
}
|
||||
|
||||
this._monitor_actors.forEach(({ containerActor, monitorClone, effect }) => {
|
||||
containerActor.remove_effect(effect);
|
||||
this.monitor_actors.forEach(({ viewport, containerActor, monitorClone, effect }) => {
|
||||
viewport.remove_effect(effect);
|
||||
containerActor.remove_child(monitorClone);
|
||||
this.remove_child(containerActor);
|
||||
viewport.remove_child(containerActor);
|
||||
this.remove_child(viewport);
|
||||
});
|
||||
this._monitor_actors = [];
|
||||
this.monitor_actors = [];
|
||||
|
||||
this._property_bindings.forEach(binding => binding.unbind());
|
||||
this._property_bindings = [];
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 4f299ecc7da6d4cdfb164cbcb22f60580fb2295a
|
||||
Subproject commit 64c31bb7f40f911130d69a7ca83ef9617c3d0e07
|
||||
Loading…
Reference in New Issue