import Meta from 'gi://Meta'; import St from 'gi://St'; import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; export default class TransparentTopBarExtension extends Extension { constructor(metadata) { super(metadata); this._actorSignalIds = null; this._windowSignalIds = null; } enable() { this._actorSignalIds = new Map(); this._windowSignalIds = new Map(); this._actorSignalIds.set(Main.overview, [ Main.overview.connect('showing', this._updateTransparent.bind(this)), Main.overview.connect('hiding', this._updateTransparent.bind(this)) ]); this._actorSignalIds.set(Main.sessionMode, [ Main.sessionMode.connect('updated', this._updateTransparent.bind(this)) ]); for (const metaWindowActor of global.get_window_actors()) { this._onWindowActorAdded(metaWindowActor.get_parent(), metaWindowActor); } this._actorSignalIds.set(global.window_group, [ global.window_group.connect('child-added', this._onWindowActorAdded.bind(this)), global.window_group.connect('child-removed', this._onWindowActorRemoved.bind(this)) ]); this._updateTransparent(); } disable() { for (const actorSignalIds of [this._actorSignalIds, this._windowSignalIds]) { for (const [actor, signalIds] of actorSignalIds) { for (const signalId of signalIds) { actor.disconnect(signalId); } } } this._actorSignalIds = null; this._windowSignalIds = null; Main.panel.remove_style_class_name('transparent-top-bar'); } _onWindowActorAdded(container, metaWindowActor) { this._windowSignalIds.set(metaWindowActor, [ metaWindowActor.connect('notify::allocation', this._updateTransparent.bind(this)), metaWindowActor.connect('notify::visible', this._updateTransparent.bind(this)) ]); } _onWindowActorRemoved(container, metaWindowActor) { for (const signalId of this._windowSignalIds.get(metaWindowActor)) { metaWindowActor.disconnect(signalId); } this._windowSignalIds.delete(metaWindowActor); this._updateTransparent(); } _updateTransparent() { if (Main.panel.has_style_pseudo_class('overview') || !Main.sessionMode.hasWindows) { this._setTransparent(true); return; } if (!Main.layoutManager.primaryMonitor) { return; } // Get all the windows in the active workspace that are in the primary monitor and visible. const workspaceManager = global.workspace_manager; const activeWorkspace = workspaceManager.get_active_workspace(); const windows = activeWorkspace.list_windows().filter(metaWindow => { return metaWindow.is_on_primary_monitor() && metaWindow.showing_on_its_workspace() && !metaWindow.is_hidden() && metaWindow.get_window_type() !== Meta.WindowType.DESKTOP; }); // Check if at least one window is near enough to the panel. const panelTop = Main.panel.get_transformed_position()[1]; const panelBottom = panelTop + Main.panel.get_height(); const scale = St.ThemeContext.get_for_stage(global.stage).scale_factor; const isNearEnough = windows.some(metaWindow => { const verticalPosition = metaWindow.get_frame_rect().y; if ( panelTop < 0 ) { return verticalPosition < panelBottom + Main.panel.get_height() + 5 * scale; } else { return verticalPosition < panelBottom + 5 * scale ; } }); this._setTransparent(!isNearEnough); } _setTransparent(transparent) { if (transparent) { Main.panel.add_style_class_name('transparent-top-bar'); } else { Main.panel.remove_style_class_name('transparent-top-bar'); } } };