/* eslint-disable no-invalid-this */ /* eslint-disable no-undef */ /* The above is for use of global in this file as Shell.global */ /* Gnome Shell Override * * Copyright (C) 2023 Sundeep Mediratta (smedius@gmail.com) * * 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, version 3 of the License. * * 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, see . */ /* exported GnomeShellOverride */ const {Meta, Clutter, GObject} = imports.gi; // Show desktop windows on workspace thumbnails const SHOW_ON_WORKSPACE_THUMBNAILS = true; const SHOW_ICONS_ON_OVERVIEW = false; const ANIMATION_MULTIPLE = 1; import {WorkspaceBackground} from 'resource:///org/gnome/shell/ui/workspace.js'; import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import * as Util from 'resource:///org/gnome/shell/misc/util.js'; export {GnomeShellOverride}; var GnomeShellOverride = class { constructor() { this._injectionManager = new InjectionManager(); } enable() { const Background = WorkspaceBackground; this._injectionManager.overrideMethod(Background.prototype, '_init', this._newBackgroundInit.bind(this)); } disable() { this._injectionManager.clear(); } _newBackgroundInit(origninalMethod) { return function (...args) { origninalMethod.call(this, ...args); /** @enum {number} */ const ControlsState = { HIDDEN: 0, WINDOW_PICKER: 1, APP_GRID: 2, }; const opaque = 255; const transparent = 0; const adjustment = Main.overview._overview._controls._stateAdjustment function _windowIsOnThisMonitor(metawindow, monitorIndex) { const geometry = global.display.get_monitor_geometry(monitorIndex); const [intersects] = metawindow.get_frame_rect().intersect(geometry); return intersects; } function _modifyTransparency(value) { const {initialState, finalState, } = adjustment.getStateTransitionParams(); if ((initialState == ControlsState.HIDDEN || finalState == ControlsState.HIDDEN) && (Math.abs(initialState - finalState) == 1)) return _setTransparency(value); return transparent; } function _setTransparency(value) { if (SHOW_ICONS_ON_OVERVIEW) return opaque; return Util.lerp(opaque, transparent, Math.min(ANIMATION_MULTIPLE * value, 1.0)); } const desktopWindows = global.get_window_actors().filter(a => a.meta_window.get_window_type() === Meta.WindowType.DESKTOP && _windowIsOnThisMonitor(a.meta_window, this._monitorIndex)); if (desktopWindows.length) { const desktopLayer = new Clutter.Actor({ layout_manager: new DesktopLayout(), clip_to_allocation: true, }); for (let windowActor of desktopWindows) { const clone = new Clutter.Clone({ source: windowActor, }); desktopLayer.add_child(clone); windowActor.connectObject('destroy', () => { clone.destroy(); }, this); } const offset = 0; const syncAll = Clutter.BindConstraint.new( this._bgManager.backgroundActor, Clutter.BindCoordinate.ALL, offset); desktopLayer.add_constraint(syncAll); desktopLayer.opacity = _setTransparency(opaque); this._stateAdjustment.connectObject('notify::value', (stAdjustment) => { if (SHOW_ON_WORKSPACE_THUMBNAILS) desktopLayer.opacity = _setTransparency(this._stateAdjustment.value); else desktopLayer.opacity = _modifyTransparency(stAdjustment.value); }, this ); this._backgroundGroup.insert_child_above( desktopLayer, this._bgManager.backgroundActor ); } }; } }; class DesktopLayout extends Clutter.LayoutManager { static { GObject.registerClass(this); } vfunc_get_preferred_width() { return [0, 0]; } vfunc_get_preferred_height() { return [0, 0]; } vfunc_allocate(container, box) { const monitorIndex = Main.layoutManager.findIndexForActor(container); const monitor = Main.layoutManager.monitors[monitorIndex]; const hscale = box.get_width() / monitor.width; const vscale = box.get_height() / monitor.height; for (const child of container) { const childBox = new Clutter.ActorBox(); const frameRect = child.get_source()?.metaWindow.get_frame_rect(); childBox.set_size( Math.round(frameRect.width * hscale), Math.round(frameRect.height * vscale) ); childBox.set_origin( Math.round((frameRect.x - monitor.x) * hscale), Math.round((frameRect.y - monitor.y) * vscale) ); child.allocate(childBox); } } }