From 96cca197183e3b2a83c03b19048909758da8b751 Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Fri, 25 Mar 2016 15:48:16 -0500 Subject: [PATCH 01/11] Code reorganization; begin work on "window stealing"; right click for settings --- convenience.js | 52 ++- myDash.js => dash.js | 797 +++++++----------------------------- dockedDash.js => docking.js | 326 +++------------ extension.js | 7 +- icons.js | 547 +++++++++++++++++++++++++ intellihide.js | 45 +- prefs.js | 44 +- stylesheet.css | 26 ++ theming.js | 236 +++++++++++ windows.js | 104 +++++ 10 files changed, 1196 insertions(+), 988 deletions(-) rename myDash.js => dash.js (70%) rename dockedDash.js => docking.js (85%) create mode 100644 icons.js create mode 100644 theming.js create mode 100644 windows.js diff --git a/convenience.js b/convenience.js index b4d336c03..11f2b5383 100644 --- a/convenience.js +++ b/convenience.js @@ -3,18 +3,16 @@ /* * Part of this file comes from gnome-shell-extensions: * http://git.gnome.org/browse/gnome-shell-extensions/ - * */ - const Gettext = imports.gettext; const Gio = imports.gi.Gio; +const Clutter = imports.gi.Clutter; const Lang = imports.lang; const Config = imports.misc.config; const ExtensionUtils = imports.misc.extensionUtils; - /** * initTranslations: * @domain: (optional): the gettext domain to use @@ -27,7 +25,7 @@ function initTranslations(domain) { domain = domain || extension.metadata['gettext-domain']; - // check if this extension was built with "make zip-file", and thus + // Check if this extension was built with "make zip-file", and thus // has the locale files in a subfolder // otherwise assume that extension has been installed in the // same prefix as gnome-shell @@ -53,7 +51,7 @@ function getSettings(schema) { const GioSSS = Gio.SettingsSchemaSource; - // check if this extension was built with "make zip-file", and thus + // Check if this extension was built with "make zip-file", and thus // has the schema files in a subfolder // otherwise assume that extension has been installed in the // same prefix as gnome-shell (and therefore schemas are available @@ -75,16 +73,18 @@ function getSettings(schema) { return new Gio.Settings({ settings_schema: schemaObj }); } -// simplify global signals and function injections handling -// abstract class +/** + * Simplify global signals and function injections handling + * abstract class + */ const BasicHandler = new Lang.Class({ - Name: 'dashToDock.BasicHandler', + Name: 'DashToDock.BasicHandler', - _init: function(){ + _init: function() { this._storage = new Object(); }, - add: function(/*unlimited 3-long array arguments*/){ + add: function(/*unlimited 3-long array arguments*/) { // convert arguments object to array, concatenate with generic let args = Array.concat('generic', Array.slice(arguments)); @@ -109,7 +109,7 @@ const BasicHandler = new Lang.Class({ }, - removeWithLabel: function(label){ + removeWithLabel: function(label) { if(this._storage[label]) { for( let i = 0; i < this._storage[label].length; i++ ) { @@ -122,17 +122,19 @@ const BasicHandler = new Lang.Class({ /* Virtual methods to be implemented by subclass */ // create single element to be stored in the storage structure - _create: function(item){ + _create: function(item) { throw new Error('no implementation of _create in ' + this); }, // correctly delete single element - _remove: function(item){ + _remove: function(item) { throw new Error('no implementation of _remove in ' + this); } }); -// Manage global signals +/** + * Manage global signals + */ const GlobalSignalsHandler = new Lang.Class({ Name: 'DashToDock.GlobalSignalHandler', Extends: BasicHandler, @@ -147,13 +149,15 @@ const GlobalSignalsHandler = new Lang.Class({ return [object, id]; }, - _remove: function(item){ + _remove: function(item) { item[0].disconnect(item[1]); } }); -// Manage function injection: both instances and prototype can be overridden -// and restored +/** + * Manage function injection: both instances and prototype can be overridden + * and restored + */ const InjectionsHandler = new Lang.Class({ Name: 'DashToDock.InjectionsHandler', Extends: BasicHandler, @@ -176,3 +180,17 @@ const InjectionsHandler = new Lang.Class({ object[name] = original; } }); + +/** + * Return the actual position reverseing left and right in rtl + */ +function getPosition(settings) { + let position = settings.get_enum('dock-position'); + if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) { + if (position == St.Side.LEFT) + position = St.Side.RIGHT; + else if (position == St.Side.RIGHT) + position = St.Side.LEFT; + } + return position; +} diff --git a/myDash.js b/dash.js similarity index 70% rename from myDash.js rename to dash.js index 61c8780a9..f6185eac0 100644 --- a/myDash.js +++ b/dash.js @@ -24,84 +24,14 @@ const Workspace = imports.ui.workspace; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; +const Icons = Me.imports.icons; +const Windows = Me.imports.windows; let DASH_ANIMATION_TIME = Dash.DASH_ANIMATION_TIME; let DASH_ITEM_LABEL_SHOW_TIME = Dash.DASH_ITEM_LABEL_SHOW_TIME; let DASH_ITEM_LABEL_HIDE_TIME = Dash.DASH_ITEM_LABEL_HIDE_TIME; let DASH_ITEM_HOVER_TIMEOUT = Dash.DASH_ITEM_HOVER_TIMEOUT; -/* Return the actual position reverseing left and right in rtl */ -function getPosition(settings) { - let position = settings.get_enum('dock-position'); - if(Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) { - if (position == St.Side.LEFT) - position = St.Side.RIGHT; - else if (position == St.Side.RIGHT) - position = St.Side.LEFT; - } - return position; -} - -/** - * Extend AppIconMenu - * - * - Pass settings to the constructor - * - set popup arrow side based on dash orientation - * - Add close windows option based on quitfromdash extension - * (https://github.com/deuill/shell-extension-quitfromdash) - */ - -const myAppIconMenu = new Lang.Class({ - Name: 'myAppIconMenu', - Extends: AppDisplay.AppIconMenu, - - _init: function(source, settings) { - - let side = getPosition(settings); - - // Damm it, there has to be a proper way of doing this... - // As I can't call the parent parent constructor (?) passing the side - // parameter, I overwite what I need later - this.parent(source); - - // Change the initialized side where required. - this._arrowSide = side; - this._boxPointer._arrowSide = side; - this._boxPointer._userArrowSide = side; - }, - - // helper function for the quit windows abilities - _closeWindowInstance: function(metaWindow) { - metaWindow.delete(global.get_current_time()); - }, - - _redisplay: function() { - - this.parent(); - - // quit menu - let app = this._source.app; - let count = getAppInterestingWindows(app).length; - if ( count > 0) { - this._appendSeparator(); - let quitFromDashMenuText = ""; - if (count == 1) - quitFromDashMenuText = _("Quit"); - else - quitFromDashMenuText = _("Quit") + ' ' + count + ' ' + _("Windows"); - - this._quitfromDashMenuItem = this._appendMenuItem(quitFromDashMenuText); - this._quitfromDashMenuItem.connect('activate', Lang.bind(this, function() { - let app = this._source.app; - let windows = app.get_windows(); - for (let i = 0; i < windows.length; i++) { - this._closeWindowInstance(windows[i]) - } - })); - } - } -}); - /** * Extend DashItemContainer * @@ -112,91 +42,13 @@ const myAppIconMenu = new Lang.Class({ * thus use this ugly pattern. */ -// define first this function to use it in both extendShowAppsIcon and extendDashItemContainer -function ItemShowLabel() { - if (!this._labelText) { - return; - } - - this.label.set_text(this._labelText); - this.label.opacity = 0; - this.label.show(); - - let [stageX, stageY] = this.get_transformed_position(); - let node = this.label.get_theme_node(); - - let itemWidth = this.allocation.x2 - this.allocation.x1; - let itemHeight = this.allocation.y2 - this.allocation.y1; - - - let labelWidth = this.label.get_width(); - let labelHeight = this.label.get_height(); - - let x, y, xOffset, yOffset; - - let position = getPosition(this._dtdSettings); - this._isHorizontal = ( position == St.Side.TOP || - position == St.Side.BOTTOM); - let labelOffset = node.get_length('-x-offset'); - - switch(position) { - case St.Side.LEFT: - yOffset = Math.floor((itemHeight - labelHeight) / 2); - y = stageY + yOffset; - xOffset = labelOffset; - x = stageX + this.get_width() + xOffset; - break; - case St.Side.RIGHT: - yOffset = Math.floor((itemHeight - labelHeight) / 2); - y = stageY + yOffset; - xOffset = labelOffset; - x = Math.round(stageX) - labelWidth - xOffset; - break; - case St.Side.TOP: - y = stageY + labelOffset + itemHeight; - xOffset = Math.floor((itemWidth - labelWidth) / 2); - x = stageX + xOffset; - break; - case St.Side.BOTTOM: - yOffset = labelOffset; - y = stageY - labelHeight - yOffset; - xOffset = Math.floor((itemWidth - labelWidth) / 2); - x = stageX + xOffset; - break; - } - - // keep the label inside the screen border - // Only needed fot the x coordinate. - - // Leave a few pixel gap - let gap = 5; - let monitor = Main.layoutManager.findMonitorForActor(this); - if ( x - monitor.x monitor.x + monitor.width - gap) - x-= x + labelWidth -( monitor.x + monitor.width) + gap; - - this.label.set_position(x, y); - Tweener.addTween(this.label, - { opacity: 255, - time: DASH_ITEM_LABEL_SHOW_TIME, - transition: 'easeOutQuad', - }); -}; - -function extendDashItemContainer(dashItemContainer, settings) { - - dashItemContainer._dtdSettings = settings; - dashItemContainer.showLabel = ItemShowLabel; -}; /* * A menu for the showAppsIcon */ const myShowAppsIconMenu = new Lang.Class({ - - Name: 'dashToDockShowAppsIconMenu', - Extends: myAppIconMenu, + Name: 'DashToDock.ShowAppsIconMenu', + Extends: Icons.MyAppIconMenu, _redisplay: function() { this.removeAll(); @@ -207,7 +59,6 @@ const myShowAppsIconMenu = new Lang.Class({ Util.spawn(["gnome-shell-extension-prefs", Me.metadata.uuid]); }); } - }); /** @@ -220,9 +71,7 @@ const myShowAppsIconMenu = new Lang.Class({ * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. * thus use this ugly pattern. */ - -function extendShowAppsIcon(showAppsIcon, settings){ - +function extendShowAppsIcon(showAppsIcon, settings) { showAppsIcon._dtdSettings = settings; /* the variable equivalent to toggleButton has a different name in the appIcon class @@ -244,7 +93,6 @@ function extendShowAppsIcon(showAppsIcon, settings){ showAppsIcon._removeMenuTimeout(); }; - showAppsIcon.actor.connect('leave-event', Lang.bind( showAppsIcon, showAppsIcon._onLeaveEvent)); showAppsIcon.actor.connect('button-press-event', Lang.bind( showAppsIcon, showAppsIcon._onButtonPress)); showAppsIcon.actor.connect('touch-event', Lang.bind( showAppsIcon, showAppsIcon._onTouchEvent)); @@ -254,12 +102,10 @@ function extendShowAppsIcon(showAppsIcon, settings){ showAppsIcon._menu = null; showAppsIcon._menuManager = new PopupMenu.PopupMenuManager(showAppsIcon); showAppsIcon._menuTimeoutId = 0; - - showAppsIcon.showLabel = ItemShowLabel; + showAppsIcon.showLabel = itemShowLabel; - - showAppsIcon.popupMenu = function() { + showAppsIcon.popupMenu = function() { showAppsIcon._removeMenuTimeout(); showAppsIcon.actor.fake_release(); @@ -297,14 +143,14 @@ function extendShowAppsIcon(showAppsIcon, settings){ * - modified chldBox calculations for when 'show-apps-at-top' option is checked * - handle horizontal dash */ -const myDashActor = new Lang.Class({ - Name: 'DashToDockmyDashActor', +const MyDashActor = new Lang.Class({ + Name: 'DashToDock.MyDashActor', _init: function(settings) { this._dtdSettings = settings; this._rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; - this._position = getPosition(settings); + this._position = Convenience.getPosition(settings); this._isHorizontal = ( this._position == St.Side.TOP || this._position == St.Side.BOTTOM ); @@ -319,6 +165,30 @@ const myDashActor = new Lang.Class({ this.actor.connect('allocate', Lang.bind(this, this._allocate)); this.actor._delegate = this; + + // Popup menu + + this.menu = new PopupMenu.PopupMenu(this.actor, 0.0, St.Side.RIGHT, 0); + this.menu.actor.hide(); + this.menu.actor.add_style_class_name('panel-menu'); + let settingsMenuItem = new PopupMenu.PopupMenuItem('Dash to Dock ' + _('Settings')); + settingsMenuItem.connect('activate', Lang.bind(this, function() { + Util.spawn(['gnome-shell-extension-prefs', Me.metadata.uuid]); + })); + this.menu.addMenuItem(settingsMenuItem); + + Main.uiGroup.add_actor(this.menu.actor); + this.menu.close(); + + this._menuManager = new PopupMenu.PopupMenuManager(this); + this._menuManager.addMenu(this.menu); + + this.actor.reactive = true; + this.actor.connect('button-press-event', Lang.bind(this, function(actor, event) { + if (event.get_state() & Clutter.ModifierType.BUTTON3_MASK) { + this.menu.toggle(); + } + })); }, @@ -399,7 +269,10 @@ const myDashActor = new Lang.Class({ } }); -/* This class is a fork of the upstream dash class (ui.dash.js) +const baseIconSizes = [ 16, 22, 24, 32, 48, 64, 96, 128 ]; + +/** + * This class is a fork of the upstream dash class (ui.dash.js) * * Summary of changes: * - disconnect global signals adding a destroy method; @@ -408,16 +281,14 @@ const myDashActor = new Lang.Class({ * - show running and/or favorite applications * - emit a custom signal when an app icon is added * - hide showApps label when the custom menu is shown. - * - Add scrollview - * Ensure actor is visible on keyfocus inseid the scrollview + * - add scrollview + * ensure actor is visible on keyfocus inseid the scrollview * - add 128px icon size, might be usefull for hidpi display - * - Sync minimization application target position. + * - sync minimization application target position. + * - support configurable "window stealing" */ - -const baseIconSizes = [ 16, 22, 24, 32, 48, 64, 96, 128 ]; - -const myDash = new Lang.Class({ - Name: 'dashToDock.myDash', +const MyDash = new Lang.Class({ + Name: 'DashToDock.MyDash', _init : function(settings) { this._maxHeight = -1; @@ -426,7 +297,7 @@ const myDash = new Lang.Class({ this._shownInitially = false; this._dtdSettings = settings; - this._position = getPosition(settings); + this._position = Convenience.getPosition(settings); this._isHorizontal = ( this._position == St.Side.TOP || this._position == St.Side.BOTTOM ); this._signalsHandler = new Convenience.GlobalSignalsHandler(); @@ -439,7 +310,7 @@ const myDash = new Lang.Class({ this._ensureAppIconVisibilityTimeoutId = 0; this._labelShowing = false; - this._containerObject = new myDashActor(settings); + this._containerObject = new MyDashActor(settings); this._container = this._containerObject.actor; this._scrollView = new St.ScrollView({ name: 'dashtodockDashScrollview', hscrollbar_policy: Gtk.PolicyType.NEVER, @@ -497,9 +368,9 @@ const myDash = new Lang.Class({ // Update minimization animation target position on allocation of the // container and on scrollview change. - this._box.connect('notify::allocation', Lang.bind(this, this._updateAppIconsGeometry)); + this._box.connect('notify::allocation', Lang.bind(this, this._updateAppIcons)); let scrollViewAdjustment = this._isHorizontal?this._scrollView.hscroll.adjustment:this._scrollView.vscroll.adjustment; - scrollViewAdjustment.connect('notify::value', Lang.bind(this, this._updateAppIconsGeometry)); + scrollViewAdjustment.connect('notify::value', Lang.bind(this, this._updateAppIcons)); this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay)); @@ -696,7 +567,7 @@ const myDash = new Lang.Class({ }, _createAppItem: function(app) { - let appIcon = new myAppIcon(this._dtdSettings, app, + let appIcon = new Icons.MyAppIcon(this._dtdSettings, app, { setSizeManually: true, showLabel: false }); if (appIcon._draggable) { @@ -723,8 +594,8 @@ const myDash = new Lang.Class({ item.setChild(appIcon.actor); appIcon.actor.connect('notify::hover', Lang.bind(this, function() { - if (appIcon.actor.hover){ - this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function(){ + if (appIcon.actor.hover) { + this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function() { ensureActorVisibleInScrollView(this._scrollView, appIcon.actor); this._ensureAppIconVisibilityTimeoutId = 0; return GLib.SOURCE_REMOVE; @@ -765,7 +636,7 @@ const myDash = new Lang.Class({ return item; }, - + // Return an array with the "proper" appIcons currently in the dash _getAppIcons: function() { // Only consider children which are "proper" @@ -779,17 +650,17 @@ const myDash = new Lang.Class({ !actor.animatingOut; }); - let appIcons = iconChildren.map(function(actor){ + let appIcons = iconChildren.map(function(actor) { return actor.child._delegate; }); return appIcons; }, - _updateAppIconsGeometry: function() { + _updateAppIcons: function() { let appIcons = this._getAppIcons(); - appIcons.forEach(function(icon){ - icon.updateIconGeometry(); + appIcons.forEach(function(icon) { + icon.onWindowsChanged(); }); }, @@ -892,7 +763,7 @@ const myDash = new Lang.Class({ }); // Subtract icon padding and box spacing from the available height - if(this._isHorizontal){ + if(this._isHorizontal) { availHeight -= iconChildren.length * (natWidth - this.iconSize * scaleFactor) + (iconChildren.length - 1) * spacing; } else { @@ -1018,10 +889,11 @@ const myDash = new Lang.Class({ // App added at newIndex if (newApps[newIndex] && oldApps.indexOf(newApps[newIndex]) == -1) { - addedItems.push({ app: newApps[newIndex], - item: this._createAppItem(newApps[newIndex]), - pos: newIndex }); - newIndex++; + let newItem = this._createAppItem(newApps[newIndex]); + addedItems.push({ app: newApps[newIndex], + item: newItem, + pos: newIndex }); + newIndex++; continue; } @@ -1035,16 +907,16 @@ const myDash = new Lang.Class({ if (insertHere || alreadyRemoved) { let newItem = this._createAppItem(newApps[newIndex]); - addedItems.push({ app: newApps[newIndex], - item: newItem, - pos: newIndex + removedActors.length }); - newIndex++; + addedItems.push({ app: newApps[newIndex], + item: newItem, + pos: newIndex + removedActors.length }); + newIndex++; } else { removedActors.push(children[oldIndex]); oldIndex++; } } - + for (let i = 0; i < addedItems.length; i++) this._box.insert_child_at_index(addedItems[i].item, addedItems[i].pos); @@ -1061,7 +933,7 @@ const myDash = new Lang.Class({ this._adjustIconSize(); - for (let i = 0; i < addedItems.length; i++){ + for (let i = 0; i < addedItems.length; i++) { // Emit a custom signal notifying that a new item has been added this.emit('item-added', addedItems[i]); } @@ -1084,7 +956,7 @@ const myDash = new Lang.Class({ this._box.queue_relayout(); // This is required for icon reordering when the scrollview is used. - this._updateAppIconsGeometry(); + this._updateAppIcons(); }, setIconSize: function (max_size, doNotAnimate) { @@ -1096,7 +968,7 @@ const myDash = new Lang.Class({ this._availableIconSizes = [ max_size ]; } else { this._availableIconSizes = baseIconSizes.filter( - function(val){ + function(val) { return (val numChildren) pos = numChildren; @@ -1307,455 +1179,9 @@ const myDash = new Lang.Class({ this.showAppsButton.set_width(0) this.showAppsButton.set_height(0) } - }); -Signals.addSignalMethods(myDash.prototype); - - -/** - * Extend AppIcon - * - * - Pass settings to the constructor and bind settings changes - * - Apply a css class based on the number of windows of each application (#N); - * - Draw a dot for each window of the application based on the default "dot" style which is hidden (#N); - * a class of the form "running#N" is applied to the AppWellIcon actor. - * like the original .running one. - * - add a .focused style to the focused app - * - Customize click actions. - * - Update minimization animation target - * - */ - -let tracker = Shell.WindowTracker.get_default(); - -const clickAction = { - SKIP: 0, - MINIMIZE: 1, - LAUNCH: 2, - CYCLE_WINDOWS: 3 -}; - -let recentlyClickedAppLoopId = 0; -let recentlyClickedApp = null; -let recentlyClickedAppWindows = null; -let recentlyClickedAppIndex = 0; - -const myAppIcon = new Lang.Class({ - Name: 'dashToDock.AppIcon', - Extends: AppDisplay.AppIcon, - - // settings are required inside. - _init: function(settings, app, iconParams, onActivateOverride) { - - this._dtdSettings = settings; - this._nWindows = 0; - - this.parent(app, iconParams, onActivateOverride); - - // Monitor windows-changes instead of app state. - // Keep using the same Id and function callback (that is extended) - if(this._stateChangedId>0){ - this.app.disconnect(this._stateChangedId); - this._stateChangedId=0; - } - - this._stateChangedId = this.app.connect('windows-changed', - Lang.bind(this, - this.onWindowsChanged)); - this._focuseAppChangeId = tracker.connect('notify::focus-app', - Lang.bind(this, - this._onFocusAppChanged)); - - this._dots = null; - - let keys = ['apply-custom-theme', - 'custom-theme-running-dots', - 'custom-theme-customize-running-dots', - 'custom-theme-running-dots-color', - 'custom-theme-running-dots-border-color', - 'custom-theme-running-dots-border-width']; - - keys.forEach(function(key){ - this._dtdSettings.connect('changed::'+key, - Lang.bind(this, this._toggleDots) - ); - }, this ); - - this._toggleDots(); - }, - - _onDestroy: function() { - this.parent(); - - // Disconect global signals - // stateChangedId is already handled by parent) - if(this._focusAppId>0) - tracker.disconnect(this._focusAppId); - }, - - onWindowsChanged: function() { - - this._updateRunningStyle(); - this.updateIconGeometry(); - - }, - - // Update taraget for minimization animation - updateIconGeometry: function() { - - // If (for unknown reason) the actor is not on the stage the reported size - // and position are random values, which might exceeds the integer range - // resulting in an error when assigned to the a rect. This is a more like - // a workaround to prevent flooding the system with errors. - if (this.actor.get_stage() == null) - return - - let rect = new Meta.Rectangle(); - - [rect.x, rect.y] = this.actor.get_transformed_position(); - [rect.width, rect.height] = this.actor.get_transformed_size(); - - let windows = this.app.get_windows(); - windows.forEach(function(w) { - w.set_icon_geometry(rect); - }); - - }, - - _toggleDots: function() { - - if ( this._dtdSettings.get_boolean('custom-theme-running-dots') - || this._dtdSettings.get_boolean('apply-custom-theme') ) - this._showDots(); - else - this._hideDots(); - }, - - _showDots: function() { - // I use opacity to hide the default dot because the show/hide function - // are used by the parent class. - this._dot.opacity = 0; - - // Just update style if dots already exist - if (this._dots) { - this._updateCounterClass(); - return; - } - - this._dots = new St.DrawingArea({x_expand: true, y_expand: true}); - this._dots.connect('repaint', Lang.bind(this, - function() { - this._drawCircles(this._dots, getPosition(this._dtdSettings)); - })); - this._iconContainer.add_child(this._dots); - this._updateCounterClass(); - - }, - - _hideDots: function() { - this._dot.opacity=255; - if (this._dots) - this._dots.destroy() - this._dots = null; - }, - - _updateRunningStyle: function() { - this.parent(); - this._updateCounterClass(); - }, - - popupMenu: function() { - this._removeMenuTimeout(); - this.actor.fake_release(); - this._draggable.fakeRelease(); - - if (!this._menu) { - this._menu = new myAppIconMenu(this, this._dtdSettings); - this._menu.connect('activate-window', Lang.bind(this, function (menu, window) { - this.activateWindow(window); - })); - this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) { - if (!isPoppedUp) - this._onMenuPoppedDown(); - })); - let id = Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); })); - this._menu.actor.connect('destroy', function() { - Main.overview.disconnect(id); - }); - - this._menuManager.addMenu(this._menu); - } - - this.emit('menu-state-changed', true); - - this.actor.set_hover(true); - this._menu.popup(); - this._menuManager.ignoreRelease(); - this.emit('sync-tooltip'); - - return false; - }, - - _onFocusAppChanged: function() { - if(tracker.focus_app == this.app) - this.actor.add_style_class_name('focused'); - else - this.actor.remove_style_class_name('focused'); - }, - - activate: function(button) { - - if ( !this._dtdSettings.get_boolean('customize-click') ){ - this.parent(button); - return; - } - - let event = Clutter.get_current_event(); - let modifiers = event ? event.get_state() : 0; - let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK && - this.app.state == Shell.AppState.RUNNING || - button && button == 2; - let focusedApp = tracker.focus_app; - - if (this.app.state == Shell.AppState.STOPPED || openNewWindow) - this.animateLaunch(); - - if(button && button == 1 && this.app.state == Shell.AppState.RUNNING) { - - if(modifiers & Clutter.ModifierType.CONTROL_MASK){ - // Keep default behaviour: launch new window - // By calling the parent method I make it compatible - // with other extensions tweaking ctrl + click - this.parent(button); - return; - - } else if (this._dtdSettings.get_boolean('minimize-shift') && modifiers & Clutter.ModifierType.SHIFT_MASK){ - // On double click, minimize all windows in the current workspace - minimizeWindow(this.app, event.get_click_count() > 1); - - } else if(this.app == focusedApp && !Main.overview._shown){ - - if(this._dtdSettings.get_enum('click-action') == clickAction.CYCLE_WINDOWS) - cycleThroughWindows(this.app); - else if(this._dtdSettings.get_enum('click-action') == clickAction.MINIMIZE) - minimizeWindow(this.app, true); - else if(this._dtdSettings.get_enum('click-action') == clickAction.LAUNCH) - this.app.open_new_window(-1); - - } else { - // Activate all window of the app or only le last used - if (this._dtdSettings.get_enum('click-action') == clickAction.CYCLE_WINDOWS && !Main.overview._shown){ - // If click cycles through windows I can activate one windows at a time - let windows = getAppInterestingWindows(this.app); - let w = windows[0]; - Main.activateWindow(w); - } else if(this._dtdSettings.get_enum('click-action') == clickAction.LAUNCH) - this.app.open_new_window(-1); - else if(this._dtdSettings.get_enum('click-action') == clickAction.MINIMIZE){ - // If click minimizes all, then one expects all windows to be reshown - activateAllWindows(this.app); - } else - this.app.activate(); - } - } else { - // Default behaviour - if (openNewWindow) - this.app.open_new_window(-1); - else - this.app.activate(); - } - - Main.overview.hide(); - }, - - _updateCounterClass: function() { - - let maxN = 4; - this._nWindows = Math.min(getAppInterestingWindows(this.app).length, maxN); - - for(let i = 1; i<=maxN; i++){ - let className = 'running'+i; - if(i!=this._nWindows) - this.actor.remove_style_class_name(className); - else - this.actor.add_style_class_name(className); - } - - if (this._dots) - this._dots.queue_repaint(); - }, - - _drawCircles: function(area, side) { - - let borderColor, borderWidth, bodyColor; - - if (!this._dtdSettings.get_boolean('apply-custom-theme') - && this._dtdSettings.get_boolean('custom-theme-running-dots') - && this._dtdSettings.get_boolean('custom-theme-customize-running-dots')) { - borderColor = Clutter.color_from_string(this._dtdSettings.get_string('custom-theme-running-dots-border-color'))[1]; - borderWidth = this._dtdSettings.get_int('custom-theme-running-dots-border-width'); - bodyColor = Clutter.color_from_string(this._dtdSettings.get_string('custom-theme-running-dots-color'))[1]; - } else { - // Re-use the style - background color, and border width and color - - // of the default dot - let themeNode = this._dot.get_theme_node(); - borderColor = themeNode.get_border_color(side); - borderWidth = themeNode.get_border_width(side); - bodyColor = themeNode.get_background_color(); - } - - let [width, height] = area.get_surface_size(); - let cr = area.get_context(); - - // Draw the required numbers of dots - let radius = width/22 - borderWidth/2; - radius = Math.max(radius, borderWidth/4+1); - let padding = 0; // distance from the margin - let spacing = radius + borderWidth; // separation between the dots - let n = this._nWindows; - - cr.setLineWidth(borderWidth); - Clutter.cairo_set_source_color(cr, borderColor); - - switch (side) { - case St.Side.TOP: - cr.translate((width - (2*n)*radius - (n-1)*spacing)/2, padding); - for (let i=0; i=0; i--){ - if(windows[i].get_workspace().index() == activeWorkspace){ - Main.activateWindow(windows[i]); - activatedWindows++; - } - } -} - -function cycleThroughWindows(app) { - - // Store for a little amount of time last clicked app and its windows - // since the order changes upon window interaction - let MEMORY_TIME=3000; - - let app_windows = getAppInterestingWindows(app); - - if(recentlyClickedAppLoopId>0) - Mainloop.source_remove(recentlyClickedAppLoopId); - recentlyClickedAppLoopId = Mainloop.timeout_add(MEMORY_TIME, resetRecentlyClickedApp); - - // If there isn't already a list of windows for the current app, - // or the stored list is outdated, use the current windows list. - if( !recentlyClickedApp || - recentlyClickedApp.get_id() != app.get_id() || - recentlyClickedAppWindows.length != app_windows.length - ){ - - recentlyClickedApp = app; - recentlyClickedAppWindows = app_windows; - recentlyClickedAppIndex = 0; - } - - recentlyClickedAppIndex++; - let index = recentlyClickedAppIndex % recentlyClickedAppWindows.length; - let window = recentlyClickedAppWindows[index]; - - Main.activateWindow(window); -} - -function resetRecentlyClickedApp() { - - if(recentlyClickedAppLoopId>0) - Mainloop.source_remove(recentlyClickedAppLoopId); - recentlyClickedAppLoopId=0; - recentlyClickedApp =null; - recentlyClickedAppWindows = null; - recentlyClickedAppIndex = 0; - - return false; -} - -function getAppInterestingWindows(app) { - // Filter out unnecessary windows, for instance - // nautilus desktop window. - let windows = app.get_windows().filter(function(w) { - return !w.skip_taskbar; - }); - - return windows; -} - +Signals.addSignalMethods(MyDash.prototype); /* * This is a copy of the same function in utils.js, but also adjust horizontal scrolling @@ -1778,7 +1204,7 @@ function ensureActorVisibleInScrollView(scrollView, actor) { let voffset = 0; let hoffset = 0; let fade = scrollView.get_effect("fade"); - if (fade){ + if (fade) { voffset = fade.vfade_offset; hoffset = fade.hfade_offset; } @@ -1825,3 +1251,80 @@ function ensureActorVisibleInScrollView(scrollView, actor) { return [hvalue- hvalue0, vvalue - vvalue0]; } + +// This function is used for both extendShowAppsIcon and extendDashItemContainer +function itemShowLabel() { + if (!this._labelText) { + return; + } + + this.label.set_text(this._labelText); + this.label.opacity = 0; + this.label.show(); + + let [stageX, stageY] = this.get_transformed_position(); + let node = this.label.get_theme_node(); + + let itemWidth = this.allocation.x2 - this.allocation.x1; + let itemHeight = this.allocation.y2 - this.allocation.y1; + + + let labelWidth = this.label.get_width(); + let labelHeight = this.label.get_height(); + + let x, y, xOffset, yOffset; + + let position = Convenience.getPosition(this._dtdSettings); + this._isHorizontal = ( position == St.Side.TOP || + position == St.Side.BOTTOM); + let labelOffset = node.get_length('-x-offset'); + + switch(position) { + case St.Side.LEFT: + yOffset = Math.floor((itemHeight - labelHeight) / 2); + y = stageY + yOffset; + xOffset = labelOffset; + x = stageX + this.get_width() + xOffset; + break; + case St.Side.RIGHT: + yOffset = Math.floor((itemHeight - labelHeight) / 2); + y = stageY + yOffset; + xOffset = labelOffset; + x = Math.round(stageX) - labelWidth - xOffset; + break; + case St.Side.TOP: + y = stageY + labelOffset + itemHeight; + xOffset = Math.floor((itemWidth - labelWidth) / 2); + x = stageX + xOffset; + break; + case St.Side.BOTTOM: + yOffset = labelOffset; + y = stageY - labelHeight - yOffset; + xOffset = Math.floor((itemWidth - labelWidth) / 2); + x = stageX + xOffset; + break; + } + + // keep the label inside the screen border + // Only needed fot the x coordinate. + + // Leave a few pixel gap + let gap = 5; + let monitor = Main.layoutManager.findMonitorForActor(this); + if ( x - monitor.x monitor.x + monitor.width - gap) + x-= x + labelWidth -( monitor.x + monitor.width) + gap; + + this.label.set_position(x, y); + Tweener.addTween(this.label, + { opacity: 255, + time: DASH_ITEM_LABEL_SHOW_TIME, + transition: 'easeOutQuad', + }); +} + +function extendDashItemContainer(dashItemContainer, settings) { + dashItemContainer._dtdSettings = settings; + dashItemContainer.showLabel = itemShowLabel; +} diff --git a/dockedDash.js b/docking.js similarity index 85% rename from dockedDash.js rename to docking.js index 95e11e8af..fb95874da 100644 --- a/dockedDash.js +++ b/docking.js @@ -26,7 +26,8 @@ const LayoutManager = imports.ui.main.layoutManager; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; const Intellihide = Me.imports.intellihide; -const MyDash = Me.imports.myDash; +const Theming = Me.imports.theming; +const MyDash = Me.imports.dash; const DOCK_DWELL_CHECK_INTERVAL = 100; //TODO @@ -37,18 +38,6 @@ const State = { HIDING: 3 }; -/* Return the actual position reverseing left and right in rtl */ -function getPosition(settings) { - let position = settings.get_enum('dock-position'); - if(Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) { - if (position == St.Side.LEFT) - position = St.Side.RIGHT; - else if (position == St.Side.RIGHT) - position = St.Side.LEFT; - } - return position; -} - /* * A simple St.Widget with one child whose allocation takes into account the * slide out of its child via the _slidex parameter ([0:1]). @@ -67,7 +56,7 @@ function getPosition(settings) { */ const DashSlideContainer = new Lang.Class({ - Name: 'DashSlideContainer', + Name: 'DashToDock.DashSlideContainer', _init: function(params) { @@ -79,7 +68,7 @@ const DashSlideContainer = new Lang.Class({ let localParams = Params.parse(params, localDefaults, true); - if (params){ + if (params) { /* Remove local params before passing the params to the parent constructor to avoid errors. */ let prop; @@ -104,7 +93,6 @@ const DashSlideContainer = new Lang.Class({ this._slideoutSize = 0; // minimum size when slided out }, - _allocate: function(actor, box, flags) { if (this._child == null) @@ -192,11 +180,10 @@ const DashSlideContainer = new Lang.Class({ get slidex() { return this._slidex; } - }); -const dockedDash = new Lang.Class({ - Name: 'dockedDash', +const DockedDash = new Lang.Class({ + Name: 'DashToDock.DockedDash', _init: function(settings) { @@ -206,7 +193,7 @@ const dockedDash = new Lang.Class({ this._settings = settings; this._bindSettingsChanges(); - this._position = getPosition(settings); + this._position = Convenience.getPosition(settings); this._isHorizontal = ( this._position == St.Side.TOP || this._position == St.Side.BOTTOM ); @@ -220,7 +207,7 @@ const dockedDash = new Lang.Class({ this._fixedIsEnabled = null; // Create intellihide object to monitor windows overlapping - this._intellihide = new Intellihide.intellihide(this._settings); + this._intellihide = new Intellihide.Intellihide(this._settings); // initialize dock state this._dockState = State.HIDDEN; @@ -250,7 +237,7 @@ const dockedDash = new Lang.Class({ this._dockDwellTimeoutId = 0 // Create a new dash object - this.dash = new MyDash.myDash(this._settings); + this.dash = new MyDash.MyDash(this._settings); // set stored icon size to the new dash Main.overview.dashIconSize = this.dash.iconSize; @@ -371,7 +358,7 @@ const dockedDash = new Lang.Class({ ); this._injectionsHandler = new Convenience.InjectionsHandler(); - this._themeManager = new themeManager(this._settings, this.actor, this.dash); + this._themeManager = new Theming.ThemeManager(this._settings, this.actor, this.dash); // Since the actor is not a topLevel child and its parent is now not added to the Chrome, // the allocation change of the parent container (slide in and slideout) doesn't trigger @@ -383,7 +370,7 @@ const dockedDash = new Lang.Class({ this._slider.actor.connect(this._isHorizontal?'notify::x':'notify::y', Lang.bind(this, this._updateStaticBox)); // sync hover after a popupmenu is closed - this.dash.connect('menu-closed', Lang.bind(this, function(){this._box.sync_hover();})); + this.dash.connect('menu-closed', Lang.bind(this, function() {this._box.sync_hover();})); // Restore dash accessibility Main.ctrlAltTabManager.addGroup( @@ -450,9 +437,9 @@ const dockedDash = new Lang.Class({ }, - _initialize: function(){ + _initialize: function() { - if(this._paintId>0){ + if(this._paintId>0) { this.actor.disconnect(this._paintId); this._paintId=0; } @@ -471,7 +458,7 @@ const dockedDash = new Lang.Class({ // In case we are already inside the overview when the extension is loaded, // for instance on unlocking the screen if it was locked with the overview open. - if (Main.overview.visibleTarget){ + if (Main.overview.visibleTarget) { this._onOverviewShowing(); this._pageChanged(); } @@ -485,7 +472,7 @@ const dockedDash = new Lang.Class({ }, - destroy: function(){ + destroy: function() { // Disconnect global signals this._signalsHandler.destroy(); @@ -507,7 +494,7 @@ const dockedDash = new Lang.Class({ this._removeBarrier(); // Remove pointer watcher - if(this._dockWatch){ + if(this._dockWatch) { PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch); this._dockWatch = null; } @@ -530,38 +517,38 @@ const dockedDash = new Lang.Class({ _bindSettingsChanges: function() { - this._settings.connect('changed::scroll-switch-workspace', Lang.bind(this, function(){ + this._settings.connect('changed::scroll-switch-workspace', Lang.bind(this, function() { this._optionalScrollWorkspaceSwitch(this._settings.get_boolean('scroll-switch-workspace')); })); - this._settings.connect('changed::dash-max-icon-size', Lang.bind(this, function(){ + this._settings.connect('changed::dash-max-icon-size', Lang.bind(this, function() { this.dash.setIconSize(this._settings.get_int('dash-max-icon-size')); })); - this._settings.connect('changed::icon-size-fixed', Lang.bind(this, function(){ + this._settings.connect('changed::icon-size-fixed', Lang.bind(this, function() { this.dash.setIconSize(this._settings.get_int('dash-max-icon-size')); })); - this._settings.connect('changed::show-favorites', Lang.bind(this, function(){ + this._settings.connect('changed::show-favorites', Lang.bind(this, function() { this.dash.resetAppIcons(); })); - this._settings.connect('changed::show-running', Lang.bind(this, function(){ + this._settings.connect('changed::show-running', Lang.bind(this, function() { this.dash.resetAppIcons(); })); - this._settings.connect('changed::show-apps-at-top', Lang.bind(this, function(){ + this._settings.connect('changed::show-apps-at-top', Lang.bind(this, function() { this.dash.resetAppIcons(); })); - this._settings.connect('changed::show-show-apps-button', Lang.bind(this, function(){ + this._settings.connect('changed::show-show-apps-button', Lang.bind(this, function() { if (this._settings.get_boolean('show-show-apps-button')) this.dash.showShowAppsButton(); else this.dash.hideShowAppsButton(); })); - this._settings.connect('changed::dock-fixed', Lang.bind(this, function(){ + this._settings.connect('changed::dock-fixed', Lang.bind(this, function() { if(this._settings.get_boolean('dock-fixed')) { Main.layoutManager._trackActor(this._box, {affectsStruts: true, trackFullscreen: true}); @@ -579,20 +566,20 @@ const dockedDash = new Lang.Class({ this._settings.connect('changed::intellihide', Lang.bind(this, this._updateVisibilityMode)); - this._settings.connect('changed::intellihide-mode', Lang.bind(this, function(){ + this._settings.connect('changed::intellihide-mode', Lang.bind(this, function() { this._intellihide.forceUpdate(); })); - this._settings.connect('changed::autohide', Lang.bind(this, function(){ + this._settings.connect('changed::autohide', Lang.bind(this, function() { this._updateVisibilityMode(); this._updateBarrier(); })); this._settings.connect('changed::extend-height', Lang.bind(this,this._resetPosition)); this._settings.connect('changed::preferred-monitor', Lang.bind(this,this._resetPosition)); this._settings.connect('changed::height-fraction', Lang.bind(this,this._resetPosition)); - this._settings.connect('changed::require-pressure-to-show', Lang.bind(this,function(){ + this._settings.connect('changed::require-pressure-to-show', Lang.bind(this,function() { // Remove pointer watcher - if(this._dockWatch){ + if(this._dockWatch) { PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch); this._dockWatch = null; } @@ -704,7 +691,7 @@ const dockedDash = new Lang.Class({ if ( this._dockState == State.HIDDEN || this._dockState == State.HIDING ) { - if(this._dockState == State.HIDING){ + if(this._dockState == State.HIDING) { // suppress all potential queued hiding animations - i.e. added to Tweener but not started, // always give priority to show this._removeAnimations(); @@ -759,7 +746,7 @@ const dockedDash = new Lang.Class({ }); }, - _animateOut: function(time, delay){ + _animateOut: function(time, delay) { this._dockState = State.HIDING; Tweener.addTween(this._slider,{ @@ -795,7 +782,7 @@ const dockedDash = new Lang.Class({ // Check for the correct screen edge // Position is approximated to the lower integer - if(this._position==St.Side.LEFT){ + if(this._position==St.Side.LEFT) { shouldDwell = shouldDwell && x == this._monitor.x; } else if(this._position==St.Side.RIGHT) { shouldDwell = shouldDwell && x == this._monitor.x + this._monitor.width - 1; @@ -868,7 +855,7 @@ const dockedDash = new Lang.Class({ this._pressureBarrier = null; } - if (this._barrier){ + if (this._barrier) { this._barrier.destroy(); this._barrier = null; } @@ -877,7 +864,7 @@ const dockedDash = new Lang.Class({ if (this._canUsePressure) { this._pressureBarrier = new Layout.PressureBarrier(pressureThreshold, this._settings.get_double('show-delay')*1000, Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW); - this._pressureBarrier.connect('trigger', Lang.bind(this, function(barrier){ + this._pressureBarrier.connect('trigger', Lang.bind(this, function(barrier) { if (!this._settings.get_boolean('autohide-in-fullscreen') && this._monitor.inFullscreen) return; this._onPressureSensed(); @@ -933,7 +920,7 @@ const dockedDash = new Lang.Class({ if (this._canUsePressure && this._autohideIsEnabled && this._settings.get_boolean('require-pressure-to-show')) { let x1, x2, y1, y2, direction; - if(this._position==St.Side.LEFT){ + if(this._position==St.Side.LEFT) { x1 = this.staticBox.x1; x2 = this.staticBox.x1; y1 = this.staticBox.y1; @@ -997,7 +984,7 @@ const dockedDash = new Lang.Class({ // Reserve space for the dash on the overview // if the dock is on the primary monitor - if (this._isPrimaryMonitor()){ + if (this._isPrimaryMonitor()) { this._dashSpacer.show(); } else { // No space is required in the overview of the dash @@ -1013,7 +1000,7 @@ const dockedDash = new Lang.Class({ let anchor_point; - if(this._isHorizontal){ + if(this._isHorizontal) { this.actor.width = Math.round( fraction * workArea.width); @@ -1030,7 +1017,7 @@ const dockedDash = new Lang.Class({ this.actor.x = workArea.x + Math.round( (1-fraction)/2 * workArea.width); this.actor.y = pos_y; - if(extendHeight){ + if(extendHeight) { this.dash._container.set_width(this.actor.width); this.actor.add_style_class_name('extended'); } else { @@ -1055,7 +1042,7 @@ const dockedDash = new Lang.Class({ this.actor.x = pos_x; this.actor.y = workArea.y + Math.round( (1-fraction)/2 * workArea.height); - if(extendHeight){ + if(extendHeight) { this.dash._container.set_height(this.actor.height); this.actor.add_style_class_name('extended'); } else { @@ -1071,7 +1058,7 @@ const dockedDash = new Lang.Class({ this._updateStaticBox(); }, - _adjustLegacyTray: function(){ + _adjustLegacyTray: function() { let use_work_area = true; @@ -1128,7 +1115,7 @@ const dockedDash = new Lang.Class({ Tweener.removeTweens(this._slider); }, - _onDragStart: function(){ + _onDragStart: function() { // The dash need to be above the top_window_group, otherwise it doesn't // accept dnd of app icons when not in overiew mode. Main.layoutManager.uiGroup.set_child_above_sibling(this.actor, global.top_window_group); @@ -1137,7 +1124,7 @@ const dockedDash = new Lang.Class({ this._animateIn(this._settings.get_double('animation-time'), 0); }, - _onDragEnd: function(){ + _onDragEnd: function() { // Restore drag default dash stack order Main.layoutManager.uiGroup.set_child_below_sibling(this.actor, Main.layoutManager.modalDialogGroup); if (this._oldignoreHover !== null) @@ -1154,7 +1141,7 @@ const dockedDash = new Lang.Class({ let dashVisible = (activePage == ViewSelector.ViewPage.WINDOWS || activePage == ViewSelector.ViewPage.APPS); - if(dashVisible){ + if(dashVisible) { this._animateIn(this._settings.get_double('animation-time'), 0); } else { this._animateOut(this._settings.get_double('animation-time'), 0); @@ -1183,7 +1170,7 @@ const dockedDash = new Lang.Class({ }, // Show dock and give key focus to it - _onAccessibilityFocus: function(){ + _onAccessibilityFocus: function() { this._box.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); this._animateIn(this._settings.get_double('animation-time'), 0); }, @@ -1199,7 +1186,7 @@ const dockedDash = new Lang.Class({ let animate = this._settings.get_boolean('animate-show-apps'); let selector = Main.overview.viewSelector; - if(selector._showAppsButton.checked !== this.dash.showAppsButton.checked){ + if(selector._showAppsButton.checked !== this.dash.showAppsButton.checked) { // find visible view let visibleView; @@ -1212,7 +1199,7 @@ const dockedDash = new Lang.Class({ } }); - if(this.dash.showAppsButton.checked){ + if(this.dash.showAppsButton.checked) { // force spring animation triggering.By default the animation only // runs if we are already inside the overview. @@ -1238,7 +1225,7 @@ const dockedDash = new Lang.Class({ // and the appgrid could already be allocated from previous shown. // It has to be triggered after the overview is shown as wrong coordinates are obtained // otherwise. - let overviewShownId = Main.overview.connect('shown', Lang.bind(this, function(){ + let overviewShownId = Main.overview.connect('shown', Lang.bind(this, function() { Main.overview.disconnect(overviewShownId); Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { grid.actor.opacity = 255; @@ -1262,7 +1249,7 @@ const dockedDash = new Lang.Class({ // onComplete to avoid ugly flashing of original icons. let view = Main.overview.viewSelector.appDisplay._views[visibleView].view; let grid = view._grid; - view.animate(IconGrid.AnimationDirection.OUT, Lang.bind(this, function(){ + view.animate(IconGrid.AnimationDirection.OUT, Lang.bind(this, function() { Main.overview.viewSelector._appsPage.hide(); Main.overview.hide(); selector._showAppsButton.checked = false; @@ -1300,7 +1287,7 @@ const dockedDash = new Lang.Class({ let label = 'optionalScrollWorkspaceSwitch'; - this._settings.connect('changed::scroll-switch-workspace',Lang.bind(this, function(){ + this._settings.connect('changed::scroll-switch-workspace',Lang.bind(this, function() { if(this._settings.get_boolean('scroll-switch-workspace')) Lang.bind(this, enable)(); else @@ -1310,7 +1297,7 @@ const dockedDash = new Lang.Class({ if(this._settings.get_boolean('scroll-switch-workspace')) Lang.bind(this, enable)(); - function enable(){ + function enable() { this._signalsHandler.removeWithLabel(label); @@ -1328,7 +1315,7 @@ const dockedDash = new Lang.Class({ function disable() { this._signalsHandler.removeWithLabel(label); - if(this._optionalScrollWorkspaceSwitchDeadTimeId>0){ + if(this._optionalScrollWorkspaceSwitchDeadTimeId>0) { Mainloop.source_remove(this._optionalScrollWorkspaceSwitchDeadTimeId); this._optionalScrollWorkspaceSwitchDeadTimeId=0; } @@ -1353,7 +1340,7 @@ const dockedDash = new Lang.Class({ break; case Clutter.ScrollDirection.SMOOTH: let [dx, dy] = event.get_scroll_delta(); - if(dy < 0){ + if(dy < 0) { direction = Meta.MotionDirection.UP; } else if(dy > 0) { direction = Meta.MotionDirection.DOWN; @@ -1361,7 +1348,7 @@ const dockedDash = new Lang.Class({ break; } - if(direction !==null ){ + if(direction !==null ) { // Prevent scroll events from triggering too many workspace switches // by adding a 250ms deadtime between each scroll event. @@ -1408,212 +1395,5 @@ const dockedDash = new Lang.Class({ } }); -Signals.addSignalMethods(dockedDash.prototype); - -/* - * Manage theme customization and custom theme support -*/ -const themeManager = new Lang.Class({ - Name: 'ThemeManager', - - _init: function(settings, actor, dash) { - - this._settings = settings; - this._bindSettingsChanges(); - this._actor = actor; - this._dash = dash; - - // initialize colors with generic values - this._defaultBackground = {red: 0, green:0, blue: 0, alpha:0}; - this._defaultBackgroundColor = {red: 0, green:0, blue: 0, alpha:0}; - this._customizedBackground = {red: 0, green:0, blue: 0, alpha:0}; - - this._signalsHandler = new Convenience.GlobalSignalsHandler(); - this._signalsHandler.add( - // When theme changes re-obtain default background color - [ - St.ThemeContext.get_for_stage (global.stage), - 'changed', - Lang.bind(this, this.updateCustomTheme) - ], - // update :overview pseudoclass - [ - Main.overview, - 'showing', - Lang.bind(this, this._onOverviewShowing) - ], - [ - Main.overview, - 'hiding', - Lang.bind(this, this._onOverviewHiding) - ] - ); - - this._updateCustomStyleClasses(); - - }, - - destroy: function() { - this._signalsHandler.destroy(); - }, - - _onOverviewShowing: function() { - this._actor.add_style_pseudo_class('overview'); - }, - - _onOverviewHiding: function() { - this._actor.remove_style_pseudo_class('overview'); - }, - - _updateBackgroundOpacity: function() { - - let newAlpha = this._settings.get_double('background-opacity'); - this._defaultBackground = 'rgba('+ - this._defaultBackgroundColor.red + ','+ - this._defaultBackgroundColor.green + ','+ - this._defaultBackgroundColor.blue + ','+ - Math.round(this._defaultBackgroundColor.alpha/2.55)/100 + ')'; - - this._customizedBackground = 'rgba('+ - this._defaultBackgroundColor.red + ','+ - this._defaultBackgroundColor.green + ','+ - this._defaultBackgroundColor.blue + ','+ - newAlpha + ')'; - }, - - _getBackgroundColor: function() { - - // Prevent shell crash if the actor is not on the stage. - // It happens enabling/disabling repeatedly the extension - if(!this._dash._container.get_stage()) - return; - - // Remove custom style - let oldStyle = this._dash._container.get_style(); - this._dash._container.set_style(null); - - let themeNode = this._dash._container.get_theme_node(); - this._dash._container.set_style(oldStyle); - - this._defaultBackgroundColor = themeNode.get_background_color(); - }, - - _updateCustomStyleClasses: function(){ - - if (this._settings.get_boolean('apply-custom-theme')) - this._actor.add_style_class_name('dashtodock'); - else { - this._actor.remove_style_class_name('dashtodock'); - } - - if (this._settings.get_boolean('custom-theme-shrink')) - this._actor.add_style_class_name('shrink'); - else { - this._actor.remove_style_class_name('shrink'); - } - - }, - - updateCustomTheme: function() { - this._updateCustomStyleClasses(); - this._getBackgroundColor(); - this._updateBackgroundOpacity(); - this._adjustTheme(); - this._dash._redisplay(); - }, - - /* Reimported back and adapted from atomdock */ - _adjustTheme: function() { - // Prevent shell crash if the actor is not on the stage. - // It happens enabling/disabling repeatedly the extension - if (!this._dash._container.get_stage()) { - return; - } - - // Remove prior style edits - this._dash._container.set_style(null); - - /* If built-in theme is enabled do nothing else */ - if( this._settings.get_boolean('apply-custom-theme') ) - return; - - let newStyle = ''; - let position = getPosition(this._settings); - - if ( ! this._settings.get_boolean('custom-theme-shrink') ) { - - // obtain theme border settings - let themeNode = this._dash._container.get_theme_node(); - let borderColor = themeNode.get_border_color(St.Side.TOP); - let borderWidth = themeNode.get_border_width(St.Side.TOP); - let borderRadius = themeNode.get_border_radius(St.Corner.TOPRIGHT); - - /* We're copying border and corner styles to left border and top-left - * corner, also removing bottom border and bottom-right corner styles - */ - let borderInner = ''; - let borderRadiusValue = ''; - let borderMissingStyle = ''; - - if (this._rtl && position != St.Side.RIGHT) { - borderMissingStyle = 'border-right: ' + borderWidth + 'px solid ' + - borderColor.to_string() + ';'; - } else if (!this._rtl && position != St.Side.LEFT){ - borderMissingStyle = 'border-left: ' + borderWidth + 'px solid ' + - borderColor.to_string() + ';'; - } - - switch(position) { - case St.Side.LEFT: - borderInner = 'border-left'; - borderRadiusValue = '0 ' + borderRadius + 'px ' + borderRadius + 'px 0;'; - break; - case St.Side.RIGHT: - borderInner = 'border-right'; - borderRadiusValue = borderRadius + 'px 0 0 ' + borderRadius + 'px;'; - break; - case St.Side.TOP: - borderInner = 'border-top'; - borderRadiusValue = '0 0 ' + borderRadius + 'px ' + borderRadius + 'px;'; - break; - case St.Side.BOTTOM: - borderInner = 'border-bottom'; - borderRadiusValue = borderRadius + 'px ' + borderRadius + 'px 0 0;'; - break; - } - - newStyle = borderInner + ': none;' + - 'border-radius: ' + borderRadiusValue + - borderMissingStyle ; - - /* I do call set_style possibly twice so that only the background gets the transition. - * The transition-property css rules seems to be unsupported - */ - this._dash._container.set_style(newStyle); - } - - /* Customize background */ - if ( this._settings.get_boolean('opaque-background') ) { - newStyle = newStyle + 'background-color:'+ this._customizedBackground + '; ' + - 'transition-delay: 0s; transition-duration: 0.250s;'; - this._dash._container.set_style(newStyle); - } - }, - - _bindSettingsChanges: function() { - - let keys = ['opaque-background', - 'background-opacity', - 'apply-custom-theme', - 'custom-theme-shrink', - 'extend-height']; - - keys.forEach(function(key){ - this._settings.connect('changed::'+key, - Lang.bind(this, this.updateCustomTheme) - ); - }, this ); - - } -}); +Signals.addSignalMethods(DockedDash.prototype); diff --git a/extension.js b/extension.js index 4bd19fa4c..900a02c0a 100644 --- a/extension.js +++ b/extension.js @@ -2,7 +2,7 @@ const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; -const DockedDash = Me.imports.dockedDash; +const Docking = Me.imports.docking; const Main = imports.ui.main; @@ -12,13 +12,12 @@ let dock; let oldDash; function init() { - } function enable() { settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-dock'); - dock = new DockedDash.dockedDash(settings); + dock = new Docking.DockedDash(settings); /* Pretend I'm the dash: meant to make appgrd swarm animation come from the * right position of the appShowButton. @@ -45,7 +44,7 @@ function bindSettingsChanges() { /* It's easier to just reload the extension when the dock position changes * rather than working out all changes to the differen containers. */ - settings.connect('changed::dock-position', function(){ + settings.connect('changed::dock-position', function() { disable(); enable(); }); diff --git a/icons.js b/icons.js new file mode 100644 index 000000000..b6677cb5d --- /dev/null +++ b/icons.js @@ -0,0 +1,547 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Clutter = imports.gi.Clutter; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Gtk = imports.gi.Gtk; +const Signals = imports.signals; +const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; + +const AppDisplay = imports.ui.appDisplay; +const AppFavorites = imports.ui.appFavorites; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const IconGrid = imports.ui.iconGrid; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Tweener = imports.ui.tweener; +const Util = imports.misc.util; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Convenience = Me.imports.convenience; +const Windows = Me.imports.windows; + +/** + * Extend AppIcon + * + * - Pass settings to the constructor and bind settings changes + * - Apply a css class based on the number of windows of each application (#N); + * - Draw a dot for each window of the application based on the default "dot" style which is hidden (#N); + * a class of the form "running#N" is applied to the AppWellIcon actor. + * like the original .running one. + * - add a .focused style to the focused app + * - Customize click actions. + * - Update minimization animation target + * + */ + +let tracker = Shell.WindowTracker.get_default(); + +const clickAction = { + SKIP: 0, + MINIMIZE: 1, + LAUNCH: 2, + CYCLE_WINDOWS: 3 +}; + +let recentlyClickedAppLoopId = 0; +let recentlyClickedApp = null; +let recentlyClickedAppWindows = null; +let recentlyClickedAppIndex = 0; + +const MyAppIcon = new Lang.Class({ + Name: 'DashToDock.AppIcon', + Extends: AppDisplay.AppIcon, + + // settings are required inside. + _init: function(settings, app, iconParams, onActivateOverride) { + + this._dtdSettings = settings; + this._nWindows = 0; + + this.parent(app, iconParams, onActivateOverride); + + // Monitor windows-changes instead of app state. + // Keep using the same Id and function callback (that is extended) + if(this._stateChangedId>0) { + this.app.disconnect(this._stateChangedId); + this._stateChangedId=0; + } + + this._stateChangedId = this.app.connect('windows-changed', + Lang.bind(this, + this.onWindowsChanged)); + this._focuseAppChangeId = tracker.connect('notify::focus-app', + Lang.bind(this, + this._onFocusAppChanged)); + + this._dots = null; + + let keys = ['apply-custom-theme', + 'custom-theme-running-dots', + 'custom-theme-customize-running-dots', + 'custom-theme-running-dots-color', + 'custom-theme-running-dots-border-color', + 'custom-theme-running-dots-border-width']; + + keys.forEach(function(key) { + this._dtdSettings.connect('changed::'+key, + Lang.bind(this, this._toggleDots) + ); + }, this ); + + this._toggleDots(); + }, + + _onDestroy: function() { + this.parent(); + + // Disconect global signals + // stateChangedId is already handled by parent) + if(this._focusAppId>0) + tracker.disconnect(this._focusAppId); + }, + + onWindowsChanged: function() { + this._updateRunningStyle(); + this.updateIconGeometry(); + + }, + + // Update taraget for minimization animation + updateIconGeometry: function() { + + // If (for unknown reason) the actor is not on the stage the reported size + // and position are random values, which might exceeds the integer range + // resulting in an error when assigned to the a rect. This is a more like + // a workaround to prevent flooding the system with errors. + if (this.actor.get_stage() == null) + return + + let rect = new Meta.Rectangle(); + + if (Windows.isStolen(this.app)) { + if (this.actor.child) { + this.actor.child.destroy(); + this.actor.child = null; + } + } + + [rect.x, rect.y] = this.actor.get_transformed_position(); + [rect.width, rect.height] = this.actor.get_transformed_size(); + + let windows = Windows.getAllWindows(this.app); + windows.forEach(function(w) { + w.set_icon_geometry(rect); + }); + + }, + + _toggleDots: function() { + + if ( this._dtdSettings.get_boolean('custom-theme-running-dots') + || this._dtdSettings.get_boolean('apply-custom-theme') ) + this._showDots(); + else + this._hideDots(); + }, + + _showDots: function() { + // I use opacity to hide the default dot because the show/hide function + // are used by the parent class. + this._dot.opacity = 0; + + // Just update style if dots already exist + if (this._dots) { + this._updateCounterClass(); + return; + } + + this._dots = new St.DrawingArea({x_expand: true, y_expand: true}); + this._dots.connect('repaint', Lang.bind(this, + function() { + this._drawCircles(this._dots, Convenience.getPosition(this._dtdSettings)); + })); + this._iconContainer.add_child(this._dots); + this._updateCounterClass(); + + }, + + _hideDots: function() { + this._dot.opacity=255; + if (this._dots) + this._dots.destroy() + this._dots = null; + }, + + _updateRunningStyle: function() { + this.parent(); + this._updateCounterClass(); + }, + + popupMenu: function() { + this._removeMenuTimeout(); + this.actor.fake_release(); + this._draggable.fakeRelease(); + + if (!this._menu) { + this._menu = new MyAppIconMenu(this, this._dtdSettings); + this._menu.connect('activate-window', Lang.bind(this, function (menu, window) { + this.activateWindow(window); + })); + this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) { + if (!isPoppedUp) + this._onMenuPoppedDown(); + })); + let id = Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); })); + this._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); + + this._menuManager.addMenu(this._menu); + } + + this.emit('menu-state-changed', true); + + this.actor.set_hover(true); + this._menu.popup(); + this._menuManager.ignoreRelease(); + this.emit('sync-tooltip'); + + return false; + }, + + _onFocusAppChanged: function() { + if(tracker.focus_app == this.app) + this.actor.add_style_class_name('focused'); + else + this.actor.remove_style_class_name('focused'); + }, + + activate: function(button) { + + if ( !this._dtdSettings.get_boolean('customize-click') ) { + this.parent(button); + return; + } + + let isRunning = Windows.isWindowStealer(this.app) ? + Windows.getAllWindows(this.app).length > 0 : + this.app.state == Shell.AppState.RUNNING; + + let event = Clutter.get_current_event(); + let modifiers = event ? event.get_state() : 0; + let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK && + isRunning || + button && button == 2; + + let focusedApp = tracker.focus_app; + let isFocused = Windows.isWindowStealer(this.app) ? + Windows.isStealingFrom(this.app, focusedApp) : + this.app == focusedApp; + + if (!isRunning || openNewWindow) + this.animateLaunch(); + + if(button && button == 1 && isRunning) { + + if(modifiers & Clutter.ModifierType.CONTROL_MASK) { + // Keep default behaviour: launch new window + // By calling the parent method I make it compatible + // with other extensions tweaking ctrl + click + this.parent(button); + return; + + } else if (this._dtdSettings.get_boolean('minimize-shift') && modifiers & Clutter.ModifierType.SHIFT_MASK) { + // On double click, minimize all windows in the current workspace + minimizeWindow(this.app, event.get_click_count() > 1); + + } else if(isFocused && !Main.overview._shown) { + + if(this._dtdSettings.get_enum('click-action') == clickAction.CYCLE_WINDOWS) + cycleThroughWindows(this.app); + else if(this._dtdSettings.get_enum('click-action') == clickAction.MINIMIZE) + minimizeWindow(this.app, true); + else if(this._dtdSettings.get_enum('click-action') == clickAction.LAUNCH) + this.app.open_new_window(-1); + + } else { + // Activate all window of the app or only le last used + if (this._dtdSettings.get_enum('click-action') == clickAction.CYCLE_WINDOWS && !Main.overview._shown) { + // If click cycles through windows I can activate one windows at a time + let windows = Windows.getInterestingWindows(this.app); + let w = windows[0]; + Main.activateWindow(w); + } else if(this._dtdSettings.get_enum('click-action') == clickAction.LAUNCH) + this.app.open_new_window(-1); + else if(this._dtdSettings.get_enum('click-action') == clickAction.MINIMIZE) { + // If click minimizes all, then one expects all windows to be reshown + activateAllWindows(this.app); + } else + this.app.activate(); + } + } else { + // Default behaviour + if (openNewWindow) + this.app.open_new_window(-1); + else + this.app.activate(); + } + + Main.overview.hide(); + }, + + _updateCounterClass: function() { + + let maxN = 4; + this._nWindows = Math.min(Windows.getInterestingWindows(this.app).length, maxN); + + for(let i = 1; i<=maxN; i++) { + let className = 'running'+i; + if(i!=this._nWindows) + this.actor.remove_style_class_name(className); + else + this.actor.add_style_class_name(className); + } + + if (this._dots) + this._dots.queue_repaint(); + }, + + _drawCircles: function(area, side) { + + let borderColor, borderWidth, bodyColor; + + if (!this._dtdSettings.get_boolean('apply-custom-theme') + && this._dtdSettings.get_boolean('custom-theme-running-dots') + && this._dtdSettings.get_boolean('custom-theme-customize-running-dots')) { + borderColor = Clutter.color_from_string(this._dtdSettings.get_string('custom-theme-running-dots-border-color'))[1]; + borderWidth = this._dtdSettings.get_int('custom-theme-running-dots-border-width'); + bodyColor = Clutter.color_from_string(this._dtdSettings.get_string('custom-theme-running-dots-color'))[1]; + } else { + // Re-use the style - background color, and border width and color - + // of the default dot + let themeNode = this._dot.get_theme_node(); + borderColor = themeNode.get_border_color(side); + borderWidth = themeNode.get_border_width(side); + bodyColor = themeNode.get_background_color(); + } + + let [width, height] = area.get_surface_size(); + let cr = area.get_context(); + + // Draw the required numbers of dots + let radius = width/22 - borderWidth/2; + radius = Math.max(radius, borderWidth/4+1); + let padding = 0; // distance from the margin + let spacing = radius + borderWidth; // separation between the dots + let n = this._nWindows; + + cr.setLineWidth(borderWidth); + Clutter.cairo_set_source_color(cr, borderColor); + + switch (side) { + case St.Side.TOP: + cr.translate((width - (2*n)*radius - (n-1)*spacing)/2, padding); + for (let i=0; i=0; i--) { + if(windows[i].get_workspace().index() == activeWorkspace) { + Main.activateWindow(windows[i]); + activatedWindows++; + } + } +} + +function cycleThroughWindows(app) { + + // Store for a little amount of time last clicked app and its windows + // since the order changes upon window interaction + let MEMORY_TIME=3000; + + let app_windows = Windows.getInterestingWindows(app); + + if(recentlyClickedAppLoopId>0) + Mainloop.source_remove(recentlyClickedAppLoopId); + recentlyClickedAppLoopId = Mainloop.timeout_add(MEMORY_TIME, resetRecentlyClickedApp); + + // If there isn't already a list of windows for the current app, + // or the stored list is outdated, use the current windows list. + if( !recentlyClickedApp || + recentlyClickedApp.get_id() != app.get_id() || + recentlyClickedAppWindows.length != app_windows.length + ) { + + recentlyClickedApp = app; + recentlyClickedAppWindows = app_windows; + recentlyClickedAppIndex = 0; + } + + recentlyClickedAppIndex++; + let index = recentlyClickedAppIndex % recentlyClickedAppWindows.length; + let window = recentlyClickedAppWindows[index]; + + Main.activateWindow(window); +} + +function resetRecentlyClickedApp() { + + if(recentlyClickedAppLoopId>0) + Mainloop.source_remove(recentlyClickedAppLoopId); + recentlyClickedAppLoopId=0; + recentlyClickedApp =null; + recentlyClickedAppWindows = null; + recentlyClickedAppIndex = 0; + + return false; +} + +/** + * Extend AppIconMenu + * + * - Pass settings to the constructor + * - set popup arrow side based on dash orientation + * - Add close windows option based on quitfromdash extension + * (https://github.com/deuill/shell-extension-quitfromdash) + */ + +const MyAppIconMenu = new Lang.Class({ + Name: 'DashToDock.MyAppIconMenu', + Extends: AppDisplay.AppIconMenu, + + _init: function(source, settings) { + + let side = Convenience.getPosition(settings); + + // Damm it, there has to be a proper way of doing this... + // As I can't call the parent parent constructor (?) passing the side + // parameter, I overwite what I need later + this.parent(source); + + // Change the initialized side where required. + this._arrowSide = side; + this._boxPointer._arrowSide = side; + this._boxPointer._userArrowSide = side; + + this._settings = settings; + }, + + // helper function for the quit windows abilities + _closeWindowInstance: function(metaWindow) { + metaWindow.delete(global.get_current_time()); + }, + + _redisplay: function() { + + this.parent(); + + // steal windows menu + this._appendSeparator(); + this._stealWindowsMenuItem = this._appendMenuItem(_('Steal Windows')); + this._stealWindowsMenuItem.connect('activate', Lang.bind(this, function() { + + //let r = Util.spawn(['gnome-shell-extension-prefs', 'dash-to-dock@micxgx.gmail.com']); + //global.log('>>>>>>>>>>>> ' + r); + + })); + + // quit menu + let app = this._source.app; + let count = Windows.getInterestingWindows(app).length; + if ( count > 0) { + this._appendSeparator(); + let quitFromDashMenuText = ""; + if (count == 1) + quitFromDashMenuText = _("Quit"); + else + quitFromDashMenuText = _("Quit") + ' ' + count + ' ' + _("Windows"); + + this._quitfromDashMenuItem = this._appendMenuItem(quitFromDashMenuText); + this._quitfromDashMenuItem.connect('activate', Lang.bind(this, function() { + let app = this._source.app; + let windows = Windows.getAllWindows(app); + for (let i = 0; i < windows.length; i++) { + this._closeWindowInstance(windows[i]) + } + })); + } + } +}); diff --git a/intellihide.js b/intellihide.js index 069b385c4..736ea7823 100644 --- a/intellihide.js +++ b/intellihide.js @@ -30,25 +30,24 @@ const IntellihideMode = { // List of windows type taken into account. Order is important (keep the original // enum order). const handledWindowTypes = [ - Meta.WindowType.NORMAL, - Meta.WindowType.DOCK, - Meta.WindowType.DIALOG, - Meta.WindowType.MODAL_DIALOG, - Meta.WindowType.TOOLBAR, - Meta.WindowType.MENU, - Meta.WindowType.UTILITY, - Meta.WindowType.SPLASHSCREEN + Meta.WindowType.NORMAL, + Meta.WindowType.DOCK, + Meta.WindowType.DIALOG, + Meta.WindowType.MODAL_DIALOG, + Meta.WindowType.TOOLBAR, + Meta.WindowType.MENU, + Meta.WindowType.UTILITY, + Meta.WindowType.SPLASHSCREEN ]; -/* +/** * A rough and ugly implementation of the intellihide behaviour. * Intallihide object: emit 'status-changed' signal when the overlap of windows * with the provided targetBoxClutter.ActorBox changes; * */ - -const intellihide = new Lang.Class({ - Name: 'Intellihide', +const Intellihide = new Lang.Class({ + Name: 'DashToDock.Intellihide', _init: function(settings) { @@ -110,7 +109,7 @@ const intellihide = new Lang.Class({ enable: function() { this._isEnabled = true; this._status = OverlapStatus.UNDEFINED; - global.get_window_actors().forEach(function(win){ + global.get_window_actors().forEach(function(win) { this._addWindowSignals(win.get_meta_window()) }, this); this._doCheckOverlap(); @@ -118,7 +117,7 @@ const intellihide = new Lang.Class({ disable: function() { this._isEnabled = false; - global.get_window_actors().forEach(function(win){ + global.get_window_actors().forEach(function(win) { this._removeWindowSignals(win.get_meta_window()) }, this); @@ -167,7 +166,7 @@ const intellihide = new Lang.Class({ this._doCheckOverlap(); }, - getOverlapStatus: function(){ + getOverlapStatus: function() { if(this._status == OverlapStatus.TRUE) return true; else @@ -180,7 +179,7 @@ const intellihide = new Lang.Class({ return; /* Limit the number of calls to the doCheckOverlap function */ - if(this._checkOverlapTimeoutId){ + if(this._checkOverlapTimeoutId) { this._checkOverlapTimeoutContinue = true; return } @@ -191,7 +190,7 @@ const intellihide = new Lang.Class({ Mainloop.timeout_add(INTELLIHIDE_CHECK_INTERVAL, Lang.bind(this, function() { this._doCheckOverlap(); - if (this._checkOverlapTimeoutContinue){ + if (this._checkOverlapTimeoutContinue) { this._checkOverlapTimeoutContinue = false; return GLib.SOURCE_CONTINUE; } else { @@ -210,7 +209,7 @@ const intellihide = new Lang.Class({ let overlaps = OverlapStatus.FALSE; let windows = global.get_window_actors(); - if (windows.length>0){ + if (windows.length>0) { /* @@ -243,10 +242,10 @@ const intellihide = new Lang.Class({ windows = windows.filter(this._intellihideFilterInteresting, this); - for(let i=0; i< windows.length; i++){ + for(let i=0; i< windows.length; i++) { let win = windows[i].get_meta_window(); - if(win){ + if(win) { let rect = win.get_frame_rect(); let test = ( rect.x < this._targetBox.x2) && @@ -254,7 +253,7 @@ const intellihide = new Lang.Class({ ( rect.y < this._targetBox.y2 ) && ( rect.y +rect.height > this._targetBox.y1 ); - if(test){ + if(test) { overlaps = OverlapStatus.TRUE; break; } @@ -273,7 +272,7 @@ const intellihide = new Lang.Class({ // Filter interesting windows to be considered for intellihide. // Consider all windows visible on the current workspace. // Optionally skip windows of other applications - _intellihideFilterInteresting: function(wa){ + _intellihideFilterInteresting: function(wa) { let meta_win = wa.get_meta_window(); if (!meta_win || !this._handledWindow(meta_win)) { @@ -365,4 +364,4 @@ const intellihide = new Lang.Class({ }); -Signals.addSignalMethods(intellihide.prototype); +Signals.addSignalMethods(Intellihide.prototype); diff --git a/prefs.js b/prefs.js index 82ec7dd9d..74da8f84d 100644 --- a/prefs.js +++ b/prefs.js @@ -1,4 +1,4 @@ -// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; @@ -8,7 +8,6 @@ const Gdk = imports.gi.Gdk; const Lang = imports.lang; const Mainloop = imports.mainloop; - const Gettext = imports.gettext.domain('dashtodock'); const _ = Gettext.gettext; const N_ = function(e) { return e }; @@ -20,11 +19,11 @@ const Convenience = Me.imports.convenience; const SCALE_UPDATE_TIMEOUT = 500; const DEFAULT_ICONS_SIZES = [ 128, 96, 64, 48, 32, 24, 16 ]; -/* -This function was copied from the activities-config extension -https://github.com/nls1729/acme-code/tree/master/activities-config -by Norman L. Smith. -*/ +/** + * This function was copied from the activities-config extension + * https://github.com/nls1729/acme-code/tree/master/activities-config + * by Norman L. Smith. + */ function cssHexString(css) { let rrggbb = '#'; let start; @@ -52,10 +51,8 @@ function cssHexString(css) { return rrggbb; } - const Settings = new Lang.Class({ - Name: 'DashToDockSettings', - + Name: 'DashToDock.Settings', _init: function() { @@ -105,7 +102,7 @@ const Settings = new Lang.Class({ // Add connected monitors let ctr = 0; for (let i = 0; i < n_monitors; i++) { - if (i !== primary_monitor){ + if (i !== primary_monitor) { ctr++; this._monitors.push(ctr); this._builder.get_object('dock_monitor_combo').append_text(_("Secondary monitor ") + ctr); @@ -250,7 +247,7 @@ const Settings = new Lang.Class({ // restore default settings for the relevant keys let keys = ['intellihide', 'autohide', 'intellihide-mode', 'autohide-in-fullscreen', 'require-pressure-to-show', 'animation-time', 'show-delay', 'hide-delay', 'pressure-threshold']; - keys.forEach(function(val){ + keys.forEach(function(val) { this._settings.set_value(val, this._settings.get_default_value(val)); }, this); intellihideModeRadioButtons[this._settings.get_enum('intellihide-mode')].set_active(true); @@ -272,7 +269,7 @@ const Settings = new Lang.Class({ let icon_size_scale = this._builder.get_object('icon_size_scale'); icon_size_scale.set_range(DEFAULT_ICONS_SIZES[DEFAULT_ICONS_SIZES.length -1], DEFAULT_ICONS_SIZES[0]); icon_size_scale.set_value(this._settings.get_int('dash-max-icon-size')); - DEFAULT_ICONS_SIZES.forEach(function(val){ + DEFAULT_ICONS_SIZES.forEach(function(val) { icon_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); }); @@ -420,7 +417,6 @@ const Settings = new Lang.Class({ }, - // Object containing all signals defined in the glade file _SignalHandler: { @@ -428,7 +424,7 @@ const Settings = new Lang.Class({ this._settings.set_int('preferred-monitor', this._monitors[combo.get_active()]); }, - position_top_button_toggled_cb: function (button){ + position_top_button_toggled_cb: function (button) { if (button.get_active()) this._settings.set_enum('dock-position', 0); }, @@ -456,12 +452,12 @@ const Settings = new Lang.Class({ return Math.round(value*100)+ ' %'; }, - dock_size_scale_value_changed_cb: function(scale){ + dock_size_scale_value_changed_cb: function(scale) { // Avoid settings the size consinuosly if (this._dock_size_timeout >0) Mainloop.source_remove(this._dock_size_timeout); - this._dock_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function(){ + this._dock_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { this._settings.set_double('height-fraction', scale.get_value()); this._dock_size_timeout = 0; return GLib.SOURCE_REMOVE; @@ -472,24 +468,24 @@ const Settings = new Lang.Class({ return value+ ' px'; }, - icon_size_scale_value_changed_cb: function(scale){ + icon_size_scale_value_changed_cb: function(scale) { // Avoid settings the size consinuosly if (this._icon_size_timeout >0) Mainloop.source_remove(this._icon_size_timeout); - this._icon_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function(){ + this._icon_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { this._settings.set_int('dash-max-icon-size', scale.get_value()); this._icon_size_timeout = 0; return GLib.SOURCE_REMOVE; })); }, - custom_opacity_scale_value_changed_cb: function(scale){ + custom_opacity_scale_value_changed_cb: function(scale) { // Avoid settings the opacity consinuosly as it's change is animated if (this._opacity_timeout >0) Mainloop.source_remove(this._opacity_timeout); - this._opacity_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function(){ + this._opacity_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { this._settings.set_double('background-opacity', scale.get_value()); this._opacity_timeout = 0; return GLib.SOURCE_REMOVE; @@ -500,17 +496,17 @@ const Settings = new Lang.Class({ return Math.round(value*100) + ' %'; }, - all_windows_radio_button_toggled_cb: function (button){ + all_windows_radio_button_toggled_cb: function (button) { if (button.get_active()) this._settings.set_enum('intellihide-mode', 0); }, - focus_application_windows_radio_button_toggled_cb: function (button){ + focus_application_windows_radio_button_toggled_cb: function (button) { if (button.get_active()) this._settings.set_enum('intellihide-mode', 1); }, - maximized_windows_radio_button_toggled_cb: function (button){ + maximized_windows_radio_button_toggled_cb: function (button) { if (button.get_active()) this._settings.set_enum('intellihide-mode', 2); } diff --git a/stylesheet.css b/stylesheet.css index 869840783..8e3399553 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -87,3 +87,29 @@ #dashtodockContainer.dashtodock #dash { background: #2e3436; } + +/* +#dashtodockContainer2 .stolen { + border: 0px solid red; + margin: 0px; + padding: 0px; + width: 0px; + height: 0px; +} + +#dashtodockContainer2 .stolen StBin { + border: 0px solid red; + margin: 0px; + padding: 0px; + width: 0px; + height: 0px; +} + +#dashtodockContainer2 .stolen StWidget { + border: 0px solid red; + margin: 0px; + padding: 0px; + width: 0px; + height: 0px; +} +*/ diff --git a/theming.js b/theming.js new file mode 100644 index 000000000..44a235c28 --- /dev/null +++ b/theming.js @@ -0,0 +1,236 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Clutter = imports.gi.Clutter; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Gtk = imports.gi.Gtk; +const Signals = imports.signals; +const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; + +const AppDisplay = imports.ui.appDisplay; +const AppFavorites = imports.ui.appFavorites; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const IconGrid = imports.ui.iconGrid; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Tweener = imports.ui.tweener; +const Util = imports.misc.util; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Convenience = Me.imports.convenience; +const Icons = Me.imports.icons; +const Windows = Me.imports.windows; + +/* + * Manage theme customization and custom theme support +*/ +const ThemeManager = new Lang.Class({ + Name: 'DashToDock.ThemeManager', + + _init: function(settings, actor, dash) { + + this._settings = settings; + this._bindSettingsChanges(); + this._actor = actor; + this._dash = dash; + + // initialize colors with generic values + this._defaultBackground = {red: 0, green:0, blue: 0, alpha:0}; + this._defaultBackgroundColor = {red: 0, green:0, blue: 0, alpha:0}; + this._customizedBackground = {red: 0, green:0, blue: 0, alpha:0}; + + this._signalsHandler = new Convenience.GlobalSignalsHandler(); + this._signalsHandler.add( + // When theme changes re-obtain default background color + [ + St.ThemeContext.get_for_stage (global.stage), + 'changed', + Lang.bind(this, this.updateCustomTheme) + ], + // update :overview pseudoclass + [ + Main.overview, + 'showing', + Lang.bind(this, this._onOverviewShowing) + ], + [ + Main.overview, + 'hiding', + Lang.bind(this, this._onOverviewHiding) + ] + ); + + this._updateCustomStyleClasses(); + + }, + + destroy: function() { + this._signalsHandler.destroy(); + }, + + _onOverviewShowing: function() { + this._actor.add_style_pseudo_class('overview'); + }, + + _onOverviewHiding: function() { + this._actor.remove_style_pseudo_class('overview'); + }, + + _updateBackgroundOpacity: function() { + + let newAlpha = this._settings.get_double('background-opacity'); + + this._defaultBackground = 'rgba('+ + this._defaultBackgroundColor.red + ','+ + this._defaultBackgroundColor.green + ','+ + this._defaultBackgroundColor.blue + ','+ + Math.round(this._defaultBackgroundColor.alpha/2.55)/100 + ')'; + + this._customizedBackground = 'rgba('+ + this._defaultBackgroundColor.red + ','+ + this._defaultBackgroundColor.green + ','+ + this._defaultBackgroundColor.blue + ','+ + newAlpha + ')'; + }, + + _getBackgroundColor: function() { + + // Prevent shell crash if the actor is not on the stage. + // It happens enabling/disabling repeatedly the extension + if(!this._dash._container.get_stage()) + return; + + // Remove custom style + let oldStyle = this._dash._container.get_style(); + this._dash._container.set_style(null); + + let themeNode = this._dash._container.get_theme_node(); + this._dash._container.set_style(oldStyle); + + this._defaultBackgroundColor = themeNode.get_background_color(); + }, + + _updateCustomStyleClasses: function() { + + if (this._settings.get_boolean('apply-custom-theme')) + this._actor.add_style_class_name('dashtodock'); + else { + this._actor.remove_style_class_name('dashtodock'); + } + + if (this._settings.get_boolean('custom-theme-shrink')) + this._actor.add_style_class_name('shrink'); + else { + this._actor.remove_style_class_name('shrink'); + } + + }, + + updateCustomTheme: function() { + this._updateCustomStyleClasses(); + this._getBackgroundColor(); + this._updateBackgroundOpacity(); + this._adjustTheme(); + this._dash._redisplay(); + }, + + /* Reimported back and adapted from atomdock */ + _adjustTheme: function() { + // Prevent shell crash if the actor is not on the stage. + // It happens enabling/disabling repeatedly the extension + if (!this._dash._container.get_stage()) { + return; + } + + // Remove prior style edits + this._dash._container.set_style(null); + + /* If built-in theme is enabled do nothing else */ + if( this._settings.get_boolean('apply-custom-theme') ) + return; + + let newStyle = ''; + let position = Convenience.getPosition(this._settings); + + if ( ! this._settings.get_boolean('custom-theme-shrink') ) { + + // obtain theme border settings + let themeNode = this._dash._container.get_theme_node(); + let borderColor = themeNode.get_border_color(St.Side.TOP); + let borderWidth = themeNode.get_border_width(St.Side.TOP); + let borderRadius = themeNode.get_border_radius(St.Corner.TOPRIGHT); + + /* We're copying border and corner styles to left border and top-left + * corner, also removing bottom border and bottom-right corner styles + */ + let borderInner = ''; + let borderRadiusValue = ''; + let borderMissingStyle = ''; + + if (this._rtl && position != St.Side.RIGHT) { + borderMissingStyle = 'border-right: ' + borderWidth + 'px solid ' + + borderColor.to_string() + ';'; + } else if (!this._rtl && position != St.Side.LEFT) { + borderMissingStyle = 'border-left: ' + borderWidth + 'px solid ' + + borderColor.to_string() + ';'; + } + + switch(position) { + case St.Side.LEFT: + borderInner = 'border-left'; + borderRadiusValue = '0 ' + borderRadius + 'px ' + borderRadius + 'px 0;'; + break; + case St.Side.RIGHT: + borderInner = 'border-right'; + borderRadiusValue = borderRadius + 'px 0 0 ' + borderRadius + 'px;'; + break; + case St.Side.TOP: + borderInner = 'border-top'; + borderRadiusValue = '0 0 ' + borderRadius + 'px ' + borderRadius + 'px;'; + break; + case St.Side.BOTTOM: + borderInner = 'border-bottom'; + borderRadiusValue = borderRadius + 'px ' + borderRadius + 'px 0 0;'; + break; + } + + newStyle = borderInner + ': none;' + + 'border-radius: ' + borderRadiusValue + + borderMissingStyle ; + + /* I do call set_style possibly twice so that only the background gets the transition. + * The transition-property css rules seems to be unsupported + */ + this._dash._container.set_style(newStyle); + } + + /* Customize background */ + if ( this._settings.get_boolean('opaque-background') ) { + newStyle = newStyle + 'background-color:'+ this._customizedBackground + '; ' + + 'transition-delay: 0s; transition-duration: 0.250s;'; + this._dash._container.set_style(newStyle); + } + }, + + _bindSettingsChanges: function() { + + let keys = ['opaque-background', + 'background-opacity', + 'apply-custom-theme', + 'custom-theme-shrink', + 'extend-height']; + + keys.forEach(function(key) { + this._settings.connect('changed::'+key, + Lang.bind(this, this.updateCustomTheme) + ); + }, this ); + + } +}); diff --git a/windows.js b/windows.js new file mode 100644 index 000000000..d32441769 --- /dev/null +++ b/windows.js @@ -0,0 +1,104 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Shell = imports.gi.Shell; + +let SETTINGS = { + 'sapir-claws-mail.desktop': ['Claws-mail'], + 'sapir-pidgin.desktop': ['Pidgin'] +}; + +function isWindowStealer(app) { + return SETTINGS[app.id] != null; +} + +function isStolen(app) { + return hasStolenWindows(app) && !getNonStolenWindows(app).length; +} + +function isStealingFrom(app, stolenApp) { + if (stolenApp !== null) { + let windows = stolenApp.get_windows(); + for (let w in windows) { + if (isStealingWindow(app, windows[w])) { + return true; + } + } + } + return false; +} + +function isStolenWindow(window) { + let clazz = window.wm_class; + for (let id in SETTINGS) { + let classesToSteal = SETTINGS[id]; + for (let i in classesToSteal) { + if (clazz == classesToSteal[i]) { + return true; + } + } + } + return false; +} + +function isStealingWindow(app, window) { + let classesToSteal = SETTINGS[app.id]; + if (classesToSteal) { + let clazz = window.wm_class; + for (let c in classesToSteal) { + if (classesToSteal[c] == clazz) { + return true; + } + } + } + return false; +} + +function hasStolenWindows(app) { + let windows = app.get_windows(); + for (let w in windows) { + if (isStolenWindow(windows[w])) { + return true; + } + } + return false; +} + +function getStolenWindows(app) { + return app.get_windows().filter(function(w) { + return isStolenWindow(w); + }); +} + +function getNonStolenWindows(app) { + return app.get_windows().filter(function(w) { + return !isStolenWindow(w); + }); +} + +// Includes stolen windows +function getAllWindows(app) { + let windows = app.get_windows(); + let classesToSteal = SETTINGS[app.id]; + if (classesToSteal) { + let running = Shell.AppSystem.get_default().get_running(); + running.forEach(function(r) { + r.get_windows().forEach(function(window) { + let clazz = window.wm_class; + for (let c in classesToSteal) { + if (classesToSteal[c] == clazz) { + windows.push(window); + } + } + }); + }); + } + return windows; +} + +// Filter out unnecessary windows, for instance +// nautilus desktop window. +function getInterestingWindows(app) { + return getAllWindows(app).filter(function(w) { + return !w.skip_taskbar; + }); +} From de2e056a86b4ae3d9981be59bc9f630c005855eb Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Sat, 26 Mar 2016 16:34:29 -0500 Subject: [PATCH 02/11] More cleanup; use GSettings for window stealing --- convenience.js | 70 +- dash.js | 672 +++++++----------- docking.js | 652 ++++++++--------- extension.js | 12 +- icons.js | 439 ++++++++---- intellihide.js | 207 +++--- prefs.js | 253 ++++--- ....shell.extensions.dash-to-dock.gschema.xml | 5 + theming.js | 162 ++--- windows.js | 184 +++-- 10 files changed, 1289 insertions(+), 1367 deletions(-) diff --git a/convenience.js b/convenience.js index 11f2b5383..632591633 100644 --- a/convenience.js +++ b/convenience.js @@ -70,7 +70,9 @@ function getSettings(schema) { throw new Error('Schema ' + schema + ' could not be found for extension ' + extension.metadata.uuid + '. Please check your installation.'); - return new Gio.Settings({ settings_schema: schemaObj }); + return new Gio.Settings({ + settings_schema: schemaObj + }); } /** @@ -84,11 +86,10 @@ const BasicHandler = new Lang.Class({ this._storage = new Object(); }, - add: function(/*unlimited 3-long array arguments*/) { - - // convert arguments object to array, concatenate with generic + add: function(/* unlimited 3-long array arguments */) { + // Convert arguments object to array, concatenate with generic let args = Array.concat('generic', Array.slice(arguments)); - // call addWithLabel with ags as if they were passed arguments + // Call addWithLabel with ags as if they were passed arguments this.addWithLabel.apply(this, args); }, @@ -97,38 +98,39 @@ const BasicHandler = new Lang.Class({ this.removeWithLabel(label); }, - addWithLabel: function( label /* plus unlimited 3-long array arguments*/) { - - if(this._storage[label] == undefined) + addWithLabel: function(label /* plus unlimited 3-long array arguments*/) { + if (this._storage[label] == undefined) this._storage[label] = new Array(); - // skip first element of the arguments - for( let i = 1; i < arguments.length; i++ ) { - this._storage[label].push( this._create(arguments[i]) ); + // Skip first element of the arguments + for (let i = 1; i < arguments.length; i++) { + this._storage[label].push( this._create(arguments[i])); } - }, removeWithLabel: function(label) { - - if(this._storage[label]) { - for( let i = 0; i < this._storage[label].length; i++ ) { + if (this._storage[label]) { + for (let i = 0; i < this._storage[label].length; i++) this._remove(this._storage[label][i]); - } delete this._storage[label]; } }, - /* Virtual methods to be implemented by subclass */ - // create single element to be stored in the storage structure + // Virtual methods to be implemented by subclass + + /** + * Create single element to be stored in the storage structure + */ _create: function(item) { - throw new Error('no implementation of _create in ' + this); + throw new Error('no implementation of _create in ' + this); }, - // correctly delete single element + /** + * Correctly delete single element + */ _remove: function(item) { - throw new Error('no implementation of _remove in ' + this); + throw new Error('no implementation of _remove in ' + this); } }); @@ -140,17 +142,16 @@ const GlobalSignalsHandler = new Lang.Class({ Extends: BasicHandler, _create: function(item) { + let object = item[0]; + let event = item[1]; + let callback = item[2] + let id = object.connect(event, callback); - let object = item[0]; - let event = item[1]; - let callback = item[2] - let id = object.connect(event, callback); - - return [object, id]; + return [object, id]; }, _remove: function(item) { - item[0].disconnect(item[1]); + item[0].disconnect(item[1]); } }); @@ -163,14 +164,13 @@ const InjectionsHandler = new Lang.Class({ Extends: BasicHandler, _create: function(item) { + let object = item[0]; + let name = item[1]; + let injectedFunction = item[2]; + let original = object[name]; - let object = item[0]; - let name = item[1]; - let injectedFunction = item[2]; - let original = object[name]; - - object[name] = injectedFunction; - return [object, name, injectedFunction, original]; + object[name] = injectedFunction; + return [object, name, injectedFunction, original]; }, _remove: function(item) { diff --git a/dash.js b/dash.js index f6185eac0..12e2f7516 100644 --- a/dash.js +++ b/dash.js @@ -28,7 +28,6 @@ const Icons = Me.imports.icons; const Windows = Me.imports.windows; let DASH_ANIMATION_TIME = Dash.DASH_ANIMATION_TIME; -let DASH_ITEM_LABEL_SHOW_TIME = Dash.DASH_ITEM_LABEL_SHOW_TIME; let DASH_ITEM_LABEL_HIDE_TIME = Dash.DASH_ITEM_LABEL_HIDE_TIME; let DASH_ITEM_HOVER_TIMEOUT = Dash.DASH_ITEM_HOVER_TIMEOUT; @@ -41,102 +40,13 @@ let DASH_ITEM_HOVER_TIMEOUT = Dash.DASH_ITEM_HOVER_TIMEOUT; * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. * thus use this ugly pattern. */ - - -/* - * A menu for the showAppsIcon -*/ -const myShowAppsIconMenu = new Lang.Class({ - Name: 'DashToDock.ShowAppsIconMenu', - Extends: Icons.MyAppIconMenu, - - _redisplay: function() { - this.removeAll(); - - let item = this._appendMenuItem("Dash to Dock " + _("Settings")); - - item.connect('activate', function () { - Util.spawn(["gnome-shell-extension-prefs", Me.metadata.uuid]); - }); - } -}); - -/** - * Extend ShowAppsIcon - * - * - Pass settings to the constructor - * - set label position based on dash orientation - * - implement a popupMenu based on the AppIcon code - * - * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. - * thus use this ugly pattern. - */ -function extendShowAppsIcon(showAppsIcon, settings) { - - showAppsIcon._dtdSettings = settings; - /* the variable equivalent to toggleButton has a different name in the appIcon class - (actor): duplicate reference to easily reuse appIcon methods */ - showAppsIcon.actor = showAppsIcon.toggleButton; - - // Re-use appIcon methods - showAppsIcon._removeMenuTimeout = AppDisplay.AppIcon.prototype._removeMenuTimeout; - showAppsIcon._setPopupTimeout = AppDisplay.AppIcon.prototype._setPopupTimeout; - showAppsIcon._onButtonPress = AppDisplay.AppIcon.prototype._onButtonPress; - showAppsIcon._onKeyboardPopupMenu = AppDisplay.AppIcon.prototype._onKeyboardPopupMenu; - showAppsIcon._onLeaveEvent = AppDisplay.AppIcon.prototype._onLeaveEvent; - showAppsIcon._onTouchEvent = AppDisplay.AppIcon.prototype._onTouchEvent; - showAppsIcon._onMenuPoppedDown = AppDisplay.AppIcon.prototype._onMenuPoppedDown; - - - // No action on clicked (showing of the appsview is controlled elsewhere) - showAppsIcon._onClicked = function(actor, button) { - showAppsIcon._removeMenuTimeout(); - }; - - showAppsIcon.actor.connect('leave-event', Lang.bind( showAppsIcon, showAppsIcon._onLeaveEvent)); - showAppsIcon.actor.connect('button-press-event', Lang.bind( showAppsIcon, showAppsIcon._onButtonPress)); - showAppsIcon.actor.connect('touch-event', Lang.bind( showAppsIcon, showAppsIcon._onTouchEvent)); - showAppsIcon.actor.connect('clicked', Lang.bind( showAppsIcon, showAppsIcon._onClicked)); - showAppsIcon.actor.connect('popup-menu', Lang.bind( showAppsIcon, showAppsIcon._onKeyboardPopupMenu)); - - showAppsIcon._menu = null; - showAppsIcon._menuManager = new PopupMenu.PopupMenuManager(showAppsIcon); - showAppsIcon._menuTimeoutId = 0; - - showAppsIcon.showLabel = itemShowLabel; - - showAppsIcon.popupMenu = function() { - - showAppsIcon._removeMenuTimeout(); - showAppsIcon.actor.fake_release(); - - if (!showAppsIcon._menu) { - showAppsIcon._menu = new myShowAppsIconMenu(showAppsIcon, showAppsIcon._dtdSettings); - showAppsIcon._menu.connect('open-state-changed', Lang.bind(showAppsIcon, function (menu, isPoppedUp) { - if (!isPoppedUp) - showAppsIcon._onMenuPoppedDown(); - })); - let id = Main.overview.connect('hiding', Lang.bind(showAppsIcon, function () { showAppsIcon._menu.close(); })); - showAppsIcon._menu.actor.connect('destroy', function() { - Main.overview.disconnect(id); - }); - showAppsIcon._menuManager.addMenu(showAppsIcon._menu); - } - - showAppsIcon.emit('menu-state-changed', true); - - showAppsIcon.actor.set_hover(true); - showAppsIcon._menu.popup(); - showAppsIcon._menuManager.ignoreRelease(); - showAppsIcon.emit('sync-tooltip'); - - return false; - }; - - Signals.addSignalMethods(showAppsIcon); +function extendDashItemContainer(dashItemContainer, settings) { + dashItemContainer._dtdSettings = settings; + dashItemContainer.showLabel = Icons.itemShowLabel; } -/* This class is a fork of the upstream DashActor class (ui.dash.js) +/** + * This class is a fork of the upstream DashActor class (ui.dash.js) * * Summary of changes: * - passed settings to class as parameter @@ -148,48 +58,51 @@ const MyDashActor = new Lang.Class({ _init: function(settings) { this._dtdSettings = settings; - this._rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; + this._rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL); this._position = Convenience.getPosition(settings); - this._isHorizontal = ( this._position == St.Side.TOP || - this._position == St.Side.BOTTOM ); + this._isHorizontal = ((this._position == St.Side.TOP) || + (this._position == St.Side.BOTTOM)); - let layout = new Clutter.BoxLayout({ orientation: - this._isHorizontal?Clutter.Orientation.HORIZONTAL:Clutter.Orientation.VERTICAL }); + let layout = new Clutter.BoxLayout({ + orientation: this._isHorizontal?Clutter.Orientation.HORIZONTAL:Clutter.Orientation.VERTICAL + }); - this.actor = new Shell.GenericContainer({ name: 'dash', - layout_manager: layout, - clip_to_allocation: true }); + this.actor = new Shell.GenericContainer({ + name: 'dash', + layout_manager: layout, + clip_to_allocation: true + }); this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth)); this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight)); this.actor.connect('allocate', Lang.bind(this, this._allocate)); this.actor._delegate = this; - + // Popup menu - - this.menu = new PopupMenu.PopupMenu(this.actor, 0.0, St.Side.RIGHT, 0); - this.menu.actor.hide(); - this.menu.actor.add_style_class_name('panel-menu'); - let settingsMenuItem = new PopupMenu.PopupMenuItem('Dash to Dock ' + _('Settings')); - settingsMenuItem.connect('activate', Lang.bind(this, function() { - Util.spawn(['gnome-shell-extension-prefs', Me.metadata.uuid]); - })); - this.menu.addMenuItem(settingsMenuItem); - - Main.uiGroup.add_actor(this.menu.actor); - this.menu.close(); + let side = Convenience.getPosition(settings); + this.menu = new PopupMenu.PopupMenu(this.actor, 0.0, side, 0); + this.menu.actor.add_style_class_name('panel-menu'); + let settingsMenuItem = new PopupMenu.PopupMenuItem('Dash to Dock ' + _('Settings')); + settingsMenuItem.connect('activate', Lang.bind(this, function() { + Util.spawn(['gnome-shell-extension-prefs', Me.metadata.uuid]); + })); + this.menu.addMenuItem(settingsMenuItem); + + Main.uiGroup.add_actor(this.menu.actor); + this.menu.close(); + // Menu manager is required this._menuManager = new PopupMenu.PopupMenuManager(this); this._menuManager.addMenu(this.menu); - this.actor.reactive = true; + // Right-click on dash to toggle popup menu + this.actor.reactive = true; this.actor.connect('button-press-event', Lang.bind(this, function(actor, event) { - if (event.get_state() & Clutter.ModifierType.BUTTON3_MASK) { - this.menu.toggle(); - } - })); - + if (event.get_state() & Clutter.ModifierType.BUTTON3_MASK) { + this.menu.toggle(); + } + })); }, _allocate: function(actor, box, flags) { @@ -205,10 +118,9 @@ const MyDashActor = new Lang.Class({ let offset_y = this._isHorizontal?0:showAppsNatHeight; let childBox = new Clutter.ActorBox(); - if( (this._dtdSettings.get_boolean('show-apps-at-top') && !this._isHorizontal) + if ((this._dtdSettings.get_boolean('show-apps-at-top') && !this._isHorizontal) || (this._dtdSettings.get_boolean('show-apps-at-top') && !this._rtl) - || (!this._dtdSettings.get_boolean('show-apps-at-top') && this._isHorizontal && this._rtl) - ) { + || (!this._dtdSettings.get_boolean('show-apps-at-top') && this._isHorizontal && this._rtl)) { childBox.x1 = contentBox.x1 + offset_x; childBox.y1 = contentBox.y1 + offset_y; childBox.x2 = contentBox.x2; @@ -220,7 +132,8 @@ const MyDashActor = new Lang.Class({ childBox.x2 = contentBox.x1 + showAppsNatWidth; childBox.y2 = contentBox.y1 + showAppsNatHeight; showAppsButton.allocate(childBox, flags); - } else { + } + else { childBox.x1 = contentBox.x1; childBox.y1 = contentBox.y1; childBox.x2 = contentBox.x2 - offset_x; @@ -269,7 +182,7 @@ const MyDashActor = new Lang.Class({ } }); -const baseIconSizes = [ 16, 22, 24, 32, 48, 64, 96, 128 ]; +const baseIconSizes = [16, 22, 24, 32, 48, 64, 96, 128]; /** * This class is a fork of the upstream dash class (ui.dash.js) @@ -290,7 +203,7 @@ const baseIconSizes = [ 16, 22, 24, 32, 48, 64, 96, 128 ]; const MyDash = new Lang.Class({ Name: 'DashToDock.MyDash', - _init : function(settings) { + _init: function(settings) { this._maxHeight = -1; this.iconSize = 64; this._availableIconSizes = baseIconSizes; @@ -298,8 +211,8 @@ const MyDash = new Lang.Class({ this._dtdSettings = settings; this._position = Convenience.getPosition(settings); - this._isHorizontal = ( this._position == St.Side.TOP || - this._position == St.Side.BOTTOM ); + this._isHorizontal = ((this._position == St.Side.TOP) || + (this._position == St.Side.BOTTOM)); this._signalsHandler = new Convenience.GlobalSignalsHandler(); this._dragPlaceholder = null; @@ -312,108 +225,105 @@ const MyDash = new Lang.Class({ this._containerObject = new MyDashActor(settings); this._container = this._containerObject.actor; - this._scrollView = new St.ScrollView({ name: 'dashtodockDashScrollview', - hscrollbar_policy: Gtk.PolicyType.NEVER, - vscrollbar_policy: Gtk.PolicyType.NEVER, - enable_mouse_scrolling: false }); + this._scrollView = new St.ScrollView({ + name: 'dashtodockDashScrollview', + hscrollbar_policy: Gtk.PolicyType.NEVER, + vscrollbar_policy: Gtk.PolicyType.NEVER, + enable_mouse_scrolling: false + }); - this._scrollView.connect('scroll-event', Lang.bind(this, this._onScrollEvent )); + this._scrollView.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); - this._box = new St.BoxLayout({ vertical: !this._isHorizontal, - clip_to_allocation: false, - x_align: Clutter.ActorAlign.START, - y_align: Clutter.ActorAlign.START }); + this._box = new St.BoxLayout({ + vertical: !this._isHorizontal, + clip_to_allocation: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START + }); this._box._delegate = this; this._container.add_actor(this._scrollView); this._scrollView.add_actor(this._box); this._showAppsIcon = new Dash.ShowAppsIcon(); - extendShowAppsIcon(this._showAppsIcon, this._dtdSettings); + Icons.extendShowAppsIcon(this._showAppsIcon, this._dtdSettings); this._showAppsIcon.childScale = 1; this._showAppsIcon.childOpacity = 255; this._showAppsIcon.icon.setIconSize(this.iconSize); this._hookUpLabel(this._showAppsIcon); - let appsIcon = this._showAppsIcon; - appsIcon.connect('menu-state-changed', - Lang.bind(this, function(appsIcon, opened) { - this._itemMenuStateChanged(appsIcon, opened); - })); + appsIcon.connect('menu-state-changed', Lang.bind(this, function(appsIcon, opened) { + this._itemMenuStateChanged(appsIcon, opened); + })); this.showAppsButton = this._showAppsIcon.toggleButton; this._container.add_actor(this._showAppsIcon); let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; - this.actor = new St.Bin({ child: this._container, - y_align: St.Align.START, x_align:rtl?St.Align.END:St.Align.START + this.actor = new St.Bin({ + child: this._container, + y_align: St.Align.START, + x_align: rtl ? St.Align.END : St.Align.START }); - if(this._isHorizontal) { - this.actor.connect('notify::width', Lang.bind(this, - function() { - if (this._maxHeight != this.actor.width) - this._queueRedisplay(); - this._maxHeight = this.actor.width; - })); - } else { - this.actor.connect('notify::height', Lang.bind(this, - function() { - if (this._maxHeight != this.actor.height) - this._queueRedisplay(); - this._maxHeight = this.actor.height; - })); + if (this._isHorizontal) { + this.actor.connect('notify::width', Lang.bind(this, function() { + if (this._maxHeight != this.actor.width) + this._queueRedisplay(); + this._maxHeight = this.actor.width; + })); + } + else { + this.actor.connect('notify::height', Lang.bind(this, function() { + if (this._maxHeight != this.actor.height) + this._queueRedisplay(); + this._maxHeight = this.actor.height; + })); } // Update minimization animation target position on allocation of the // container and on scrollview change. this._box.connect('notify::allocation', Lang.bind(this, this._updateAppIcons)); - let scrollViewAdjustment = this._isHorizontal?this._scrollView.hscroll.adjustment:this._scrollView.vscroll.adjustment; + let scrollViewAdjustment = this._isHorizontal ? this._scrollView.hscroll.adjustment : this._scrollView.vscroll.adjustment; scrollViewAdjustment.connect('notify::value', Lang.bind(this, this._updateAppIcons)); this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay)); - this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' }); + this._settings = new Gio.Settings({ + schema_id: 'org.gnome.shell' + }); this._appSystem = Shell.AppSystem.get_default(); - this._signalsHandler.add( - [ - this._appSystem, - 'installed-changed', - Lang.bind(this, function() { - AppFavorites.getAppFavorites().reload(); - this._queueRedisplay(); - }) - ], - [ - AppFavorites.getAppFavorites(), - 'changed', - Lang.bind(this, this._queueRedisplay) - ], - [ - this._appSystem, - 'app-state-changed', - Lang.bind(this, this._queueRedisplay) - ], - [ - Main.overview, - 'item-drag-begin', - Lang.bind(this, this._onDragBegin) - ], - [ - Main.overview, - 'item-drag-end', - Lang.bind(this, this._onDragEnd) - ], - [ - Main.overview, - 'item-drag-cancelled', - Lang.bind(this, this._onDragCancelled) - ] - ); - + this._signalsHandler.add([ + this._appSystem, + 'installed-changed', + Lang.bind(this, function() { + AppFavorites.getAppFavorites().reload(); + this._queueRedisplay(); + }) + ], [ + AppFavorites.getAppFavorites(), + 'changed', + Lang.bind(this, this._queueRedisplay) + ], [ + this._appSystem, + 'app-state-changed', + Lang.bind(this, this._queueRedisplay) + ], [ + Main.overview, + 'item-drag-begin', + Lang.bind(this, this._onDragBegin) + ], [ + Main.overview, + 'item-drag-end', + Lang.bind(this, this._onDragEnd) + ], [ + Main.overview, + 'item-drag-cancelled', + Lang.bind(this, this._onDragCancelled) + ]); }, destroy: function() { @@ -421,10 +331,9 @@ const MyDash = new Lang.Class({ }, _onScrollEvent: function(actor, event) { - // If scroll is not used because the icon is resized, let the scroll event propagate. if (!this._dtdSettings.get_boolean('icon-size-fixed')) - return Clutter.EVENT_PROPAGATE; + return Clutter.EVENT_PROPAGATE; // Event coordinates are relative to the stage but can be transformed // as the actor will only receive events within his bounds. @@ -440,9 +349,9 @@ const MyDash = new Lang.Class({ || (this._position == St.Side.TOP && event_y <= 1) || (this._position == St.Side.BOTTOM && event_y >= actor_h - 2)) return Clutter.EVENT_PROPAGATE; - + // reset timeout to avid conflicts with the mousehover event - if (this._ensureAppIconVisibilityTimeoutId>0) { + if (this._ensureAppIconVisibilityTimeoutId > 0) { Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId); this._ensureAppIconVisibilityTimeoutId = 0; } @@ -460,7 +369,7 @@ const MyDash = new Lang.Class({ let increment = adjustment.step_increment; - switch ( event.get_scroll_direction() ) { + switch (event.get_scroll_direction()) { case Clutter.ScrollDirection.UP: delta = -increment; break; @@ -469,18 +378,16 @@ const MyDash = new Lang.Class({ break; case Clutter.ScrollDirection.SMOOTH: let [dx, dy] = event.get_scroll_delta(); - delta = dy*increment; + delta = dy * increment; // Also consider horizontal component, for instance touchpad if (this._isHorizontal) - delta += dx*increment; + delta += dx * increment; break; - } adjustment.set_value(adjustment.get_value() + delta); return Clutter.EVENT_STOP; - }, _onDragBegin: function() { @@ -521,8 +428,7 @@ const MyDash = new Lang.Class({ if (app == null) return DND.DragMotionResult.CONTINUE; - let showAppsHovered = - this._showAppsIcon.contains(dragEvent.targetActor); + let showAppsHovered = this._showAppsIcon.contains(dragEvent.targetActor); if (!this._box.contains(dragEvent.targetActor) || showAppsHovered) this._clearDragPlaceholder(); @@ -542,7 +448,7 @@ const MyDash = new Lang.Class({ return ids; }, - _queueRedisplay: function () { + _queueRedisplay: function() { Main.queueDeferredWork(this._workId); }, @@ -571,27 +477,23 @@ const MyDash = new Lang.Class({ { setSizeManually: true, showLabel: false }); if (appIcon._draggable) { - appIcon._draggable.connect('drag-begin', - Lang.bind(this, function() { - appIcon.actor.opacity = 50; - })); - appIcon._draggable.connect('drag-end', - Lang.bind(this, function() { - appIcon.actor.opacity = 255; - })); + appIcon._draggable.connect('drag-begin', Lang.bind(this, function() { + appIcon.actor.opacity = 50; + })); + appIcon._draggable.connect('drag-end', Lang.bind(this, function() { + appIcon.actor.opacity = 255; + })); } - appIcon.connect('menu-state-changed', - Lang.bind(this, function(appIcon, opened) { - this._itemMenuStateChanged(item, opened); - })); + appIcon.connect('menu-state-changed', Lang.bind(this, function(appIcon, opened) { + this._itemMenuStateChanged(item, opened); + })); let item = new Dash.DashItemContainer(); extendDashItemContainer(item, this._dtdSettings); item.setChild(appIcon.actor); - item.setChild(appIcon.actor); appIcon.actor.connect('notify::hover', Lang.bind(this, function() { if (appIcon.actor.hover) { @@ -600,30 +502,28 @@ const MyDash = new Lang.Class({ this._ensureAppIconVisibilityTimeoutId = 0; return GLib.SOURCE_REMOVE; })); - } else { - if (this._ensureAppIconVisibilityTimeoutId>0) { + } + else { + if (this._ensureAppIconVisibilityTimeoutId > 0) { Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId); this._ensureAppIconVisibilityTimeoutId = 0; } } })); - appIcon.actor.connect('clicked', - Lang.bind(this, function(actor) { - ensureActorVisibleInScrollView(this._scrollView, actor); + appIcon.actor.connect('clicked', Lang.bind(this, function(actor) { + ensureActorVisibleInScrollView(this._scrollView, actor); })); - appIcon.actor.connect('key-focus-in', - Lang.bind(this, function(actor) { - - let [x_shift, y_shift] = ensureActorVisibleInScrollView(this._scrollView, actor); + appIcon.actor.connect('key-focus-in', Lang.bind(this, function(actor) { + let [x_shift, y_shift] = ensureActorVisibleInScrollView(this._scrollView, actor); - // This signal is triggered also by mouse click. The popup menu is opened at the original - // coordinates. Thus correct for the shift which is going to be applied to the scrollview. - if (appIcon._menu) { - appIcon._menu._boxPointer.xOffset = -x_shift; - appIcon._menu._boxPointer.yOffset = -y_shift; - } + // This signal is triggered also by mouse click. The popup menu is opened at the original + // coordinates. Thus correct for the shift which is going to be applied to the scrollview. + if (appIcon._menu) { + appIcon._menu._boxPointer.xOffset = -x_shift; + appIcon._menu._boxPointer.yOffset = -y_shift; + } })); // Override default AppIcon label_actor, now the @@ -636,8 +536,10 @@ const MyDash = new Lang.Class({ return item; }, - - // Return an array with the "proper" appIcons currently in the dash + + /** + * Return an array with the "proper" appIcons currently in the dash + */ _getAppIcons: function() { // Only consider children which are "proper" // icons (i.e. ignoring drag placeholders) and which are not @@ -674,7 +576,8 @@ const MyDash = new Lang.Class({ } item.hideLabel(); - } else { + } + else { // I want to listen from outside when a menu is closed. I used to // add a custom signal to the appIcon, since gnome 3.8 the signal // calling this callback was added upstream. @@ -682,37 +585,36 @@ const MyDash = new Lang.Class({ } }, - _syncLabel: function (item, appIcon) { + _syncLabel: function(item, appIcon) { let shouldShow = appIcon ? appIcon.shouldShowTooltip() : item.child.get_hover(); if (shouldShow) { if (this._showLabelTimeoutId == 0) { let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT; - this._showLabelTimeoutId = Mainloop.timeout_add(timeout, - Lang.bind(this, function() { - this._labelShowing = true; - item.showLabel(); - this._showLabelTimeoutId = 0; - return GLib.SOURCE_REMOVE; - })); + this._showLabelTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, function() { + this._labelShowing = true; + item.showLabel(); + this._showLabelTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel'); if (this._resetHoverTimeoutId > 0) { Mainloop.source_remove(this._resetHoverTimeoutId); this._resetHoverTimeoutId = 0; } } - } else { + } + else { if (this._showLabelTimeoutId > 0) Mainloop.source_remove(this._showLabelTimeoutId); this._showLabelTimeoutId = 0; item.hideLabel(); if (this._labelShowing) { - this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT, - Lang.bind(this, function() { - this._labelShowing = false; - this._resetHoverTimeoutId = 0; - return GLib.SOURCE_REMOVE; - })); + this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT, Lang.bind(this, function() { + this._labelShowing = false; + this._resetHoverTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); GLib.Source.set_name_by_id(this._resetHoverTimeoutId, '[gnome-shell] this._labelShowing'); } } @@ -736,9 +638,12 @@ const MyDash = new Lang.Class({ return; let themeNode = this._container.get_theme_node(); - let maxAllocation = new Clutter.ActorBox({ x1: 0, y1: 0, - x2: this._isHorizontal?this._maxHeight:42 /* whatever */, - y2: this._isHorizontal?42:this._maxHeight }); + let maxAllocation = new Clutter.ActorBox({ + x1: 0, + y1: 0, + x2: this._isHorizontal ? this._maxHeight : 42 /* whatever */, + y2: this._isHorizontal ? 42 : this._maxHeight + }); let maxContent = themeNode.get_content_box(maxAllocation); let availHeight; if (this._isHorizontal) @@ -763,13 +668,12 @@ const MyDash = new Lang.Class({ }); // Subtract icon padding and box spacing from the available height - if(this._isHorizontal) { + if (this._isHorizontal) availHeight -= iconChildren.length * (natWidth - this.iconSize * scaleFactor) + (iconChildren.length - 1) * spacing; - } else { + else availHeight -= iconChildren.length * (natHeight - this.iconSize * scaleFactor) + (iconChildren.length - 1) * spacing; - } let availSize = availHeight / iconChildren.length; @@ -818,32 +722,32 @@ const MyDash = new Lang.Class({ } }, - _redisplay: function () { + _redisplay: function() { let favorites = AppFavorites.getAppFavorites().getFavoriteMap(); let running = this._appSystem.get_running(); let children = this._box.get_children().filter(function(actor) { - return actor.child && - actor.child._delegate && - actor.child._delegate.app; - }); + return actor.child && + actor.child._delegate && + actor.child._delegate.app; + }); // Apps currently in the dash let oldApps = children.map(function(actor) { - return actor.child._delegate.app; - }); + return actor.child._delegate.app; + }); // Apps supposed to be in the dash let newApps = []; - if( this._dtdSettings.get_boolean('show-favorites') ) { + if (this._dtdSettings.get_boolean('show-favorites')) { for (let id in favorites) newApps.push(favorites[id]); } - if( this._dtdSettings.get_boolean('show-running') ) { + if (this._dtdSettings.get_boolean('show-running')) { for (let i = 0; i < running.length; i++) { let app = running[i]; - if (this._dtdSettings.get_boolean('show-favorites') && (app.get_id() in favorites) ) + if (this._dtdSettings.get_boolean('show-favorites') && (app.get_id() in favorites)) continue; newApps.push(app); } @@ -865,12 +769,13 @@ const MyDash = new Lang.Class({ // If above assumptions turns out to be a problem, we might need // to use a more sophisticated algorithm, e.g. Longest Common // Subsequence as used by diff. + let addedItems = []; let removedActors = []; let newIndex = 0; let oldIndex = 0; - while (newIndex < newApps.length || oldIndex < oldApps.length) { + while ((newIndex < newApps.length) || (oldIndex < oldApps.length)) { // No change at oldIndex/newIndex if (oldApps[oldIndex] == newApps[newIndex]) { oldIndex++; @@ -879,27 +784,24 @@ const MyDash = new Lang.Class({ } // App removed at oldIndex - if (oldApps[oldIndex] && - newApps.indexOf(oldApps[oldIndex]) == -1) { + if (oldApps[oldIndex] && (newApps.indexOf(oldApps[oldIndex]) == -1)) { removedActors.push(children[oldIndex]); oldIndex++; continue; } // App added at newIndex - if (newApps[newIndex] && - oldApps.indexOf(newApps[newIndex]) == -1) { + if (newApps[newIndex] && (oldApps.indexOf(newApps[newIndex]) == -1)) { let newItem = this._createAppItem(newApps[newIndex]); - addedItems.push({ app: newApps[newIndex], - item: newItem, - pos: newIndex }); - newIndex++; + addedItems.push({ app: newApps[newIndex], + item: newItem, + pos: newIndex }); + newIndex++; continue; } // App moved - let insertHere = newApps[newIndex + 1] && - newApps[newIndex + 1] == oldApps[oldIndex]; + let insertHere = newApps[newIndex + 1] && (newApps[newIndex + 1] == oldApps[oldIndex]); let alreadyRemoved = removedActors.reduce(function(result, actor) { let removedApp = actor.child._delegate.app; return result || removedApp == newApps[newIndex]; @@ -907,16 +809,19 @@ const MyDash = new Lang.Class({ if (insertHere || alreadyRemoved) { let newItem = this._createAppItem(newApps[newIndex]); - addedItems.push({ app: newApps[newIndex], - item: newItem, - pos: newIndex + removedActors.length }); - newIndex++; - } else { + addedItems.push({ + app: newApps[newIndex], + item: newItem, + pos: newIndex + removedActors.length + }); + newIndex++; + } + else { removedActors.push(children[oldIndex]); oldIndex++; } } - + for (let i = 0; i < addedItems.length; i++) this._box.insert_child_at_index(addedItems[i].item, addedItems[i].pos); @@ -933,10 +838,9 @@ const MyDash = new Lang.Class({ this._adjustIconSize(); - for (let i = 0; i < addedItems.length; i++) { + for (let i = 0; i < addedItems.length; i++) // Emit a custom signal notifying that a new item has been added this.emit('item-added', addedItems[i]); - } // Skip animations on first run when adding the initial set // of items, to avoid all items zooming in at once @@ -947,9 +851,8 @@ const MyDash = new Lang.Class({ if (!this._shownInitially) this._shownInitially = true; - for (let i = 0; i < addedItems.length; i++) { + for (let i = 0; i < addedItems.length; i++) addedItems[i].item.show(animate); - } // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744 // Without it, StBoxLayout may use a stale size cache @@ -959,19 +862,16 @@ const MyDash = new Lang.Class({ this._updateAppIcons(); }, - setIconSize: function (max_size, doNotAnimate) { - + setIconSize: function(max_size, doNotAnimate) { let max_allowed = baseIconSizes[baseIconSizes.length-1]; max_size = Math.min(max_size, max_allowed); - if (this._dtdSettings.get_boolean('icon-size-fixed')) { - this._availableIconSizes = [ max_size ]; - } else { - this._availableIconSizes = baseIconSizes.filter( - function(val) { - return (val numChildren) pos = numChildren; - } else + } + else pos = 0; // always insert at the top when dash is empty - /* Take into account childredn position in rtl*/ - if (this._isHorizontal && - Clutter.get_default_text_direction() == Clutter.TextDirection.RTL - ) + // Take into account childredn position in rtl + if (this._isHorizontal && (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)) pos = numChildren - pos; - if (pos != this._dragPlaceholderPos && pos <= numFavorites && this._animatingPlaceholdersCount == 0) { + if ((pos != this._dragPlaceholderPos) && (pos <= numFavorites) && (this._animatingPlaceholdersCount == 0)) { this._dragPlaceholderPos = pos; // Don't allow positioning before or after self - if (favPos != -1 && (pos == favPos || pos == favPos + 1)) { + if ((favPos != -1) && (pos == favPos || pos == favPos + 1)) { this._clearDragPlaceholder(); return DND.DragMotionResult.CONTINUE; } @@ -1083,9 +979,9 @@ const MyDash = new Lang.Class({ if (this._dragPlaceholder) { this._dragPlaceholder.destroy(); fadeIn = false; - } else { - fadeIn = true; } + else + fadeIn = true; this._dragPlaceholder = new Dash.DragPlaceholderItem(); this._dragPlaceholder.child.set_width (this.iconSize); @@ -1117,15 +1013,15 @@ const MyDash = new Lang.Class({ return DND.DragMotionResult.COPY_DROP; }, - // Draggable target interface - acceptDrop : function(source, actor, x, y, time) { - + /** + * Draggable target interface + */ + acceptDrop: function(source, actor, x, y, time) { let app = Dash.getAppFromSource(source); // Don't allow favoriting of transient apps - if (app == null || app.is_window_backed()) { + if (app == null || app.is_window_backed()) return false; - } if (!this._settings.is_writable('favorite-apps') || !this._dtdSettings.get_boolean('show-favorites')) return false; @@ -1139,8 +1035,7 @@ const MyDash = new Lang.Class({ let favPos = 0; let children = this._box.get_children(); for (let i = 0; i < this._dragPlaceholderPos; i++) { - if (this._dragPlaceholder && - children[i] == this._dragPlaceholder) + if (this._dragPlaceholder && (children[i] == this._dragPlaceholder)) continue; let childId = children[i].child._delegate.app.get_id(); @@ -1155,15 +1050,14 @@ const MyDash = new Lang.Class({ if (!this._dragPlaceholder) return true; - Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, - function () { - let appFavorites = AppFavorites.getAppFavorites(); - if (srcIsFavorite) - appFavorites.moveFavoriteToPos(id, favPos); - else - appFavorites.addFavoriteAtPos(id, favPos); - return false; - })); + Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { + let appFavorites = AppFavorites.getAppFavorites(); + if (srcIsFavorite) + appFavorites.moveFavoriteToPos(id, favPos); + else + appFavorites.addFavoriteAtPos(id, favPos); + return false; + })); return true; }, @@ -1183,14 +1077,13 @@ const MyDash = new Lang.Class({ Signals.addSignalMethods(MyDash.prototype); -/* +/** * This is a copy of the same function in utils.js, but also adjust horizontal scrolling * and perform few further cheks on the current value to avoid changing the values when * it would be clamp to the current one in any case. * Return the amount of shift applied -*/ + */ function ensureActorVisibleInScrollView(scrollView, actor) { - let adjust_v = true; let adjust_h = true; @@ -1203,7 +1096,7 @@ function ensureActorVisibleInScrollView(scrollView, actor) { let voffset = 0; let hoffset = 0; - let fade = scrollView.get_effect("fade"); + let fade = scrollView.get_effect('fade'); if (fade) { voffset = fade.vfade_offset; hoffset = fade.hfade_offset; @@ -1215,7 +1108,7 @@ function ensureActorVisibleInScrollView(scrollView, actor) { let parent = actor.get_parent(); while (parent != scrollView) { if (!parent) - throw new Error("actor not in scroll view"); + throw new Error('Actor not in scroll view'); let box = parent.get_allocation_box(); y1 += box.y1; @@ -1236,10 +1129,10 @@ function ensureActorVisibleInScrollView(scrollView, actor) { hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize); if (vvalue !== vvalue0) { - Tweener.addTween(vadjustment, - { value: vvalue, - time: Util.SCROLL_TIME, - transition: 'easeOutQuad' }); + Tweener.addTween(vadjustment, { value: vvalue, + time: Util.SCROLL_TIME, + transition: 'easeOutQuad' + }); } if (hvalue !== hvalue0) { @@ -1251,80 +1144,3 @@ function ensureActorVisibleInScrollView(scrollView, actor) { return [hvalue- hvalue0, vvalue - vvalue0]; } - -// This function is used for both extendShowAppsIcon and extendDashItemContainer -function itemShowLabel() { - if (!this._labelText) { - return; - } - - this.label.set_text(this._labelText); - this.label.opacity = 0; - this.label.show(); - - let [stageX, stageY] = this.get_transformed_position(); - let node = this.label.get_theme_node(); - - let itemWidth = this.allocation.x2 - this.allocation.x1; - let itemHeight = this.allocation.y2 - this.allocation.y1; - - - let labelWidth = this.label.get_width(); - let labelHeight = this.label.get_height(); - - let x, y, xOffset, yOffset; - - let position = Convenience.getPosition(this._dtdSettings); - this._isHorizontal = ( position == St.Side.TOP || - position == St.Side.BOTTOM); - let labelOffset = node.get_length('-x-offset'); - - switch(position) { - case St.Side.LEFT: - yOffset = Math.floor((itemHeight - labelHeight) / 2); - y = stageY + yOffset; - xOffset = labelOffset; - x = stageX + this.get_width() + xOffset; - break; - case St.Side.RIGHT: - yOffset = Math.floor((itemHeight - labelHeight) / 2); - y = stageY + yOffset; - xOffset = labelOffset; - x = Math.round(stageX) - labelWidth - xOffset; - break; - case St.Side.TOP: - y = stageY + labelOffset + itemHeight; - xOffset = Math.floor((itemWidth - labelWidth) / 2); - x = stageX + xOffset; - break; - case St.Side.BOTTOM: - yOffset = labelOffset; - y = stageY - labelHeight - yOffset; - xOffset = Math.floor((itemWidth - labelWidth) / 2); - x = stageX + xOffset; - break; - } - - // keep the label inside the screen border - // Only needed fot the x coordinate. - - // Leave a few pixel gap - let gap = 5; - let monitor = Main.layoutManager.findMonitorForActor(this); - if ( x - monitor.x monitor.x + monitor.width - gap) - x-= x + labelWidth -( monitor.x + monitor.width) + gap; - - this.label.set_position(x, y); - Tweener.addTween(this.label, - { opacity: 255, - time: DASH_ITEM_LABEL_SHOW_TIME, - transition: 'easeOutQuad', - }); -} - -function extendDashItemContainer(dashItemContainer, settings) { - dashItemContainer._dtdSettings = settings; - dashItemContainer.showLabel = itemShowLabel; -} diff --git a/docking.js b/docking.js index fb95874da..a72faf42a 100644 --- a/docking.js +++ b/docking.js @@ -29,7 +29,7 @@ const Intellihide = Me.imports.intellihide; const Theming = Me.imports.theming; const MyDash = Me.imports.dash; -const DOCK_DWELL_CHECK_INTERVAL = 100; //TODO +const DOCK_DWELL_CHECK_INTERVAL = 100; // TODO const State = { HIDDEN: 0, @@ -38,7 +38,7 @@ const State = { HIDING: 3 }; -/* +/** * A simple St.Widget with one child whose allocation takes into account the * slide out of its child via the _slidex parameter ([0:1]). * @@ -54,13 +54,11 @@ const State = { * It can't be an extended object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. * thus use the Shell.GenericContainer pattern. */ - const DashSlideContainer = new Lang.Class({ Name: 'DashToDock.DashSlideContainer', _init: function(params) { - - /* Default local params */ + // Default local params let localDefaults = { side: St.Side.LEFT, initialSlideValue: 1 @@ -69,8 +67,8 @@ const DashSlideContainer = new Lang.Class({ let localParams = Params.parse(params, localDefaults, true); if (params) { - /* Remove local params before passing the params to the parent - constructor to avoid errors. */ + // Remove local params before passing the params to the parent + // constructor to avoid errors. let prop; for (prop in localDefaults) { if ((prop in params)) @@ -94,7 +92,6 @@ const DashSlideContainer = new Lang.Class({ }, _allocate: function(actor, box, flags) { - if (this._child == null) return; @@ -111,62 +108,64 @@ const DashSlideContainer = new Lang.Class({ let slideoutSize = this._slideoutSize; if (this._side == St.Side.LEFT) { - childBox.x1 = (this._slidex -1)*(childWidth - slideoutSize); + childBox.x1 = (this._slidex -1) * (childWidth - slideoutSize); childBox.x2 = slideoutSize + this._slidex*(childWidth - slideoutSize); childBox.y1 = 0; childBox.y2 = childBox.y1 + childHeight; - } else if (this._side == St.Side.RIGHT - || this._side == St.Side.BOTTOM) { + } + else if ((this._side == St.Side.RIGHT) || (this._side == St.Side.BOTTOM)) { childBox.x1 = 0; childBox.x2 = childWidth; childBox.y1 = 0; childBox.y2 = childBox.y1 + childHeight; - } else if (this._side == St.Side.TOP) { + } + else if (this._side == St.Side.TOP) { childBox.x1 = 0; childBox.x2 = childWidth; - childBox.y1 = (this._slidex -1)*(childHeight - slideoutSize); - childBox.y2 = slideoutSize + this._slidex*(childHeight - slideoutSize); + childBox.y1 = (this._slidex -1) * (childHeight - slideoutSize); + childBox.y2 = slideoutSize + this._slidex * (childHeight - slideoutSize); } this._child.allocate(childBox, flags); this._child.set_clip(-childBox.x1, -childBox.y1, - -childBox.x1+availWidth,-childBox.y1 + availHeight); + -childBox.x1+availWidth, -childBox.y1 + availHeight); }, - /* Just the child width but taking into account the slided out part */ + /** + * Just the child width but taking into account the slided out part + */ _getPreferredWidth: function(actor, forHeight, alloc) { - let [minWidth, natWidth ] = this._child.get_preferred_width(forHeight); - if (this._side == St.Side.LEFT - || this._side == St.Side.RIGHT) { - minWidth = (minWidth - this._slideoutSize)*this._slidex + this._slideoutSize; - natWidth = (natWidth - this._slideoutSize)*this._slidex + this._slideoutSize; + let [minWidth, natWidth] = this._child.get_preferred_width(forHeight); + if ((this._side == St.Side.LEFT) || (this._side == St.Side.RIGHT)) { + minWidth = (minWidth - this._slideoutSize) * this._slidex + this._slideoutSize; + natWidth = (natWidth - this._slideoutSize) * this._slidex + this._slideoutSize; } alloc.min_size = minWidth; alloc.natural_size = natWidth; }, - /* Just the child height but taking into account the slided out part */ + /** + * Just the child height but taking into account the slided out part + */ _getPreferredHeight: function(actor, forWidth, alloc) { let [minHeight, natHeight] = this._child.get_preferred_height(forWidth); - if (this._side == St.Side.TOP - || this._side == St.Side.BOTTOM) { - minHeight = (minHeight - this._slideoutSize)*this._slidex + this._slideoutSize; - natHeight = (natHeight - this._slideoutSize)*this._slidex + this._slideoutSize; + if ((this._side == St.Side.TOP) || (this._side == St.Side.BOTTOM)) { + minHeight = (minHeight - this._slideoutSize) * this._slidex + this._slideoutSize; + natHeight = (natHeight - this._slideoutSize) * this._slidex + this._slideoutSize; } alloc.min_size = minHeight; alloc.natural_size = natHeight; }, - /* I was expecting it to be a virtual function... stil I don't understand - how things work. - */ + /** + * I was expecting it to be a virtual function... stil I don't understand + * how things work. + */ add_child: function(actor) { - - /* I'm supposed to have only on child */ - if(this._child !== null) { + // I'm supposed to have only on child + if (this._child !== null) this.actor.remove_child(actor); - } this._child = actor; this.actor.add_child(actor); @@ -184,18 +183,16 @@ const DashSlideContainer = new Lang.Class({ const DockedDash = new Lang.Class({ Name: 'DashToDock.DockedDash', - - _init: function(settings) { - this._rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; + _init: function(settings) { + this._rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL); // Load settings this._settings = settings; this._bindSettingsChanges(); this._position = Convenience.getPosition(settings); - this._isHorizontal = ( this._position == St.Side.TOP || - this._position == St.Side.BOTTOM ); + this._isHorizontal = ((this._position == St.Side.TOP) || (this._position == St.Side.BOTTOM)); // Temporary ignore hover events linked to autohide for whatever reason this._ignoreHover = false; @@ -253,109 +250,107 @@ const DockedDash = new Lang.Class({ let positionStyleClass = ['top', 'right', 'bottom', 'left']; // This is the centering actor - this.actor = new St.Bin({ name: 'dashtodockContainer',reactive: false, - style_class:positionStyleClass[this._position], + this.actor = new St.Bin({ + name: 'dashtodockContainer', + reactive: false, + style_class: positionStyleClass[this._position], x_align: this._isHorizontal?St.Align.MIDDLE:St.Align.START, - y_align: this._isHorizontal?St.Align.START:St.Align.MIDDLE}); + y_align: this._isHorizontal?St.Align.START:St.Align.MIDDLE + }); this.actor._delegate = this; // This is the sliding actor whose allocation is to be tracked for input regions - this._slider = new DashSlideContainer({side: this._position, initialSlideValue: 0}); + this._slider = new DashSlideContainer({ + side: this._position, + initialSlideValue: 0 + }); // This is the actor whose hover status us tracked for autohide - this._box = new St.BoxLayout({ name: 'dashtodockBox', reactive: true, track_hover:true } ); - this._box.connect("notify::hover", Lang.bind(this, this._hoverChanged)); + this._box = new St.BoxLayout({ + name: 'dashtodockBox', + reactive: true, + track_hover: true + }); + this._box.connect('notify::hover', Lang.bind(this, this._hoverChanged)); // Create and apply height constraint to the dash. It's controlled by this.actor height - this.constrainSize = new Clutter.BindConstraint({ source: this.actor, - coordinate: this._isHorizontal?Clutter.BindCoordinate.WIDTH:Clutter.BindCoordinate.HEIGHT }); + this.constrainSize = new Clutter.BindConstraint({ + source: this.actor, + coordinate: this._isHorizontal?Clutter.BindCoordinate.WIDTH:Clutter.BindCoordinate.HEIGHT + }); this.dash.actor.add_constraint(this.constrainSize); // Connect global signals this._signalsHandler = new Convenience.GlobalSignalsHandler(); - this._signalsHandler.add( - [ - Main.overview, - 'item-drag-begin', - Lang.bind(this, this._onDragStart) - ], - [ - Main.overview, - 'item-drag-end', - Lang.bind(this, this._onDragEnd) - ], - [ - Main.overview, - 'item-drag-cancelled', - Lang.bind(this, this._onDragEnd) - ], + this._signalsHandler.add([ + Main.overview, + 'item-drag-begin', + Lang.bind(this, this._onDragStart) + ], [ + Main.overview, + 'item-drag-end', + Lang.bind(this, this._onDragEnd) + ], [ + Main.overview, + 'item-drag-cancelled', + Lang.bind(this, this._onDragEnd) + ], [ // update when monitor changes, for instance in multimonitor when monitor are attached - [ - global.screen, - 'monitors-changed', - Lang.bind(this, this._resetPosition ) - ], + global.screen, + 'monitors-changed', + Lang.bind(this, this._resetPosition ) + ], [ // update when workarea changes, for instance if other extensions modify the struts //(like moving th panel at the bottom) - [ - global.screen, - 'workareas-changed', - Lang.bind(this, this._resetPosition) - ], - [ - Main.overview, - 'showing', - Lang.bind(this, this._onOverviewShowing) - ], - [ - Main.overview, - 'hiding', - Lang.bind(this, this._onOverviewHiding) - ], + global.screen, + 'workareas-changed', + Lang.bind(this, this._resetPosition) + ], [ + Main.overview, + 'showing', + Lang.bind(this, this._onOverviewShowing) + ], [ + Main.overview, + 'hiding', + Lang.bind(this, this._onOverviewHiding) + ], [ // Hide on appview - [ - Main.overview.viewSelector, - 'page-changed', - Lang.bind(this, this._pageChanged) - ], - [ - Main.overview.viewSelector, - 'page-empty', - Lang.bind(this, this._onPageEmpty) - ], + Main.overview.viewSelector, + 'page-changed', + Lang.bind(this, this._pageChanged) + ], [ + Main.overview.viewSelector, + 'page-empty', + Lang.bind(this, this._onPageEmpty) + ], [ // Ensure the ShowAppsButton status is kept in sync - [ - Main.overview.viewSelector._showAppsButton, - 'notify::checked', - Lang.bind(this, this._syncShowAppsButtonToggled) - ], + Main.overview.viewSelector._showAppsButton, + 'notify::checked', + Lang.bind(this, this._syncShowAppsButtonToggled) + ], [ // Monitor windows overlapping - [ - this._intellihide, - 'status-changed', - Lang.bind(this, this._updateDashVisibility) - ], + this._intellihide, + 'status-changed', + Lang.bind(this, this._updateDashVisibility) + ], [ // Keep dragged icon consistent in size with this dash - [ - this.dash, - 'icon-size-changed', - Lang.bind(this, function() { - Main.overview.dashIconSize = this.dash.iconSize; - }) - ], + this.dash, + 'icon-size-changed', + Lang.bind(this, function() { + Main.overview.dashIconSize = this.dash.iconSize; + }) + ], [ // This duplicate the similar signal which is in owerview.js. // Being connected and thus executed later this effectively // overwrite any attempt to use the size of the default dash //which given the customization is usually much smaller. // I can't easily disconnect the original signal - [ - Main.overview._controls.dash, - 'icon-size-changed', - Lang.bind(this, function() { - Main.overview.dashIconSize = this.dash.iconSize; - }) - ] - ); + Main.overview._controls.dash, + 'icon-size-changed', + Lang.bind(this, function() { + Main.overview.dashIconSize = this.dash.iconSize; + }) + ]); this._injectionsHandler = new Convenience.InjectionsHandler(); this._themeManager = new Theming.ThemeManager(this._settings, this.actor, this.dash); @@ -367,14 +362,16 @@ const DockedDash = new Lang.Class({ Lang.bind(Main.layoutManager, Main.layoutManager._queueUpdateRegions)); this.dash._container.connect('allocation-changed', Lang.bind(this, this._updateStaticBox)); - this._slider.actor.connect(this._isHorizontal?'notify::x':'notify::y', Lang.bind(this, this._updateStaticBox)); + this._slider.actor.connect(this._isHorizontal ? 'notify::x' : 'notify::y', Lang.bind(this, this._updateStaticBox)); // sync hover after a popupmenu is closed - this.dash.connect('menu-closed', Lang.bind(this, function() {this._box.sync_hover();})); + this.dash.connect('menu-closed', Lang.bind(this, function() { + this._box.sync_hover(); + })); // Restore dash accessibility Main.ctrlAltTabManager.addGroup( - this.dash.actor, _("Dash"),'user-bookmarks-symbolic', + this.dash.actor, _('Dash'), 'user-bookmarks-symbolic', {focusCallback: Lang.bind(this, this._onAccessibilityFocus)}); // Load optional features @@ -383,7 +380,7 @@ const DockedDash = new Lang.Class({ // Delay operations that require the shell to be fully loaded and with // user theme applied. - this._paintId = this.actor.connect("paint", Lang.bind(this, this._initialize)); + this._paintId = this.actor.connect('paint', Lang.bind(this, this._initialize)); // Hide usual Dash Main.overview._controls.dash.actor.hide(); @@ -402,14 +399,14 @@ const DockedDash = new Lang.Class({ this._dashSpacer = new OverviewControls.DashSpacer(); this._dashSpacer.setDashActor(this._box); - if (this._position == St.Side.LEFT) - Main.overview._controls._group.insert_child_at_index(this._dashSpacer, this._rtl?-1:0); // insert on first + if (this._position == St.Side.LEFT) + Main.overview._controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? -1 : 0); // insert on first else if (this._position == St.Side.RIGHT) - Main.overview._controls._group.insert_child_at_index(this._dashSpacer, this._rtl?0:-1); // insert on last - else if (this._position == St.Side.TOP) + Main.overview._controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? 0 : -1); // insert on last + else if (this._position == St.Side.TOP) Main.overview._overview.insert_child_at_index(this._dashSpacer, 0); - else if (this._position == St.Side.BOTTOM) - Main.overview._overview.insert_child_at_index(this._dashSpacer, -1); + else if (this._position == St.Side.BOTTOM) + Main.overview._overview.insert_child_at_index(this._dashSpacer, -1); // Add dash container actor and the container to the Chrome. this.actor.set_child(this._slider.actor); @@ -425,21 +422,19 @@ const DockedDash = new Lang.Class({ // Keep the dash below the modalDialogGroup Main.layoutManager.uiGroup.set_child_below_sibling(this.actor,Main.layoutManager.modalDialogGroup); - if ( this._settings.get_boolean('dock-fixed') ) - Main.layoutManager._trackActor(this._box, {affectsStruts: true, trackFullscreen: true}); + if (this._settings.get_boolean('dock-fixed')) + Main.layoutManager._trackActor(this._box, {affectsStruts: true, trackFullscreen: true}); // pretend this._slider is isToplevel child so that fullscreen is actually tracked let index = Main.layoutManager._findActor(this._slider.actor); - Main.layoutManager._trackedActors[index].isToplevel = true ; + Main.layoutManager._trackedActors[index].isToplevel = true; // Set initial position this._resetPosition(); - }, _initialize: function() { - - if(this._paintId>0) { + if (this._paintId > 0) { this.actor.disconnect(this._paintId); this._paintId=0; } @@ -451,8 +446,8 @@ const DockedDash = new Lang.Class({ // Since Gnome 3.8 dragging an app without having opened the overview before cause the attemp to //animate a null target since some variables are not initialized when the viewSelector is created - if(Main.overview.viewSelector._activePage == null) - Main.overview.viewSelector._activePage = Main.overview.viewSelector._workspacesPage; + if (Main.overview.viewSelector._activePage == null) + Main.overview.viewSelector._activePage = Main.overview.viewSelector._workspacesPage; this._updateVisibilityMode(); @@ -469,11 +464,9 @@ const DockedDash = new Lang.Class({ // setup dwelling system if pressure barriers are not available this._setupDockDwellIfNeeded(); - }, destroy: function() { - // Disconnect global signals this._signalsHandler.destroy(); // The dash and intellihide have global signals as well internally @@ -494,7 +487,7 @@ const DockedDash = new Lang.Class({ this._removeBarrier(); // Remove pointer watcher - if(this._dockWatch) { + if (this._dockWatch) { PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch); this._dockWatch = null; } @@ -516,7 +509,6 @@ const DockedDash = new Lang.Class({ }, _bindSettingsChanges: function() { - this._settings.connect('changed::scroll-switch-workspace', Lang.bind(this, function() { this._optionalScrollWorkspaceSwitch(this._settings.get_boolean('scroll-switch-workspace')); })); @@ -550,11 +542,10 @@ const DockedDash = new Lang.Class({ this._settings.connect('changed::dock-fixed', Lang.bind(this, function() { - if(this._settings.get_boolean('dock-fixed')) { + if (this._settings.get_boolean('dock-fixed')) Main.layoutManager._trackActor(this._box, {affectsStruts: true, trackFullscreen: true}); - } else { + else Main.layoutManager._untrackActor(this._box); - } this._resetPosition(); @@ -579,7 +570,7 @@ const DockedDash = new Lang.Class({ this._settings.connect('changed::height-fraction', Lang.bind(this,this._resetPosition)); this._settings.connect('changed::require-pressure-to-show', Lang.bind(this,function() { // Remove pointer watcher - if(this._dockWatch) { + if (this._dockWatch) { PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch); this._dockWatch = null; } @@ -593,14 +584,16 @@ const DockedDash = new Lang.Class({ }, - // This is call when visibility settings change + /** + * This is call when visibility settings change + */ _updateVisibilityMode: function() { - if (this._settings.get_boolean('dock-fixed')) { this._fixedIsEnabled = true; this._autohideIsEnabled = false; this._intellihideIsEnabled = false; - } else { + } + else { this._fixedIsEnabled = false; this._autohideIsEnabled = this._settings.get_boolean('autohide') this._intellihideIsEnabled = this._settings.get_boolean('intellihide') @@ -614,7 +607,8 @@ const DockedDash = new Lang.Class({ this._updateDashVisibility(); }, - /* Show/hide dash based on, in order of priority: + /** + * Show/hide dash based on, in order of priority: * overview visibility * fixed mode * intellihide @@ -622,39 +616,38 @@ const DockedDash = new Lang.Class({ * overview visibility */ _updateDashVisibility: function() { - if (Main.overview.visibleTarget) return; - if ( this._fixedIsEnabled ) { + if (this._fixedIsEnabled) { this._removeAnimations(); this._animateIn(this._settings.get_double('animation-time'), 0); - } else if (this._intellihideIsEnabled) { - if ( this._intellihide.getOverlapStatus() ) { + } + else if (this._intellihideIsEnabled) { + if (this._intellihide.getOverlapStatus()) { this._ignoreHover = false; // Do not hide if autohide is enabled and mouse is hover - if (!this._box.hover || !this._autohideIsEnabled) { + if (!this._box.hover || !this._autohideIsEnabled) this._animateOut(this._settings.get_double('animation-time'), 0); - } - } else { + } + else { this._ignoreHover = true; this._removeAnimations(); this._animateIn(this._settings.get_double('animation-time'), 0); } - } else { + } + else { if (this._autohideIsEnabled) { this._ignoreHover = false; global.sync_pointer(); - if( this._box.hover ) { + if (this._box.hover) this._animateIn(this._settings.get_double('animation-time'), 0); - } else { + else this._animateOut(this._settings.get_double('animation-time'), 0); - } - - } else { - this._animateOut(this._settings.get_double('animation-time'), 0); } + else + this._animateOut(this._settings.get_double('animation-time'), 0); } }, @@ -672,96 +665,85 @@ const DockedDash = new Lang.Class({ }, _hoverChanged: function() { - if (!this._ignoreHover) { - // Skip if dock is not in autohide mode for instance because it is shown // by intellihide. - if(this._autohideIsEnabled) { - if( this._box.hover ) { + if (this._autohideIsEnabled) { + if (this._box.hover) this._show(); - } else { + else this._hide(); - } } } }, _show: function() { - - if ( this._dockState == State.HIDDEN || this._dockState == State.HIDING ) { - - if(this._dockState == State.HIDING) { + if ((this._dockState == State.HIDDEN) || (this._dockState == State.HIDING)) { + if (this._dockState == State.HIDING) // suppress all potential queued hiding animations - i.e. added to Tweener but not started, // always give priority to show this._removeAnimations(); - } - this.emit("showing"); + this.emit('showing'); this._animateIn(this._settings.get_double('animation-time'), 0); } }, _hide: function() { - // If no hiding animation is running or queued - if ( this._dockState == State.SHOWN || this._dockState == State.SHOWING ) { - + if ((this._dockState == State.SHOWN) || (this._dockState == State.SHOWING)) { let delay; - if (this._dockState == State.SHOWING) { + if (this._dockState == State.SHOWING) //if a show already started, let it finish; queue hide without removing the show. - // to obtain this I increase the delay to avoid the overlap and interference + // to obtain this I increase the delay to avoid the overlap and interference // between the animations delay = this._settings.get_double('hide-delay') + this._settings.get_double('animation-time'); - } else { + else delay = this._settings.get_double('hide-delay'); - } - this.emit("hiding"); + this.emit('hiding'); this._animateOut(this._settings.get_double('animation-time'), delay); - } }, _animateIn: function(time, delay) { - this._dockState = State.SHOWING; - Tweener.addTween(this._slider,{ + Tweener.addTween(this._slider, { slidex: 1, time: time, delay: delay, transition: 'easeOutQuad', onComplete: Lang.bind(this, function() { - this._dockState = State.SHOWN; - // Remove barrier so that mouse pointer is released and can access monitors on other side of dock - // NOTE: Delay needed to keep mouse from moving past dock and re-hiding dock immediately. This - // gives users an opportunity to hover over the dock - if (this._removeBarrierTimeoutId > 0) { - Mainloop.source_remove(this._removeBarrierTimeoutId); - } - this._removeBarrierTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, this._removeBarrier)); - }) + this._dockState = State.SHOWN; + // Remove barrier so that mouse pointer is released and can access monitors on other side of dock + // NOTE: Delay needed to keep mouse from moving past dock and re-hiding dock immediately. This + // gives users an opportunity to hover over the dock + if (this._removeBarrierTimeoutId > 0) + Mainloop.source_remove(this._removeBarrierTimeoutId); + this._removeBarrierTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, this._removeBarrier)); + }) }); }, _animateOut: function(time, delay) { - this._dockState = State.HIDING; - Tweener.addTween(this._slider,{ + Tweener.addTween(this._slider, { slidex: 0, time: time, delay: delay , transition: 'easeOutQuad', onComplete: Lang.bind(this, function() { - this._dockState = State.HIDDEN; - this._updateBarrier(); + this._dockState = State.HIDDEN; + this._updateBarrier(); }) }); }, - // Dwelling system based on the GNOME Shell 3.14 messageTray code. + /** + * Dwelling system based on the GNOME Shell 3.14 messageTray code. + */ _setupDockDwellIfNeeded: function() { // If we don't have extended barrier features, then we need // to support the old tray dwelling mechanism. @@ -782,15 +764,14 @@ const DockedDash = new Lang.Class({ // Check for the correct screen edge // Position is approximated to the lower integer - if(this._position==St.Side.LEFT) { - shouldDwell = shouldDwell && x == this._monitor.x; - } else if(this._position==St.Side.RIGHT) { - shouldDwell = shouldDwell && x == this._monitor.x + this._monitor.width - 1; - } else if(this._position==St.Side.TOP) { - shouldDwell = shouldDwell && y == this._monitor.y; - } else if (this._position==St.Side.BOTTOM) { - shouldDwell = shouldDwell && y == this._monitor.y + this._monitor.height - 1; - } + if (this._position == St.Side.LEFT) + shouldDwell = shouldDwell && (x == this._monitor.x); + else if (this._position == St.Side.RIGHT) + shouldDwell = shouldDwell && (x == this._monitor.x + this._monitor.width - 1); + else if (this._position == St.Side.TOP) + shouldDwell = shouldDwell && (y == this._monitor.y); + else if (this._position == St.Side.BOTTOM) + shouldDwell = shouldDwell && (y == this._monitor.y + this._monitor.height - 1); if (shouldDwell) { // We only set up dwell timeout when the user is not hovering over the dock @@ -798,17 +779,18 @@ const DockedDash = new Lang.Class({ // The _dockDwelling variable is used so that we only try to // fire off one dock dwell - if it fails (because, say, the user has the mouse down), // we don't try again until the user moves the mouse up and down again. - if (!this._dockDwelling && !this._box.hover && this._dockDwellTimeoutId == 0) { + if (!this._dockDwelling && !this._box.hover && (this._dockDwellTimeoutId == 0)) { // Save the interaction timestamp so we can detect user input let focusWindow = global.display.focus_window; this._dockDwellUserTime = focusWindow ? focusWindow.user_time : 0; - this._dockDwellTimeoutId = Mainloop.timeout_add(this._settings.get_double('show-delay')*1000, + this._dockDwellTimeoutId = Mainloop.timeout_add(this._settings.get_double('show-delay') * 1000, Lang.bind(this, this._dockDwellTimeout)); GLib.Source.set_name_by_id(this._dockDwellTimeoutId, '[dash-to-dock] this._dockDwellTimeout'); } this._dockDwelling = true; - } else { + } + else { this._cancelDockDwell(); this._dockDwelling = false; } @@ -872,30 +854,31 @@ const DockedDash = new Lang.Class({ } }, - // handler for mouse pressure sensed + /** + * handler for mouse pressure sensed + */ _onPressureSensed: function() { - if (Main.overview.visibleTarget) return; // In case the mouse move away from the dock area before hovering it, in such case the leave event // would never be triggered and the dock would stay visible forever. - let triggerTimeoutId = Mainloop.timeout_add(250, - Lang.bind(this, function() { - triggerTimeoutId = 0; - this._hoverChanged(); - return GLib.SOURCE_REMOVE; - })); + let triggerTimeoutId = Mainloop.timeout_add(250, Lang.bind(this, function() { + triggerTimeoutId = 0; + this._hoverChanged(); + return GLib.SOURCE_REMOVE; + })); this._show(); }, - // Remove pressure barrier + /** + * Remove pressure barrier + */ _removeBarrier: function() { if (this._barrier) { - if (this._pressureBarrier) { + if (this._pressureBarrier) this._pressureBarrier.removeBarrier(this._barrier); - } this._barrier.destroy(); this._barrier = null; } @@ -903,7 +886,9 @@ const DockedDash = new Lang.Class({ return false; }, - // Update pressure barrier size + /** + * Update pressure barrier size + */ _updateBarrier: function() { // Remove existing barrier this._removeBarrier(); @@ -920,25 +905,28 @@ const DockedDash = new Lang.Class({ if (this._canUsePressure && this._autohideIsEnabled && this._settings.get_boolean('require-pressure-to-show')) { let x1, x2, y1, y2, direction; - if(this._position==St.Side.LEFT) { + if (this._position == St.Side.LEFT) { x1 = this.staticBox.x1; x2 = this.staticBox.x1; y1 = this.staticBox.y1; y2 = this.staticBox.y2; direction = Meta.BarrierDirection.POSITIVE_X; - } else if(this._position==St.Side.RIGHT) { + } + else if (this._position == St.Side.RIGHT) { x1 = this.staticBox.x2; x2 = this.staticBox.x2; y1 = this.staticBox.y1; y2 = this.staticBox.y2; direction = Meta.BarrierDirection.NEGATIVE_X; - } else if(this._position==St.Side.TOP) { + } + else if (this._position == St.Side.TOP) { x1 = this.staticBox.x1; x2 = this.staticBox.x2; y1 = this.staticBox.y1; y2 = this.staticBox.y1; direction = Meta.BarrierDirection.POSITIVE_Y; - } else if (this._position==St.Side.BOTTOM) { + } + else if (this._position == St.Side.BOTTOM) { x1 = this.staticBox.x1; x2 = this.staticBox.x2; y1 = this.staticBox.y2; @@ -946,31 +934,32 @@ const DockedDash = new Lang.Class({ direction = Meta.BarrierDirection.NEGATIVE_Y; } - this._barrier = new Meta.Barrier({display: global.display, - x1: x1, x2: x2, - y1: y1, y2: y2, - directions: direction}); - if (this._pressureBarrier) { + this._barrier = new Meta.Barrier({ + display: global.display, + x1: x1, + x2: x2, + y1: y1, + y2: y2, + directions: direction + }); + if (this._pressureBarrier) this._pressureBarrier.addBarrier(this._barrier); - } } - }, _isPrimaryMonitor: function() { - return (this._monitor.x == Main.layoutManager.primaryMonitor.x && - this._monitor.y == Main.layoutManager.primaryMonitor.y); + return ((this._monitor.x == Main.layoutManager.primaryMonitor.x) && + (this._monitor.y == Main.layoutManager.primaryMonitor.y)); }, _resetPosition: function() { - // Ensure variables linked to settings are updated. this._updateVisibilityMode(); let monitorIndex = this._settings.get_int('preferred-monitor'); let extendHeight = this._settings.get_boolean('extend-height'); - if (monitorIndex >0 && monitorIndex< Main.layoutManager.monitors.length) + if ((monitorIndex > 0) && (monitorIndex < Main.layoutManager.monitors.length)) this._monitor = Main.layoutManager.monitors[monitorIndex]; else { monitorIndex = Main.layoutManager.primaryIndex @@ -984,68 +973,69 @@ const DockedDash = new Lang.Class({ // Reserve space for the dash on the overview // if the dock is on the primary monitor - if (this._isPrimaryMonitor()) { + if (this._isPrimaryMonitor()) this._dashSpacer.show(); - } else { + else // No space is required in the overview of the dash this._dashSpacer.hide(); - } let fraction = this._settings.get_double('height-fraction'); - if(extendHeight) + if (extendHeight) fraction = 1; - else if(fraction<0 || fraction >1) + else if ((fraction < 0) || (fraction > 1)) fraction = 0.95; let anchor_point; - if(this._isHorizontal) { - + if (this._isHorizontal) { this.actor.width = Math.round( fraction * workArea.width); let pos_y; - if( this._position == St.Side.BOTTOM) { + if (this._position == St.Side.BOTTOM) { pos_y = this._monitor.y + this._monitor.height; anchor_point = Clutter.Gravity.SOUTH_WEST; - } else { + } + else { pos_y = this._monitor.y; anchor_point = Clutter.Gravity.NORTH_WEST; } this.actor.move_anchor_point_from_gravity(anchor_point); - this.actor.x = workArea.x + Math.round( (1-fraction)/2 * workArea.width); + this.actor.x = workArea.x + Math.round((1 - fraction) / 2 * workArea.width); this.actor.y = pos_y; - if(extendHeight) { + if (extendHeight) { this.dash._container.set_width(this.actor.width); this.actor.add_style_class_name('extended'); - } else { + } + else { this.dash._container.set_width(-1); this.actor.remove_style_class_name('extended'); } - - } else { - - this.actor.height = Math.round( fraction * workArea.height); + } + else { + this.actor.height = Math.round(fraction * workArea.height); let pos_x; - if( this._position == St.Side.RIGHT) { + if (this._position == St.Side.RIGHT) { pos_x = this._monitor.x + this._monitor.width; anchor_point = Clutter.Gravity.NORTH_EAST; - } else { + } + else { pos_x = this._monitor.x; anchor_point = Clutter.Gravity.NORTH_WEST; } this.actor.move_anchor_point_from_gravity(anchor_point); this.actor.x = pos_x; - this.actor.y = workArea.y + Math.round( (1-fraction)/2 * workArea.height); + this.actor.y = workArea.y + Math.round((1 - fraction) / 2 * workArea.height); - if(extendHeight) { + if (extendHeight) { this.dash._container.set_height(this.actor.height); this.actor.add_style_class_name('extended'); - } else { + } + else { this.dash._container.set_height(-1); this.actor.remove_style_class_name('extended'); } @@ -1059,35 +1049,34 @@ const DockedDash = new Lang.Class({ }, _adjustLegacyTray: function() { - let use_work_area = true; - if ( this._fixedIsEnabled && !this._settings.get_boolean('extend-height') - && this._isPrimaryMonitor() - && (this._position == St.Side.BOTTOM ||this._position == St.Side.LEFT ) - ) - { + if (this._fixedIsEnabled && !this._settings.get_boolean('extend-height') + && this._isPrimaryMonitor() + && ((this._position == St.Side.BOTTOM) || (this._position == St.Side.LEFT))) use_work_area = false; - } Main.legacyTray.actor.clear_constraints(); - let constraint = new Layout.MonitorConstraint({ primary: true, - work_area: use_work_area}); + let constraint = new Layout.MonitorConstraint({ + primary: true, + work_area: use_work_area + }); Main.legacyTray.actor.add_constraint(constraint); }, _resetLegacyTray: function() { Main.legacyTray.actor.clear_constraints(); - let constraint = new Layout.MonitorConstraint({ primary: true, - work_area: true }); + let constraint = new Layout.MonitorConstraint({ + primary: true, + work_area: true + }); Main.legacyTray.actor.add_constraint(constraint); }, _updateStaticBox: function() { - this.staticBox.init_rect( - this.actor.x + this._slider.actor.x - (this._position==St.Side.RIGHT?this._box.width:0), - this.actor.y + this._slider.actor.y - (this._position==St.Side.BOTTOM?this._box.height:0), + this.actor.x + this._slider.actor.x - (this._position == St.Side.RIGHT ? this._box.width : 0), + this.actor.y + this._slider.actor.y - (this._position == St.Side.BOTTOM ? this._box.height : 0), this._box.width, this._box.height ); @@ -1095,15 +1084,17 @@ const DockedDash = new Lang.Class({ this._intellihide.updateTargetBox(this.staticBox); }, - // Adjust Panel corners + /** + * Adjust Panel corners + */ _adjustPanelCorners: function() { let extendHeight = this._settings.get_boolean('extend-height'); if (!this._isHorizontal && this._isPrimaryMonitor() && extendHeight && this._fixedIsEnabled) { Main.panel._rightCorner.actor.hide(); Main.panel._leftCorner.actor.hide(); - } else { - this._revertPanelCorners(); } + else + this._revertPanelCorners(); }, _revertPanelCorners: function() { @@ -1131,21 +1122,19 @@ const DockedDash = new Lang.Class({ this._ignoreHover = this._oldignoreHover; this._oldignoreHover = null; this._box.sync_hover(); - if(Main.overview._shown) + if (Main.overview._shown) this._pageChanged(); }, _pageChanged: function() { - let activePage = Main.overview.viewSelector.getActivePage(); let dashVisible = (activePage == ViewSelector.ViewPage.WINDOWS || activePage == ViewSelector.ViewPage.APPS); - if(dashVisible) { + if (dashVisible) this._animateIn(this._settings.get_double('animation-time'), 0); - } else { + else this._animateOut(this._settings.get_double('animation-time'), 0); - } }, _onPageEmpty: function() { @@ -1169,14 +1158,15 @@ const DockedDash = new Lang.Class({ this._dashSpacer.visible = (this._isHorizontal || activePage == ViewSelector.ViewPage.WINDOWS); }, - // Show dock and give key focus to it + /** + * Show dock and give key focus to it + */ _onAccessibilityFocus: function() { this._box.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); this._animateIn(this._settings.get_double('animation-time'), 0); }, _onShowAppsButtonToggled: function() { - // Sync the status of the default appButtons. Only if the two statuses are // different, that means the user interacted with the extension provided // application button, cutomize the behaviour. Otherwise the shell has changed the @@ -1186,21 +1176,19 @@ const DockedDash = new Lang.Class({ let animate = this._settings.get_boolean('animate-show-apps'); let selector = Main.overview.viewSelector; - if(selector._showAppsButton.checked !== this.dash.showAppsButton.checked) { - + if (selector._showAppsButton.checked !== this.dash.showAppsButton.checked) { // find visible view let visibleView; Main.overview.viewSelector.appDisplay._views.every(function(v, index) { if (v.view.actor.visible) { visibleView = index; return false; - } else { - return true; } + else + return true; }); - if(this.dash.showAppsButton.checked) { - + if (this.dash.showAppsButton.checked) { // force spring animation triggering.By default the animation only // runs if we are already inside the overview. if (!Main.overview._shown) { @@ -1219,7 +1207,6 @@ const DockedDash = new Lang.Class({ Main.overview.viewSelector._activePage.show(); grid.actor.opacity = 0; - // The animation has to be trigered manually because the AppDisplay.animate // method is waiting for an allocation not happening, as we skip the workspace view // and the appgrid could already be allocated from previous shown. @@ -1231,15 +1218,15 @@ const DockedDash = new Lang.Class({ grid.actor.opacity = 255; grid.animateSpring(IconGrid.AnimationDirection.IN, this.dash.showAppsButton); })); - })); + })); } } // Finally show the overview selector._showAppsButton.checked = true; Main.overview.show(); - - } else { + } + else { if (this.forcedOverview) { // force exiting overview if needed @@ -1255,75 +1242,75 @@ const DockedDash = new Lang.Class({ selector._showAppsButton.checked = false; this.forcedOverview = false; })); - } else { + } + else { Main.overview.hide(); this.forcedOverview = false; } - } else { + } + else { selector._showAppsButton.checked = false; this.forcedOverview = false; } - } } // whenever the button is unactivated even if not by the user still reset the // forcedOverview flag - if( this.dash.showAppsButton.checked==false) + if (this.dash.showAppsButton.checked == false) this.forcedOverview = false; }, - // Keep ShowAppsButton status in sync with the overview status + /** + * Keep ShowAppsButton status in sync with the overview status + */ _syncShowAppsButtonToggled: function() { let status = Main.overview.viewSelector._showAppsButton.checked; - if(this.dash.showAppsButton.checked !== status) + if (this.dash.showAppsButton.checked !== status) this.dash.showAppsButton.checked = status; }, // Optional features enable/disable - // Switch workspace by scrolling over the dock + /** + * Switch workspace by scrolling over the dock + */ _optionalScrollWorkspaceSwitch: function() { - let label = 'optionalScrollWorkspaceSwitch'; - this._settings.connect('changed::scroll-switch-workspace',Lang.bind(this, function() { - if(this._settings.get_boolean('scroll-switch-workspace')) + this._settings.connect('changed::scroll-switch-workspace', Lang.bind(this, function() { + if (this._settings.get_boolean('scroll-switch-workspace')) Lang.bind(this, enable)(); else Lang.bind(this, disable)(); })); - if(this._settings.get_boolean('scroll-switch-workspace')) + if (this._settings.get_boolean('scroll-switch-workspace')) Lang.bind(this, enable)(); function enable() { - this._signalsHandler.removeWithLabel(label); - this._signalsHandler.addWithLabel(label, - [ - this._box, - 'scroll-event', - Lang.bind(this, onScrollEvent) - ] - ); + this._signalsHandler.addWithLabel(label, [ + this._box, + 'scroll-event', + Lang.bind(this, onScrollEvent) + ]); - this._optionalScrollWorkspaceSwitchDeadTimeId=0; + this._optionalScrollWorkspaceSwitchDeadTimeId = 0; } function disable() { this._signalsHandler.removeWithLabel(label); - if(this._optionalScrollWorkspaceSwitchDeadTimeId>0) { + if (this._optionalScrollWorkspaceSwitchDeadTimeId > 0) { Mainloop.source_remove(this._optionalScrollWorkspaceSwitchDeadTimeId); - this._optionalScrollWorkspaceSwitchDeadTimeId=0; + this._optionalScrollWorkspaceSwitchDeadTimeId = 0; } } // This was inspired to desktop-scroller@obsidien.github.com function onScrollEvent(actor, event) { - // When in overview change workscape only in windows view if (Main.overview.visible && Main.overview.viewSelector.getActivePage() !== ViewSelector.ViewPage.WINDOWS) return false; @@ -1331,7 +1318,7 @@ const DockedDash = new Lang.Class({ let activeWs = global.screen.get_active_workspace(); let direction = null; - switch ( event.get_scroll_direction() ) { + switch (event.get_scroll_direction()) { case Clutter.ScrollDirection.UP: direction = Meta.MotionDirection.UP; break; @@ -1340,32 +1327,25 @@ const DockedDash = new Lang.Class({ break; case Clutter.ScrollDirection.SMOOTH: let [dx, dy] = event.get_scroll_delta(); - if(dy < 0) { + if (dy < 0) direction = Meta.MotionDirection.UP; - } else if(dy > 0) { + else if (dy > 0) direction = Meta.MotionDirection.DOWN; - } break; } - if(direction !==null ) { - + if (direction !== null) { // Prevent scroll events from triggering too many workspace switches // by adding a 250ms deadtime between each scroll event. // Usefull on laptops when using a touchpad. // During the deadtime do nothing - if(this._optionalScrollWorkspaceSwitchDeadTimeId>0) + if (this._optionalScrollWorkspaceSwitchDeadTimeId > 0) return false; - else { - this._optionalScrollWorkspaceSwitchDeadTimeId = - Mainloop.timeout_add(250, - Lang.bind(this, function() { - this._optionalScrollWorkspaceSwitchDeadTimeId=0; - } - )); - } - + else + this._optionalScrollWorkspaceSwitchDeadTimeId = Mainloop.timeout_add(250, Lang.bind(this, function() { + this._optionalScrollWorkspaceSwitchDeadTimeId = 0; + })); let ws; @@ -1382,17 +1362,15 @@ const DockedDash = new Lang.Class({ }); // Do not show wokspaceSwithcer in overview - if(!Main.overview.visible) - Main.wm._workspaceSwitcherPopup.display(direction, ws.index()); + if (!Main.overview.visible) + Main.wm._workspaceSwitcherPopup.display(direction, ws.index()); Main.wm.actionMoveWorkspace(ws); return true; - - } else { - return false; } + else + return false; } - } }); diff --git a/extension.js b/extension.js index 900a02c0a..34498a9f8 100644 --- a/extension.js +++ b/extension.js @@ -8,20 +8,17 @@ const Main = imports.ui.main; let settings; let dock; - let oldDash; function init() { } function enable() { - settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-dock'); dock = new Docking.DockedDash(settings); - /* Pretend I'm the dash: meant to make appgrd swarm animation come from the - * right position of the appShowButton. - */ + // Pretend I'm the dash: meant to make appgrd swarm animation come from the + // right position of the appShowButton. oldDash = Main.overview._dash; Main.overview._dash = dock.dash; bindSettingsChanges(); @@ -41,9 +38,8 @@ function disable() { function bindSettingsChanges() { // This settings change require a full reload. - /* It's easier to just reload the extension when the dock position changes - * rather than working out all changes to the differen containers. - */ + // It's easier to just reload the extension when the dock position changes + // rather than working out all changes to the differen containers. settings.connect('changed::dock-position', function() { disable(); enable(); diff --git a/icons.js b/icons.js index b6677cb5d..f037852dc 100644 --- a/icons.js +++ b/icons.js @@ -26,22 +26,10 @@ const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; const Windows = Me.imports.windows; -/** - * Extend AppIcon - * - * - Pass settings to the constructor and bind settings changes - * - Apply a css class based on the number of windows of each application (#N); - * - Draw a dot for each window of the application based on the default "dot" style which is hidden (#N); - * a class of the form "running#N" is applied to the AppWellIcon actor. - * like the original .running one. - * - add a .focused style to the focused app - * - Customize click actions. - * - Update minimization animation target - * - */ - let tracker = Shell.WindowTracker.get_default(); +let DASH_ITEM_LABEL_SHOW_TIME = Dash.DASH_ITEM_LABEL_SHOW_TIME; + const clickAction = { SKIP: 0, MINIMIZE: 1, @@ -54,13 +42,24 @@ let recentlyClickedApp = null; let recentlyClickedAppWindows = null; let recentlyClickedAppIndex = 0; +/** + * Extend AppIcon + * + * - Pass settings to the constructor and bind settings changes + * - Apply a css class based on the number of windows of each application (#N); + * - Draw a dot for each window of the application based on the default "dot" style which is hidden (#N); + * a class of the form "running#N" is applied to the AppWellIcon actor. + * like the original .running one. + * - Add a .focused style to the focused app + * - Customize click actions. + * - Update minimization animation target + */ const MyAppIcon = new Lang.Class({ Name: 'DashToDock.AppIcon', Extends: AppDisplay.AppIcon, // settings are required inside. _init: function(settings, app, iconParams, onActivateOverride) { - this._dtdSettings = settings; this._nWindows = 0; @@ -68,9 +67,9 @@ const MyAppIcon = new Lang.Class({ // Monitor windows-changes instead of app state. // Keep using the same Id and function callback (that is extended) - if(this._stateChangedId>0) { + if (this._stateChangedId > 0) { this.app.disconnect(this._stateChangedId); - this._stateChangedId=0; + this._stateChangedId = 0; } this._stateChangedId = this.app.connect('windows-changed', @@ -83,17 +82,15 @@ const MyAppIcon = new Lang.Class({ this._dots = null; let keys = ['apply-custom-theme', - 'custom-theme-running-dots', + 'custom-theme-running-dots', 'custom-theme-customize-running-dots', 'custom-theme-running-dots-color', 'custom-theme-running-dots-border-color', 'custom-theme-running-dots-border-width']; keys.forEach(function(key) { - this._dtdSettings.connect('changed::'+key, - Lang.bind(this, this._toggleDots) - ); - }, this ); + this._dtdSettings.connect('changed::' + key, Lang.bind(this, this._toggleDots)); + }, this); this._toggleDots(); }, @@ -103,19 +100,19 @@ const MyAppIcon = new Lang.Class({ // Disconect global signals // stateChangedId is already handled by parent) - if(this._focusAppId>0) + if (this._focusAppId > 0) tracker.disconnect(this._focusAppId); }, onWindowsChanged: function() { - this._updateRunningStyle(); - this.updateIconGeometry(); - + this._updateRunningStyle(); + this.updateIconGeometry(); }, - // Update taraget for minimization animation + /** + * Update taraget for minimization animation + */ updateIconGeometry: function() { - // If (for unknown reason) the actor is not on the stage the reported size // and position are random values, which might exceeds the integer range // resulting in an error when assigned to the a rect. This is a more like @@ -125,27 +122,25 @@ const MyAppIcon = new Lang.Class({ let rect = new Meta.Rectangle(); - if (Windows.isStolen(this.app)) { - if (this.actor.child) { - this.actor.child.destroy(); - this.actor.child = null; - } - } + if (Windows.isStolen(this.app, this._dtdSettings)) { + // Hide stolen app icon + if (this.actor.child) { + this.actor.child.destroy(); + this.actor.child = null; + } + } - [rect.x, rect.y] = this.actor.get_transformed_position(); - [rect.width, rect.height] = this.actor.get_transformed_size(); + [rect.x, rect.y] = this.actor.get_transformed_position(); + [rect.width, rect.height] = this.actor.get_transformed_size(); - let windows = Windows.getAllWindows(this.app); + let windows = Windows.getAllWindows(this.app, this._dtdSettings); windows.forEach(function(w) { w.set_icon_geometry(rect); }); - }, _toggleDots: function() { - - if ( this._dtdSettings.get_boolean('custom-theme-running-dots') - || this._dtdSettings.get_boolean('apply-custom-theme') ) + if (this._dtdSettings.get_boolean('custom-theme-running-dots') || this._dtdSettings.get_boolean('apply-custom-theme')) this._showDots(); else this._hideDots(); @@ -163,17 +158,15 @@ const MyAppIcon = new Lang.Class({ } this._dots = new St.DrawingArea({x_expand: true, y_expand: true}); - this._dots.connect('repaint', Lang.bind(this, - function() { - this._drawCircles(this._dots, Convenience.getPosition(this._dtdSettings)); - })); + this._dots.connect('repaint', Lang.bind(this, function() { + this._drawCircles(this._dots, Convenience.getPosition(this._dtdSettings)); + })); this._iconContainer.add_child(this._dots); this._updateCounterClass(); - }, _hideDots: function() { - this._dot.opacity=255; + this._dot.opacity = 255; if (this._dots) this._dots.destroy() this._dots = null; @@ -191,14 +184,16 @@ const MyAppIcon = new Lang.Class({ if (!this._menu) { this._menu = new MyAppIconMenu(this, this._dtdSettings); - this._menu.connect('activate-window', Lang.bind(this, function (menu, window) { + this._menu.connect('activate-window', Lang.bind(this, function(menu, window) { this.activateWindow(window); })); - this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) { + this._menu.connect('open-state-changed', Lang.bind(this, function(menu, isPoppedUp) { if (!isPoppedUp) this._onMenuPoppedDown(); })); - let id = Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); })); + let id = Main.overview.connect('hiding', Lang.bind(this, function() { + this._menu.close(); + })); this._menu.actor.connect('destroy', function() { Main.overview.disconnect(id); }); @@ -217,93 +212,97 @@ const MyAppIcon = new Lang.Class({ }, _onFocusAppChanged: function() { - if(tracker.focus_app == this.app) + let focusedApp = tracker.focus_app; + let isFocused = Windows.isWindowStealer(this.app, this._dtdSettings) ? + Windows.isStealingFrom(this.app, focusedApp, this._dtdSettings) : + this.app == focusedApp; + if (isFocused) this.actor.add_style_class_name('focused'); else this.actor.remove_style_class_name('focused'); }, activate: function(button) { - - if ( !this._dtdSettings.get_boolean('customize-click') ) { + if (!this._dtdSettings.get_boolean('customize-click')) { this.parent(button); return; } - - let isRunning = Windows.isWindowStealer(this.app) ? - Windows.getAllWindows(this.app).length > 0 : - this.app.state == Shell.AppState.RUNNING; + + let isRunning = Windows.isWindowStealer(this.app, this._dtdSettings) ? + Windows.getAllWindows(this.app, this._dtdSettings).length > 0 : + this.app.state == Shell.AppState.RUNNING; let event = Clutter.get_current_event(); let modifiers = event ? event.get_state() : 0; - let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK && + let openNewWindow = (modifiers & Clutter.ModifierType.CONTROL_MASK) && isRunning || - button && button == 2; + button && (button == 2); - let focusedApp = tracker.focus_app; - let isFocused = Windows.isWindowStealer(this.app) ? - Windows.isStealingFrom(this.app, focusedApp) : - this.app == focusedApp; + let focusedApp = tracker.focus_app; + let isFocused = Windows.isWindowStealer(this.app, this._dtdSettings) ? + Windows.isStealingFrom(this.app, focusedApp, this._dtdSettings) : + this.app == focusedApp; if (!isRunning || openNewWindow) this.animateLaunch(); - if(button && button == 1 && isRunning) { - - if(modifiers & Clutter.ModifierType.CONTROL_MASK) { + if (button && button == 1 && isRunning) { + if (modifiers & Clutter.ModifierType.CONTROL_MASK) { // Keep default behaviour: launch new window // By calling the parent method I make it compatible // with other extensions tweaking ctrl + click this.parent(button); return; - } else if (this._dtdSettings.get_boolean('minimize-shift') && modifiers & Clutter.ModifierType.SHIFT_MASK) { + } + else if (this._dtdSettings.get_boolean('minimize-shift') && modifiers & Clutter.ModifierType.SHIFT_MASK) { // On double click, minimize all windows in the current workspace - minimizeWindow(this.app, event.get_click_count() > 1); - - } else if(isFocused && !Main.overview._shown) { - - if(this._dtdSettings.get_enum('click-action') == clickAction.CYCLE_WINDOWS) - cycleThroughWindows(this.app); - else if(this._dtdSettings.get_enum('click-action') == clickAction.MINIMIZE) - minimizeWindow(this.app, true); - else if(this._dtdSettings.get_enum('click-action') == clickAction.LAUNCH) + minimizeWindow(this.app, event.get_click_count() > 1, this._dtdSettings); + } + else if (isFocused && !Main.overview._shown) { + if (this._dtdSettings.get_enum('click-action') == clickAction.CYCLE_WINDOWS) + cycleThroughWindows(this.app, this._dtdSettings); + else if (this._dtdSettings.get_enum('click-action') == clickAction.MINIMIZE) + minimizeWindow(this.app, true, this._dtdSettings); + else if (this._dtdSettings.get_enum('click-action') == clickAction.LAUNCH) this.app.open_new_window(-1); - - } else { + } + else { // Activate all window of the app or only le last used if (this._dtdSettings.get_enum('click-action') == clickAction.CYCLE_WINDOWS && !Main.overview._shown) { // If click cycles through windows I can activate one windows at a time - let windows = Windows.getInterestingWindows(this.app); + let windows = Windows.getInterestingWindows(this.app, this._dtdSettings); let w = windows[0]; Main.activateWindow(w); - } else if(this._dtdSettings.get_enum('click-action') == clickAction.LAUNCH) + } + else if (this._dtdSettings.get_enum('click-action') == clickAction.LAUNCH) this.app.open_new_window(-1); - else if(this._dtdSettings.get_enum('click-action') == clickAction.MINIMIZE) { + else if (this._dtdSettings.get_enum('click-action') == clickAction.MINIMIZE) { // If click minimizes all, then one expects all windows to be reshown - activateAllWindows(this.app); - } else + activateAllWindows(this.app, this._dtdSettings); + } + else this.app.activate(); } - } else { - // Default behaviour - if (openNewWindow) - this.app.open_new_window(-1); - else - this.app.activate(); + } + else { + // Default behaviour + if (openNewWindow) + this.app.open_new_window(-1); + else + this.app.activate(); } Main.overview.hide(); }, _updateCounterClass: function() { - let maxN = 4; - this._nWindows = Math.min(Windows.getInterestingWindows(this.app).length, maxN); + this._nWindows = Math.min(Windows.getInterestingWindows(this.app, this._dtdSettings).length, maxN); - for(let i = 1; i<=maxN; i++) { - let className = 'running'+i; - if(i!=this._nWindows) + for (let i = 1; i <= maxN; i++) { + let className = 'running' + i; + if (i != this._nWindows) this.actor.remove_style_class_name(className); else this.actor.add_style_class_name(className); @@ -314,7 +313,6 @@ const MyAppIcon = new Lang.Class({ }, _drawCircles: function(area, side) { - let borderColor, borderWidth, bodyColor; if (!this._dtdSettings.get_boolean('apply-custom-theme') @@ -323,7 +321,8 @@ const MyAppIcon = new Lang.Class({ borderColor = Clutter.color_from_string(this._dtdSettings.get_string('custom-theme-running-dots-border-color'))[1]; borderWidth = this._dtdSettings.get_int('custom-theme-running-dots-border-width'); bodyColor = Clutter.color_from_string(this._dtdSettings.get_string('custom-theme-running-dots-color'))[1]; - } else { + } + else { // Re-use the style - background color, and border width and color - // of the default dot let themeNode = this._dot.get_theme_node(); @@ -348,7 +347,7 @@ const MyAppIcon = new Lang.Class({ switch (side) { case St.Side.TOP: cr.translate((width - (2*n)*radius - (n-1)*spacing)/2, padding); - for (let i=0; i=0; i--) { - if(windows[i].get_workspace().index() == activeWorkspace) { + for (let i = windows.length - 1; i >= 0; i--) { + if (windows[i].get_workspace().index() == activeWorkspace) { Main.activateWindow(windows[i]); activatedWindows++; } } } -function cycleThroughWindows(app) { - +function cycleThroughWindows(app, settings) { // Store for a little amount of time last clicked app and its windows // since the order changes upon window interaction let MEMORY_TIME=3000; - let app_windows = Windows.getInterestingWindows(app); + let app_windows = Windows.getInterestingWindows(app, settings); - if(recentlyClickedAppLoopId>0) + if (recentlyClickedAppLoopId > 0) Mainloop.source_remove(recentlyClickedAppLoopId); recentlyClickedAppLoopId = Mainloop.timeout_add(MEMORY_TIME, resetRecentlyClickedApp); // If there isn't already a list of windows for the current app, // or the stored list is outdated, use the current windows list. - if( !recentlyClickedApp || + if (!recentlyClickedApp || recentlyClickedApp.get_id() != app.get_id() || - recentlyClickedAppWindows.length != app_windows.length - ) { - + recentlyClickedAppWindows.length != app_windows.length) { recentlyClickedApp = app; recentlyClickedAppWindows = app_windows; recentlyClickedAppIndex = 0; @@ -463,8 +457,7 @@ function cycleThroughWindows(app) { } function resetRecentlyClickedApp() { - - if(recentlyClickedAppLoopId>0) + if (recentlyClickedAppLoopId > 0) Mainloop.source_remove(recentlyClickedAppLoopId); recentlyClickedAppLoopId=0; recentlyClickedApp =null; @@ -482,13 +475,11 @@ function resetRecentlyClickedApp() { * - Add close windows option based on quitfromdash extension * (https://github.com/deuill/shell-extension-quitfromdash) */ - const MyAppIconMenu = new Lang.Class({ Name: 'DashToDock.MyAppIconMenu', Extends: AppDisplay.AppIconMenu, _init: function(source, settings) { - let side = Convenience.getPosition(settings); // Damm it, there has to be a proper way of doing this... @@ -500,44 +491,42 @@ const MyAppIconMenu = new Lang.Class({ this._arrowSide = side; this._boxPointer._arrowSide = side; this._boxPointer._userArrowSide = side; - - this._settings = settings; + + this._dtdSettings = settings; }, - // helper function for the quit windows abilities + /** + * Helper function for the quit windows abilities + */ _closeWindowInstance: function(metaWindow) { metaWindow.delete(global.get_current_time()); }, _redisplay: function() { - this.parent(); - // steal windows menu - this._appendSeparator(); - this._stealWindowsMenuItem = this._appendMenuItem(_('Steal Windows')); - this._stealWindowsMenuItem.connect('activate', Lang.bind(this, function() { - - //let r = Util.spawn(['gnome-shell-extension-prefs', 'dash-to-dock@micxgx.gmail.com']); - //global.log('>>>>>>>>>>>> ' + r); - - })); + // steal windows menu + this._appendSeparator(); + this._stealWindowsMenuItem = this._appendMenuItem(_('Steal Windows')); + this._stealWindowsMenuItem.connect('activate', Lang.bind(this, function() { + //global.log('>>>>>>>>>>>> ' + r); + })); // quit menu let app = this._source.app; - let count = Windows.getInterestingWindows(app).length; - if ( count > 0) { + let count = Windows.getInterestingWindows(app, this._dtdSettings).length; + if (count > 0) { this._appendSeparator(); - let quitFromDashMenuText = ""; + let quitFromDashMenuText = ''; if (count == 1) - quitFromDashMenuText = _("Quit"); + quitFromDashMenuText = _('Quit'); else - quitFromDashMenuText = _("Quit") + ' ' + count + ' ' + _("Windows"); + quitFromDashMenuText = _('Quit') + ' ' + count + ' ' + _('Windows'); this._quitfromDashMenuItem = this._appendMenuItem(quitFromDashMenuText); this._quitfromDashMenuItem.connect('activate', Lang.bind(this, function() { let app = this._source.app; - let windows = Windows.getAllWindows(app); + let windows = Windows.getAllWindows(app, this._dtdSettings); for (let i = 0; i < windows.length; i++) { this._closeWindowInstance(windows[i]) } @@ -545,3 +534,167 @@ const MyAppIconMenu = new Lang.Class({ } } }); + +/** + * Extend ShowAppsIcon + * + * - Pass settings to the constructor + * - set label position based on dash orientation + * - implement a popupMenu based on the AppIcon code + * + * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. + * thus use this ugly pattern. + */ +function extendShowAppsIcon(showAppsIcon, settings) { + showAppsIcon._dtdSettings = settings; + /* the variable equivalent to toggleButton has a different name in the appIcon class + (actor): duplicate reference to easily reuse appIcon methods */ + showAppsIcon.actor = showAppsIcon.toggleButton; + + // Re-use appIcon methods + showAppsIcon._removeMenuTimeout = AppDisplay.AppIcon.prototype._removeMenuTimeout; + showAppsIcon._setPopupTimeout = AppDisplay.AppIcon.prototype._setPopupTimeout; + showAppsIcon._onButtonPress = AppDisplay.AppIcon.prototype._onButtonPress; + showAppsIcon._onKeyboardPopupMenu = AppDisplay.AppIcon.prototype._onKeyboardPopupMenu; + showAppsIcon._onLeaveEvent = AppDisplay.AppIcon.prototype._onLeaveEvent; + showAppsIcon._onTouchEvent = AppDisplay.AppIcon.prototype._onTouchEvent; + showAppsIcon._onMenuPoppedDown = AppDisplay.AppIcon.prototype._onMenuPoppedDown; + + + // No action on clicked (showing of the appsview is controlled elsewhere) + showAppsIcon._onClicked = function(actor, button) { + showAppsIcon._removeMenuTimeout(); + }; + + showAppsIcon.actor.connect('leave-event', Lang.bind(showAppsIcon, showAppsIcon._onLeaveEvent)); + showAppsIcon.actor.connect('button-press-event', Lang.bind(showAppsIcon, showAppsIcon._onButtonPress)); + showAppsIcon.actor.connect('touch-event', Lang.bind(showAppsIcon, showAppsIcon._onTouchEvent)); + showAppsIcon.actor.connect('clicked', Lang.bind(showAppsIcon, showAppsIcon._onClicked)); + showAppsIcon.actor.connect('popup-menu', Lang.bind(showAppsIcon, showAppsIcon._onKeyboardPopupMenu)); + + showAppsIcon._menu = null; + showAppsIcon._menuManager = new PopupMenu.PopupMenuManager(showAppsIcon); + showAppsIcon._menuTimeoutId = 0; + + showAppsIcon.showLabel = itemShowLabel; + + showAppsIcon.popupMenu = function() { + showAppsIcon._removeMenuTimeout(); + showAppsIcon.actor.fake_release(); + + if (!showAppsIcon._menu) { + showAppsIcon._menu = new MyShowAppsIconMenu(showAppsIcon, showAppsIcon._dtdSettings); + showAppsIcon._menu.connect('open-state-changed', Lang.bind(showAppsIcon, function(menu, isPoppedUp) { + if (!isPoppedUp) + showAppsIcon._onMenuPoppedDown(); + })); + let id = Main.overview.connect('hiding', Lang.bind(showAppsIcon, function() { + showAppsIcon._menu.close(); + })); + showAppsIcon._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); + showAppsIcon._menuManager.addMenu(showAppsIcon._menu); + } + + showAppsIcon.emit('menu-state-changed', true); + + showAppsIcon.actor.set_hover(true); + showAppsIcon._menu.popup(); + showAppsIcon._menuManager.ignoreRelease(); + showAppsIcon.emit('sync-tooltip'); + + return false; + }; + + Signals.addSignalMethods(showAppsIcon); +} + +/** + * A menu for the showAppsIcon + */ +const MyShowAppsIconMenu = new Lang.Class({ + Name: 'DashToDock.ShowAppsIconMenu', + Extends: MyAppIconMenu, + + _redisplay: function() { + this.removeAll(); + + let item = this._appendMenuItem('Dash to Dock ' + _('Settings')); + + item.connect('activate', function () { + Util.spawn(["gnome-shell-extension-prefs", Me.metadata.uuid]); + }); + } +}); + +/** + * This function is used for both extendShowAppsIcon and extendDashItemContainer + */ +function itemShowLabel() { + if (!this._labelText) + return; + + this.label.set_text(this._labelText); + this.label.opacity = 0; + this.label.show(); + + let [stageX, stageY] = this.get_transformed_position(); + let node = this.label.get_theme_node(); + + let itemWidth = this.allocation.x2 - this.allocation.x1; + let itemHeight = this.allocation.y2 - this.allocation.y1; + + let labelWidth = this.label.get_width(); + let labelHeight = this.label.get_height(); + + let x, y, xOffset, yOffset; + + let position = Convenience.getPosition(this._dtdSettings); + this._isHorizontal = ((position == St.Side.TOP) || (position == St.Side.BOTTOM)); + let labelOffset = node.get_length('-x-offset'); + + switch (position) { + case St.Side.LEFT: + yOffset = Math.floor((itemHeight - labelHeight) / 2); + y = stageY + yOffset; + xOffset = labelOffset; + x = stageX + this.get_width() + xOffset; + break; + case St.Side.RIGHT: + yOffset = Math.floor((itemHeight - labelHeight) / 2); + y = stageY + yOffset; + xOffset = labelOffset; + x = Math.round(stageX) - labelWidth - xOffset; + break; + case St.Side.TOP: + y = stageY + labelOffset + itemHeight; + xOffset = Math.floor((itemWidth - labelWidth) / 2); + x = stageX + xOffset; + break; + case St.Side.BOTTOM: + yOffset = labelOffset; + y = stageY - labelHeight - yOffset; + xOffset = Math.floor((itemWidth - labelWidth) / 2); + x = stageX + xOffset; + break; + } + + // keep the label inside the screen border + // Only needed fot the x coordinate. + + // Leave a few pixel gap + let gap = 5; + let monitor = Main.layoutManager.findMonitorForActor(this); + if (x - monitor.x < gap) + x += monitor.x - x + labelOffset; + else if (x + labelWidth > monitor.x + monitor.width - gap) + x -= x + labelWidth - (monitor.x + monitor.width) + gap; + + this.label.set_position(x, y); + Tweener.addTween(this.label, { + opacity: 255, + time: DASH_ITEM_LABEL_SHOW_TIME, + transition: 'easeOutQuad', + }); +} diff --git a/intellihide.js b/intellihide.js index 736ea7823..a27504d96 100644 --- a/intellihide.js +++ b/intellihide.js @@ -30,34 +30,32 @@ const IntellihideMode = { // List of windows type taken into account. Order is important (keep the original // enum order). const handledWindowTypes = [ - Meta.WindowType.NORMAL, - Meta.WindowType.DOCK, - Meta.WindowType.DIALOG, - Meta.WindowType.MODAL_DIALOG, - Meta.WindowType.TOOLBAR, - Meta.WindowType.MENU, - Meta.WindowType.UTILITY, - Meta.WindowType.SPLASHSCREEN + Meta.WindowType.NORMAL, + Meta.WindowType.DOCK, + Meta.WindowType.DIALOG, + Meta.WindowType.MODAL_DIALOG, + Meta.WindowType.TOOLBAR, + Meta.WindowType.MENU, + Meta.WindowType.UTILITY, + Meta.WindowType.SPLASHSCREEN ]; /** * A rough and ugly implementation of the intellihide behaviour. * Intallihide object: emit 'status-changed' signal when the overlap of windows * with the provided targetBoxClutter.ActorBox changes; - * -*/ + */ const Intellihide = new Lang.Class({ Name: 'DashToDock.Intellihide', _init: function(settings) { - // Load settings this._settings = settings; this._signalsHandler = new Convenience.GlobalSignalsHandler(); this._tracker = Shell.WindowTracker.get_default(); this._focusApp = null; // The application whose window is focused. - this._topApp = null; //The application whose window is on top on the monitor with the dock. + this._topApp = null; // The application whose window is on top on the monitor with the dock. this._isEnabled = false; this.status = OverlapStatus.UNDEFINED; @@ -67,35 +65,29 @@ const Intellihide = new Lang.Class({ this._checkOverlapTimeoutId = 0; // Connect global signals - this._signalsHandler.add ( + this._signalsHandler.add([ // Add signals on windows created from now on - [ - global.display, - 'window-created', - Lang.bind(this, this._windowCreated) - ], + global.display, + 'window-created', + Lang.bind(this, this._windowCreated) + ], [ // triggered for instance when the window list order changes, // included when the workspace is switched - [ - global.screen, - 'restacked', - Lang.bind(this, this._checkOverlap) - ], - // when windows are alwasy on top, the focus window can change + global.screen, + 'restacked', + Lang.bind(this, this._checkOverlap) + ], [ + // 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', - Lang.bind(this, this._checkOverlap) - ], + this._tracker, + 'notify::focus-app', + Lang.bind(this, this._checkOverlap) + ], [ // update wne monitor changes, for instance in multimonitor when monitor are attached - [ - global.screen, - 'monitors-changed', - Lang.bind(this, this._checkOverlap ) - ] - ); - + global.screen, + 'monitors-changed', + Lang.bind(this, this._checkOverlap ) + ]); }, destroy: function() { @@ -107,21 +99,21 @@ const Intellihide = new Lang.Class({ }, enable: function() { - this._isEnabled = true; - this._status = OverlapStatus.UNDEFINED; - global.get_window_actors().forEach(function(win) { - this._addWindowSignals(win.get_meta_window()) - }, this); - this._doCheckOverlap(); + this._isEnabled = true; + this._status = OverlapStatus.UNDEFINED; + global.get_window_actors().forEach(function(win) { + this._addWindowSignals(win.get_meta_window()); + }, this); + this._doCheckOverlap(); }, disable: function() { this._isEnabled = false; global.get_window_actors().forEach(function(win) { - this._removeWindowSignals(win.get_meta_window()) - }, this); + this._removeWindowSignals(win.get_meta_window()); + }, this); - if(this._checkOverlapTimeoutId>0) { + if (this._checkOverlapTimeoutId > 0) { Mainloop.source_remove(this._checkOverlapTimeoutId); this._checkOverlapTimeoutId = 0; } @@ -132,27 +124,23 @@ const Intellihide = new Lang.Class({ }, _addWindowSignals: function(meta_win) { - if(!meta_win || !this._handledWindow(meta_win)) - return; + if (!meta_win || !this._handledWindow(meta_win)) + return; - meta_win.dtd_onPositionChanged = meta_win.connect( - 'position-changed', Lang.bind(this, this._checkOverlap, meta_win) - ); + meta_win.dtd_onPositionChanged = meta_win.connect('position-changed', Lang.bind(this, this._checkOverlap, meta_win)); - meta_win.dtd_onSizeChanged = meta_win.connect( - 'size-changed', Lang.bind(this, this._checkOverlap, meta_win) - ); + meta_win.dtd_onSizeChanged = meta_win.connect('size-changed', Lang.bind(this, this._checkOverlap, meta_win)); }, _removeWindowSignals: function(meta_win) { - if( meta_win && meta_win.dtd_onSizeChanged ) { - meta_win.disconnect(meta_win.dtd_onSizeChanged); - delete meta_win.dtd_onSizeChanged; + if (meta_win && meta_win.dtd_onSizeChanged) { + meta_win.disconnect(meta_win.dtd_onSizeChanged); + delete meta_win.dtd_onSizeChanged; } - if( meta_win && meta_win.dtd_onPositionChanged ) { - meta_win.disconnect(meta_win.dtd_onPositionChanged); - delete meta_win.dtd_onPositionChanged; + if (meta_win && meta_win.dtd_onPositionChanged) { + meta_win.disconnect(meta_win.dtd_onPositionChanged); + delete meta_win.dtd_onPositionChanged; } }, @@ -167,51 +155,42 @@ const Intellihide = new Lang.Class({ }, getOverlapStatus: function() { - if(this._status == OverlapStatus.TRUE) - return true; - else - return false; + return (this._status == OverlapStatus.TRUE); }, _checkOverlap: function() { - - if( !this._isEnabled || this._targetBox == null) + if (!this._isEnabled || (this._targetBox == null)) return; /* Limit the number of calls to the doCheckOverlap function */ - if(this._checkOverlapTimeoutId) { + if (this._checkOverlapTimeoutId) { this._checkOverlapTimeoutContinue = true; return } this._doCheckOverlap(); - this._checkOverlapTimeoutId = - Mainloop.timeout_add(INTELLIHIDE_CHECK_INTERVAL, - Lang.bind(this, function() { - this._doCheckOverlap(); - if (this._checkOverlapTimeoutContinue) { - this._checkOverlapTimeoutContinue = false; - return GLib.SOURCE_CONTINUE; - } else { - this._checkOverlapTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - } - )); + this._checkOverlapTimeoutId = Mainloop.timeout_add(INTELLIHIDE_CHECK_INTERVAL, Lang.bind(this, function() { + this._doCheckOverlap(); + if (this._checkOverlapTimeoutContinue) { + this._checkOverlapTimeoutContinue = false; + return GLib.SOURCE_CONTINUE; + } else { + this._checkOverlapTimeoutId = 0; + return GLib.SOURCE_REMOVE; + } + })); }, _doCheckOverlap: function() { - if( !this._isEnabled || this._targetBox == null) + if (!this._isEnabled || (this._targetBox == null)) return; let overlaps = OverlapStatus.FALSE; let windows = global.get_window_actors(); - if (windows.length>0) { - - + if (windows.length > 0) { /* * Get the top window on the monitor where the dock is placed. * The idea is that we dont want to overlap with the windows of the topmost application, @@ -221,39 +200,36 @@ const Intellihide = new Lang.Class({ let monitorIndex = this._settings.get_int('preferred-monitor'); - if (monitorIndex < 0 || monitorIndex > Main.layoutManager.monitors.length) + if ((monitorIndex < 0) || (monitorIndex > Main.layoutManager.monitors.length)) monitorIndex = Main.layoutManager.primaryIndex; let topWindow = null; - for (let i = windows.length-1; i>=0; i--) { + for (let i = windows.length - 1; i >= 0; i--) { let meta_win = windows[i].get_meta_window(); - if (this._handledWindow(meta_win) - && meta_win.get_monitor() == monitorIndex) { + if (this._handledWindow(meta_win) && (meta_win.get_monitor() == monitorIndex)) { topWindow = meta_win; break; } } if (topWindow !== null) { - this._topApp = this._tracker.get_window_app(topWindow); // If there isn't a focused app, use that of the window on top this._focusApp = this._tracker.focus_app || this._topApp windows = windows.filter(this._intellihideFilterInteresting, this); - for(let i=0; i< windows.length; i++) { - + for (let i in windows.length) { let win = windows[i].get_meta_window(); - if(win) { + if (win) { let rect = win.get_frame_rect(); - let test = ( rect.x < this._targetBox.x2) && - ( rect.x +rect.width > this._targetBox.x1 ) && - ( rect.y < this._targetBox.y2 ) && - ( rect.y +rect.height > this._targetBox.y1 ); + let test = (rect.x < this._targetBox.x2) && + (rect.x + rect.width > this._targetBox.x1) && + (rect.y < this._targetBox.y2) && + (rect.y + rect.height > this._targetBox.y1); - if(test) { + if (test) { overlaps = OverlapStatus.TRUE; break; } @@ -262,7 +238,7 @@ const Intellihide = new Lang.Class({ } } - if ( this._status !== overlaps ) { + if (this._status !== overlaps) { this._status = overlaps; this.emit('status-changed', this._status); } @@ -273,11 +249,9 @@ const Intellihide = new Lang.Class({ // Consider all windows visible on the current workspace. // Optionally skip windows of other applications _intellihideFilterInteresting: function(wa) { - let meta_win = wa.get_meta_window(); - if (!meta_win || !this._handledWindow(meta_win)) { + if (!meta_win || !this._handledWindow(meta_win)) return false; - } let currentWorkspace = global.screen.get_active_workspace_index(); let wksp = meta_win.get_workspace(); @@ -291,7 +265,7 @@ const Intellihide = new Lang.Class({ case IntellihideMode.FOCUS_APPLICATION_WINDOWS: // Skip windows of other apps - if (this._focusApp ) { + if (this._focusApp) { // The DropDownTerminal extension is not an application per se // so we match its window by wm class instead if (meta_win.get_wm_class() == 'DropDownTerminalWindow') @@ -302,21 +276,18 @@ const Intellihide = new Lang.Class({ // Consider half maximized windows side by side // and windows which are alwayson top - if( currentApp != this._focusApp && currentApp != this._topApp - && !( (focusWindow && focusWindow.maximized_vertically && !focusWindow.maximized_horizontally) + if((currentApp != this._focusApp) && (currentApp != this._topApp) + && !((focusWindow && focusWindow.maximized_vertically && !focusWindow.maximized_horizontally) && (meta_win.maximized_vertically && !meta_win.maximized_horizontally) - && meta_win.get_monitor() == focusWindow.get_monitor() - ) - && !meta_win.is_above() - ) { + && meta_win.get_monitor() == focusWindow.get_monitor()) + && !meta_win.is_above()) return false; - } } break; case IntellihideMode.MAXIMIZED_WINDOWS: // Skip unmaximized windows - if (!meta_win.maximized_vertically && !meta_win.maximized_horizontally) + if (!meta_win.maximized_vertically && !meta_win.maximized_horizontally) return false; break; } @@ -332,12 +303,11 @@ const Intellihide = new Lang.Class({ start hiding the dock, which is readily reshown as soon as the window position is updated. */ - if ( wksp_index == currentWorkspace && meta_win.showing_on_its_workspace() - && (Main.overview.visible || wa.mapped)) { + if (wksp_index == currentWorkspace && meta_win.showing_on_its_workspace() + && (Main.overview.visible || wa.mapped)) return true; - } else { + else return false; - } }, @@ -349,19 +319,16 @@ const Intellihide = new Lang.Class({ if (metaWindow.get_wm_class() == 'DropDownTerminalWindow') return true; - var wtype = metaWindow.get_window_type(); - for (var i = 0; i < handledWindowTypes.length; i++) { + let wtype = metaWindow.get_window_type(); + for (let i in handledWindowTypes) { var hwtype = handledWindowTypes[i]; - if (hwtype == wtype) { + if (hwtype == wtype) return true; - } else if (hwtype > wtype) { + else if (hwtype > wtype) return false; - } } return false; - } - }); Signals.addSignalMethods(Intellihide.prototype); diff --git a/prefs.js b/prefs.js index 74da8f84d..08a6b9e15 100644 --- a/prefs.js +++ b/prefs.js @@ -27,25 +27,25 @@ const DEFAULT_ICONS_SIZES = [ 128, 96, 64, 48, 32, 24, 16 ]; function cssHexString(css) { let rrggbb = '#'; let start; - for(let loop = 0; loop < 3; loop++) { + for (let loop = 0; loop < 3; loop++) { let end = 0; let xx = ''; - for(let loop = 0; loop < 2; loop++) { - while(true) { + for (let loop = 0; loop < 2; loop++) { + while (true) { let x = css.slice(end, end + 1); - if(x == '(' || x == ',' || x == ')') + if ((x == '(') || (x == ',') || (x == ')')) break; - end = end + 1; + end++; } - if(loop == 0) { - end = end + 1; + if (loop == 0) { + end++; start = end; } } xx = parseInt(css.slice(start, end)).toString(16); - if(xx.length == 1) + if (xx.length == 1) xx = '0' + xx; - rrggbb = rrggbb + xx; + rrggbb += xx; css = css.slice(end); } return rrggbb; @@ -55,10 +55,9 @@ const Settings = new Lang.Class({ Name: 'DashToDock.Settings', _init: function() { - this._settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-dock'); - this._rtl = Gtk.Widget.get_default_direction()==Gtk.TextDirection.RTL; + this._rtl = (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL); this._builder = new Gtk.Builder(); this._builder.set_translation_domain(Me.metadata['gettext-domain']); @@ -74,17 +73,17 @@ const Settings = new Lang.Class({ this._bindSettings(); this._builder.connect_signals_full(Lang.bind(this, this._connector)); - }, - // Connect signals + /** + * Connect signals + */ _connector: function(builder, object, signal, handler) { object.connect(signal, Lang.bind(this, this._SignalHandler[handler])); }, _bindSettings: function() { - - /* Position and size panel */ + // Position and size panel // Monitor options @@ -96,7 +95,7 @@ const Settings = new Lang.Class({ let monitor = this._settings.get_int('preferred-monitor'); // Add primary monitor with index 0, because in GNOME Shell the primary monitor is always 0 - this._builder.get_object('dock_monitor_combo').append_text(_("Primary monitor")); + this._builder.get_object('dock_monitor_combo').append_text(_('Primary monitor')); this._monitors.push(0); // Add connected monitors @@ -105,14 +104,14 @@ const Settings = new Lang.Class({ if (i !== primary_monitor) { ctr++; this._monitors.push(ctr); - this._builder.get_object('dock_monitor_combo').append_text(_("Secondary monitor ") + ctr); + this._builder.get_object('dock_monitor_combo').append_text(_('Secondary monitor ') + ctr); } } // If one of the external monitor is set as preferred, show it even if not attached - if ( monitor >= n_monitors && monitor !== primary_monitor) { + if ((monitor >= n_monitors) && (monitor !== primary_monitor)) { this._monitors.push(monitor) - this._builder.get_object('dock_monitor_combo').append_text(_("Secondary monitor ") + ++ctr); + this._builder.get_object('dock_monitor_combo').append_text(_('Secondary monitor ') + ++ctr); } this._builder.get_object('dock_monitor_combo').set_active(this._monitors.indexOf(monitor)); @@ -137,8 +136,8 @@ const Settings = new Lang.Class({ if (this._rtl) { /* Left is Right in rtl as a setting */ - this._builder.get_object('position_left_button').set_label(_("Right")); - this._builder.get_object('position_right_button').set_label(_("Left")); + this._builder.get_object('position_left_button').set_label(_('Right')); + this._builder.get_object('position_right_button').set_label(_('Left')); } // Intelligent autohide options @@ -188,14 +187,14 @@ const Settings = new Lang.Class({ // Create dialog for intelligent autohide advanced settings this._builder.get_object('intelligent_autohide_button').connect('clicked', Lang.bind(this, function() { - let dialog = new Gtk.Dialog({ title: _("Intelligent autohide customization"), + let dialog = new Gtk.Dialog({ title: _('Intelligent autohide customization'), transient_for: this.widget.get_toplevel(), use_header_bar: true, modal: true }); // GTK+ leaves positive values for application-defined response ids. - // Use +1 for the reset action - dialog.add_button(_("Reset to defaults"), 1); + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); let box = this._builder.get_object('intelligent_autohide_advanced_settings_box'); dialog.get_content_area().add(box); @@ -270,7 +269,7 @@ const Settings = new Lang.Class({ icon_size_scale.set_range(DEFAULT_ICONS_SIZES[DEFAULT_ICONS_SIZES.length -1], DEFAULT_ICONS_SIZES[0]); icon_size_scale.set_value(this._settings.get_int('dash-max-icon-size')); DEFAULT_ICONS_SIZES.forEach(function(val) { - icon_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); + icon_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); }); // Corrent for rtl languages @@ -278,10 +277,9 @@ const Settings = new Lang.Class({ // Flip value position: this is not done automatically this._builder.get_object('dock_size_scale').set_value_pos(Gtk.PositionType.LEFT); icon_size_scale.set_value_pos(Gtk.PositionType.LEFT); - /* I suppose due to a bug, having a more than one mark and one above a value of 100 - * makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable - * and then manually inverting it - */ + // I suppose due to a bug, having a more than one mark and one above a value of 100 + // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable + // and then manually inverting it icon_size_scale.set_flippable(false); icon_size_scale.set_inverted(true); } @@ -291,7 +289,7 @@ const Settings = new Lang.Class({ this._settings.bind('extend-height', this._builder.get_object('dock_size_scale'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN); - /* Behavior panel */ + // Behavior panel this._settings.bind('show-running', this._builder.get_object('show_running_switch'), @@ -324,18 +322,18 @@ const Settings = new Lang.Class({ this._builder.get_object('click_action_combo').set_active(this._settings.get_enum('click-action')); this._builder.get_object('click_action_combo').connect('changed', Lang.bind (this, function(widget) { - this._settings.set_enum('click-action', widget.get_active()); + this._settings.set_enum('click-action', widget.get_active()); })); this._builder.get_object('shift_click_action_combo').set_active(this._settings.get_boolean('minimize-shift')?1:0); this._builder.get_object('shift_click_action_combo').connect('changed', Lang.bind (this, function(widget) { - this._settings.set_boolean('minimize-shift', widget.get_active()==1); + this._settings.set_boolean('minimize-shift', widget.get_active()==1); })); this._settings.bind('scroll-switch-workspace', this._builder.get_object('switch_workspace_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - /* Appearance Panel */ + // Appearance Panel this._settings.bind('apply-custom-theme', this._builder.get_object('customize_theme'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN | Gio.SettingsBindFlags.GET); this._settings.bind('apply-custom-theme', this._builder.get_object('builtin_theme_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); @@ -353,7 +351,7 @@ const Settings = new Lang.Class({ // Create dialog for running dots advanced settings this._builder.get_object('running_dots_advance_settings_button').connect('clicked', Lang.bind(this, function() { - let dialog = new Gtk.Dialog({ title: _("Customize running indicators"), + let dialog = new Gtk.Dialog({ title: _('Customize running indicators'), transient_for: this.widget.get_toplevel(), use_header_bar: true, modal: true }); @@ -411,105 +409,105 @@ const Settings = new Lang.Class({ this._builder.get_object('custom_opacity_scale').set_value(this._settings.get_double('background-opacity')); this._settings.bind('opaque-background', this._builder.get_object('custom_opacity'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); - /* About Panel */ + // About Panel this._builder.get_object('extension_version').set_label(Me.metadata.version.toString()); - }, - // Object containing all signals defined in the glade file + /** + * Object containing all signals defined in the glade file + */ _SignalHandler: { + dock_display_combo_changed_cb: function(combo) { + this._settings.set_int('preferred-monitor', this._monitors[combo.get_active()]); + }, + + position_top_button_toggled_cb: function(button) { + if (button.get_active()) + this._settings.set_enum('dock-position', 0); + }, + + position_right_button_toggled_cb: function(button) { + if (button.get_active()) + this._settings.set_enum('dock-position', 1); + }, + + position_bottom_button_toggled_cb: function(button) { + if (button.get_active()) + this._settings.set_enum('dock-position', 2); + }, + + position_left_button_toggled_cb: function(button) { + if (button.get_active()) + this._settings.set_enum('dock-position', 3); + }, + + icon_size_combo_changed_cb: function(combo) { + this._settings.set_int('dash-max-icon-size', this._allIconSizes[combo.get_active()]); + }, + + dock_size_scale_format_value_cb: function(scale, value) { + return Math.round(value*100)+ ' %'; + }, + + dock_size_scale_value_changed_cb: function(scale) { + // Avoid settings the size consinuosly + if (this._dock_size_timeout > 0) + Mainloop.source_remove(this._dock_size_timeout); + + this._dock_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._settings.set_double('height-fraction', scale.get_value()); + this._dock_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + }, - dock_display_combo_changed_cb: function (combo) { - this._settings.set_int('preferred-monitor', this._monitors[combo.get_active()]); - }, - - position_top_button_toggled_cb: function (button) { - if (button.get_active()) - this._settings.set_enum('dock-position', 0); - }, - - position_right_button_toggled_cb: function (button) { - if (button.get_active()) - this._settings.set_enum('dock-position', 1); - }, - - position_bottom_button_toggled_cb: function (button) { - if (button.get_active()) - this._settings.set_enum('dock-position', 2); - }, - - position_left_button_toggled_cb: function (button) { - if (button.get_active()) - this._settings.set_enum('dock-position', 3); - }, - - icon_size_combo_changed_cb: function(combo) { - this._settings.set_int('dash-max-icon-size', this._allIconSizes[combo.get_active()]); - }, - - dock_size_scale_format_value_cb: function(scale, value) { - return Math.round(value*100)+ ' %'; - }, - - dock_size_scale_value_changed_cb: function(scale) { - // Avoid settings the size consinuosly - if (this._dock_size_timeout >0) - Mainloop.source_remove(this._dock_size_timeout); - - this._dock_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { - this._settings.set_double('height-fraction', scale.get_value()); - this._dock_size_timeout = 0; - return GLib.SOURCE_REMOVE; - })); - }, - - icon_size_scale_format_value_cb: function(scale, value) { - return value+ ' px'; - }, - - icon_size_scale_value_changed_cb: function(scale) { - // Avoid settings the size consinuosly - if (this._icon_size_timeout >0) - Mainloop.source_remove(this._icon_size_timeout); - - this._icon_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { - this._settings.set_int('dash-max-icon-size', scale.get_value()); - this._icon_size_timeout = 0; - return GLib.SOURCE_REMOVE; - })); - }, - - custom_opacity_scale_value_changed_cb: function(scale) { - // Avoid settings the opacity consinuosly as it's change is animated - if (this._opacity_timeout >0) - Mainloop.source_remove(this._opacity_timeout); - - this._opacity_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { - this._settings.set_double('background-opacity', scale.get_value()); - this._opacity_timeout = 0; - return GLib.SOURCE_REMOVE; - })); - }, - - custom_opacity_scale_format_value_cb: function(scale, value) { - return Math.round(value*100) + ' %'; - }, - - all_windows_radio_button_toggled_cb: function (button) { - if (button.get_active()) - this._settings.set_enum('intellihide-mode', 0); - }, - - focus_application_windows_radio_button_toggled_cb: function (button) { - if (button.get_active()) - this._settings.set_enum('intellihide-mode', 1); - }, - - maximized_windows_radio_button_toggled_cb: function (button) { - if (button.get_active()) - this._settings.set_enum('intellihide-mode', 2); - } + icon_size_scale_format_value_cb: function(scale, value) { + return value+ ' px'; + }, + + icon_size_scale_value_changed_cb: function(scale) { + // Avoid settings the size consinuosly + if (this._icon_size_timeout > 0) + Mainloop.source_remove(this._icon_size_timeout); + + this._icon_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._settings.set_int('dash-max-icon-size', scale.get_value()); + this._icon_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + }, + + custom_opacity_scale_value_changed_cb: function(scale) { + // Avoid settings the opacity consinuosly as it's change is animated + if (this._opacity_timeout > 0) + Mainloop.source_remove(this._opacity_timeout); + + this._opacity_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._settings.set_double('background-opacity', scale.get_value()); + this._opacity_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + }, + + custom_opacity_scale_format_value_cb: function(scale, value) { + return Math.round(value*100) + ' %'; + }, + + all_windows_radio_button_toggled_cb: function(button) { + if (button.get_active()) + this._settings.set_enum('intellihide-mode', 0); + }, + + focus_application_windows_radio_button_toggled_cb: function(button) { + if (button.get_active()) + this._settings.set_enum('intellihide-mode', 1); + }, + + maximized_windows_radio_button_toggled_cb: function(button) { + if (button.get_active()) + this._settings.set_enum('intellihide-mode', 2); + } } }); @@ -523,4 +521,3 @@ function buildPrefsWidget() { widget.show_all(); return widget; } - diff --git a/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml index 8a3345dbb..c8a8a4c76 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml @@ -191,6 +191,11 @@ true Activate only one window + + [] + Window stealing + Each string is a space-separated list, where the first item in the list is the app ID and the subsequent items are WM_CLASS names + 'cycle-windows' Action when clicking on a running app diff --git a/theming.js b/theming.js index 44a235c28..49eb3ff41 100644 --- a/theming.js +++ b/theming.js @@ -27,44 +27,39 @@ const Convenience = Me.imports.convenience; const Icons = Me.imports.icons; const Windows = Me.imports.windows; -/* +/** * Manage theme customization and custom theme support -*/ + */ const ThemeManager = new Lang.Class({ Name: 'DashToDock.ThemeManager', _init: function(settings, actor, dash) { - this._settings = settings; this._bindSettingsChanges(); this._actor = actor; this._dash = dash; // initialize colors with generic values - this._defaultBackground = {red: 0, green:0, blue: 0, alpha:0}; - this._defaultBackgroundColor = {red: 0, green:0, blue: 0, alpha:0}; - this._customizedBackground = {red: 0, green:0, blue: 0, alpha:0}; + this._defaultBackground = {red: 0, green: 0, blue: 0, alpha: 0}; + this._defaultBackgroundColor = {red: 0, green: 0, blue: 0, alpha: 0}; + this._customizedBackground = {red: 0, green: 0, blue: 0, alpha: 0}; this._signalsHandler = new Convenience.GlobalSignalsHandler(); - this._signalsHandler.add( + this._signalsHandler.add([ // When theme changes re-obtain default background color - [ - St.ThemeContext.get_for_stage (global.stage), - 'changed', - Lang.bind(this, this.updateCustomTheme) - ], + St.ThemeContext.get_for_stage (global.stage), + 'changed', + Lang.bind(this, this.updateCustomTheme) + ], [ // update :overview pseudoclass - [ - Main.overview, - 'showing', - Lang.bind(this, this._onOverviewShowing) - ], - [ - Main.overview, - 'hiding', - Lang.bind(this, this._onOverviewHiding) - ] - ); + Main.overview, + 'showing', + Lang.bind(this, this._onOverviewShowing) + ], [ + Main.overview, + 'hiding', + Lang.bind(this, this._onOverviewHiding) + ]); this._updateCustomStyleClasses(); @@ -83,27 +78,25 @@ const ThemeManager = new Lang.Class({ }, _updateBackgroundOpacity: function() { - let newAlpha = this._settings.get_double('background-opacity'); - this._defaultBackground = 'rgba('+ - this._defaultBackgroundColor.red + ','+ - this._defaultBackgroundColor.green + ','+ - this._defaultBackgroundColor.blue + ','+ + this._defaultBackground = 'rgba(' + + this._defaultBackgroundColor.red + ',' + + this._defaultBackgroundColor.green + ',' + + this._defaultBackgroundColor.blue + ',' + Math.round(this._defaultBackgroundColor.alpha/2.55)/100 + ')'; - this._customizedBackground = 'rgba('+ - this._defaultBackgroundColor.red + ','+ - this._defaultBackgroundColor.green + ','+ - this._defaultBackgroundColor.blue + ','+ + this._customizedBackground = 'rgba(' + + this._defaultBackgroundColor.red + ',' + + this._defaultBackgroundColor.green + ',' + + this._defaultBackgroundColor.blue + ',' + newAlpha + ')'; }, _getBackgroundColor: function() { - // Prevent shell crash if the actor is not on the stage. // It happens enabling/disabling repeatedly the extension - if(!this._dash._container.get_stage()) + if (!this._dash._container.get_stage()) return; // Remove custom style @@ -117,19 +110,15 @@ const ThemeManager = new Lang.Class({ }, _updateCustomStyleClasses: function() { - if (this._settings.get_boolean('apply-custom-theme')) this._actor.add_style_class_name('dashtodock'); - else { + else this._actor.remove_style_class_name('dashtodock'); - } if (this._settings.get_boolean('custom-theme-shrink')) this._actor.add_style_class_name('shrink'); - else { + else this._actor.remove_style_class_name('shrink'); - } - }, updateCustomTheme: function() { @@ -140,78 +129,75 @@ const ThemeManager = new Lang.Class({ this._dash._redisplay(); }, - /* Reimported back and adapted from atomdock */ + /** + * Reimported back and adapted from atomdock + */ _adjustTheme: function() { // Prevent shell crash if the actor is not on the stage. // It happens enabling/disabling repeatedly the extension - if (!this._dash._container.get_stage()) { + if (!this._dash._container.get_stage()) return; - } // Remove prior style edits this._dash._container.set_style(null); - /* If built-in theme is enabled do nothing else */ - if( this._settings.get_boolean('apply-custom-theme') ) + // If built-in theme is enabled do nothing else + if (this._settings.get_boolean('apply-custom-theme')) return; let newStyle = ''; let position = Convenience.getPosition(this._settings); - if ( ! this._settings.get_boolean('custom-theme-shrink') ) { - + if (!this._settings.get_boolean('custom-theme-shrink')) { // obtain theme border settings let themeNode = this._dash._container.get_theme_node(); let borderColor = themeNode.get_border_color(St.Side.TOP); let borderWidth = themeNode.get_border_width(St.Side.TOP); let borderRadius = themeNode.get_border_radius(St.Corner.TOPRIGHT); - /* We're copying border and corner styles to left border and top-left - * corner, also removing bottom border and bottom-right corner styles - */ + // We're copying border and corner styles to left border and top-left + // corner, also removing bottom border and bottom-right corner styles let borderInner = ''; let borderRadiusValue = ''; let borderMissingStyle = ''; - if (this._rtl && position != St.Side.RIGHT) { + if (this._rtl && (position != St.Side.RIGHT)) borderMissingStyle = 'border-right: ' + borderWidth + 'px solid ' + borderColor.to_string() + ';'; - } else if (!this._rtl && position != St.Side.LEFT) { + else if (!this._rtl && (position != St.Side.LEFT)) borderMissingStyle = 'border-left: ' + borderWidth + 'px solid ' + borderColor.to_string() + ';'; - } - switch(position) { - case St.Side.LEFT: - borderInner = 'border-left'; - borderRadiusValue = '0 ' + borderRadius + 'px ' + borderRadius + 'px 0;'; - break; - case St.Side.RIGHT: - borderInner = 'border-right'; - borderRadiusValue = borderRadius + 'px 0 0 ' + borderRadius + 'px;'; - break; - case St.Side.TOP: - borderInner = 'border-top'; - borderRadiusValue = '0 0 ' + borderRadius + 'px ' + borderRadius + 'px;'; - break; - case St.Side.BOTTOM: - borderInner = 'border-bottom'; - borderRadiusValue = borderRadius + 'px ' + borderRadius + 'px 0 0;'; - break; + switch (position) { + case St.Side.LEFT: + borderInner = 'border-left'; + borderRadiusValue = '0 ' + borderRadius + 'px ' + borderRadius + 'px 0;'; + break; + case St.Side.RIGHT: + borderInner = 'border-right'; + borderRadiusValue = borderRadius + 'px 0 0 ' + borderRadius + 'px;'; + break; + case St.Side.TOP: + borderInner = 'border-top'; + borderRadiusValue = '0 0 ' + borderRadius + 'px ' + borderRadius + 'px;'; + break; + case St.Side.BOTTOM: + borderInner = 'border-bottom'; + borderRadiusValue = borderRadius + 'px ' + borderRadius + 'px 0 0;'; + break; } newStyle = borderInner + ': none;' + - 'border-radius: ' + borderRadiusValue + - borderMissingStyle ; + 'border-radius: ' + borderRadiusValue + + borderMissingStyle; - /* I do call set_style possibly twice so that only the background gets the transition. - * The transition-property css rules seems to be unsupported - */ + // I do call set_style possibly twice so that only the background gets the transition. + // The transition-property css rules seems to be unsupported this._dash._container.set_style(newStyle); } - /* Customize background */ - if ( this._settings.get_boolean('opaque-background') ) { + // Customize background + if (this._settings.get_boolean('opaque-background')) { newStyle = newStyle + 'background-color:'+ this._customizedBackground + '; ' + 'transition-delay: 0s; transition-duration: 0.250s;'; this._dash._container.set_style(newStyle); @@ -219,18 +205,14 @@ const ThemeManager = new Lang.Class({ }, _bindSettingsChanges: function() { - - let keys = ['opaque-background', - 'background-opacity', - 'apply-custom-theme', - 'custom-theme-shrink', - 'extend-height']; - - keys.forEach(function(key) { - this._settings.connect('changed::'+key, - Lang.bind(this, this.updateCustomTheme) - ); - }, this ); - + let keys = ['opaque-background', + 'background-opacity', + 'apply-custom-theme', + 'custom-theme-shrink', + 'extend-height']; + + keys.forEach(function(key) { + this._settings.connect('changed::' + key, Lang.bind(this, this.updateCustomTheme)); + }, this); } }); diff --git a/windows.js b/windows.js index d32441769..46f3c04c5 100644 --- a/windows.js +++ b/windows.js @@ -1,104 +1,132 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- const Shell = imports.gi.Shell; +const Gio = imports.gi.Gio; -let SETTINGS = { - 'sapir-claws-mail.desktop': ['Claws-mail'], - 'sapir-pidgin.desktop': ['Pidgin'] -}; +// Example settings: +let exampleSettings = [ + 'sapir-claws-mail.desktop Claws-mail', + 'sapir-pidgin.desktop Pidgin' +]; -function isWindowStealer(app) { - return SETTINGS[app.id] != null; +function getSettings(settings) { + let table = {}; + if (!settings.get_strv('window-stealing').length) { + settings.set_strv('window-stealing', exampleSettings); + Gio.Settings.sync(); + } + let array = settings.get_strv('window-stealing'); + for (let a in array) { + let entry = array[a].split(' '); + if (entry.length) { + let key = entry[0]; + entry.splice(0, 1); + table[key] = entry; + } + } + return table; } -function isStolen(app) { - return hasStolenWindows(app) && !getNonStolenWindows(app).length; +function isWindowStealer(app, settings) { + settings = getSettings(settings); + return settings[app.id] != null; } -function isStealingFrom(app, stolenApp) { - if (stolenApp !== null) { - let windows = stolenApp.get_windows(); - for (let w in windows) { - if (isStealingWindow(app, windows[w])) { - return true; - } - } - } - return false; +function isStolen(app, settings) { + return hasStolenWindows(app, settings) && !getNonStolenWindows(app, settings).length; } -function isStolenWindow(window) { - let clazz = window.wm_class; - for (let id in SETTINGS) { - let classesToSteal = SETTINGS[id]; - for (let i in classesToSteal) { - if (clazz == classesToSteal[i]) { - return true; - } - } - } - return false; +function isStealingFrom(app, stolenApp, settings) { + if (stolenApp !== null) { + let windows = stolenApp.get_windows(); + for (let w in windows) { + if (isStealingWindow(app, windows[w], settings)) { + return true; + } + } + } + return false; } -function isStealingWindow(app, window) { - let classesToSteal = SETTINGS[app.id]; - if (classesToSteal) { - let clazz = window.wm_class; - for (let c in classesToSteal) { - if (classesToSteal[c] == clazz) { - return true; - } - } - } - return false; +function isStolenWindow(window, settings) { + settings = getSettings(settings); + let clazz = window.wm_class; + for (let id in settings) { + let classesToSteal = settings[id]; + for (let i in classesToSteal) { + if (clazz == classesToSteal[i]) { + return true; + } + } + } + return false; } -function hasStolenWindows(app) { - let windows = app.get_windows(); - for (let w in windows) { - if (isStolenWindow(windows[w])) { - return true; - } - } - return false; +function isStealingWindow(app, window, settings) { + settings = getSettings(settings); + let classesToSteal = settings[app.id]; + if (classesToSteal) { + let clazz = window.wm_class; + for (let c in classesToSteal) { + if (classesToSteal[c] == clazz) { + return true; + } + } + } + return false; } -function getStolenWindows(app) { - return app.get_windows().filter(function(w) { - return isStolenWindow(w); - }); +function hasStolenWindows(app, settings) { + let windows = app.get_windows(); + for (let w in windows) { + if (isStolenWindow(windows[w], settings)) { + return true; + } + } + return false; } -function getNonStolenWindows(app) { - return app.get_windows().filter(function(w) { - return !isStolenWindow(w); - }); +function getStolenWindows(app, settings) { + return app.get_windows().filter(function(w) { + return isStolenWindow(w, settings); + }); +} + +function getNonStolenWindows(app, settings) { + return app.get_windows().filter(function(w) { + return !isStolenWindow(w, settings); + }); } -// Includes stolen windows -function getAllWindows(app) { - let windows = app.get_windows(); - let classesToSteal = SETTINGS[app.id]; - if (classesToSteal) { - let running = Shell.AppSystem.get_default().get_running(); - running.forEach(function(r) { - r.get_windows().forEach(function(window) { - let clazz = window.wm_class; - for (let c in classesToSteal) { - if (classesToSteal[c] == clazz) { - windows.push(window); - } - } - }); - }); - } - return windows; +/** + * Includes stolen windows + */ +function getAllWindows(app, settings) { + settings = getSettings(settings); + let windows = app.get_windows(); + let classesToSteal = settings[app.id]; + if (classesToSteal) { + let running = Shell.AppSystem.get_default().get_running(); + running.forEach(function(r) { + r.get_windows().forEach(function(window) { + let clazz = window.wm_class; + for (let c in classesToSteal) { + if (classesToSteal[c] == clazz) { + windows.push(window); + } + } + }); + }); + } + return windows; } -// Filter out unnecessary windows, for instance -// nautilus desktop window. -function getInterestingWindows(app) { - return getAllWindows(app).filter(function(w) { +/** + * Filter out unnecessary windows, for instance + * nautilus desktop window. + */ +function getInterestingWindows(app, settings) { + return getAllWindows(app, settings).filter(function(w) { return !w.skip_taskbar; }); } From 4ef94fb60af9eda01386967e90f280122dc6b39b Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Sun, 27 Mar 2016 04:19:02 -0500 Subject: [PATCH 03/11] Window stealing settings --- convenience.js | 5 +- dash.js | 28 +++++------ docking.js | 15 +++--- extension.js | 4 +- icons.js | 60 +++++++++++------------- intellihide.js | 5 +- prefs.js | 7 +-- theming.js | 20 +------- windows.js | 125 +++++++++++++++++++++++++++++++++++++++++++++++-- 9 files changed, 183 insertions(+), 86 deletions(-) diff --git a/convenience.js b/convenience.js index 632591633..16f939c40 100644 --- a/convenience.js +++ b/convenience.js @@ -6,13 +6,14 @@ */ const Gettext = imports.gettext; -const Gio = imports.gi.Gio; -const Clutter = imports.gi.Clutter; const Lang = imports.lang; const Config = imports.misc.config; const ExtensionUtils = imports.misc.extensionUtils; +const Clutter = imports.gi.Clutter; +const Gio = imports.gi.Gio; + /** * initTranslations: * @domain: (optional): the gettext domain to use diff --git a/dash.js b/dash.js index 12e2f7516..524a339dc 100644 --- a/dash.js +++ b/dash.js @@ -1,26 +1,25 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +const Lang = imports.lang; +const Mainloop = imports.mainloop; +const Signals = imports.signals; + const Clutter = imports.gi.Clutter; const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const Gtk = imports.gi.Gtk; -const Signals = imports.signals; -const Lang = imports.lang; const Meta = imports.gi.Meta; const Shell = imports.gi.Shell; const St = imports.gi.St; -const Mainloop = imports.mainloop; -const AppDisplay = imports.ui.appDisplay; const AppFavorites = imports.ui.appFavorites; const Dash = imports.ui.dash; const DND = imports.ui.dnd; -const IconGrid = imports.ui.iconGrid; const Main = imports.ui.main; const PopupMenu = imports.ui.popupMenu; const Tweener = imports.ui.tweener; + const Util = imports.misc.util; -const Workspace = imports.ui.workspace; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; @@ -324,6 +323,8 @@ const MyDash = new Lang.Class({ 'item-drag-cancelled', Lang.bind(this, this._onDragCancelled) ]); + + this._windowStealingChangedId = this._dtdSettings.connect('changed::window-stealing', Lang.bind(this, this._redisplay)); }, destroy: function() { @@ -702,8 +703,7 @@ const MyDash = new Lang.Class({ // Don't animate the icon size change when the overview // is transitioning, or when initially filling // the dash - if (Main.overview.animationInProgress || - !this._shownInitially) + if (Main.overview.animationInProgress || !this._shownInitially) continue; let [targetWidth, targetHeight] = icon.icon.get_size(); @@ -713,12 +713,12 @@ const MyDash = new Lang.Class({ icon.icon.set_size(icon.icon.width * scale, icon.icon.height * scale); - Tweener.addTween(icon.icon, - { width: targetWidth, - height: targetHeight, - time: DASH_ANIMATION_TIME, - transition: 'easeOutQuad', - }); + Tweener.addTween(icon.icon, { + width: targetWidth, + height: targetHeight, + time: DASH_ANIMATION_TIME, + transition: 'easeOutQuad', + }); } }, diff --git a/docking.js b/docking.js index a72faf42a..432a7a88a 100644 --- a/docking.js +++ b/docking.js @@ -1,27 +1,26 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +const Lang = imports.lang; +const Mainloop = imports.mainloop; +const Signals = imports.signals; + const Clutter = imports.gi.Clutter; const GLib = imports.gi.GLib; const Gtk = imports.gi.Gtk; -const Lang = imports.lang; const Meta = imports.gi.Meta; const Shell = imports.gi.Shell; const St = imports.gi.St; -const Mainloop = imports.mainloop; -const Params = imports.misc.params; const Main = imports.ui.main; -const Dash = imports.ui.dash; const IconGrid = imports.ui.iconGrid; -const Overview = imports.ui.overview; const OverviewControls = imports.ui.overviewControls; const PointerWatcher = imports.ui.pointerWatcher; const Tweener = imports.ui.tweener; -const Signals = imports.signals; const ViewSelector = imports.ui.viewSelector; -const WorkspaceSwitcherPopup= imports.ui.workspaceSwitcherPopup; +const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup; const Layout = imports.ui.layout; -const LayoutManager = imports.ui.main.layoutManager; + +const Params = imports.misc.params; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; diff --git a/extension.js b/extension.js index 34498a9f8..d14981d86 100644 --- a/extension.js +++ b/extension.js @@ -1,11 +1,11 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +const Main = imports.ui.main; + const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; const Docking = Me.imports.docking; -const Main = imports.ui.main; - let settings; let dock; let oldDash; diff --git a/icons.js b/icons.js index f037852dc..e98b2f6ca 100644 --- a/icons.js +++ b/icons.js @@ -1,26 +1,21 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -const Clutter = imports.gi.Clutter; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const Gtk = imports.gi.Gtk; -const Signals = imports.signals; const Lang = imports.lang; +const Mainloop = imports.mainloop; +const Signals = imports.signals; + +const Clutter = imports.gi.Clutter; const Meta = imports.gi.Meta; const Shell = imports.gi.Shell; const St = imports.gi.St; -const Mainloop = imports.mainloop; const AppDisplay = imports.ui.appDisplay; -const AppFavorites = imports.ui.appFavorites; const Dash = imports.ui.dash; -const DND = imports.ui.dnd; -const IconGrid = imports.ui.iconGrid; const Main = imports.ui.main; const PopupMenu = imports.ui.popupMenu; const Tweener = imports.ui.tweener; + const Util = imports.misc.util; -const Workspace = imports.ui.workspace; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; @@ -30,7 +25,7 @@ let tracker = Shell.WindowTracker.get_default(); let DASH_ITEM_LABEL_SHOW_TIME = Dash.DASH_ITEM_LABEL_SHOW_TIME; -const clickAction = { +const ClickAction = { SKIP: 0, MINIMIZE: 1, LAUNCH: 2, @@ -53,12 +48,15 @@ let recentlyClickedAppIndex = 0; * - Add a .focused style to the focused app * - Customize click actions. * - Update minimization animation target + * - Support configurable "window stealing" */ const MyAppIcon = new Lang.Class({ Name: 'DashToDock.AppIcon', Extends: AppDisplay.AppIcon, - // settings are required inside. + /** + * Settings are required inside. + */ _init: function(settings, app, iconParams, onActivateOverride) { this._dtdSettings = settings; this._nWindows = 0; @@ -72,12 +70,8 @@ const MyAppIcon = new Lang.Class({ this._stateChangedId = 0; } - this._stateChangedId = this.app.connect('windows-changed', - Lang.bind(this, - this.onWindowsChanged)); - this._focuseAppChangeId = tracker.connect('notify::focus-app', - Lang.bind(this, - this._onFocusAppChanged)); + this._stateChangedId = this.app.connect('windows-changed', Lang.bind(this, this.onWindowsChanged)); + this._focusAppChangeId = tracker.connect('notify::focus-app', Lang.bind(this, this._onFocusAppChanged)); this._dots = null; @@ -99,9 +93,9 @@ const MyAppIcon = new Lang.Class({ this.parent(); // Disconect global signals - // stateChangedId is already handled by parent) - if (this._focusAppId > 0) - tracker.disconnect(this._focusAppId); + // (stateChangedId is already handled by parent) + if (this._focusAppChangeId > 0) + tracker.disconnect(this._focusAppChangeId); }, onWindowsChanged: function() { @@ -125,6 +119,7 @@ const MyAppIcon = new Lang.Class({ if (Windows.isStolen(this.app, this._dtdSettings)) { // Hide stolen app icon if (this.actor.child) { + // TODO: if settings changed, how do we recreate the child? this.actor.child.destroy(); this.actor.child = null; } @@ -260,24 +255,24 @@ const MyAppIcon = new Lang.Class({ minimizeWindow(this.app, event.get_click_count() > 1, this._dtdSettings); } else if (isFocused && !Main.overview._shown) { - if (this._dtdSettings.get_enum('click-action') == clickAction.CYCLE_WINDOWS) + if (this._dtdSettings.get_enum('click-action') == ClickAction.CYCLE_WINDOWS) cycleThroughWindows(this.app, this._dtdSettings); - else if (this._dtdSettings.get_enum('click-action') == clickAction.MINIMIZE) + else if (this._dtdSettings.get_enum('click-action') == ClickAction.MINIMIZE) minimizeWindow(this.app, true, this._dtdSettings); - else if (this._dtdSettings.get_enum('click-action') == clickAction.LAUNCH) + else if (this._dtdSettings.get_enum('click-action') == ClickAction.LAUNCH) this.app.open_new_window(-1); } else { // Activate all window of the app or only le last used - if (this._dtdSettings.get_enum('click-action') == clickAction.CYCLE_WINDOWS && !Main.overview._shown) { + if (this._dtdSettings.get_enum('click-action') == ClickAction.CYCLE_WINDOWS && !Main.overview._shown) { // If click cycles through windows I can activate one windows at a time let windows = Windows.getInterestingWindows(this.app, this._dtdSettings); let w = windows[0]; Main.activateWindow(w); } - else if (this._dtdSettings.get_enum('click-action') == clickAction.LAUNCH) + else if (this._dtdSettings.get_enum('click-action') == ClickAction.LAUNCH) this.app.open_new_window(-1); - else if (this._dtdSettings.get_enum('click-action') == clickAction.MINIMIZE) { + else if (this._dtdSettings.get_enum('click-action') == ClickAction.MINIMIZE) { // If click minimizes all, then one expects all windows to be reshown activateAllWindows(this.app, this._dtdSettings); } @@ -396,7 +391,7 @@ function minimizeWindow(app, param, settings) { w.minimize(); // Just minimize one window. By specification it should be the // focused window on the current workspace. - if(!param) + if (!param) break; } } @@ -431,7 +426,7 @@ function activateAllWindows(app, settings) { function cycleThroughWindows(app, settings) { // Store for a little amount of time last clicked app and its windows // since the order changes upon window interaction - let MEMORY_TIME=3000; + const MEMORY_TIME = 3000; let app_windows = Windows.getInterestingWindows(app, settings); @@ -459,8 +454,8 @@ function cycleThroughWindows(app, settings) { function resetRecentlyClickedApp() { if (recentlyClickedAppLoopId > 0) Mainloop.source_remove(recentlyClickedAppLoopId); - recentlyClickedAppLoopId=0; - recentlyClickedApp =null; + recentlyClickedAppLoopId = 0; + recentlyClickedApp = null; recentlyClickedAppWindows = null; recentlyClickedAppIndex = 0; @@ -509,7 +504,8 @@ const MyAppIconMenu = new Lang.Class({ this._appendSeparator(); this._stealWindowsMenuItem = this._appendMenuItem(_('Steal Windows')); this._stealWindowsMenuItem.connect('activate', Lang.bind(this, function() { - //global.log('>>>>>>>>>>>> ' + r); + let dialog = new Windows.WindowStealingSettings(this._source.app, this._dtdSettings); + dialog.open(); })); // quit menu diff --git a/intellihide.js b/intellihide.js index a27504d96..dd9e52461 100644 --- a/intellihide.js +++ b/intellihide.js @@ -1,13 +1,14 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -const GLib = imports.gi.GLib; const Lang = imports.lang; const Mainloop = imports.mainloop; +const Signals = imports.signals; + +const GLib = imports.gi.GLib; const Meta = imports.gi.Meta; const Shell = imports.gi.Shell; const Main = imports.ui.main; -const Signals = imports.signals; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; diff --git a/prefs.js b/prefs.js index 08a6b9e15..a836d0b6c 100644 --- a/prefs.js +++ b/prefs.js @@ -1,12 +1,13 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +const Lang = imports.lang; +const Mainloop = imports.mainloop; + const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const GObject = imports.gi.GObject; const Gtk = imports.gi.Gtk; const Gdk = imports.gi.Gdk; -const Lang = imports.lang; -const Mainloop = imports.mainloop; const Gettext = imports.gettext.domain('dashtodock'); const _ = Gettext.gettext; @@ -17,7 +18,7 @@ const Me = ExtensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; const SCALE_UPDATE_TIMEOUT = 500; -const DEFAULT_ICONS_SIZES = [ 128, 96, 64, 48, 32, 24, 16 ]; +const DEFAULT_ICONS_SIZES = [128, 96, 64, 48, 32, 24, 16]; /** * This function was copied from the activities-config extension diff --git a/theming.js b/theming.js index 49eb3ff41..95bc9fb23 100644 --- a/theming.js +++ b/theming.js @@ -1,31 +1,13 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -const Clutter = imports.gi.Clutter; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const Gtk = imports.gi.Gtk; -const Signals = imports.signals; const Lang = imports.lang; -const Meta = imports.gi.Meta; -const Shell = imports.gi.Shell; + const St = imports.gi.St; -const Mainloop = imports.mainloop; -const AppDisplay = imports.ui.appDisplay; -const AppFavorites = imports.ui.appFavorites; -const Dash = imports.ui.dash; -const DND = imports.ui.dnd; -const IconGrid = imports.ui.iconGrid; const Main = imports.ui.main; -const PopupMenu = imports.ui.popupMenu; -const Tweener = imports.ui.tweener; -const Util = imports.misc.util; -const Workspace = imports.ui.workspace; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; -const Icons = Me.imports.icons; -const Windows = Me.imports.windows; /** * Manage theme customization and custom theme support diff --git a/windows.js b/windows.js index 46f3c04c5..8e413b8c3 100644 --- a/windows.js +++ b/windows.js @@ -1,7 +1,13 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -const Shell = imports.gi.Shell; +const Lang = imports.lang; + +const Clutter = imports.gi.Clutter; const Gio = imports.gi.Gio; +const Shell = imports.gi.Shell; +const St = imports.gi.St; + +const ModalDialog = imports.ui.modalDialog; // Example settings: let exampleSettings = [ @@ -11,11 +17,15 @@ let exampleSettings = [ function getSettings(settings) { let table = {}; - if (!settings.get_strv('window-stealing').length) { - settings.set_strv('window-stealing', exampleSettings); + + let array = settings.get_strv('window-stealing') || []; + + if ((array == null) || !array.length) { + array = exampleSettings; + settings.set_strv('window-stealing', array); Gio.Settings.sync(); } - let array = settings.get_strv('window-stealing'); + for (let a in array) { let entry = array[a].split(' '); if (entry.length) { @@ -130,3 +140,110 @@ function getInterestingWindows(app, settings) { return !w.skip_taskbar; }); } + +/** + * Window stealing settings + */ +const WindowStealingSettings = new Lang.Class({ + Name: 'DashToDock.WindowStealingSettings', + Extends: ModalDialog.ModalDialog, + + _init: function(app, settings) { + this.parent(); + + this._app = app; + this._dtdSettings = settings; + + let value = ''; + + let array = this._dtdSettings.get_strv('window-stealing') || []; + for (let a in array) { + let entry = array[a].split(' ', 2); + if (entry.length == 2) { + if (this._app.id == entry[0]) { + value = entry[1]; + break; + } + } + } + + let mainContentBox = new St.BoxLayout({vertical: false}); + this.contentLayout.add(mainContentBox, { + x_fill: true, + y_fill: true + }); + + let messageBox = new St.BoxLayout({vertical: true}); + mainContentBox.add(messageBox, { + expand: true, + y_align: St.Align.START + }); + + let appIdLabel = new St.Label({text: _('App ID: ') + app.id}); + messageBox.add(appIdLabel, { + expand: true, + x_fill: true, + x_align: St.Align.MIDDLE + }); + + let wmClassLabel = new St.Label({text: _('Space-separated list of WM_CLASS names')}); + messageBox.add(wmClassLabel, { + }); + + this._entry = new St.Entry({can_focus: true}); + this._entry.set_text(value); + messageBox.add(this._entry, { + }); + this.setInitialKeyFocus(this._entry.clutter_text); + + this._cancelButton = this.addButton({ + label: _('Cancel'), + action: Lang.bind(this, this._onCancel), + key: Clutter.Escape + }, { + expand: true + }); + + this._okButton = this.addButton({ + label: _('Save'), + action: Lang.bind(this, this._onSave), + key: Clutter.Escape + }, { + expand: false, + x_fill: false, + x_align: St.Align.END + }); + }, + + _onCancel: function() { + this.close(); + }, + + _onSave: function() { + let value = this._entry.get_text(); + global.log('>>>>>>>>>> ' + value); + value = this._app.id + ' ' + value; + + let array = this._dtdSettings.get_strv('window-stealing') || []; + let found = false; + for (let a in array) { + let entry = array[a].split(' ', 2); + if (entry.length == 2) { + if (this._app.id == entry[0]) { + array[a] = value; + found = true; + break; + } + } + } + + if (!found) { + array.push(value); + } + + this._dtdSettings.set_strv('window-stealing', array); + Gio.Settings.sync(); + + this.close(); + } +}); From befc8aff796cb8c2c2b16e2b58a71b76b8877e04 Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Sun, 27 Mar 2016 04:38:49 -0500 Subject: [PATCH 04/11] Add support-window-stealing flag to prefs --- Settings.ui | 42 +++++++++++++++++++ dash.js | 1 + icons.js | 14 ++++--- prefs.js | 6 ++- ....shell.extensions.dash-to-dock.gschema.xml | 4 ++ windows.js | 5 ++- 6 files changed, 64 insertions(+), 8 deletions(-) diff --git a/Settings.ui b/Settings.ui index 0368601e9..8da32c1f1 100644 --- a/Settings.ui +++ b/Settings.ui @@ -937,6 +937,48 @@ + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + + + 1 + 0 + + + + + True + False + True + 0 + Support window stealing + + + 0 + 0 + + + + + + diff --git a/dash.js b/dash.js index 524a339dc..8547fdd5e 100644 --- a/dash.js +++ b/dash.js @@ -324,6 +324,7 @@ const MyDash = new Lang.Class({ Lang.bind(this, this._onDragCancelled) ]); + this._supportWindowStealingChangedId = this._dtdSettings.connect('changed::support-window-stealing', Lang.bind(this, this._redisplay)); this._windowStealingChangedId = this._dtdSettings.connect('changed::window-stealing', Lang.bind(this, this._redisplay)); }, diff --git a/icons.js b/icons.js index e98b2f6ca..4f6e170f3 100644 --- a/icons.js +++ b/icons.js @@ -501,12 +501,14 @@ const MyAppIconMenu = new Lang.Class({ this.parent(); // steal windows menu - this._appendSeparator(); - this._stealWindowsMenuItem = this._appendMenuItem(_('Steal Windows')); - this._stealWindowsMenuItem.connect('activate', Lang.bind(this, function() { - let dialog = new Windows.WindowStealingSettings(this._source.app, this._dtdSettings); - dialog.open(); - })); + if (this._dtdSettings.get_boolean('support-window-stealing')) { + this._appendSeparator(); + this._stealWindowsMenuItem = this._appendMenuItem(_('Steal Windows')); + this._stealWindowsMenuItem.connect('activate', Lang.bind(this, function() { + let dialog = new Windows.WindowStealingSettings(this._source.app, this._dtdSettings); + dialog.open(); + })); + } // quit menu let app = this._source.app; diff --git a/prefs.js b/prefs.js index a836d0b6c..14c2994da 100644 --- a/prefs.js +++ b/prefs.js @@ -320,13 +320,17 @@ const Settings = new Lang.Class({ this._builder.get_object('application_button_animation_button'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('support-window-stealing', + this._builder.get_object('support_window_stealing_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); this._builder.get_object('click_action_combo').set_active(this._settings.get_enum('click-action')); this._builder.get_object('click_action_combo').connect('changed', Lang.bind (this, function(widget) { this._settings.set_enum('click-action', widget.get_active()); })); - this._builder.get_object('shift_click_action_combo').set_active(this._settings.get_boolean('minimize-shift')?1:0); + this._builder.get_object('shift_click_action_combo').set_active(this._settings.get_boolean('minimize-shift') ? 1 : 0); this._builder.get_object('shift_click_action_combo').connect('changed', Lang.bind (this, function(widget) { this._settings.set_boolean('minimize-shift', widget.get_active()==1); diff --git a/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml index c8a8a4c76..ce35dcafc 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml @@ -191,6 +191,10 @@ true Activate only one window + + false + Support window stealing + [] Window stealing diff --git a/windows.js b/windows.js index 8e413b8c3..555904166 100644 --- a/windows.js +++ b/windows.js @@ -16,8 +16,11 @@ let exampleSettings = [ ]; function getSettings(settings) { - let table = {}; + if (!settings.get_boolean('support-window-stealing')) + return {}; + let table = {}; + let array = settings.get_strv('window-stealing') || []; if ((array == null) || !array.length) { From 77cd6c1703893c6bc082125c17147a202996b382 Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Sun, 27 Mar 2016 14:06:48 -0500 Subject: [PATCH 05/11] Improve window stealing dialog --- docking.js | 124 +++++++++++++++++++-------------------- intellihide.js | 6 +- prefs.js | 153 +++++++++++++++++++++++++------------------------ theming.js | 18 +++--- windows.js | 124 +++++++++++++++++++++++++-------------- 5 files changed, 233 insertions(+), 192 deletions(-) diff --git a/docking.js b/docking.js index 432a7a88a..e1f729f38 100644 --- a/docking.js +++ b/docking.js @@ -187,7 +187,7 @@ const DockedDash = new Lang.Class({ this._rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL); // Load settings - this._settings = settings; + this._dtdSettings = settings; this._bindSettingsChanges(); this._position = Convenience.getPosition(settings); @@ -203,7 +203,7 @@ const DockedDash = new Lang.Class({ this._fixedIsEnabled = null; // Create intellihide object to monitor windows overlapping - this._intellihide = new Intellihide.Intellihide(this._settings); + this._intellihide = new Intellihide.Intellihide(this._dtdSettings); // initialize dock state this._dockState = State.HIDDEN; @@ -233,7 +233,7 @@ const DockedDash = new Lang.Class({ this._dockDwellTimeoutId = 0 // Create a new dash object - this.dash = new MyDash.MyDash(this._settings); + this.dash = new MyDash.MyDash(this._dtdSettings); // set stored icon size to the new dash Main.overview.dashIconSize = this.dash.iconSize; @@ -241,7 +241,7 @@ const DockedDash = new Lang.Class({ // connect app icon into the view selector this.dash.showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled)); - if (!this._settings.get_boolean('show-show-apps-button')) + if (!this._dtdSettings.get_boolean('show-show-apps-button')) this.dash.hideShowAppsButton(); // Create the main actor and the containers for sliding in and out and @@ -352,7 +352,7 @@ const DockedDash = new Lang.Class({ ]); this._injectionsHandler = new Convenience.InjectionsHandler(); - this._themeManager = new Theming.ThemeManager(this._settings, this.actor, this.dash); + this._themeManager = new Theming.ThemeManager(this._dtdSettings, this.actor, this.dash); // Since the actor is not a topLevel child and its parent is now not added to the Chrome, // the allocation change of the parent container (slide in and slideout) doesn't trigger @@ -421,7 +421,7 @@ const DockedDash = new Lang.Class({ // Keep the dash below the modalDialogGroup Main.layoutManager.uiGroup.set_child_below_sibling(this.actor,Main.layoutManager.modalDialogGroup); - if (this._settings.get_boolean('dock-fixed')) + if (this._dtdSettings.get_boolean('dock-fixed')) Main.layoutManager._trackActor(this._box, {affectsStruts: true, trackFullscreen: true}); // pretend this._slider is isToplevel child so that fullscreen is actually tracked @@ -438,7 +438,7 @@ const DockedDash = new Lang.Class({ this._paintId=0; } - this.dash.setIconSize(this._settings.get_int('dash-max-icon-size'), true); + this.dash.setIconSize(this._dtdSettings.get_int('dash-max-icon-size'), true); // Apply custome css class according to the settings this._themeManager.updateCustomTheme(); @@ -508,40 +508,40 @@ const DockedDash = new Lang.Class({ }, _bindSettingsChanges: function() { - this._settings.connect('changed::scroll-switch-workspace', Lang.bind(this, function() { - this._optionalScrollWorkspaceSwitch(this._settings.get_boolean('scroll-switch-workspace')); + this._dtdSettings.connect('changed::scroll-switch-workspace', Lang.bind(this, function() { + this._optionalScrollWorkspaceSwitch(this._dtdSettings.get_boolean('scroll-switch-workspace')); })); - this._settings.connect('changed::dash-max-icon-size', Lang.bind(this, function() { - this.dash.setIconSize(this._settings.get_int('dash-max-icon-size')); + this._dtdSettings.connect('changed::dash-max-icon-size', Lang.bind(this, function() { + this.dash.setIconSize(this._dtdSettings.get_int('dash-max-icon-size')); })); - this._settings.connect('changed::icon-size-fixed', Lang.bind(this, function() { - this.dash.setIconSize(this._settings.get_int('dash-max-icon-size')); + this._dtdSettings.connect('changed::icon-size-fixed', Lang.bind(this, function() { + this.dash.setIconSize(this._dtdSettings.get_int('dash-max-icon-size')); })); - this._settings.connect('changed::show-favorites', Lang.bind(this, function() { + this._dtdSettings.connect('changed::show-favorites', Lang.bind(this, function() { this.dash.resetAppIcons(); })); - this._settings.connect('changed::show-running', Lang.bind(this, function() { + this._dtdSettings.connect('changed::show-running', Lang.bind(this, function() { this.dash.resetAppIcons(); })); - this._settings.connect('changed::show-apps-at-top', Lang.bind(this, function() { + this._dtdSettings.connect('changed::show-apps-at-top', Lang.bind(this, function() { this.dash.resetAppIcons(); })); - this._settings.connect('changed::show-show-apps-button', Lang.bind(this, function() { - if (this._settings.get_boolean('show-show-apps-button')) + this._dtdSettings.connect('changed::show-show-apps-button', Lang.bind(this, function() { + if (this._dtdSettings.get_boolean('show-show-apps-button')) this.dash.showShowAppsButton(); else this.dash.hideShowAppsButton(); })); - this._settings.connect('changed::dock-fixed', Lang.bind(this, function() { + this._dtdSettings.connect('changed::dock-fixed', Lang.bind(this, function() { - if (this._settings.get_boolean('dock-fixed')) + if (this._dtdSettings.get_boolean('dock-fixed')) Main.layoutManager._trackActor(this._box, {affectsStruts: true, trackFullscreen: true}); else Main.layoutManager._untrackActor(this._box); @@ -554,20 +554,20 @@ const DockedDash = new Lang.Class({ this._updateVisibilityMode(); })); - this._settings.connect('changed::intellihide', Lang.bind(this, this._updateVisibilityMode)); + this._dtdSettings.connect('changed::intellihide', Lang.bind(this, this._updateVisibilityMode)); - this._settings.connect('changed::intellihide-mode', Lang.bind(this, function() { + this._dtdSettings.connect('changed::intellihide-mode', Lang.bind(this, function() { this._intellihide.forceUpdate(); })); - this._settings.connect('changed::autohide', Lang.bind(this, function() { + this._dtdSettings.connect('changed::autohide', Lang.bind(this, function() { this._updateVisibilityMode(); this._updateBarrier(); })); - this._settings.connect('changed::extend-height', Lang.bind(this,this._resetPosition)); - this._settings.connect('changed::preferred-monitor', Lang.bind(this,this._resetPosition)); - this._settings.connect('changed::height-fraction', Lang.bind(this,this._resetPosition)); - this._settings.connect('changed::require-pressure-to-show', Lang.bind(this,function() { + this._dtdSettings.connect('changed::extend-height', Lang.bind(this,this._resetPosition)); + this._dtdSettings.connect('changed::preferred-monitor', Lang.bind(this,this._resetPosition)); + this._dtdSettings.connect('changed::height-fraction', Lang.bind(this,this._resetPosition)); + this._dtdSettings.connect('changed::require-pressure-to-show', Lang.bind(this,function() { // Remove pointer watcher if (this._dockWatch) { PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch); @@ -576,7 +576,7 @@ const DockedDash = new Lang.Class({ this._setupDockDwellIfNeeded(); this._updateBarrier(); })); - this._settings.connect('changed::pressure-threshold', Lang.bind(this,function() { + this._dtdSettings.connect('changed::pressure-threshold', Lang.bind(this,function() { this._updatePressureBarrier(); this._updateBarrier(); })); @@ -587,15 +587,15 @@ const DockedDash = new Lang.Class({ * This is call when visibility settings change */ _updateVisibilityMode: function() { - if (this._settings.get_boolean('dock-fixed')) { + if (this._dtdSettings.get_boolean('dock-fixed')) { this._fixedIsEnabled = true; this._autohideIsEnabled = false; this._intellihideIsEnabled = false; } else { this._fixedIsEnabled = false; - this._autohideIsEnabled = this._settings.get_boolean('autohide') - this._intellihideIsEnabled = this._settings.get_boolean('intellihide') + this._autohideIsEnabled = this._dtdSettings.get_boolean('autohide') + this._intellihideIsEnabled = this._dtdSettings.get_boolean('intellihide') } if (this._intellihideIsEnabled) @@ -620,19 +620,19 @@ const DockedDash = new Lang.Class({ if (this._fixedIsEnabled) { this._removeAnimations(); - this._animateIn(this._settings.get_double('animation-time'), 0); + this._animateIn(this._dtdSettings.get_double('animation-time'), 0); } else if (this._intellihideIsEnabled) { if (this._intellihide.getOverlapStatus()) { this._ignoreHover = false; // Do not hide if autohide is enabled and mouse is hover if (!this._box.hover || !this._autohideIsEnabled) - this._animateOut(this._settings.get_double('animation-time'), 0); + this._animateOut(this._dtdSettings.get_double('animation-time'), 0); } else { this._ignoreHover = true; this._removeAnimations(); - this._animateIn(this._settings.get_double('animation-time'), 0); + this._animateIn(this._dtdSettings.get_double('animation-time'), 0); } } else { @@ -641,12 +641,12 @@ const DockedDash = new Lang.Class({ global.sync_pointer(); if (this._box.hover) - this._animateIn(this._settings.get_double('animation-time'), 0); + this._animateIn(this._dtdSettings.get_double('animation-time'), 0); else - this._animateOut(this._settings.get_double('animation-time'), 0); + this._animateOut(this._dtdSettings.get_double('animation-time'), 0); } else - this._animateOut(this._settings.get_double('animation-time'), 0); + this._animateOut(this._dtdSettings.get_double('animation-time'), 0); } }, @@ -654,7 +654,7 @@ const DockedDash = new Lang.Class({ this._ignoreHover = true; this._intellihide.disable(); this._removeAnimations(); - this._animateIn(this._settings.get_double('animation-time'), 0); + this._animateIn(this._dtdSettings.get_double('animation-time'), 0); }, _onOverviewHiding: function() { @@ -684,7 +684,7 @@ const DockedDash = new Lang.Class({ this._removeAnimations(); this.emit('showing'); - this._animateIn(this._settings.get_double('animation-time'), 0); + this._animateIn(this._dtdSettings.get_double('animation-time'), 0); } }, @@ -697,12 +697,12 @@ const DockedDash = new Lang.Class({ //if a show already started, let it finish; queue hide without removing the show. // to obtain this I increase the delay to avoid the overlap and interference // between the animations - delay = this._settings.get_double('hide-delay') + this._settings.get_double('animation-time'); + delay = this._dtdSettings.get_double('hide-delay') + this._dtdSettings.get_double('animation-time'); else - delay = this._settings.get_double('hide-delay'); + delay = this._dtdSettings.get_double('hide-delay'); this.emit('hiding'); - this._animateOut(this._settings.get_double('animation-time'), delay); + this._animateOut(this._dtdSettings.get_double('animation-time'), delay); } }, @@ -746,7 +746,7 @@ const DockedDash = new Lang.Class({ _setupDockDwellIfNeeded: function() { // If we don't have extended barrier features, then we need // to support the old tray dwelling mechanism. - if (!global.display.supports_extended_barriers() || !this._settings.get_boolean('require-pressure-to-show')) { + if (!global.display.supports_extended_barriers() || !this._dtdSettings.get_boolean('require-pressure-to-show')) { let pointerWatcher = PointerWatcher.getPointerWatcher(); this._dockWatch = pointerWatcher.addWatch(DOCK_DWELL_CHECK_INTERVAL, Lang.bind(this, this._checkDockDwell)); this._dockDwelling = false; @@ -783,7 +783,7 @@ const DockedDash = new Lang.Class({ let focusWindow = global.display.focus_window; this._dockDwellUserTime = focusWindow ? focusWindow.user_time : 0; - this._dockDwellTimeoutId = Mainloop.timeout_add(this._settings.get_double('show-delay') * 1000, + this._dockDwellTimeoutId = Mainloop.timeout_add(this._dtdSettings.get_double('show-delay') * 1000, Lang.bind(this, this._dockDwellTimeout)); GLib.Source.set_name_by_id(this._dockDwellTimeoutId, '[dash-to-dock] this._dockDwellTimeout'); } @@ -805,7 +805,7 @@ const DockedDash = new Lang.Class({ _dockDwellTimeout: function() { this._dockDwellTimeoutId = 0; - if (!this._settings.get_boolean('autohide-in-fullscreen') && this._monitor.inFullscreen) + if (!this._dtdSettings.get_boolean('autohide-in-fullscreen') && this._monitor.inFullscreen) return GLib.SOURCE_REMOVE; // We don't want to open the tray when a modal dialog @@ -828,7 +828,7 @@ const DockedDash = new Lang.Class({ _updatePressureBarrier: function() { this._canUsePressure = global.display.supports_extended_barriers(); - let pressureThreshold = this._settings.get_double('pressure-threshold'); + let pressureThreshold = this._dtdSettings.get_double('pressure-threshold'); // Remove existing pressure barrier if (this._pressureBarrier) { @@ -843,10 +843,10 @@ const DockedDash = new Lang.Class({ // Create new pressure barrier based on pressure threshold setting if (this._canUsePressure) { - this._pressureBarrier = new Layout.PressureBarrier(pressureThreshold, this._settings.get_double('show-delay')*1000, + this._pressureBarrier = new Layout.PressureBarrier(pressureThreshold, this._dtdSettings.get_double('show-delay')*1000, Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW); this._pressureBarrier.connect('trigger', Lang.bind(this, function(barrier) { - if (!this._settings.get_boolean('autohide-in-fullscreen') && this._monitor.inFullscreen) + if (!this._dtdSettings.get_boolean('autohide-in-fullscreen') && this._monitor.inFullscreen) return; this._onPressureSensed(); })); @@ -901,7 +901,7 @@ const DockedDash = new Lang.Class({ // Create new barrier // Note: dash in fixed position doesn't use pressure barrier - if (this._canUsePressure && this._autohideIsEnabled && this._settings.get_boolean('require-pressure-to-show')) { + if (this._canUsePressure && this._autohideIsEnabled && this._dtdSettings.get_boolean('require-pressure-to-show')) { let x1, x2, y1, y2, direction; if (this._position == St.Side.LEFT) { @@ -955,8 +955,8 @@ const DockedDash = new Lang.Class({ // Ensure variables linked to settings are updated. this._updateVisibilityMode(); - let monitorIndex = this._settings.get_int('preferred-monitor'); - let extendHeight = this._settings.get_boolean('extend-height'); + let monitorIndex = this._dtdSettings.get_int('preferred-monitor'); + let extendHeight = this._dtdSettings.get_boolean('extend-height'); if ((monitorIndex > 0) && (monitorIndex < Main.layoutManager.monitors.length)) this._monitor = Main.layoutManager.monitors[monitorIndex]; @@ -978,7 +978,7 @@ const DockedDash = new Lang.Class({ // No space is required in the overview of the dash this._dashSpacer.hide(); - let fraction = this._settings.get_double('height-fraction'); + let fraction = this._dtdSettings.get_double('height-fraction'); if (extendHeight) fraction = 1; @@ -1050,7 +1050,7 @@ const DockedDash = new Lang.Class({ _adjustLegacyTray: function() { let use_work_area = true; - if (this._fixedIsEnabled && !this._settings.get_boolean('extend-height') + if (this._fixedIsEnabled && !this._dtdSettings.get_boolean('extend-height') && this._isPrimaryMonitor() && ((this._position == St.Side.BOTTOM) || (this._position == St.Side.LEFT))) use_work_area = false; @@ -1087,7 +1087,7 @@ const DockedDash = new Lang.Class({ * Adjust Panel corners */ _adjustPanelCorners: function() { - let extendHeight = this._settings.get_boolean('extend-height'); + let extendHeight = this._dtdSettings.get_boolean('extend-height'); if (!this._isHorizontal && this._isPrimaryMonitor() && extendHeight && this._fixedIsEnabled) { Main.panel._rightCorner.actor.hide(); Main.panel._leftCorner.actor.hide(); @@ -1111,7 +1111,7 @@ const DockedDash = new Lang.Class({ Main.layoutManager.uiGroup.set_child_above_sibling(this.actor, global.top_window_group); this._oldignoreHover = this._ignoreHover; this._ignoreHover = true; - this._animateIn(this._settings.get_double('animation-time'), 0); + this._animateIn(this._dtdSettings.get_double('animation-time'), 0); }, _onDragEnd: function() { @@ -1131,9 +1131,9 @@ const DockedDash = new Lang.Class({ activePage == ViewSelector.ViewPage.APPS); if (dashVisible) - this._animateIn(this._settings.get_double('animation-time'), 0); + this._animateIn(this._dtdSettings.get_double('animation-time'), 0); else - this._animateOut(this._settings.get_double('animation-time'), 0); + this._animateOut(this._dtdSettings.get_double('animation-time'), 0); }, _onPageEmpty: function() { @@ -1162,7 +1162,7 @@ const DockedDash = new Lang.Class({ */ _onAccessibilityFocus: function() { this._box.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); - this._animateIn(this._settings.get_double('animation-time'), 0); + this._animateIn(this._dtdSettings.get_double('animation-time'), 0); }, _onShowAppsButtonToggled: function() { @@ -1172,7 +1172,7 @@ const DockedDash = new Lang.Class({ // status (due to the _syncShowAppsButtonToggled function below) and it // has already performed the desired action. - let animate = this._settings.get_boolean('animate-show-apps'); + let animate = this._dtdSettings.get_boolean('animate-show-apps'); let selector = Main.overview.viewSelector; if (selector._showAppsButton.checked !== this.dash.showAppsButton.checked) { @@ -1277,14 +1277,14 @@ const DockedDash = new Lang.Class({ _optionalScrollWorkspaceSwitch: function() { let label = 'optionalScrollWorkspaceSwitch'; - this._settings.connect('changed::scroll-switch-workspace', Lang.bind(this, function() { - if (this._settings.get_boolean('scroll-switch-workspace')) + this._dtdSettings.connect('changed::scroll-switch-workspace', Lang.bind(this, function() { + if (this._dtdSettings.get_boolean('scroll-switch-workspace')) Lang.bind(this, enable)(); else Lang.bind(this, disable)(); })); - if (this._settings.get_boolean('scroll-switch-workspace')) + if (this._dtdSettings.get_boolean('scroll-switch-workspace')) Lang.bind(this, enable)(); function enable() { diff --git a/intellihide.js b/intellihide.js index dd9e52461..63832cf2d 100644 --- a/intellihide.js +++ b/intellihide.js @@ -51,7 +51,7 @@ const Intellihide = new Lang.Class({ _init: function(settings) { // Load settings - this._settings = settings; + this._dtdSettings = settings; this._signalsHandler = new Convenience.GlobalSignalsHandler(); this._tracker = Shell.WindowTracker.get_default(); @@ -199,7 +199,7 @@ const Intellihide = new Lang.Class({ * select a window in the secondary monitor. */ - let monitorIndex = this._settings.get_int('preferred-monitor'); + let monitorIndex = this._dtdSettings.get_int('preferred-monitor'); if ((monitorIndex < 0) || (monitorIndex > Main.layoutManager.monitors.length)) monitorIndex = Main.layoutManager.primaryIndex; @@ -259,7 +259,7 @@ const Intellihide = new Lang.Class({ let wksp_index = wksp.index(); // Depending on the intellihide mode, exclude non-relevent windows - switch (this._settings.get_enum('intellihide-mode')) { + switch (this._dtdSettings.get_enum('intellihide-mode')) { case IntellihideMode.ALL_WINDOWS: // Do nothing break; diff --git a/prefs.js b/prefs.js index 14c2994da..27aba4efe 100644 --- a/prefs.js +++ b/prefs.js @@ -56,7 +56,7 @@ const Settings = new Lang.Class({ Name: 'DashToDock.Settings', _init: function() { - this._settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-dock'); + this._dtdSettings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-dock'); this._rtl = (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL); @@ -93,7 +93,7 @@ const Settings = new Lang.Class({ let n_monitors = Gdk.Screen.get_default().get_n_monitors(); let primary_monitor = Gdk.Screen.get_default().get_primary_monitor(); - let monitor = this._settings.get_int('preferred-monitor'); + let monitor = this._dtdSettings.get_int('preferred-monitor'); // Add primary monitor with index 0, because in GNOME Shell the primary monitor is always 0 this._builder.get_object('dock_monitor_combo').append_text(_('Primary monitor')); @@ -118,7 +118,7 @@ const Settings = new Lang.Class({ this._builder.get_object('dock_monitor_combo').set_active(this._monitors.indexOf(monitor)); // Position option - let position = this._settings.get_enum('dock-position'); + let position = this._dtdSettings.get_enum('dock-position'); switch (position) { case 0: @@ -142,56 +142,58 @@ const Settings = new Lang.Class({ } // Intelligent autohide options - this._settings.bind('dock-fixed', + this._dtdSettings.bind('dock-fixed', this._builder.get_object('intelligent_autohide_switch'), 'active', Gio.SettingsBindFlags.INVERT_BOOLEAN); - this._settings.bind('dock-fixed', + this._dtdSettings.bind('dock-fixed', this._builder.get_object('intelligent_autohide_button'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN); - this._settings.bind('autohide', + this._dtdSettings.bind('autohide', this._builder.get_object('autohide_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('autohide-in-fullscreen', + this._dtdSettings.bind('autohide-in-fullscreen', this._builder.get_object('autohide_enable_in_fullscreen_checkbutton'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('require-pressure-to-show', + this._dtdSettings.bind('require-pressure-to-show', this._builder.get_object('require_pressure_checkbutton'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('intellihide', + this._dtdSettings.bind('intellihide', this._builder.get_object('intellihide_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('animation-time', + this._dtdSettings.bind('animation-time', this._builder.get_object('animation_duration_spinbutton'), 'value', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('hide-delay', + this._dtdSettings.bind('hide-delay', this._builder.get_object('hide_timeout_spinbutton'), 'value', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-delay', + this._dtdSettings.bind('show-delay', this._builder.get_object('show_timeout_spinbutton'), 'value', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('pressure-threshold', + this._dtdSettings.bind('pressure-threshold', this._builder.get_object('pressure_threshold_spinbutton'), 'value', Gio.SettingsBindFlags.DEFAULT); - //this._builder.get_object('animation_duration_spinbutton').set_value(this._settings.get_double('animation-time')); + //this._builder.get_object('animation_duration_spinbutton').set_value(this._dtdSettings.get_double('animation-time')); // Create dialog for intelligent autohide advanced settings this._builder.get_object('intelligent_autohide_button').connect('clicked', Lang.bind(this, function() { - let dialog = new Gtk.Dialog({ title: _('Intelligent autohide customization'), - transient_for: this.widget.get_toplevel(), - use_header_bar: true, - modal: true }); + let dialog = new Gtk.Dialog({ + title: _('Intelligent autohide customization'), + transient_for: this.widget.get_toplevel(), + use_header_bar: true, + modal: true + }); // GTK+ leaves positive values for application-defined response ids. // Use +1 for the reset action @@ -200,7 +202,7 @@ const Settings = new Lang.Class({ let box = this._builder.get_object('intelligent_autohide_advanced_settings_box'); dialog.get_content_area().add(box); - this._settings.bind('intellihide', + this._dtdSettings.bind('intellihide', this._builder.get_object('intellihide_mode_box'), 'sensitive', Gio.SettingsBindFlags.GET); @@ -213,31 +215,31 @@ const Settings = new Lang.Class({ this._builder.get_object('maximized_windows_radio_button') ]; - intellihideModeRadioButtons[this._settings.get_enum('intellihide-mode')].set_active(true); + intellihideModeRadioButtons[this._dtdSettings.get_enum('intellihide-mode')].set_active(true); - this._settings.bind('autohide', + this._dtdSettings.bind('autohide', this._builder.get_object('require_pressure_checkbutton'), 'sensitive', Gio.SettingsBindFlags.GET); - this._settings.bind('autohide', + this._dtdSettings.bind('autohide', this._builder.get_object('autohide_enable_in_fullscreen_checkbutton'), 'sensitive', Gio.SettingsBindFlags.GET); - this._settings.bind('require-pressure-to-show', + this._dtdSettings.bind('require-pressure-to-show', this._builder.get_object('show_timeout_spinbutton'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN); - this._settings.bind('require-pressure-to-show', + this._dtdSettings.bind('require-pressure-to-show', this._builder.get_object('show_timeout_label'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN); - this._settings.bind('require-pressure-to-show', + this._dtdSettings.bind('require-pressure-to-show', this._builder.get_object('pressure_threshold_spinbutton'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('require-pressure-to-show', + this._dtdSettings.bind('require-pressure-to-show', this._builder.get_object('pressure_threshold_label'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); @@ -248,10 +250,11 @@ const Settings = new Lang.Class({ let keys = ['intellihide', 'autohide', 'intellihide-mode', 'autohide-in-fullscreen', 'require-pressure-to-show', 'animation-time', 'show-delay', 'hide-delay', 'pressure-threshold']; keys.forEach(function(val) { - this._settings.set_value(val, this._settings.get_default_value(val)); + this._dtdSettings.set_value(val, this._dtdSettings.get_default_value(val)); }, this); - intellihideModeRadioButtons[this._settings.get_enum('intellihide-mode')].set_active(true); - } else { + intellihideModeRadioButtons[this._dtdSettings.get_enum('intellihide-mode')].set_active(true); + } + else { // remove the settings box so it doesn't get destroyed; dialog.get_content_area().remove(box); dialog.destroy(); @@ -264,11 +267,11 @@ const Settings = new Lang.Class({ })); // size options - this._builder.get_object('dock_size_scale').set_value(this._settings.get_double('height-fraction')); + this._builder.get_object('dock_size_scale').set_value(this._dtdSettings.get_double('height-fraction')); this._builder.get_object('dock_size_scale').add_mark(0.9, Gtk.PositionType.TOP, null); let icon_size_scale = this._builder.get_object('icon_size_scale'); - icon_size_scale.set_range(DEFAULT_ICONS_SIZES[DEFAULT_ICONS_SIZES.length -1], DEFAULT_ICONS_SIZES[0]); - icon_size_scale.set_value(this._settings.get_int('dash-max-icon-size')); + icon_size_scale.set_range(DEFAULT_ICONS_SIZES[DEFAULT_ICONS_SIZES.length - 1], DEFAULT_ICONS_SIZES[0]); + icon_size_scale.set_value(this._dtdSettings.get_int('dash-max-icon-size')); DEFAULT_ICONS_SIZES.forEach(function(val) { icon_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); }); @@ -285,70 +288,70 @@ const Settings = new Lang.Class({ icon_size_scale.set_inverted(true); } - this._settings.bind('icon-size-fixed', this._builder.get_object('icon_size_fixed_checkbutton'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('extend-height', this._builder.get_object('dock_size_extend_checkbutton'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('extend-height', this._builder.get_object('dock_size_scale'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN); + this._dtdSettings.bind('icon-size-fixed', this._builder.get_object('icon_size_fixed_checkbutton'), 'active', Gio.SettingsBindFlags.DEFAULT); + this._dtdSettings.bind('extend-height', this._builder.get_object('dock_size_extend_checkbutton'), 'active', Gio.SettingsBindFlags.DEFAULT); + this._dtdSettings.bind('extend-height', this._builder.get_object('dock_size_scale'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN); // Behavior panel - this._settings.bind('show-running', + this._dtdSettings.bind('show-running', this._builder.get_object('show_running_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-favorites', + this._dtdSettings.bind('show-favorites', this._builder.get_object('show_favorite_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-show-apps-button', + this._dtdSettings.bind('show-show-apps-button', this._builder.get_object('show_applications_button_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-apps-at-top', + this._dtdSettings.bind('show-apps-at-top', this._builder.get_object('application_button_first_button'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-show-apps-button', + this._dtdSettings.bind('show-show-apps-button', this._builder.get_object('application_button_first_button'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('animate-show-apps', + this._dtdSettings.bind('animate-show-apps', this._builder.get_object('application_button_animation_button'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-show-apps-button', + this._dtdSettings.bind('show-show-apps-button', this._builder.get_object('application_button_animation_button'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('support-window-stealing', + this._dtdSettings.bind('support-window-stealing', this._builder.get_object('support_window_stealing_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._builder.get_object('click_action_combo').set_active(this._settings.get_enum('click-action')); + this._builder.get_object('click_action_combo').set_active(this._dtdSettings.get_enum('click-action')); this._builder.get_object('click_action_combo').connect('changed', Lang.bind (this, function(widget) { - this._settings.set_enum('click-action', widget.get_active()); + this._dtdSettings.set_enum('click-action', widget.get_active()); })); - this._builder.get_object('shift_click_action_combo').set_active(this._settings.get_boolean('minimize-shift') ? 1 : 0); + this._builder.get_object('shift_click_action_combo').set_active(this._dtdSettings.get_boolean('minimize-shift') ? 1 : 0); this._builder.get_object('shift_click_action_combo').connect('changed', Lang.bind (this, function(widget) { - this._settings.set_boolean('minimize-shift', widget.get_active()==1); + this._dtdSettings.set_boolean('minimize-shift', widget.get_active() == 1); })); - this._settings.bind('scroll-switch-workspace', this._builder.get_object('switch_workspace_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); + this._dtdSettings.bind('scroll-switch-workspace', this._builder.get_object('switch_workspace_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); // Appearance Panel - this._settings.bind('apply-custom-theme', this._builder.get_object('customize_theme'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN | Gio.SettingsBindFlags.GET); - this._settings.bind('apply-custom-theme', this._builder.get_object('builtin_theme_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('custom-theme-shrink', this._builder.get_object('shrink_dash_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); + this._dtdSettings.bind('apply-custom-theme', this._builder.get_object('customize_theme'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN | Gio.SettingsBindFlags.GET); + this._dtdSettings.bind('apply-custom-theme', this._builder.get_object('builtin_theme_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); + this._dtdSettings.bind('custom-theme-shrink', this._builder.get_object('shrink_dash_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('custom-theme-running-dots', + this._dtdSettings.bind('custom-theme-running-dots', this._builder.get_object('running_dots_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('custom-theme-running-dots', + this._dtdSettings.bind('custom-theme-running-dots', this._builder.get_object('running_dots_advance_settings_button'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); @@ -364,36 +367,36 @@ const Settings = new Lang.Class({ let box = this._builder.get_object('running_dots_advance_settings_box'); dialog.get_content_area().add(box); - this._settings.bind('custom-theme-customize-running-dots', + this._dtdSettings.bind('custom-theme-customize-running-dots', this._builder.get_object('dot_style_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('custom-theme-customize-running-dots', + this._dtdSettings.bind('custom-theme-customize-running-dots', this._builder.get_object('dot_style_settings_box'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); let rgba = new Gdk.RGBA(); - rgba.parse(this._settings.get_string('custom-theme-running-dots-color')); + rgba.parse(this._dtdSettings.get_string('custom-theme-running-dots-color')); this._builder.get_object('dot_color_colorbutton').set_rgba(rgba); this._builder.get_object('dot_color_colorbutton').connect('notify::color', Lang.bind(this, function(button) { let rgba = button.get_rgba(); let css = rgba.to_string(); let hexString = cssHexString(css); - this._settings.set_string('custom-theme-running-dots-color', hexString); + this._dtdSettings.set_string('custom-theme-running-dots-color', hexString); })); - rgba.parse(this._settings.get_string('custom-theme-running-dots-border-color')); + rgba.parse(this._dtdSettings.get_string('custom-theme-running-dots-border-color')); this._builder.get_object('dot_border_color_colorbutton').set_rgba(rgba); this._builder.get_object('dot_border_color_colorbutton').connect('notify::color', Lang.bind(this, function(button) { let rgba = button.get_rgba(); let css = rgba.to_string(); let hexString = cssHexString(css); - this._settings.set_string('custom-theme-running-dots-border-color', hexString); + this._dtdSettings.set_string('custom-theme-running-dots-border-color', hexString); })); - this._settings.bind('custom-theme-running-dots-border-width', + this._dtdSettings.bind('custom-theme-running-dots-border-width', this._builder.get_object('dot_border_width_spin_button'), 'value', Gio.SettingsBindFlags.DEFAULT); @@ -410,9 +413,9 @@ const Settings = new Lang.Class({ })); - this._settings.bind('opaque-background', this._builder.get_object('customize_opacity_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._builder.get_object('custom_opacity_scale').set_value(this._settings.get_double('background-opacity')); - this._settings.bind('opaque-background', this._builder.get_object('custom_opacity'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); + this._dtdSettings.bind('opaque-background', this._builder.get_object('customize_opacity_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); + this._builder.get_object('custom_opacity_scale').set_value(this._dtdSettings.get_double('background-opacity')); + this._dtdSettings.bind('opaque-background', this._builder.get_object('custom_opacity'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); // About Panel @@ -424,31 +427,31 @@ const Settings = new Lang.Class({ */ _SignalHandler: { dock_display_combo_changed_cb: function(combo) { - this._settings.set_int('preferred-monitor', this._monitors[combo.get_active()]); + this._dtdSettings.set_int('preferred-monitor', this._monitors[combo.get_active()]); }, position_top_button_toggled_cb: function(button) { if (button.get_active()) - this._settings.set_enum('dock-position', 0); + this._dtdSettings.set_enum('dock-position', 0); }, position_right_button_toggled_cb: function(button) { if (button.get_active()) - this._settings.set_enum('dock-position', 1); + this._dtdSettings.set_enum('dock-position', 1); }, position_bottom_button_toggled_cb: function(button) { if (button.get_active()) - this._settings.set_enum('dock-position', 2); + this._dtdSettings.set_enum('dock-position', 2); }, position_left_button_toggled_cb: function(button) { if (button.get_active()) - this._settings.set_enum('dock-position', 3); + this._dtdSettings.set_enum('dock-position', 3); }, icon_size_combo_changed_cb: function(combo) { - this._settings.set_int('dash-max-icon-size', this._allIconSizes[combo.get_active()]); + this._dtdSettings.set_int('dash-max-icon-size', this._allIconSizes[combo.get_active()]); }, dock_size_scale_format_value_cb: function(scale, value) { @@ -461,7 +464,7 @@ const Settings = new Lang.Class({ Mainloop.source_remove(this._dock_size_timeout); this._dock_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { - this._settings.set_double('height-fraction', scale.get_value()); + this._dtdSettings.set_double('height-fraction', scale.get_value()); this._dock_size_timeout = 0; return GLib.SOURCE_REMOVE; })); @@ -477,7 +480,7 @@ const Settings = new Lang.Class({ Mainloop.source_remove(this._icon_size_timeout); this._icon_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { - this._settings.set_int('dash-max-icon-size', scale.get_value()); + this._dtdSettings.set_int('dash-max-icon-size', scale.get_value()); this._icon_size_timeout = 0; return GLib.SOURCE_REMOVE; })); @@ -489,7 +492,7 @@ const Settings = new Lang.Class({ Mainloop.source_remove(this._opacity_timeout); this._opacity_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { - this._settings.set_double('background-opacity', scale.get_value()); + this._dtdSettings.set_double('background-opacity', scale.get_value()); this._opacity_timeout = 0; return GLib.SOURCE_REMOVE; })); @@ -501,17 +504,17 @@ const Settings = new Lang.Class({ all_windows_radio_button_toggled_cb: function(button) { if (button.get_active()) - this._settings.set_enum('intellihide-mode', 0); + this._dtdSettings.set_enum('intellihide-mode', 0); }, focus_application_windows_radio_button_toggled_cb: function(button) { if (button.get_active()) - this._settings.set_enum('intellihide-mode', 1); + this._dtdSettings.set_enum('intellihide-mode', 1); }, maximized_windows_radio_button_toggled_cb: function(button) { if (button.get_active()) - this._settings.set_enum('intellihide-mode', 2); + this._dtdSettings.set_enum('intellihide-mode', 2); } } }); diff --git a/theming.js b/theming.js index 95bc9fb23..cbd3dd90f 100644 --- a/theming.js +++ b/theming.js @@ -16,7 +16,7 @@ const ThemeManager = new Lang.Class({ Name: 'DashToDock.ThemeManager', _init: function(settings, actor, dash) { - this._settings = settings; + this._dtdSettings = settings; this._bindSettingsChanges(); this._actor = actor; this._dash = dash; @@ -60,7 +60,7 @@ const ThemeManager = new Lang.Class({ }, _updateBackgroundOpacity: function() { - let newAlpha = this._settings.get_double('background-opacity'); + let newAlpha = this._dtdSettings.get_double('background-opacity'); this._defaultBackground = 'rgba(' + this._defaultBackgroundColor.red + ',' + @@ -92,12 +92,12 @@ const ThemeManager = new Lang.Class({ }, _updateCustomStyleClasses: function() { - if (this._settings.get_boolean('apply-custom-theme')) + if (this._dtdSettings.get_boolean('apply-custom-theme')) this._actor.add_style_class_name('dashtodock'); else this._actor.remove_style_class_name('dashtodock'); - if (this._settings.get_boolean('custom-theme-shrink')) + if (this._dtdSettings.get_boolean('custom-theme-shrink')) this._actor.add_style_class_name('shrink'); else this._actor.remove_style_class_name('shrink'); @@ -124,13 +124,13 @@ const ThemeManager = new Lang.Class({ this._dash._container.set_style(null); // If built-in theme is enabled do nothing else - if (this._settings.get_boolean('apply-custom-theme')) + if (this._dtdSettings.get_boolean('apply-custom-theme')) return; let newStyle = ''; - let position = Convenience.getPosition(this._settings); + let position = Convenience.getPosition(this._dtdSettings); - if (!this._settings.get_boolean('custom-theme-shrink')) { + if (!this._dtdSettings.get_boolean('custom-theme-shrink')) { // obtain theme border settings let themeNode = this._dash._container.get_theme_node(); let borderColor = themeNode.get_border_color(St.Side.TOP); @@ -179,7 +179,7 @@ const ThemeManager = new Lang.Class({ } // Customize background - if (this._settings.get_boolean('opaque-background')) { + if (this._dtdSettings.get_boolean('opaque-background')) { newStyle = newStyle + 'background-color:'+ this._customizedBackground + '; ' + 'transition-delay: 0s; transition-duration: 0.250s;'; this._dash._container.set_style(newStyle); @@ -194,7 +194,7 @@ const ThemeManager = new Lang.Class({ 'extend-height']; keys.forEach(function(key) { - this._settings.connect('changed::' + key, Lang.bind(this, this.updateCustomTheme)); + this._dtdSettings.connect('changed::' + key, Lang.bind(this, this.updateCustomTheme)); }, this); } }); diff --git a/windows.js b/windows.js index 555904166..43d61fd45 100644 --- a/windows.js +++ b/windows.js @@ -8,6 +8,7 @@ const Shell = imports.gi.Shell; const St = imports.gi.St; const ModalDialog = imports.ui.modalDialog; +const ShellEntry = imports.ui.shellEntry; // Example settings: let exampleSettings = [ @@ -152,7 +153,7 @@ const WindowStealingSettings = new Lang.Class({ Extends: ModalDialog.ModalDialog, _init: function(app, settings) { - this.parent(); + this.parent({styleClass: 'run-dialog'}); this._app = app; this._dtdSettings = settings; @@ -161,61 +162,72 @@ const WindowStealingSettings = new Lang.Class({ let array = this._dtdSettings.get_strv('window-stealing') || []; for (let a in array) { - let entry = array[a].split(' ', 2); - if (entry.length == 2) { - if (this._app.id == entry[0]) { - value = entry[1]; + let c = array[a].indexOf(' '); + if (c != -1) { + if (this._app.id == array[a].substring(0, c)) { + value = array[a].substring(c + 1); break; } } } - let mainContentBox = new St.BoxLayout({vertical: false}); + let mainContentBox = new St.BoxLayout({vertical: true}); this.contentLayout.add(mainContentBox, { x_fill: true, y_fill: true }); - let messageBox = new St.BoxLayout({vertical: true}); - mainContentBox.add(messageBox, { - expand: true, - y_align: St.Align.START + // Title + let appIdLabel = new St.Label({ + style_class: 'run-dialog-label', + text: _('Application ID: ') + app.id }); - - let appIdLabel = new St.Label({text: _('App ID: ') + app.id}); - messageBox.add(appIdLabel, { - expand: true, + mainContentBox.add(appIdLabel, { x_fill: true, x_align: St.Align.MIDDLE }); - let wmClassLabel = new St.Label({text: _('Space-separated list of WM_CLASS names')}); - messageBox.add(wmClassLabel, { + // Instructions + let wmClassLabel = new St.Label({ + style_class: 'run-dialog-label', + text: _('Enter space-separated list of WM_CLASS names to steal') + }); + mainContentBox.add(wmClassLabel, { + x_fill: false, + x_align: St.Align.START, + y_align: St.Align.START }); - this._entry = new St.Entry({can_focus: true}); + // Entry + this._entry = new St.Entry({ + style_class: 'run-dialog-entry', + can_focus: true + }); + ShellEntry.addContextMenu(this._entry); // adds copy/paste context menu this._entry.set_text(value); - messageBox.add(this._entry, { + mainContentBox.add(this._entry, { + y_align: St.Align.START }); this.setInitialKeyFocus(this._entry.clutter_text); + this._entry.clutter_text.connect('key-press-event', Lang.bind(this, function(owner, event) { + let symbol = event.get_key_symbol(); + if ((symbol == Clutter.Return) || (symbol == Clutter.KP_Enter)) { + this._onSave(); + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + })); - this._cancelButton = this.addButton({ + // Buttons + this.setButtons([{ label: _('Cancel'), action: Lang.bind(this, this._onCancel), key: Clutter.Escape }, { - expand: true - }); - - this._okButton = this.addButton({ label: _('Save'), action: Lang.bind(this, this._onSave), - key: Clutter.Escape - }, { - expand: false, - x_fill: false, - x_align: St.Align.END - }); + default: true + }]); }, _onCancel: function() { @@ -224,24 +236,50 @@ const WindowStealingSettings = new Lang.Class({ _onSave: function() { let value = this._entry.get_text(); - global.log('>>>>>>>>>> ' + value); - value = this._app.id + ' ' + value; - + + // Cleanup + value = value.split(' '); + for (let v in value) + value[v] = value[v].trim(); + value = value.join(' '); + let array = this._dtdSettings.get_strv('window-stealing') || []; - let found = false; - for (let a in array) { - let entry = array[a].split(' ', 2); - if (entry.length == 2) { - if (this._app.id == entry[0]) { - array[a] = value; - found = true; - break; + + if (value.length) { + value = this._app.id + ' ' + value; + + // Change + let found = false; + for (let a in array) { + let entry = array[a].split(' ', 2); + if (entry.length == 2) { + if (this._app.id == entry[0]) { + array[a] = value; + found = true; + global.log('Changing window stealing: ' + value); + break; + } } } + + // Add + if (!found) { + array.push(value); + global.log('Adding window stealing: ' + value); + } } - - if (!found) { - array.push(value); + else { + // Remove + for (let a in array) { + let entry = array[a].split(' ', 2); + if (entry.length == 2) { + if (this._app.id == entry[0]) { + array.splice(a, 1); + global.log('Removing window stealing: ' + this._app.id); + break; + } + } + } } this._dtdSettings.set_strv('window-stealing', array); From 2c35119b668d2312b28d9477efdae09a02269de8 Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Sun, 27 Mar 2016 14:37:39 -0500 Subject: [PATCH 06/11] Small style fix --- dash.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dash.js b/dash.js index 8547fdd5e..ffef02a37 100644 --- a/dash.js +++ b/dash.js @@ -64,7 +64,7 @@ const MyDashActor = new Lang.Class({ (this._position == St.Side.BOTTOM)); let layout = new Clutter.BoxLayout({ - orientation: this._isHorizontal?Clutter.Orientation.HORIZONTAL:Clutter.Orientation.VERTICAL + orientation: this._isHorizontal ? Clutter.Orientation.HORIZONTAL : Clutter.Orientation.VERTICAL }); this.actor = new Shell.GenericContainer({ From 7c5cd9d0b68f5b77e8b6831fe4ed6f9508af8b4f Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Sun, 27 Mar 2016 22:35:26 -0500 Subject: [PATCH 07/11] Fix makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ab19ca194..3e7c9ca9c 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ UUID = dash-to-dock@micxgx.gmail.com BASE_MODULES = extension.js stylesheet.css metadata.json COPYING README.md -EXTRA_MODULES = dockedDash.js intellihide.js myDash.js convenience.js prefs.js Settings.ui +EXTRA_MODULES = convenience.js dash.js docking.js icons.js intellihide.js prefs.js theming.js windows.js EXTRA_MEDIA = logo.svg -TOLOCALIZE = prefs.js +TOLOCALIZE = prefs.js MSGSRC = $(wildcard po/*.po) INSTALLBASE = ~/.local/share/gnome-shell/extensions INSTALLNAME = dash-to-dock@micxgx.gmail.com From 3b210a483b10dd95aeef707c80024e6f23450706 Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Sun, 27 Mar 2016 23:29:41 -0500 Subject: [PATCH 08/11] xgettext fixes --- Makefile | 2 +- dash.js | 2 +- docking.js | 2 +- icons.js | 8 ++++---- prefs.js | 24 +++++++++++++----------- windows.js | 8 ++++---- 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 3e7c9ca9c..32fa1ed78 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ UUID = dash-to-dock@micxgx.gmail.com BASE_MODULES = extension.js stylesheet.css metadata.json COPYING README.md EXTRA_MODULES = convenience.js dash.js docking.js icons.js intellihide.js prefs.js theming.js windows.js EXTRA_MEDIA = logo.svg -TOLOCALIZE = prefs.js +TOLOCALIZE = prefs.js dash.js docking.js windows.js icons.js MSGSRC = $(wildcard po/*.po) INSTALLBASE = ~/.local/share/gnome-shell/extensions INSTALLNAME = dash-to-dock@micxgx.gmail.com diff --git a/dash.js b/dash.js index ffef02a37..eb0e86199 100644 --- a/dash.js +++ b/dash.js @@ -82,7 +82,7 @@ const MyDashActor = new Lang.Class({ let side = Convenience.getPosition(settings); this.menu = new PopupMenu.PopupMenu(this.actor, 0.0, side, 0); this.menu.actor.add_style_class_name('panel-menu'); - let settingsMenuItem = new PopupMenu.PopupMenuItem('Dash to Dock ' + _('Settings')); + let settingsMenuItem = new PopupMenu.PopupMenuItem('Dash to Dock ' + _("Settings")); settingsMenuItem.connect('activate', Lang.bind(this, function() { Util.spawn(['gnome-shell-extension-prefs', Me.metadata.uuid]); })); diff --git a/docking.js b/docking.js index e1f729f38..a437bf1cd 100644 --- a/docking.js +++ b/docking.js @@ -370,7 +370,7 @@ const DockedDash = new Lang.Class({ // Restore dash accessibility Main.ctrlAltTabManager.addGroup( - this.dash.actor, _('Dash'), 'user-bookmarks-symbolic', + this.dash.actor, _("Dash"), 'user-bookmarks-symbolic', {focusCallback: Lang.bind(this, this._onAccessibilityFocus)}); // Load optional features diff --git a/icons.js b/icons.js index 4f6e170f3..1fc66ea3c 100644 --- a/icons.js +++ b/icons.js @@ -503,7 +503,7 @@ const MyAppIconMenu = new Lang.Class({ // steal windows menu if (this._dtdSettings.get_boolean('support-window-stealing')) { this._appendSeparator(); - this._stealWindowsMenuItem = this._appendMenuItem(_('Steal Windows')); + this._stealWindowsMenuItem = this._appendMenuItem(_("Steal Windows")); this._stealWindowsMenuItem.connect('activate', Lang.bind(this, function() { let dialog = new Windows.WindowStealingSettings(this._source.app, this._dtdSettings); dialog.open(); @@ -517,9 +517,9 @@ const MyAppIconMenu = new Lang.Class({ this._appendSeparator(); let quitFromDashMenuText = ''; if (count == 1) - quitFromDashMenuText = _('Quit'); + quitFromDashMenuText = _("Quit"); else - quitFromDashMenuText = _('Quit') + ' ' + count + ' ' + _('Windows'); + quitFromDashMenuText = _("Quit") + ' ' + count + ' ' + _("Windows"); this._quitfromDashMenuItem = this._appendMenuItem(quitFromDashMenuText); this._quitfromDashMenuItem.connect('activate', Lang.bind(this, function() { @@ -618,7 +618,7 @@ const MyShowAppsIconMenu = new Lang.Class({ _redisplay: function() { this.removeAll(); - let item = this._appendMenuItem('Dash to Dock ' + _('Settings')); + let item = this._appendMenuItem('Dash to Dock ' + _("Settings")); item.connect('activate', function () { Util.spawn(["gnome-shell-extension-prefs", Me.metadata.uuid]); diff --git a/prefs.js b/prefs.js index 27aba4efe..3bb430598 100644 --- a/prefs.js +++ b/prefs.js @@ -96,7 +96,7 @@ const Settings = new Lang.Class({ let monitor = this._dtdSettings.get_int('preferred-monitor'); // Add primary monitor with index 0, because in GNOME Shell the primary monitor is always 0 - this._builder.get_object('dock_monitor_combo').append_text(_('Primary monitor')); + this._builder.get_object('dock_monitor_combo').append_text(_("Primary monitor")); this._monitors.push(0); // Add connected monitors @@ -105,14 +105,14 @@ const Settings = new Lang.Class({ if (i !== primary_monitor) { ctr++; this._monitors.push(ctr); - this._builder.get_object('dock_monitor_combo').append_text(_('Secondary monitor ') + ctr); + this._builder.get_object('dock_monitor_combo').append_text(_("Secondary monitor") + ' ' + ctr); } } // If one of the external monitor is set as preferred, show it even if not attached if ((monitor >= n_monitors) && (monitor !== primary_monitor)) { this._monitors.push(monitor) - this._builder.get_object('dock_monitor_combo').append_text(_('Secondary monitor ') + ++ctr); + this._builder.get_object('dock_monitor_combo').append_text(_("Secondary monitor") + ' ' + ++ctr); } this._builder.get_object('dock_monitor_combo').set_active(this._monitors.indexOf(monitor)); @@ -137,8 +137,8 @@ const Settings = new Lang.Class({ if (this._rtl) { /* Left is Right in rtl as a setting */ - this._builder.get_object('position_left_button').set_label(_('Right')); - this._builder.get_object('position_right_button').set_label(_('Left')); + this._builder.get_object('position_left_button').set_label(_("Right")); + this._builder.get_object('position_right_button').set_label(_("Left")); } // Intelligent autohide options @@ -189,7 +189,7 @@ const Settings = new Lang.Class({ this._builder.get_object('intelligent_autohide_button').connect('clicked', Lang.bind(this, function() { let dialog = new Gtk.Dialog({ - title: _('Intelligent autohide customization'), + title: _("Intelligent autohide customization"), transient_for: this.widget.get_toplevel(), use_header_bar: true, modal: true @@ -197,7 +197,7 @@ const Settings = new Lang.Class({ // GTK+ leaves positive values for application-defined response ids. // Use +1 for the reset action - dialog.add_button(_('Reset to defaults'), 1); + dialog.add_button(_("Reset to defaults"), 1); let box = this._builder.get_object('intelligent_autohide_advanced_settings_box'); dialog.get_content_area().add(box); @@ -359,10 +359,12 @@ const Settings = new Lang.Class({ // Create dialog for running dots advanced settings this._builder.get_object('running_dots_advance_settings_button').connect('clicked', Lang.bind(this, function() { - let dialog = new Gtk.Dialog({ title: _('Customize running indicators'), - transient_for: this.widget.get_toplevel(), - use_header_bar: true, - modal: true }); + let dialog = new Gtk.Dialog({ + title: _("Customize running indicators"), + transient_for: this.widget.get_toplevel(), + use_header_bar: true, + modal: true + }); let box = this._builder.get_object('running_dots_advance_settings_box'); dialog.get_content_area().add(box); diff --git a/windows.js b/windows.js index 43d61fd45..97b9cf100 100644 --- a/windows.js +++ b/windows.js @@ -180,7 +180,7 @@ const WindowStealingSettings = new Lang.Class({ // Title let appIdLabel = new St.Label({ style_class: 'run-dialog-label', - text: _('Application ID: ') + app.id + text: _("Application ID") + ': ' + app.id }); mainContentBox.add(appIdLabel, { x_fill: true, @@ -190,7 +190,7 @@ const WindowStealingSettings = new Lang.Class({ // Instructions let wmClassLabel = new St.Label({ style_class: 'run-dialog-label', - text: _('Enter space-separated list of WM_CLASS names to steal') + text: _("Enter space-separated list of WM_CLASS names to steal") }); mainContentBox.add(wmClassLabel, { x_fill: false, @@ -220,11 +220,11 @@ const WindowStealingSettings = new Lang.Class({ // Buttons this.setButtons([{ - label: _('Cancel'), + label: _("Cancel"), action: Lang.bind(this, this._onCancel), key: Clutter.Escape }, { - label: _('Save'), + label: _("Save"), action: Lang.bind(this, this._onSave), default: true }]); From 21f234caae4a0919300dc993eabc8f7a36a567b1 Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Mon, 28 Mar 2016 00:38:15 -0500 Subject: [PATCH 09/11] Use pipes instead of spaces to separate WM_CLASS --- windows.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/windows.js b/windows.js index 97b9cf100..151581066 100644 --- a/windows.js +++ b/windows.js @@ -31,7 +31,7 @@ function getSettings(settings) { } for (let a in array) { - let entry = array[a].split(' '); + let entry = array[a].split('|'); if (entry.length) { let key = entry[0]; entry.splice(0, 1); @@ -162,7 +162,7 @@ const WindowStealingSettings = new Lang.Class({ let array = this._dtdSettings.get_strv('window-stealing') || []; for (let a in array) { - let c = array[a].indexOf(' '); + let c = array[a].indexOf('|'); if (c != -1) { if (this._app.id == array[a].substring(0, c)) { value = array[a].substring(c + 1); @@ -190,7 +190,7 @@ const WindowStealingSettings = new Lang.Class({ // Instructions let wmClassLabel = new St.Label({ style_class: 'run-dialog-label', - text: _("Enter space-separated list of WM_CLASS names to steal") + text: _("Enter pipe-separated list of WM_CLASS names to steal") }); mainContentBox.add(wmClassLabel, { x_fill: false, @@ -238,20 +238,20 @@ const WindowStealingSettings = new Lang.Class({ let value = this._entry.get_text(); // Cleanup - value = value.split(' '); + value = value.split('|'); for (let v in value) value[v] = value[v].trim(); - value = value.join(' '); + value = value.join('|'); let array = this._dtdSettings.get_strv('window-stealing') || []; if (value.length) { - value = this._app.id + ' ' + value; + value = this._app.id + '|' + value; // Change let found = false; for (let a in array) { - let entry = array[a].split(' ', 2); + let entry = array[a].split('|', 2); if (entry.length == 2) { if (this._app.id == entry[0]) { array[a] = value; @@ -271,7 +271,7 @@ const WindowStealingSettings = new Lang.Class({ else { // Remove for (let a in array) { - let entry = array[a].split(' ', 2); + let entry = array[a].split('|', 2); if (entry.length == 2) { if (this._app.id == entry[0]) { array.splice(a, 1); From eaaf24a8e1819739663d298379b3fb7cf2dcd4d0 Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Sun, 3 Apr 2016 18:30:40 -0500 Subject: [PATCH 10/11] Some fixes --- icons.js => appIcons.js | 2 +- dash.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) rename icons.js => appIcons.js (99%) diff --git a/icons.js b/appIcons.js similarity index 99% rename from icons.js rename to appIcons.js index 1fc66ea3c..1a4a6c0c3 100644 --- a/icons.js +++ b/appIcons.js @@ -112,7 +112,7 @@ const MyAppIcon = new Lang.Class({ // resulting in an error when assigned to the a rect. This is a more like // a workaround to prevent flooding the system with errors. if (this.actor.get_stage() == null) - return + return; let rect = new Meta.Rectangle(); diff --git a/dash.js b/dash.js index eb0e86199..9e8572cb5 100644 --- a/dash.js +++ b/dash.js @@ -23,7 +23,7 @@ const Util = imports.misc.util; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; -const Icons = Me.imports.icons; +const AppIcons = Me.imports.appIcons; const Windows = Me.imports.windows; let DASH_ANIMATION_TIME = Dash.DASH_ANIMATION_TIME; @@ -41,7 +41,7 @@ let DASH_ITEM_HOVER_TIMEOUT = Dash.DASH_ITEM_HOVER_TIMEOUT; */ function extendDashItemContainer(dashItemContainer, settings) { dashItemContainer._dtdSettings = settings; - dashItemContainer.showLabel = Icons.itemShowLabel; + dashItemContainer.showLabel = AppIcons.itemShowLabel; } /** @@ -244,7 +244,7 @@ const MyDash = new Lang.Class({ this._scrollView.add_actor(this._box); this._showAppsIcon = new Dash.ShowAppsIcon(); - Icons.extendShowAppsIcon(this._showAppsIcon, this._dtdSettings); + AppIcons.extendShowAppsIcon(this._showAppsIcon, this._dtdSettings); this._showAppsIcon.childScale = 1; this._showAppsIcon.childOpacity = 255; this._showAppsIcon.icon.setIconSize(this.iconSize); @@ -475,7 +475,7 @@ const MyDash = new Lang.Class({ }, _createAppItem: function(app) { - let appIcon = new Icons.MyAppIcon(this._dtdSettings, app, + let appIcon = new AppIcons.MyAppIcon(this._dtdSettings, app, { setSizeManually: true, showLabel: false }); if (appIcon._draggable) { From 41a99111dba928b50b0ab53be67bf8f648464aed Mon Sep 17 00:00:00 2001 From: Tal Liron Date: Tue, 12 Apr 2016 19:02:42 -0500 Subject: [PATCH 11/11] Fix windows iteration --- appIcons.js | 2 +- intellihide.js | 2 +- windows.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/appIcons.js b/appIcons.js index 1a4a6c0c3..b5677d90b 100644 --- a/appIcons.js +++ b/appIcons.js @@ -385,7 +385,7 @@ function minimizeWindow(app, param, settings) { // Param true make all app windows minimize let windows = Windows.getInterestingWindows(app, settings); let current_workspace = global.screen.get_active_workspace(); - for (let i = 0; i < windows.length; i++) { + for (let i = windows.length - 1; i >= 0; i--) { let w = windows[i]; if (w.get_workspace() == current_workspace && w.showing_on_its_workspace()) { w.minimize(); diff --git a/intellihide.js b/intellihide.js index 63832cf2d..331b91e27 100644 --- a/intellihide.js +++ b/intellihide.js @@ -220,7 +220,7 @@ const Intellihide = new Lang.Class({ windows = windows.filter(this._intellihideFilterInteresting, this); - for (let i in windows.length) { + for (let i = 0; i < windows.length; i++) { let win = windows[i].get_meta_window(); if (win) { let rect = win.get_frame_rect(); diff --git a/windows.js b/windows.js index 151581066..8ef295c29 100644 --- a/windows.js +++ b/windows.js @@ -53,7 +53,7 @@ function isStolen(app, settings) { function isStealingFrom(app, stolenApp, settings) { if (stolenApp !== null) { let windows = stolenApp.get_windows(); - for (let w in windows) { + for (let w = windows.length - 1; w >= 0; w--) { if (isStealingWindow(app, windows[w], settings)) { return true; } @@ -92,7 +92,7 @@ function isStealingWindow(app, window, settings) { function hasStolenWindows(app, settings) { let windows = app.get_windows(); - for (let w in windows) { + for (let w = windows.length - 1; w >= 0; w--) { if (isStolenWindow(windows[w], settings)) { return true; }