/* ======================================================================================================== * intellihide.js - intellihide functions * -------------------------------------------------------------------------------------------------------- * CREDITS: This code was copied from the dash-to-dock extension https://github.com/micheleg/dash-to-dock * and modified to create a workspaces dock. Many thanks to michele_g for a great extension. * ======================================================================================================== */ const GLib = imports.gi.GLib; const Lang = imports.lang; const Meta = imports.gi.Meta; const Signals = imports.signals; const Shell = imports.gi.Shell; const Gdk = imports.gi.Gdk; const St = imports.gi.St; const Main = imports.ui.main; const GrabHelper = imports.ui.grabHelper; const Config = imports.misc.config; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; const handledWindowTypes = [ Meta.WindowType.NORMAL, // Meta.WindowType.DESKTOP, // skip nautilus dekstop window // Meta.WindowType.DOCK, // skip other docks Meta.WindowType.DIALOG, Meta.WindowType.MODAL_DIALOG, Meta.WindowType.TOOLBAR, Meta.WindowType.MENU, Meta.WindowType.UTILITY, Meta.WindowType.SPLASHSCREEN ]; const handledWindowTypes2 = [ Meta.WindowType.POPUP_MENU, Meta.WindowType.DROPDOWN_MENU, Meta.WindowType.TOOLTIP ]; const IntellihideAction = { SHOW_FULL: 0, SHOW_PARTIAL: 1, SHOW_PARTIAL_FIXED: 2 }; const OverviewAction = { SHOW_FULL: 0, // Dock is always visible HIDE: 1, // Dock is always invisible. Visible on mouse hover SHOW_PARTIAL: 2 // Dock partially hidden. Visible on mouse hover }; const DockState = { HIDDEN: 0, SHOWING: 1, SHOWN: 2, HIDING: 3 }; let GSFunctions = {}; /* * A rough and ugly implementation of the intellihide behaviour. * Intellihide object: call show()/hide() function based on the overlap with the * the dock staticBox object; * * Dock object has to contain a Clutter.ActorBox object named staticBox and * emit a 'box-changed' signal when this changes. * */ var Intellihide = class WorkspacesToDock_Intellihide { constructor(dock) { this._gsCurrentVersion = Config.PACKAGE_VERSION.split('.'); this._settings = Convenience.getSettings('org.gnome.shell.extensions.workspaces-to-dock'); this._signalHandler = new Convenience.globalSignalHandler(); // Dock object this._dock = dock; // temporarily disable intellihide until initialized (prevents connected signals from trying to update dock visibility) this._disableIntellihide = true; // Override Gnome Shell functions this._overrideGnomeShellFunctions(); // Load settings this._bindSettingsChanges(); this._tracker = Shell.WindowTracker.get_default(); this._topWindow = null; this._focusedWin = null; // initial intellihide status is null this.status = null; // Keep track of the current overview mode (I mean if it is on/off) this._inOverview = false; // Flag set when overview mode is toggled by window drag event this._toggledOverviewOnDrag = false; // Main id of _init: function(dock) { the timeout controlling timeout for updateDockVisibility function // when windows are dragged around (move and resize) this._windowChangedTimeout = 0; // Quick show timeout this._switchWorkspaceQuickShow = this._settings.get_boolean('quick-show-on-workspace-change'); this._quickShowTimeoutId = 0; // Connect global signals this._signalHandler.push( // call updateVisibility when dock actor changes [ this._dock, 'box-changed', this._onDockSettingsChanged.bind(this) ], // Add timeout when window grab-operation begins and remove it when it ends. // These signals only exist starting from Gnome-Shell 3.4 [ global.display, 'grab-op-begin', this._grabOpBegin.bind(this) ], [ global.display, 'grab-op-end', this._grabOpEnd.bind(this) ], // direct maximize/unmazimize are not included in grab-operations [ global.window_manager, 'unminimize', this._onWindowUnminimized.bind(this) ], [ global.window_manager, 'minimize', this._onWindowMinimized.bind(this) ], [ global.window_manager, 'size-change', this._onWindowSizeChange.bind(this) ], [ global.window_manager, 'size-changed', this._onWindowSizeChanged.bind(this) ], // Probably this is also included in restacked? [ global.window_manager, 'switch-workspace', this._switchWorkspace.bind(this) ], [ global.display, 'in-fullscreen-changed', this._onFullscreenChanged.bind(this) ], // trigggered for instance when a window is closed. [ global.display, 'restacked', this._onScreenRestacked.bind(this) ], // when windows are alwasy on top, the focus window can change // without the windows being restacked. Thus monitor window focus change. [ this._tracker, 'notify::focus-app', this._onFocusAppChanged.bind(this) ], // Set visibility in overview mode [ Main.overview, 'showing', this._overviewEntered.bind(this) ], [ Main.overview, 'hiding', this._overviewExiting.bind(this) ], [ Main.overview, 'hidden', this._overviewExited.bind(this) ], // window-drag-events emitted from workspaces thumbnail window dragging action [ Main.overview, 'window-drag-begin', this._onWindowDragBegin.bind(this) ], [ Main.overview, 'window-drag-cancelled', this._onWindowDragCancelled.bind(this) ], [ Main.overview, 'window-drag-end', this._onWindowDragEnd.bind(this) ], // item-drag-events emitted from app display icon dragging action [ Main.overview, 'item-drag-begin', this._onItemDragBegin.bind(this) ], [ Main.overview, 'item-drag-cancelled', this._onItemDragCancelled.bind(this) ], [ Main.overview, 'item-drag-end', this._onItemDragEnd.bind(this) ], // update when monitor changes, for instance in multimonitor when monitors are attached [ Main.layoutManager, 'monitors-changed', this._onMonitorsChanged.bind(this) ], [ Main.panel.menuManager._grabHelper, 'focus-grabbed', this._onPanelFocusGrabbed.bind(this) ], [ Main.panel.menuManager._grabHelper, 'focus-ungrabbed', this._onPanelFocusUngrabbed.bind(this) ], [ Main.overview.viewSelector, 'page-changed', this._overviewPageChanged.bind(this) ] ); // if background manager valid, Connect grabHelper signals let primaryIndex = Main.layoutManager.primaryIndex; if (Main.layoutManager._bgManagers[primaryIndex]) { this._signalHandler.pushWithLabel( 'bgManagerSignals', [ Main.layoutManager._bgManagers[primaryIndex].backgroundActor._backgroundManager._grabHelper, 'focus-grabbed', this._onPanelFocusGrabbed.bind(this) ], [ Main.layoutManager._bgManagers[primaryIndex].backgroundActor._backgroundManager._grabHelper, 'focus-ungrabbed', this._onPanelFocusUngrabbed.bind(this) ] ); } // Start main loop and bind initialize function GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, this._initialize.bind(this)); } _initialize() { // enable intellihide now this._disableIntellihide = false; // updte dock visibility this._updateDockVisibility(); } destroy() { // Disconnect global signals this._signalHandler.disconnect(); this._restoreGnomeShellFunctions(); // Disconnect GSettings signals this._settings.run_dispose(); if (this._windowChangedTimeout > 0) GLib.source_remove(this._windowChangedTimeout); // Just to be sure } // Called during init to override/extend gnome shell functions _overrideGnomeShellFunctions() { // Extend the GrabHelper grab function to emit a signal when focus is grabbed GSFunctions['GrabHelper_grab'] = GrabHelper.GrabHelper.prototype.grab; GrabHelper.GrabHelper.prototype.grab = function(params) { let ret = GSFunctions['GrabHelper_grab'].call(this, params); if (ret) this.emit('focus-grabbed'); return ret; }; // Extend the GrabHelper ungrab function to emit a signal when focus is ungrabbed GSFunctions['GrabHelper_ungrab'] = GrabHelper.GrabHelper.prototype.ungrab; GrabHelper.GrabHelper.prototype.ungrab = function(params) { let ret = GSFunctions['GrabHelper_ungrab'].call(this, params); this.emit('focus-ungrabbed'); return ret; }; Signals.addSignalMethods(GrabHelper.GrabHelper.prototype); } // main function called during destroy to restore gnome shell functions _restoreGnomeShellFunctions() { // Restore normal GrabHelper grab function GrabHelper.GrabHelper.prototype.grab = GSFunctions['GrabHelper_grab']; // Restore normal GrabHelper ungrab function GrabHelper.GrabHelper.prototype.ungrab = GSFunctions['GrabHelper_ungrab']; } // handler to bind settings when preferences changed _bindSettingsChanges() { this._settings.connect('changed::intellihide', () => { this._updateDockVisibility(); }); this._settings.connect('changed::intellihide-option', () => { this._updateDockVisibility(); }); this._settings.connect('changed::dock-fixed', () => { if (this._settings.get_boolean('dock-fixed')) { this.status = true; // Since the dock is now shown } else { // Wait that windows rearrange after struts change GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { this._updateDockVisibility(); return false; }); } }); this._settings.connect('changed::quick-show-on-workspace-change', () => { this._switchWorkspaceQuickShow = this._settings.get_boolean('quick-show-on-workspace-change'); this._updateDockVisibility(); }); } // handler for when dock size-position is changed _onDockSettingsChanged() { this._updateDockVisibility(); } // handler for when window is unminimized _onWindowUnminimized() { this._updateDockVisibility(); } // handler for when window is minimized _onWindowMinimized() { this._updateDockVisibility(); } // handler for when window is resized _onWindowSizeChange() { this._updateDockVisibility(); } // handler for when window is resized _onWindowSizeChanged() { this._updateDockVisibility(); } // handler for when monitor in fullscreen _onFullscreenChanged() { this._updateDockVisibility(); } // handler for when screen is restacked _onScreenRestacked() { this._updateDockVisibility(); } // handler for when app focus changed _onFocusAppChanged() { this._updateDockVisibility(); } // handler for when monitor changes _onMonitorsChanged() { // disconnect bgManager signals this._signalHandler.disconnectWithLabel('bgManagerSignals'); // if background manager valid, Connect grabHelper signals let primaryIndex = Main.layoutManager.primaryIndex; if (!Main.layoutManager._bgManagers[primaryIndex] || !Main.layoutManager._bgManagers[primaryIndex].backgroundActor) return; this._signalHandler.pushWithLabel( 'bgManagerSignals', [ Main.layoutManager._bgManagers[primaryIndex].backgroundActor._backgroundManager._grabHelper, 'focus-grabbed', this._onPanelFocusGrabbed.bind(this) ], [ Main.layoutManager._bgManagers[primaryIndex].backgroundActor._backgroundManager._grabHelper, 'focus-ungrabbed', this._onPanelFocusUngrabbed.bind(this) ] ); this._updateDockVisibility(); } // handler for when thumbnail windows dragging started _onWindowDragBegin() { Main.overview.show(); this._toggledOverviewOnDrag = true; this._show(true); } // handler for when thumbnail windows dragging cancelled _onWindowDragCancelled() { if (this._toggledOverviewOnDrag) { this._toggledOverviewOnDrag = false; if (this._inOverview) { if (Main.overview.viewSelector._activePage == Main.overview.viewSelector._workspacesPage) { if (this._settings.get_boolean('dock-fixed')) { this._show(); } else { let overviewAction = this._settings.get_enum('overview-action'); if (overviewAction == OverviewAction.SHOW_FULL) { this._show(true); } else if (overviewAction == OverviewAction.SHOW_PARTIAL) { if (this._dock._dockState == DockState.SHOWING || this._dock._dockState == DockState.SHOWN) { this._hide(true); } else { this._show(); } } else if (overviewAction == OverviewAction.HIDE) { this._hide(); } } } else { this._hide(); } } } } // handler for when thumbnail windows dragging ended _onWindowDragEnd() { if (this._toggledOverviewOnDrag) { this._toggledOverviewOnDrag = false; if (this._inOverview) { if (Main.overview.viewSelector._activePage == Main.overview.viewSelector._workspacesPage) { if (this._settings.get_boolean('dock-fixed')) { this._show(); } else { let overviewAction = this._settings.get_enum('overview-action'); if (overviewAction == OverviewAction.SHOW_FULL) { this._show(true); } else if (overviewAction == OverviewAction.SHOW_PARTIAL) { if (this._dock._dockState == DockState.SHOWING || this._dock._dockState == DockState.SHOWN) { this._hide(true); } else { this._show(); } } else if (overviewAction == OverviewAction.HIDE) { this._hide(); } } } else { this._hide(); } } } } // handler for when app icon dragging started _onItemDragBegin() { Main.overview.show(); this._toggledOverviewOnDrag = true; this._show(true); } // handler for when app icon dragging cancelled _onItemDragCancelled() { if (this._toggledOverviewOnDrag) { this._toggledOverviewOnDrag = false; // Should we hide the dock? // GS38+ remains in same overview mode, therefore we need to detect mode to determine if we should hide dock. if (this._inOverview) { if (Main.overview.viewSelector._activePage == Main.overview.viewSelector._workspacesPage) { if (this._settings.get_boolean('dock-fixed')) { this._show(); } else { let overviewAction = this._settings.get_enum('overview-action'); if (overviewAction == OverviewAction.SHOW_FULL) { this._show(true); } else if (overviewAction == OverviewAction.SHOW_PARTIAL) { if (this._dock._dockState == DockState.SHOWING || this._dock._dockState == DockState.SHOWN) { this._hide(true); } else { this._show(); } } else if (overviewAction == OverviewAction.HIDE) { this._hide(); } } } else { this._hide(); } } } } // handler for when app icon dragging ended _onItemDragEnd() { if (this._toggledOverviewOnDrag) { this._toggledOverviewOnDrag = false; // Should we hide the dock? // GS38+ remains in same overview mode, therefore we need to detect mode to determine if we should hide dock. if (this._inOverview) { if (Main.overview.viewSelector._activePage == Main.overview.viewSelector._workspacesPage) { if (this._settings.get_boolean('dock-fixed')) { this._show(); } else { let overviewAction = this._settings.get_enum('overview-action'); if (overviewAction == OverviewAction.SHOW_FULL) { this._show(true); } else if (overviewAction == OverviewAction.SHOW_PARTIAL) { if (this._dock._dockState == DockState.SHOWING || this._dock._dockState == DockState.SHOWN) { this._hide(true); } else { this._show(); } } else if (overviewAction == OverviewAction.HIDE) { this._hide(); } } } else { this._hide(); } } } } // handler for when overview mode exiting _overviewExiting() { this._inOverview = false; this._updateDockVisibility(); } // handler for when overview mode exited _overviewExited() { } // handler for when overview mode entered _overviewEntered() { this._inOverview = true; if (Main.overview.viewSelector._activePage == Main.overview.viewSelector._workspacesPage) { if (this._settings.get_boolean('dock-fixed')) { this._show(); } else { let overviewAction = this._settings.get_enum('overview-action'); if (overviewAction == OverviewAction.SHOW_FULL) { this._show(true); } else if (overviewAction == OverviewAction.SHOW_PARTIAL) { if (this._dock._dockState == DockState.SHOWING || this._dock._dockState == DockState.SHOWN) { this._hide(true); } else { this._show(); } } else if (overviewAction == OverviewAction.HIDE) { this._hide(); } } } else { this._hide(); } } // handler for when Gnome Shell 3.6+ overview page is changed (GS36+) // for example, when Applications button is clicked the workspaces dock is hidden // or when search is started the workspaces dock is hidden _overviewPageChanged(source, page) { let newPage; if (page) newPage = page; else newPage = Main.overview.viewSelector._activePage; if (this._inOverview) { if (newPage == Main.overview.viewSelector._workspacesPage) { if (this._settings.get_boolean('dock-fixed')) { this._show(); } else { let overviewAction = this._settings.get_enum('overview-action'); if (overviewAction == OverviewAction.SHOW_FULL) { this._show(true); } else if (overviewAction == OverviewAction.SHOW_PARTIAL) { if (this._dock._dockState == DockState.SHOWING || this._dock._dockState == DockState.SHOWN) { this._hide(true); } else { this._show(); } } else if (overviewAction == OverviewAction.HIDE) { this._hide(); } } } else { this._hide(); } } } // handler for when panel focus is grabbed (GS 38+) _onPanelFocusGrabbed(source, event) { if (this._settings.get_boolean('ignore-top-panel')) return; let idx = source._grabStack.length - 1; let focusedActor = source._grabStack[idx].actor; let [rx, ry] = focusedActor.get_transformed_position(); let [rw, rh] = focusedActor.get_size(); let [dx, dy] = this._dock.actor.get_position(); let [dw, dh] = this._dock.actor.get_size(); let [dcx, dcy] = this._dock.actor.get_transformed_position(); let [dcw, dch] = this._dock.actor.get_size(); if (this._dock._isHorizontal) { dx = dcx; dw = dcw; let intellihideAction = this._settings.get_enum('intellihide-action'); if (intellihideAction == IntellihideAction.SHOW_PARTIAL || intellihideAction == IntellihideAction.SHOW_PARTIAL_FIXED) { if (this._dock._slider.partialSlideoutSize) dh = this._dock._slider.partialSlideoutSize; } } else { dy = dcy; dh = dch; let intellihideAction = this._settings.get_enum('intellihide-action'); if (intellihideAction == intellihideAction.SHOW_PARTIAL || intellihideAction == IntellihideAction.SHOW_PARTIAL_FIXED) { if (this._dock._slider.partialSlideoutSize) dw = this._dock._slider.partialSlideoutSize; } } let test; if (this._dock._position == St.Side.LEFT || this._dock._position == St.Side.TOP) { test = (rx < dx + dw) && (rx + rw > dx) && (ry < dy + dh) && (ry + rh > dy); } else if (this._dock._position == St.Side.RIGHT) { test = (rx < dx) && (rx + rw > dx - dw) && (ry < dy + dh) && (ry + rh > dy); } else if (this._dock._position == St.Side.BOTTOM) { test = (rx < dx + dw) && (rx + rw > dx) && (ry + rh > dy - dh) && (ry < dy); } if (test) { this._disableIntellihide = true; this._hide(); } } // handler for when panel focus is ungrabbed (GS 38+) _onPanelFocusUngrabbed(source, event) { if (this._settings.get_boolean('ignore-top-panel')) return; this._disableIntellihide = false; if (this._inOverview) { if (Main.overview.viewSelector._activePage == Main.overview.viewSelector._workspacesPage) this._show(); } else { this._updateDockVisibility(); } } // handler for when window move begins _grabOpBegin() { if (this._settings.get_boolean('intellihide')) { let INTERVAL = 100; // A good compromise between reactivity and efficiency; to be tuned. if (this._windowChangedTimeout > 0) GLib.source_remove(this._windowChangedTimeout); // Just to be sure this._windowChangedTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, INTERVAL, () => { this._updateDockVisibility(); return true; // to make the loop continue }); } } // handler for when window move ends _grabOpEnd() { if (this._settings.get_boolean('intellihide')) { if (this._windowChangedTimeout > 0) GLib.source_remove(this._windowChangedTimeout); this._windowChangedTimeout = 0 this._updateDockVisibility(); } } // handler for when workspace is switched _switchWorkspace(shellwm, from, to, direction) { // Reset quick show timeout this._switchedWorkspace = true; if (this._quickShowTimeoutId > 0) GLib.source_remove(this._quickShowTimeoutId); this._quickShowTimeoutId = 0; this._updateDockVisibility(); } // intellihide function to show dock _show(force) { if (this._settings.get_boolean('dock-fixed')) { this._dock.fadeInDock(0, 0); } else { if (force) { this._dock.disableAutoHide(true); } else { this._dock.disableAutoHide(); } } this.status = true; } // intellihide function to hide dock _hide(dontforce) { this.status = false; if (this._settings.get_boolean('dock-fixed')) { this._dock.fadeOutDock(0, 0); } else { if (dontforce) { this._dock.enableAutoHide(true); } else { this._dock.enableAutoHide(); } } } // Reset quick show timeout _quickShowExit() { this._switchedWorkspace = false; if (this._quickShowTimeoutId > 0) GLib.source_remove(this._quickShowTimeoutId); this._quickShowTimeoutId = 0; this._updateDockVisibility(); } // intellihide function to determine if dock overlaps a window _updateDockVisibility() { if (this._disableIntellihide) return; // Return if we are in overview mode if (this._inOverview) { return; } //else in normal mode: else { if (this._settings.get_boolean('intellihide') || this._settings.get_boolean('dock-fixed')) { let overlaps = false; let windows = global.get_window_actors(); if (windows.length > 0) { // SANITY CHECK //global.log("==============================================================="); //for (let i = windows.length-1; i >= 0; i--) { //let win = windows[i].get_meta_window(); //let wclass = win.get_wm_class(); //let wtype = win.get_window_type(); //let wfocus = win.has_focus(); //let wapp = this._tracker.get_window_app(win); //let msg = wclass + " [" + wtype + "] focused? " + wfocus + " wintype? " + wtype + " app? " + wapp; //global.log(msg); //} //global.log("---------------------------------------------------------------"); // This is the default window on top of all others this._topWindow = windows[windows.length-1].get_meta_window(); // Find focused window (not always top window) for (let i = windows.length-1; i >= 0; i--) { let win = windows[i].get_meta_window(); if (win.has_focus()) { this._focusedWin = win; break; } } // If there isn't a focused app, use that of the window on top //this._focusApp = this._tracker.focus_app || this._tracker.get_window_app(this._topWindow); windows = windows.filter(this._intellihideFilterInteresting, this); for (let i = 0; i < windows.length; i++) { let win = windows[i].get_meta_window(); if (win) { let rect = win.get_frame_rect(); let [dx, dy] = this._dock.actor.get_position(); let [dw, dh] = this._dock.actor.get_size(); let [dcx, dcy] = this._dock.actor.get_transformed_position(); let [dcw, dch] = this._dock.actor.get_size(); // SANITY CHECK // global.log("dx="+dx+" dy="+dy+" || dcx="+Math.round(dcx)+" dcy="+dcy); // global.log("dw="+dw+" dh="+dh+" || dcw="+dcw+" dch="+dch); if (this._dock._isHorizontal) { dx = dcx; dw = dcw; let intellihideAction = this._settings.get_enum('intellihide-action'); if (intellihideAction == IntellihideAction.SHOW_PARTIAL || intellihideAction == IntellihideAction.SHOW_PARTIAL_FIXED) { if (this._dock._slider.partialSlideoutSize) dh = this._dock._slider.partialSlideoutSize; } } else { dy = dcy; dh = dch; let intellihideAction = this._settings.get_enum('intellihide-action'); if (intellihideAction == IntellihideAction.SHOW_PARTIAL || intellihideAction == IntellihideAction.SHOW_PARTIAL_FIXED) { if (this._dock._slider.partialSlideoutSize) dw = this._dock._slider.partialSlideoutSize; } } let test; if (this._dock._position == St.Side.LEFT || this._dock._position == St.Side.TOP) { test = (rect.x < dx + dw) && (rect.x + rect.width > dx) && (rect.y < dy + dh) && (rect.y + rect.height > dy); } else if (this._dock._position == St.Side.RIGHT) { test = (rect.x < dx) && (rect.x + rect.width > dx - dw) && (rect.y < dy + dh) && (rect.y + rect.height > dy); } else if (this._dock._position == St.Side.BOTTOM) { test = (rect.x < dx + dw) && (rect.x + rect.width > dx) && (rect.y + rect.height > dy - dh) && (rect.y < dy); } if (test) { overlaps = true; break; } } } } if (this._switchWorkspaceQuickShow && this._switchedWorkspace && this._quickShowTimeoutId == 0) { this._show(true); let timeout = this._settings.get_double('quick-show-timeout'); this._quickShowTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout, this._quickShowExit.bind(this)); } else { if (this._quickShowTimeoutId == 0) { if (overlaps) { this._hide(); } else { if (!this._settings.get_boolean('dock-fixed') && this._settings.get_boolean('intellihide') && (this._settings.get_enum('intellihide-action') == IntellihideAction.SHOW_PARTIAL || this._settings.get_enum('intellihide-action') == IntellihideAction.SHOW_PARTIAL_FIXED)) { if (this._dock._dockState == DockState.SHOWING || this._dock._dockState == DockState.SHOWN) { this._hide(true); } else { this._show(); } } else { if (this._settings.get_boolean('dock-fixed') && this._dock._monitor.inFullscreen) { this._hide(); } else { this._show(); } } } } } } else { if (this._switchWorkspaceQuickShow && this._switchedWorkspace && this._quickShowTimeoutId == 0) { this._show(true); let timeout = this._settings.get_double('quick-show-timeout'); this._quickShowTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout, this._quickShowExit.bind(this)); } else { if (this._quickShowTimeoutId == 0) this._hide(); } } } } // Filter interesting windows to be considered for intellihide. // Consider all windows visible on the current workspace. _intellihideFilterInteresting(wa, edge) { let workspaceManager = global.workspace_manager; let currentWorkspace = workspaceManager.get_active_workspace_index(); let meta_win = wa.get_meta_window(); if (!meta_win) { //TODO michele: why? What does it mean? return false; } if (!this._handledWindowType(meta_win)) return false; let wksp = meta_win.get_workspace(); if (!wksp) return false; let wksp_index = wksp.index(); // check intellihide-option for windows of focused app if (this._settings.get_int('intellihide-option') == 1) { // TEST1: ignore if meta_win is a popup window if (meta_win.get_window_type() != Meta.WindowType.POPUP_MENU) { // TEST2: ignore if meta_win is not same class as the focused window (not same app) if (this._focusedWin.get_wm_class() != meta_win.get_wm_class()) return false; } } // check intellihide-option for top-level windows of focused app if (this._settings.get_int('intellihide-option') == 2) { // TEST1: ignore if meta_win is a popup window if (meta_win.get_window_type() != Meta.WindowType.POPUP_MENU) { // TEST2: ignore if meta_win is not same class as the focused window (not same app) if (this._focusedWin.get_wm_class() != meta_win.get_wm_class()) return false; // same app .. but is it top-level window? // TEST3: ignore if meta_win is not the focused window and both are normal windows if (this._focusedWin.get_window_type() == Meta.WindowType.NORMAL) { if (meta_win.get_window_type() == Meta.WindowType.NORMAL) { if (this._focusedWin != meta_win) return false; } } // TEST4: ignore if meta_win is tooltip but mouse pointer is not over focused window if (meta_win.get_window_type() == Meta.WindowType.TOOLTIP) { let pointer = Gdk.Display.get_default().get_device_manager().get_client_pointer(); let [scr,x,y] = pointer.get_position(); let rect = this._focusedWin.get_frame_rect(); let overlap = ((x > rect.x) && (x < rect.x+rect.width) && (y > rect.y) && (y < rect.y+rect.height)); if (!overlap) return false; } } } if (wksp_index == currentWorkspace && meta_win.showing_on_its_workspace()) { return true; } else { return false; } } // Filter windows by type // inspired by Opacify@gnome-shell.localdomain.pl _handledWindowType(metaWindow, grptype) { var wtype = metaWindow.get_window_type(); if (grptype == null || grptype == 1) { if (!this._settings.get_boolean('dock-fixed') && !(this._settings.get_boolean('intellihide') && this._settings.get_enum('intellihide-action') == IntellihideAction.SHOW_PARTIAL_FIXED)) { // Test primary window types .. only if dock is not fixed for (var i = 0; i < handledWindowTypes.length; i++) { var hwtype = handledWindowTypes[i]; if (hwtype == wtype) { return true; } } } } if (grptype == null || grptype == 2) { // Test secondary window types .. only if ignore-context-menus is false // and dock is not fixed if (!this._settings.get_boolean('ignore-context-menus') && !this._settings.get_boolean('dock-fixed') && !(this._settings.get_boolean('intellihide') && this._settings.get_enum('intellihide-action') == IntellihideAction.SHOW_PARTIAL_FIXED)) { for (var i = 0; i < handledWindowTypes2.length; i++) { var hwtype = handledWindowTypes2[i]; if (hwtype == wtype) { return true; } } } } return false; } };