Compare commits
	
		
			3 Commits
		
	
	
		
			wip/exalm/
			...
			wip/media-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					60d87ef4ba | ||
| 
						 | 
					d886dc17e1 | ||
| 
						 | 
					9dd2a467ba | 
@@ -2325,3 +2325,17 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
    padding-bottom: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.osd-window {
 | 
			
		||||
    color: #ededed;
 | 
			
		||||
    background-color: rgba(33, 37, 38, 0.80);
 | 
			
		||||
    border-radius: 15px;
 | 
			
		||||
    text-shadow: 0 1px rgba(0, 0, 0, 0.75);
 | 
			
		||||
 | 
			
		||||
    padding: 40px;
 | 
			
		||||
    spacing: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.osd-progress-bar {
 | 
			
		||||
    height: 0.8em;
 | 
			
		||||
    border: 1px solid;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -100,6 +100,7 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/components/__init__.js		\
 | 
			
		||||
	ui/components/autorunManager.js		\
 | 
			
		||||
	ui/components/automountManager.js	\
 | 
			
		||||
	ui/components/mediaKeysManager.js	\
 | 
			
		||||
	ui/components/networkAgent.js		\
 | 
			
		||||
	ui/components/polkitAgent.js		\
 | 
			
		||||
	ui/components/recorder.js		\
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,9 @@ const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager
 | 
			
		||||
<method name='Suspend'>
 | 
			
		||||
    <arg type='b' direction='in'/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name='Hibernate'>
 | 
			
		||||
    <arg type='b' direction='in'/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name='CanPowerOff'>
 | 
			
		||||
    <arg type='s' direction='out'/>
 | 
			
		||||
</method>
 | 
			
		||||
@@ -26,6 +29,9 @@ const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager
 | 
			
		||||
<method name='CanSuspend'>
 | 
			
		||||
    <arg type='s' direction='out'/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name='CanHibernate'>
 | 
			
		||||
    <arg type='s' direction='out'/>
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session'>
 | 
			
		||||
@@ -140,6 +146,15 @@ const LoginManagerSystemd = new Lang.Class({
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    canHibernate: function(asyncCallback) {
 | 
			
		||||
        this._proxy.CanSuspendRemote(function(result, error) {
 | 
			
		||||
            if (error)
 | 
			
		||||
                asyncCallback(false);
 | 
			
		||||
            else
 | 
			
		||||
                asyncCallback(result[0] != 'no');
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    powerOff: function() {
 | 
			
		||||
        this._proxy.PowerOffRemote(true);
 | 
			
		||||
    },
 | 
			
		||||
@@ -150,6 +165,10 @@ const LoginManagerSystemd = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    suspend: function() {
 | 
			
		||||
        this._proxy.SuspendRemote(true);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hibernate: function() {
 | 
			
		||||
        this._proxy.HibernateRemote(true);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -215,6 +234,13 @@ const LoginManagerConsoleKit = new Lang.Class({
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    canHibernate: function(asyncCallback) {
 | 
			
		||||
        Mainloop.idle_add(Lang.bind(this, function() {
 | 
			
		||||
            asyncCallback(this._upClient.get_can_hibernate());
 | 
			
		||||
            return false;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    powerOff: function() {
 | 
			
		||||
        this._proxy.StopRemote();
 | 
			
		||||
    },
 | 
			
		||||
@@ -225,5 +251,9 @@ const LoginManagerConsoleKit = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    suspend: function() {
 | 
			
		||||
        this._upClient.suspend_sync(null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hibernate: function() {
 | 
			
		||||
        this._upClient.hibernate_sync(null);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -288,3 +288,31 @@ function insertSorted(array, val, cmp) {
 | 
			
		||||
 | 
			
		||||
    return pos;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * wrapKeybinding:
 | 
			
		||||
 *
 | 
			
		||||
 * Wrap a keybinding handler so that
 | 
			
		||||
 * it ignores an invocation if the shell is modal, but
 | 
			
		||||
 * not when the overview is active, or when global
 | 
			
		||||
 * keybindings are allowed by session mode.
 | 
			
		||||
 * This function is only useful for keybindings installed
 | 
			
		||||
 * with Meta.KeybindingFlags.HANDLE_WHEN_GRABBED
 | 
			
		||||
 */
 | 
			
		||||
function wrapKeybinding(handler, onlyInOverview) {
 | 
			
		||||
    return function() {
 | 
			
		||||
        let handle;
 | 
			
		||||
 | 
			
		||||
        if (onlyInOverview) {
 | 
			
		||||
            handle = Main.sessionMode.allowKeybindingsWhenModal ||
 | 
			
		||||
                Main.modalCount == (Main.overview.visible ? 1 : 0);
 | 
			
		||||
        } else {
 | 
			
		||||
            handle = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (handle)
 | 
			
		||||
            return handler.apply(this, arguments);
 | 
			
		||||
        else
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -199,7 +199,7 @@ const AltTabPopup = new Lang.Class({
 | 
			
		||||
        this.actor.get_allocation_box();
 | 
			
		||||
 | 
			
		||||
        // Make the initial selection
 | 
			
		||||
        if (binding == 'switch-group') {
 | 
			
		||||
        if (binding == 'internal-keybinding-switch-group') {
 | 
			
		||||
            if (backward) {
 | 
			
		||||
                this._select(0, this._appIcons[0].cachedWindows.length - 1);
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -208,9 +208,9 @@ const AltTabPopup = new Lang.Class({
 | 
			
		||||
                else
 | 
			
		||||
                    this._select(0, 0);
 | 
			
		||||
            }
 | 
			
		||||
        } else if (binding == 'switch-group-backward') {
 | 
			
		||||
        } else if (binding == 'internal-keybinding-switch-group-backward') {
 | 
			
		||||
            this._select(0, this._appIcons[0].cachedWindows.length - 1);
 | 
			
		||||
        } else if (binding == 'switch-windows-backward') {
 | 
			
		||||
        } else if (binding == 'internal-keybinding-switch-windows-backward') {
 | 
			
		||||
            this._select(this._appIcons.length - 1);
 | 
			
		||||
        } else if (this._appIcons.length == 1) {
 | 
			
		||||
            this._select(0);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										647
									
								
								js/ui/components/mediaKeysManager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										647
									
								
								js/ui/components/mediaKeysManager.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,647 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gdk = imports.gi.Gdk;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const ShellMountOperation  = imports.ui.shellMountOperation;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
const INTERFACE_SETTINGS = 'org.gnome.desktop.interface';
 | 
			
		||||
const POWER_SETTINGS = 'org.gnome.settings-daemon.plugins.power';
 | 
			
		||||
const XSETTINGS_SETTINGS = 'org.gnome.settings-daemon.plugins.xsettings';
 | 
			
		||||
const TOUCHPAD_SETTINGS = 'org.gnome.settings-daemon.peripherals.touchpad';
 | 
			
		||||
const KEYBINDING_SETTINGS = 'org.gnome.settings-daemon.plugins.media-keys';
 | 
			
		||||
const CUSTOM_KEYBINDING_SETTINGS = 'org.gnome.settings-daemon.plugins.media-keys.custom-keybinding';
 | 
			
		||||
const A11Y_SETTINGS = 'org.gnome.desktop.a11y.applications';
 | 
			
		||||
const MAGNIFIER_SETTINGS = 'org.gnome.desktop.a11y.magnifier';
 | 
			
		||||
const INPUT_SOURCE_SETTINGS = 'org.gnome.desktop.input-sources';
 | 
			
		||||
 | 
			
		||||
const MediaKeysInterface = <interface name='org.gnome.SettingsDaemon.MediaKeys'>
 | 
			
		||||
<method name='GrabMediaPlayerKeys'>
 | 
			
		||||
    <arg name='application' direction='in' type='s'/>
 | 
			
		||||
    <arg name='time' direction='in' type='u'/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name='ReleaseMediaPlayerKeys'>
 | 
			
		||||
    <arg name='application' direction='in' type='s'/>
 | 
			
		||||
</method>
 | 
			
		||||
<signal name='MediaPlayerKeyPressed'>
 | 
			
		||||
    <arg name='application' type='s'/>
 | 
			
		||||
    <arg name='key' type='s'/>
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
/* [ actionName, setting, hardcodedKeysym, overviewOnly, args ] */
 | 
			
		||||
/* (overviewOnly means that the keybinding is handled when the shell is not
 | 
			
		||||
   modal, or when the overview is active, but not when other modal operations
 | 
			
		||||
   are active; otherwise the keybinding is always handled) */
 | 
			
		||||
const DEFAULT_KEYBINDINGS = [
 | 
			
		||||
    [ 'doTouchpadToggle', null, 'XF86TouchpadToggle', false ],
 | 
			
		||||
    [ 'doTouchpadSet', null, 'XF86TouchpadOn', false, [ true ] ],
 | 
			
		||||
    [ 'doTouchpadSet', null, 'XF86TouchpadOff', false, [ false ] ],
 | 
			
		||||
    [ 'doMute', 'volume-mute', null, false, [ false ] ],
 | 
			
		||||
    [ 'doVolumeAdjust', 'volume-down', null, false, [ Clutter.ScrollDirection.DOWN, false ] ],
 | 
			
		||||
    [ 'doVolumeAdjust', 'volume-up', null, false, [ Clutter.ScrollDirection.UP, false ] ],
 | 
			
		||||
    [ 'doMute', null, '<Alt>XF86AudioMute', false, [ true ] ],
 | 
			
		||||
    [ 'doVolumeAdjust', null, '<Alt>XF86AudioLowerVolume', false, [ Clutter.ScrollDirection.DOWN, true ] ],
 | 
			
		||||
    [ 'doVolumeAdjust', null, '<Alt>XF86AudioRaiseVolume', false, [ Clutter.ScrollDirection.UP, true ] ],
 | 
			
		||||
    [ 'doLogout', 'logout', null, true ],
 | 
			
		||||
    [ 'doEject', 'eject', null, false ],
 | 
			
		||||
    [ 'doHome', 'home', null, true ],
 | 
			
		||||
    [ 'doLaunchMimeHandler', 'media', null, true, [ 'application/x-vorbis+ogg' ] ],
 | 
			
		||||
    [ 'doLaunchApp', 'calculator', null, true, [ 'gcalcltool.desktop' ] ],
 | 
			
		||||
    [ 'doLaunchApp', 'search', null, true, [ 'tracker-needle.desktop' ] ],
 | 
			
		||||
    [ 'doLaunchMimeHandler', 'email', null, true, [ 'x-scheme-handler/mailto' ] ],
 | 
			
		||||
    [ 'doScreensaver', 'screensaver', null, true ],
 | 
			
		||||
    [ 'doScreensaver', null, 'XF86ScreenSaver', true ],
 | 
			
		||||
    [ 'doLaunchApp', 'help', null, true, [ 'yelp.desktop' ] ],
 | 
			
		||||
    [ 'doSpawn', 'screenshot', null, true, [ ['gnome-screenshot'] ] ],
 | 
			
		||||
    [ 'doSpawn', 'window-screenshot', null, true, [ ['gnome-screenshot', '--window'] ] ],
 | 
			
		||||
    [ 'doSpawn', 'area-screenshot', null, true, [ ['gnome-screenshot', '--area'] ] ],
 | 
			
		||||
    [ 'doSpawn', 'screenshot-clip', null, true, [ ['gnome-screenshot', '--clipboard'] ] ],
 | 
			
		||||
    [ 'doSpawn', 'window-screenshot-clip', null, true, [ ['gnome-screenshot', '--window', '--clipboard'] ] ],
 | 
			
		||||
    [ 'doSpawn', 'area-screenshot-clip', null, true, [ ['gnome-screenshot', '--area', '--clipboard'] ] ],
 | 
			
		||||
    [ 'doLaunchMimeHandler', 'www', null, true, [ 'x-scheme-handler/http' ] ],
 | 
			
		||||
    [ 'doMediaKey', 'play', null, true, [ 'Play' ] ],
 | 
			
		||||
    [ 'doMediaKey', 'pause', null, true, [ 'Pause' ] ],
 | 
			
		||||
    [ 'doMediaKey', 'stop', null, true, [ 'Stop' ] ],
 | 
			
		||||
    [ 'doMediaKey', 'previous', null, true, [ 'Previous' ] ],
 | 
			
		||||
    [ 'doMediaKey', 'next', null, true, [ 'Next' ] ],
 | 
			
		||||
    [ 'doMediaKey', null, 'XF86AudioRewind', true, [ 'Rewind' ] ],
 | 
			
		||||
    [ 'doMediaKey', null, 'XF86AudioForward', true, [ 'FastForward' ] ],
 | 
			
		||||
    [ 'doMediaKey', null, 'XF86AudioRepeat', true, [ 'Repeat' ] ],
 | 
			
		||||
    [ 'doMediaKey', null, 'XF86AudioRandomPlay', true, [ 'Shuffle' ] ],
 | 
			
		||||
    [ 'doXRandRAction', null, '<Super>p', false, [ 'VideoModeSwitch' ] ],
 | 
			
		||||
    /* Key code of the XF86Display key (Fn-F7 on Thinkpads, Fn-F4 on HP machines, etc.) */
 | 
			
		||||
    [ 'doXRandRAction', null, 'XF86Display', false, [ 'VideoModeSwitch' ] ],
 | 
			
		||||
    /* Key code of the XF86RotateWindows key (present on some tablets) */
 | 
			
		||||
    [ 'doXRandRAction', null, 'XF86RotateWindows', false, [ 'Rotate' ] ],
 | 
			
		||||
    [ 'doA11yAction', 'magnifier', null, true, [ 'screen-magnifier-enabled' ] ],
 | 
			
		||||
    [ 'doA11yAction', 'screenreader', null, true, [ 'screen-reader-enabled' ] ],
 | 
			
		||||
    [ 'doA11yAction', 'on-screen-keyboard', null, true, [ 'screen-keyboard-enabled' ] ],
 | 
			
		||||
    [ 'doTextSize', 'increase-text-size', null, true, [ 1 ] ],
 | 
			
		||||
    [ 'doTextSize', 'decrease-text-size', null, true, [ -1 ] ],
 | 
			
		||||
    [ 'doToggleContrast', 'toggle-contrast', null, true ],
 | 
			
		||||
    [ 'doMagnifierZoom', 'magnifier-zoom-in', null, true, [ 1 ] ],
 | 
			
		||||
    [ 'doMagnifierZoom', 'magnifier-zoom-out', null, true, [ -1 ] ],
 | 
			
		||||
    [ 'doPowerAction', null, 'XF86PowerOff', true, [ 'button-power' ] ],
 | 
			
		||||
    /* the kernel / Xorg names really are like this... */
 | 
			
		||||
    [ 'doPowerAction', null, 'XF86Suspend', false, [ 'button-sleep' ] ],
 | 
			
		||||
    [ 'doPowerAction', null, 'XF86Sleep', false, [ 'button-suspend' ] ],
 | 
			
		||||
    [ 'doPowerAction', null, 'XF86Hibernate', false, [ 'button-hibernate' ] ],
 | 
			
		||||
    [ 'doBrightness', null, 'XF86MonBrightnessUp', false, [ 'Screen', 'StepUp' ] ],
 | 
			
		||||
    [ 'doBrightness', null, 'XF86MonBrightnessDown', false, [ 'Screen', 'StepDown' ] ],
 | 
			
		||||
    [ 'doBrightness', null, 'XF86KbdBrightnessUp', false, [ 'Keyboard', 'StepUp' ] ],
 | 
			
		||||
    [ 'doBrightness', null, 'XF86KbdBrightnessDown', false, [ 'Keyboard', 'StepDown' ] ],
 | 
			
		||||
    [ 'doBrightnessToggle', null, 'XF86KbdLightOnOff', false, ],
 | 
			
		||||
    [ 'doInputSource', 'switch-input-source', null, false, [ +1 ] ],
 | 
			
		||||
    [ 'doInputSource', 'switch-input-source-backward', null, false, [ -1 ] ],
 | 
			
		||||
    [ 'doLaunchApp', null, 'XF86Battery', true, [ 'gnome-power-statistics.desktop' ] ]
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
var osdWin;
 | 
			
		||||
const OSDWindow = new Lang.Class({
 | 
			
		||||
    Name: 'OSDWindow',
 | 
			
		||||
 | 
			
		||||
    FADE_TIMEOUT: 1500,
 | 
			
		||||
    FADE_DURATION: 100,
 | 
			
		||||
 | 
			
		||||
    _init: function(iconName, value) {
 | 
			
		||||
        /* assume 130x130 on a 640x480 display and scale from there */
 | 
			
		||||
        let monitor = Main.layoutManager.primaryMonitor;
 | 
			
		||||
        let scalew = monitor.width / 640.0;
 | 
			
		||||
        let scaleh = monitor.height / 480.0;
 | 
			
		||||
        let scale = Math.min(scalew, scaleh);
 | 
			
		||||
        let size = 130 * Math.max(1, scale);
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'osd-window',
 | 
			
		||||
                                        vertical: true,
 | 
			
		||||
                                        reactive: false,
 | 
			
		||||
                                        visible: false,
 | 
			
		||||
                                        width: size,
 | 
			
		||||
                                        height: size,
 | 
			
		||||
                                      });
 | 
			
		||||
 | 
			
		||||
        this._icon = new St.Icon({ icon_name: iconName,
 | 
			
		||||
                                   icon_size: size / 2,
 | 
			
		||||
                                 });
 | 
			
		||||
        this.actor.add(this._icon, { expand: true,
 | 
			
		||||
                                     x_align: St.Align.MIDDLE,
 | 
			
		||||
                                     y_align: St.Align.MIDDLE });
 | 
			
		||||
 | 
			
		||||
        this._value = value;
 | 
			
		||||
        this._progressBar = new St.DrawingArea({ style_class: 'osd-progress-bar' });
 | 
			
		||||
        this._progressBar.connect('repaint', Lang.bind(this, this._drawProgress));
 | 
			
		||||
        this.actor.add(this._progressBar, { expand: true, x_fill: true, y_fill: false });
 | 
			
		||||
        this._progressBar.visible = value !== undefined;
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.addChrome(this.actor);
 | 
			
		||||
 | 
			
		||||
        /* Position in the middle of primary monitor */
 | 
			
		||||
        let [width, height] = this.actor.get_size();
 | 
			
		||||
        this.actor.x = ((monitor.width - width) / 2) + monitor.x;
 | 
			
		||||
        this.actor.y = monitor.y + (monitor.height / 2) + (monitor.height / 2 - height) / 2;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show: function() {
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
                           time: this.FADE_DURATION / 1000,
 | 
			
		||||
                           transition: 'easeInQuad' });
 | 
			
		||||
 | 
			
		||||
        if (this._timeoutId)
 | 
			
		||||
            GLib.source_remove(this._timeoutId);
 | 
			
		||||
 | 
			
		||||
        this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, this.FADE_TIMEOUT, Lang.bind(this, this.hide));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hide: function() {
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
                         { opacity: 0,
 | 
			
		||||
                           time: this.FADE_DURATION / 1000,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: function() {
 | 
			
		||||
                               this.actor.destroy();
 | 
			
		||||
                               this.actor = null;
 | 
			
		||||
                               osdWin = null;
 | 
			
		||||
                           },
 | 
			
		||||
                           onCompleteScope: this });
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setIcon: function(name) {
 | 
			
		||||
        this._icon.icon_name = name;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setValue: function(value) {
 | 
			
		||||
        if (value == this._value)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._value = value;
 | 
			
		||||
        this._progressBar.visible = value !== undefined;
 | 
			
		||||
        this._progressBar.queue_repaint();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _drawProgress: function(area) {
 | 
			
		||||
        let cr = area.get_context();
 | 
			
		||||
 | 
			
		||||
        let themeNode = this.actor.get_theme_node();
 | 
			
		||||
        let color = themeNode.get_foreground_color();
 | 
			
		||||
        Clutter.cairo_set_source_color(cr, color);
 | 
			
		||||
 | 
			
		||||
        let [width, height] = area.get_surface_size();
 | 
			
		||||
        width = width * this._value;
 | 
			
		||||
 | 
			
		||||
        cr.moveTo(0,0);
 | 
			
		||||
        cr.lineTo(width, 0);
 | 
			
		||||
        cr.lineTo(width, height);
 | 
			
		||||
        cr.lineTo(0, height);
 | 
			
		||||
        cr.fill();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function showOSD(icon, value) {
 | 
			
		||||
    if (osdWin) {
 | 
			
		||||
        osdWin.setIcon(icon);
 | 
			
		||||
        osdWin.setValue(value);
 | 
			
		||||
    } else {
 | 
			
		||||
        osdWin = new OSDWindow(icon, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    osdWin.show();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MediaKeysGrabber = new Lang.Class({
 | 
			
		||||
    Name: 'MediaKeysGrabber',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(MediaKeysInterface, this);
 | 
			
		||||
        this._apps = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    enable: function() {
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SettingsDaemon/MediaKeys');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    disable: function() {
 | 
			
		||||
        this._dbusImpl.unexport();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    GrabMediaPlayerKeysAsync: function(parameters, invocation) {
 | 
			
		||||
        let [appName, time] = parameters;
 | 
			
		||||
 | 
			
		||||
        /* I'm not sure of this code, but it is in gnome-settings-daemon
 | 
			
		||||
           (letting alone that the introspection is wrong in glib...)
 | 
			
		||||
        */
 | 
			
		||||
        if (time == Gdk.CURRENT_TIME) {
 | 
			
		||||
            let tv = new GLib.TimeVal;
 | 
			
		||||
            GLib.get_current_time(tv);
 | 
			
		||||
            time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let pos = -1;
 | 
			
		||||
        for (let i = 0; i < this._apps.length; i++) {
 | 
			
		||||
            if (this._apps[i].appName == appName) {
 | 
			
		||||
                pos = i;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (pos != -1)
 | 
			
		||||
            this._freeMediaPlayer(pos);
 | 
			
		||||
 | 
			
		||||
        let app = {
 | 
			
		||||
            appName: appName,
 | 
			
		||||
            name: invocation.get_sender(),
 | 
			
		||||
            time: time,
 | 
			
		||||
            watchId: Gio.DBus.session.watch_name(invocation.get_sender(),
 | 
			
		||||
                                                 Gio.BusNameWatcherFlags.NONE,
 | 
			
		||||
                                                 null,
 | 
			
		||||
                                                 Lang.bind(this, this._onNameVanished)),
 | 
			
		||||
        };
 | 
			
		||||
        Util.insertSorted(this._apps, app, function(a, b) {
 | 
			
		||||
            return b.time-a.time;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        invocation.return_value(GLib.Variant.new('()', []));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    ReleaseMediaPlayerAsync: function(parameters, invocation) {
 | 
			
		||||
        let name = invocation.get_sender();
 | 
			
		||||
        let [appName] = parameters;
 | 
			
		||||
 | 
			
		||||
        let pos = -1;
 | 
			
		||||
        for (let i = 0; i < this._apps.length; i++) {
 | 
			
		||||
            if (this._apps[i].appName == appName) {
 | 
			
		||||
                pos = i;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (pos == -1) {
 | 
			
		||||
            for (let i = 0; i < this._apps.length; i++) {
 | 
			
		||||
                if (this._apps[i].name == name) {
 | 
			
		||||
                    pos = i;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (pos != -1)
 | 
			
		||||
            this._freeMediaPlayer(pos);
 | 
			
		||||
 | 
			
		||||
        invocation.return_value(GLib.Variant.new('()', []));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _freeMediaPlayer: function(pos) {
 | 
			
		||||
        let app = this._apps[pos];
 | 
			
		||||
        Gio.bus_unwatch_name(app.watchId)
 | 
			
		||||
 | 
			
		||||
        this._apps.splice(pos, 1);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    mediaKeyPressed: function(key) {
 | 
			
		||||
        if (this._apps.length == 0) {
 | 
			
		||||
            showOSD('action-unavailable-symbolic');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let app = this._apps[0];
 | 
			
		||||
        Gio.DBus.session.emit_signal(app.name,
 | 
			
		||||
                                     '/org/gnome/SettingsDaemon/MediaKeys',
 | 
			
		||||
                                     'org.gnome.SettingsDaemon.MediaKeys',
 | 
			
		||||
                                     'MediaPlayerKeyPressed',
 | 
			
		||||
                                     GLib.Variant.new('(ss)', [app.appName || '',
 | 
			
		||||
                                                               key]));
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const MediaKeysManager = new Lang.Class({
 | 
			
		||||
    Name: 'MediaKeysManager',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._a11yControl = Main.panel.statusArea.a11y;
 | 
			
		||||
        this._volumeControl = Main.panel.statusArea.volume;
 | 
			
		||||
        this._userMenu = Main.panel.statusArea.userMenu;
 | 
			
		||||
        this._mediaPlayerKeys = new MediaKeysGrabber();
 | 
			
		||||
 | 
			
		||||
        this._keybindingSettings = new Gio.Settings({ schema: KEYBINDING_SETTINGS });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    enable: function() {
 | 
			
		||||
        for (let i = 0; i < DEFAULT_KEYBINDINGS.length; i++) {
 | 
			
		||||
            let [action, setting, keyval, overviewOnly, args] = DEFAULT_KEYBINDINGS[i];
 | 
			
		||||
            let func = this[action];
 | 
			
		||||
            if (!func) {
 | 
			
		||||
                log('Keybinding action %s is missing'.format(action));
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let name = setting ? setting : 'media-keys-keybindings-%d'.format(i);
 | 
			
		||||
            let ok;
 | 
			
		||||
            func = Util.wrapKeybinding(Lang.bind.apply(null, [this, func].concat(args)), overviewOnly);
 | 
			
		||||
            if (setting)
 | 
			
		||||
                ok = global.display.add_keybinding(setting, this._keybindingSettings,
 | 
			
		||||
                                                   Meta.KeyBindingFlags.BUILTIN |
 | 
			
		||||
                                                   Meta.KeyBindingFlags.IS_SINGLE |
 | 
			
		||||
                                                   Meta.KeyBindingFlags.HANDLE_WHEN_GRABBED, func);
 | 
			
		||||
            else
 | 
			
		||||
                ok = global.display.add_grabbed_key(name, keyval,
 | 
			
		||||
                                                    Meta.KeyBindingFlags.HANDLE_WHEN_GRABBED, func);
 | 
			
		||||
 | 
			
		||||
            if (!ok)
 | 
			
		||||
                log('Installing keybinding %s failed'.format(name));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._customKeybindings = [];
 | 
			
		||||
        this._changedId = this._keybindingSettings.connect('changed::custom-keybindings',
 | 
			
		||||
                                                           Lang.bind(this, this._reloadCustomKeybindings));
 | 
			
		||||
        this._reloadCustomKeybindings();
 | 
			
		||||
 | 
			
		||||
        this._mediaPlayerKeys.enable();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    disable: function() {
 | 
			
		||||
        for (let i = 0; i < DEFAULT_KEYBINDINGS.length; i++) {
 | 
			
		||||
            let [action, setting, keyval, overviewOnly, args] = DEFAULT_KEYBINDINGS[i];
 | 
			
		||||
 | 
			
		||||
            let name = setting ? setting : 'media-keys-keybindings-%d'.format(i);
 | 
			
		||||
            if (setting)
 | 
			
		||||
                global.display.remove_keybinding(setting, this._keybindingSettings);
 | 
			
		||||
            else
 | 
			
		||||
                global.display.remove_grabbed_key(name);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._clearCustomKeybindings();
 | 
			
		||||
        this._keybindingSettings.disconnect(this._changedId);
 | 
			
		||||
 | 
			
		||||
        this._mediaPlayerKeys.disable();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _clearCustomKeybindings: function() {
 | 
			
		||||
        for (let i = 0; i < this._customKeybindings.length; i++)
 | 
			
		||||
            global.display.remove_keybinding('binding', this._customKeybindings[i]);
 | 
			
		||||
 | 
			
		||||
        this._customKeybindings = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _reloadCustomKeybindings: function() {
 | 
			
		||||
        this._clearCustomKeybindings();
 | 
			
		||||
 | 
			
		||||
        let paths = this._keybindingSettings.get_strv('custom-keybindings');
 | 
			
		||||
        for (let i = 0; i < paths.length; i++) {
 | 
			
		||||
            let setting = new Gio.Settings({ schema: CUSTOM_KEYBINDING_SETTINGS,
 | 
			
		||||
                                             path: paths[i] });
 | 
			
		||||
            let func = Util.wrapKeybinding(Lang.bind(this, this.doCustom, setting), true);
 | 
			
		||||
 | 
			
		||||
            global.display.add_keybinding('binding', setting,
 | 
			
		||||
                                          Meta.KeyBindingFlags.IS_SINGLE |
 | 
			
		||||
                                          Meta.KeyBindingFlags.HANDLE_WHEN_GRABBED, func);
 | 
			
		||||
            this._customKeybindings.push(setting);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doCustom: function(display, screen, window, binding, settings) {
 | 
			
		||||
        let command = settings.get_string('command');
 | 
			
		||||
        Util.spawnCommandLine(command);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doTouchpadToggle: function(display, screen, window, binding) {
 | 
			
		||||
        let settings = new Gio.Settings({ schema: TOUCHPAD_SETTINGS });
 | 
			
		||||
        let enabled = settings.get_boolean('touchpad-enabled');
 | 
			
		||||
 | 
			
		||||
        this.doTouchpadSet(display, screen, window, binding, !enabled);
 | 
			
		||||
        settings.set_boolean(!enabled);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doTouchpadSet: function(display, screen, window, binding, enabled) {
 | 
			
		||||
        showOSD(enabled ? 'input-touchpad-symbolic' : 'touchpad-disabled-symbolic');
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doMute: function(display, screen, window, binding, quiet) {
 | 
			
		||||
        let [icon, value] = this._volumeControl.volumeMenu.toggleMute(quiet);
 | 
			
		||||
        showOSD(icon, value);
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doVolumeAdjust: function(display, screen, window, binding, direction, quiet) {
 | 
			
		||||
        let [icon, value] = this._volumeControl.volumeMenu.scroll(direction, quiet);
 | 
			
		||||
        showOSD(icon, value);
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doLogout: function(display, screen, window, binding) {
 | 
			
		||||
        this._userMenu.logOut();
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doEject: function(display, screen, window, binding) {
 | 
			
		||||
        let volumeMonitor = Gio.VolumeMonitor.get();
 | 
			
		||||
 | 
			
		||||
        let drives = volumeMonitor.get_connected_drives();
 | 
			
		||||
        let score = 0, drive;
 | 
			
		||||
        for (let i = 0; i < drives.length; i++) {
 | 
			
		||||
            if (!drives[i].can_eject())
 | 
			
		||||
                continue;
 | 
			
		||||
            if (!drives[i].is_media_removable())
 | 
			
		||||
                continue;
 | 
			
		||||
            if (score < 1) {
 | 
			
		||||
                drive = drives[i];
 | 
			
		||||
                score = 1;
 | 
			
		||||
            }
 | 
			
		||||
            if (!drives[i].has_media())
 | 
			
		||||
                continue;
 | 
			
		||||
            if (score < 2) {
 | 
			
		||||
                drive = drives[i];
 | 
			
		||||
                score = 2;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        showOSD('media-eject-custom-symbolic');
 | 
			
		||||
 | 
			
		||||
        if (!drive)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        let mountOp = new ShellMountOperation.ShellMountOperation(drive);
 | 
			
		||||
        drive.eject_with_operation(Gio.MountUnmountFlags.FORCE,
 | 
			
		||||
                                   mountOp.mountOp, null, null);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doHome: function() {
 | 
			
		||||
        let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
 | 
			
		||||
        let homeUri = homeFile.get_uri();
 | 
			
		||||
        Gio.app_info_launch_default_for_uri(homeUri, null);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doLaunchMimeHandler: function(display, screen, window, binding, mimeType) {
 | 
			
		||||
        let gioApp = Gio.AppInfo.get_default_for_type(mimeType, false);
 | 
			
		||||
        if (gioApp != null) {
 | 
			
		||||
            let app = Shell.AppSystem.get_default().lookup_app(gioApp.get_id());
 | 
			
		||||
            app.open_new_window(-1);
 | 
			
		||||
        } else {
 | 
			
		||||
            log('Could not find default application for \'%s\' mime-type'.format(mimeType));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doLaunchApp: function(display, screen, window, binding, appId) {
 | 
			
		||||
        let app = Shell.AppSystem.get_default().lookup_app(appId);
 | 
			
		||||
        app.open_new_window(-1);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doScreensaver: function() {
 | 
			
		||||
        // FIXME: handled in house, to the screenshield!
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doSpawn: function(display, screen, window, binding, argv) {
 | 
			
		||||
        Util.spawn(argv);
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doMediaKey: function(display, screen, window, binding, key) {
 | 
			
		||||
        this._mediaPlayerKeys.mediaKeyPressed(key);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onXRandRFinished: function(connection, result) {
 | 
			
		||||
        connection.call_finish(result);
 | 
			
		||||
        this._XRandRCancellable = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doXRandRAction: function(display, screen, window, binding, action) {
 | 
			
		||||
        if (this._XRandRCancellable)
 | 
			
		||||
            this._XRandRCancellable.cancel();
 | 
			
		||||
 | 
			
		||||
        this._XRandRCancellable = new Gio.Cancellable();
 | 
			
		||||
        Gio.DBus.session.call('org.gnome.SettingsDaemon',
 | 
			
		||||
                              '/org/gnome/SettingsDaemon/XRANDR',
 | 
			
		||||
                              'org.gnome.SettingsDaemon.XRANDR_2',
 | 
			
		||||
                              action,
 | 
			
		||||
                              GLib.Variant.new('(x)', [global.get_current_time()]),
 | 
			
		||||
                              null, /* reply type */
 | 
			
		||||
                              Gio.DBusCallFlags.NONE,
 | 
			
		||||
                              -1,
 | 
			
		||||
                              this._XRandRCancellable,
 | 
			
		||||
                              Lang.bind(this, this._onXRandRFinished));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doA11yAction: function(display, screen, window, binding, key) {
 | 
			
		||||
        let settings = new Gio.Settings({ schema: A11Y_SETTINGS });
 | 
			
		||||
        let enabled = settings.get_boolean(key);
 | 
			
		||||
        settings.set_boolean(key, !enabled);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doTextSize: function(display, screen, window, binding, multiplier) {
 | 
			
		||||
        // Same values used in the Seeing tab of the Universal Access panel
 | 
			
		||||
        const FACTORS = [ 0.75, 1.0, 1.25, 1.5 ];
 | 
			
		||||
 | 
			
		||||
	// Figure out the current DPI scaling factor
 | 
			
		||||
        let settings = new Gio.Settings({ schema: INTERFACE_SETTINGS });
 | 
			
		||||
        let factor = settings.get_double('text-scaling-factor');
 | 
			
		||||
        factor += multiplier * 0.25;
 | 
			
		||||
 | 
			
		||||
        /* Try to find a matching value */
 | 
			
		||||
        let distance = 1e6;
 | 
			
		||||
        let best = 1.0;
 | 
			
		||||
        for (let i = 0; i < FACTORS.length; i++) {
 | 
			
		||||
            let d = Math.abs(factor - FACTORS[i]);
 | 
			
		||||
            if (d < distance) {
 | 
			
		||||
                best = factors[i];
 | 
			
		||||
                distance = d;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (best == 1.0)
 | 
			
		||||
            settings.reset('text-scaling-factor');
 | 
			
		||||
        else
 | 
			
		||||
            settings.set_double('text-scaling-factor', best);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doToggleContrast: function(display, screen, window, binding) {
 | 
			
		||||
        this._a11yControl.toggleHighContrast();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doMagnifierZoom: function(display, screen, window, binding, offset) {
 | 
			
		||||
        let settings = new Gio.Settings({ schema: MAGNIFIER_SETTINGS });
 | 
			
		||||
 | 
			
		||||
        let value = settings.get_value('mag-factor');
 | 
			
		||||
        value = Math.round(value + offset);
 | 
			
		||||
        settings.set_value('mag-factor', value);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doPowerAction: function(display, screen, window, binding, action) {
 | 
			
		||||
        let settings = new Gio.Settings({ schema: POWER_SETTINGS });
 | 
			
		||||
        switch (settings.get_string(action)) {
 | 
			
		||||
        case 'suspend':
 | 
			
		||||
            this._userMenu.suspend();
 | 
			
		||||
            break;
 | 
			
		||||
        case 'interactive':
 | 
			
		||||
        case 'shutdown':
 | 
			
		||||
            this._userMenu.shutdown();
 | 
			
		||||
            break;
 | 
			
		||||
        case 'hibernate':
 | 
			
		||||
            this._userMenu.hibernate();
 | 
			
		||||
            break;
 | 
			
		||||
        case 'blank':
 | 
			
		||||
        case 'default':
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onBrightnessFinished: function(connection, result, kind) {
 | 
			
		||||
        let [percentage] = connection.call_finish(result).deep_unpack();
 | 
			
		||||
 | 
			
		||||
        let icon = kind == 'Keyboard' ? 'keyboard-brightness-symbolic' : 'display-brightness-symbolic';
 | 
			
		||||
        showOSD(icon, percentage / 100);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doBrightness: function(display, screen, window, binding, kind, action) {
 | 
			
		||||
        let iface = 'org.gnome.SettingsDaemon.Power.' + kind;
 | 
			
		||||
        let objectPath = '/org/gnome/SettingsDaemon/Power';
 | 
			
		||||
 | 
			
		||||
        Gio.DBus.session.call('org.gnome.SettingsDaemon',
 | 
			
		||||
                              objectPath, iface, action,
 | 
			
		||||
                              null, null, /* parameters, reply type */
 | 
			
		||||
                              Gio.DBusCallFlags.NONE, -1, null,
 | 
			
		||||
                              Lang.bind(this, this._onBrightnessFinished, kind));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    doInputSource: function(display, screen, window, binding, offset) {
 | 
			
		||||
        let settings = new Gio.Settings({ schema: INPUT_SOURCE_SETTINGS });
 | 
			
		||||
 | 
			
		||||
        let current = settings.get_uint('current');
 | 
			
		||||
        let max = settings.get_strv('sources').length - 1;
 | 
			
		||||
 | 
			
		||||
        current += offset;
 | 
			
		||||
        if (current < 0)
 | 
			
		||||
            current = 0;
 | 
			
		||||
        else if (current > max)
 | 
			
		||||
            current = max;
 | 
			
		||||
 | 
			
		||||
        settings.set_uint('current', current);
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const Component = MediaKeysManager;
 | 
			
		||||
@@ -52,6 +52,8 @@ const Recorder = new Lang.Class({
 | 
			
		||||
            Meta.disable_unredirect_for_screen(global.screen);
 | 
			
		||||
            recorder.record();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ let _overridesSettings = null;
 | 
			
		||||
let background = null;
 | 
			
		||||
 | 
			
		||||
function _sessionUpdated() {
 | 
			
		||||
    Meta.keybindings_set_custom_handler('panel-run-dialog', sessionMode.hasRunDialog ? openRunDialog : null);
 | 
			
		||||
    Meta.keybindings_set_custom_handler('internal-keybinding-panel-run-dialog', sessionMode.hasRunDialog ? Util.wrapKeybinding(openRunDialog, true) : null);
 | 
			
		||||
    if (sessionMode.isGreeter)
 | 
			
		||||
        screenShield.showDialog();
 | 
			
		||||
}
 | 
			
		||||
@@ -155,8 +155,14 @@ function start() {
 | 
			
		||||
 | 
			
		||||
    global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
 | 
			
		||||
                                            false, -1, 1);
 | 
			
		||||
    Meta.keybindings_set_custom_handler('panel-main-menu', Lang.bind(overview, overview.toggle));
 | 
			
		||||
    global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
 | 
			
		||||
    Meta.keybindings_set_custom_handler('internal-keybinding-panel-main-menu', Util.wrapKeybinding(Lang.bind(overview, function() {
 | 
			
		||||
        this.toggle();
 | 
			
		||||
        return true;
 | 
			
		||||
    }), true));
 | 
			
		||||
    global.display.connect('overlay-key', Util.wrapKeybinding(Lang.bind(overview, function() {
 | 
			
		||||
        this.toggle();
 | 
			
		||||
        return true;
 | 
			
		||||
    }), true));
 | 
			
		||||
 | 
			
		||||
    sessionMode.connect('update', _sessionUpdated);
 | 
			
		||||
    _sessionUpdated();
 | 
			
		||||
@@ -167,8 +173,6 @@ function start() {
 | 
			
		||||
 | 
			
		||||
    _startDate = new Date();
 | 
			
		||||
 | 
			
		||||
    global.stage.connect('captured-event', _globalKeyPressHandler);
 | 
			
		||||
 | 
			
		||||
    log('GNOME Shell started at ' + _startDate);
 | 
			
		||||
 | 
			
		||||
    let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
 | 
			
		||||
@@ -465,86 +469,6 @@ function getWindowActorsForWorkspace(workspaceIndex) {
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This function encapsulates hacks to make certain global keybindings
 | 
			
		||||
// work even when we are in one of our modes where global keybindings
 | 
			
		||||
// are disabled with a global grab. (When there is a global grab, then
 | 
			
		||||
// all key events will be delivered to the stage, so ::captured-event
 | 
			
		||||
// on the stage can be used for global keybindings.)
 | 
			
		||||
function _globalKeyPressHandler(actor, event) {
 | 
			
		||||
    if (modalCount == 0)
 | 
			
		||||
        return false;
 | 
			
		||||
    if (event.type() != Clutter.EventType.KEY_PRESS && event.type() != Clutter.EventType.KEY_RELEASE)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    if (!sessionMode.allowKeybindingsWhenModal) {
 | 
			
		||||
        if (modalCount > (overview.visible ? 1 : 0))
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let symbol = event.get_key_symbol();
 | 
			
		||||
    let keyCode = event.get_key_code();
 | 
			
		||||
    let ignoredModifiers = global.display.get_ignored_modifier_mask();
 | 
			
		||||
    let modifierState = event.get_state() & ~ignoredModifiers;
 | 
			
		||||
 | 
			
		||||
    // This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
 | 
			
		||||
    let action = global.display.get_keybinding_action(keyCode, modifierState);
 | 
			
		||||
 | 
			
		||||
    if (event.type() == Clutter.EventType.KEY_PRESS) {
 | 
			
		||||
        if (action == Meta.KeyBindingAction.SWITCH_PANELS) {
 | 
			
		||||
            ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK,
 | 
			
		||||
                                    modifierState);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (action) {
 | 
			
		||||
            // left/right would effectively act as synonyms for up/down if we enabled them;
 | 
			
		||||
            // but that could be considered confusing; we also disable them in the main view.
 | 
			
		||||
            //
 | 
			
		||||
            // case Meta.KeyBindingAction.WORKSPACE_LEFT:
 | 
			
		||||
            //  if (!sessionMode.hasWorkspaces)
 | 
			
		||||
            //      return false;
 | 
			
		||||
            //
 | 
			
		||||
            //     wm.actionMoveWorkspaceLeft();
 | 
			
		||||
            //     return true;
 | 
			
		||||
            // case Meta.KeyBindingAction.WORKSPACE_RIGHT:
 | 
			
		||||
            //  if (!sessionMode.hasWorkspaces)
 | 
			
		||||
            //      return false;
 | 
			
		||||
            //
 | 
			
		||||
            //     wm.actionMoveWorkspaceRight();
 | 
			
		||||
            //     return true;
 | 
			
		||||
            case Meta.KeyBindingAction.WORKSPACE_UP:
 | 
			
		||||
                if (!sessionMode.hasWorkspaces)
 | 
			
		||||
                    return false;
 | 
			
		||||
 | 
			
		||||
                wm.actionMoveWorkspace(Meta.MotionDirection.UP);
 | 
			
		||||
                return true;
 | 
			
		||||
            case Meta.KeyBindingAction.WORKSPACE_DOWN:
 | 
			
		||||
                if (!sessionMode.hasWorkspaces)
 | 
			
		||||
                    return false;
 | 
			
		||||
 | 
			
		||||
                wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
 | 
			
		||||
                return true;
 | 
			
		||||
            case Meta.KeyBindingAction.PANEL_RUN_DIALOG:
 | 
			
		||||
            case Meta.KeyBindingAction.COMMAND_2:
 | 
			
		||||
                if (!sessionMode.hasRunDialog)
 | 
			
		||||
                    return false;
 | 
			
		||||
 | 
			
		||||
                openRunDialog();
 | 
			
		||||
                return true;
 | 
			
		||||
            case Meta.KeyBindingAction.PANEL_MAIN_MENU:
 | 
			
		||||
                overview.hide();
 | 
			
		||||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (event.type() == Clutter.EventType.KEY_RELEASE) {
 | 
			
		||||
        if (action == Meta.KeyBindingAction.OVERLAY_KEY) {
 | 
			
		||||
            overview.hide();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _findModal(actor) {
 | 
			
		||||
    for (let i = 0; i < modalActorFocusStack.length; i++) {
 | 
			
		||||
        if (modalActorFocusStack[i].actor == actor)
 | 
			
		||||
@@ -685,6 +609,8 @@ function openRunDialog() {
 | 
			
		||||
        runDialog = new RunDialog.RunDialog();
 | 
			
		||||
    }
 | 
			
		||||
    runDialog.open();
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@ const _modes = {
 | 
			
		||||
        isGreeter: true,
 | 
			
		||||
        isPrimary: true,
 | 
			
		||||
        unlockDialog: imports.gdm.loginDialog.LoginDialog,
 | 
			
		||||
        components: ['polkitAgent'],
 | 
			
		||||
        components: ['polkitAgent', 'mediaKeysManager'],
 | 
			
		||||
        panel: {
 | 
			
		||||
            left: ['logo'],
 | 
			
		||||
            center: ['dateMenu'],
 | 
			
		||||
@@ -50,7 +50,7 @@ const _modes = {
 | 
			
		||||
        isLocked: true,
 | 
			
		||||
        isGreeter: undefined,
 | 
			
		||||
        unlockDialog: undefined,
 | 
			
		||||
        components: ['polkitAgent', 'telepathyClient'],
 | 
			
		||||
        components: ['polkitAgent', 'telepathyClient', 'mediaKeysManager'],
 | 
			
		||||
        panel: {
 | 
			
		||||
            left: ['userMenu'],
 | 
			
		||||
            center: [],
 | 
			
		||||
@@ -61,7 +61,7 @@ const _modes = {
 | 
			
		||||
    'unlock-dialog': {
 | 
			
		||||
        isLocked: true,
 | 
			
		||||
        unlockDialog: undefined,
 | 
			
		||||
        components: ['polkitAgent', 'telepathyClient'],
 | 
			
		||||
        components: ['polkitAgent', 'telepathyClient', 'mediaKeysManager'],
 | 
			
		||||
        panel: {
 | 
			
		||||
            left: ['userMenu'],
 | 
			
		||||
            center: [],
 | 
			
		||||
@@ -71,7 +71,7 @@ const _modes = {
 | 
			
		||||
 | 
			
		||||
    'initial-setup': {
 | 
			
		||||
        isPrimary: true,
 | 
			
		||||
        components: ['keyring'],
 | 
			
		||||
        components: ['keyring', 'mediaKeysManager'],
 | 
			
		||||
        panel: {
 | 
			
		||||
            left: [],
 | 
			
		||||
            center: ['dateMenu'],
 | 
			
		||||
@@ -91,8 +91,9 @@ const _modes = {
 | 
			
		||||
        isLocked: false,
 | 
			
		||||
        isPrimary: true,
 | 
			
		||||
        unlockDialog: imports.ui.unlockDialog.UnlockDialog,
 | 
			
		||||
        components: ['networkAgent', 'polkitAgent', 'telepathyClient',
 | 
			
		||||
                     'keyring', 'recorder', 'autorunManager', 'automountManager'],
 | 
			
		||||
        components: ['networkAgent', 'polkitAgent', 'telepathyClient', 'keyring',
 | 
			
		||||
                     'recorder', 'autorunManager', 'automountManager',
 | 
			
		||||
                     'mediaKeysManager'],
 | 
			
		||||
        panel: {
 | 
			
		||||
            left: ['activities', 'appMenu'],
 | 
			
		||||
            center: ['dateMenu'],
 | 
			
		||||
 
 | 
			
		||||
@@ -38,8 +38,8 @@ const ATIndicator = new Lang.Class({
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent('preferences-desktop-accessibility-symbolic', _("Accessibility"));
 | 
			
		||||
 | 
			
		||||
        let highContrast = this._buildHCItem();
 | 
			
		||||
        this.menu.addMenuItem(highContrast);
 | 
			
		||||
        this._highContrast = this._buildHCItem();
 | 
			
		||||
        this.menu.addMenuItem(this._highContrast);
 | 
			
		||||
 | 
			
		||||
        let magnifier = this._buildItem(_("Zoom"), APPLICATIONS_SCHEMA,
 | 
			
		||||
                                                   'screen-magnifier-enabled');
 | 
			
		||||
@@ -159,5 +159,9 @@ const ATIndicator = new Lang.Class({
 | 
			
		||||
            widget.setToggleState(active);
 | 
			
		||||
        });
 | 
			
		||||
        return widget;
 | 
			
		||||
    }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toggleHighContrast: function() {
 | 
			
		||||
        this._highContrast.toggle();
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,21 @@ const VolumeMenu = new Lang.Class({
 | 
			
		||||
        this._onControlStateChanged();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    scroll: function(direction) {
 | 
			
		||||
    toggleMute: function(quiet) {
 | 
			
		||||
        let muted = this._output.is_muted;
 | 
			
		||||
        this._output.change_is_muted(!muted);
 | 
			
		||||
 | 
			
		||||
        if (muted && !quiet)
 | 
			
		||||
            this._notifyVolumeChange();
 | 
			
		||||
 | 
			
		||||
        if (!muted)
 | 
			
		||||
            return ['audio-volume-muted-symbolic', 0];
 | 
			
		||||
        else
 | 
			
		||||
            return [this._volumeToIcon(this._output.volume),
 | 
			
		||||
                    this._output.volume / this._volumeMax];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    scroll: function(direction, quiet) {
 | 
			
		||||
        let currentVolume = this._output.volume;
 | 
			
		||||
 | 
			
		||||
        if (direction == Clutter.ScrollDirection.DOWN) {
 | 
			
		||||
@@ -85,7 +99,14 @@ const VolumeMenu = new Lang.Class({
 | 
			
		||||
            this._output.push_volume();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._notifyVolumeChange();
 | 
			
		||||
        if (!quiet)
 | 
			
		||||
            this._notifyVolumeChange();
 | 
			
		||||
 | 
			
		||||
        if (this._output.is_muted)
 | 
			
		||||
            return ['audio-volume-muted-symbolic', 0];
 | 
			
		||||
        else
 | 
			
		||||
            return [this._volumeToIcon(this._output.volume),
 | 
			
		||||
                    this._output.volume / this._volumeMax];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onControlStateChanged: function() {
 | 
			
		||||
@@ -221,14 +242,14 @@ const Indicator = new Lang.Class({
 | 
			
		||||
        this.parent('audio-volume-muted-symbolic', _("Volume"));
 | 
			
		||||
 | 
			
		||||
        this._control = getMixerControl();
 | 
			
		||||
        this._volumeMenu = new VolumeMenu(this._control);
 | 
			
		||||
        this._volumeMenu.connect('icon-changed', Lang.bind(this, function(menu, icon) {
 | 
			
		||||
        this.volumeMenu = new VolumeMenu(this._control);
 | 
			
		||||
        this.volumeMenu.connect('icon-changed', Lang.bind(this, function(menu, icon) {
 | 
			
		||||
            this._hasPulseAudio = (icon != null);
 | 
			
		||||
            this.setIcon(icon);
 | 
			
		||||
            this._syncVisibility();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this.menu.addMenuItem(this._volumeMenu);
 | 
			
		||||
        this.menu.addMenuItem(this.volumeMenu);
 | 
			
		||||
 | 
			
		||||
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
        this.menu.addSettingsAction(_("Sound Settings"), 'gnome-sound-panel.desktop');
 | 
			
		||||
@@ -242,6 +263,6 @@ const Indicator = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onScrollEvent: function(actor, event) {
 | 
			
		||||
        this._volumeMenu.scroll(event.get_scroll_direction());
 | 
			
		||||
    }
 | 
			
		||||
        this.volumeMenu.scroll(event.get_scroll_direction(), false);
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -572,6 +572,7 @@ const UserMenuButton = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
                this._updateHaveShutdown();
 | 
			
		||||
                this._updateHaveSuspend();
 | 
			
		||||
                this._updateHaveHibernate();
 | 
			
		||||
            }));
 | 
			
		||||
        this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
 | 
			
		||||
                                       Lang.bind(this, this._updateHaveShutdown));
 | 
			
		||||
@@ -655,6 +656,13 @@ const UserMenuButton = new Lang.Class({
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateHaveHibernate: function() {
 | 
			
		||||
        this._loginManager.canHibernate(Lang.bind(this,
 | 
			
		||||
            function(result) {
 | 
			
		||||
                this._haveHibernate = result;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateSuspendOrPowerOff: function() {
 | 
			
		||||
        if (!this._suspendOrPowerOffItem)
 | 
			
		||||
            return;
 | 
			
		||||
@@ -766,7 +774,7 @@ const UserMenuButton = new Lang.Class({
 | 
			
		||||
        this._loginScreenItem = item;
 | 
			
		||||
 | 
			
		||||
        item = new PopupMenu.PopupMenuItem(_("Log Out"));
 | 
			
		||||
        item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
 | 
			
		||||
        item.connect('activate', Lang.bind(this, this.logOut));
 | 
			
		||||
        this.menu.addMenuItem(item);
 | 
			
		||||
        this._logoutItem = item;
 | 
			
		||||
 | 
			
		||||
@@ -835,7 +843,7 @@ const UserMenuButton = new Lang.Class({
 | 
			
		||||
        Gdm.goto_login_session_sync(null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onQuitSessionActivate: function() {
 | 
			
		||||
    logOut: function() {
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
        this._session.LogoutRemote(0);
 | 
			
		||||
    },
 | 
			
		||||
@@ -847,25 +855,60 @@ const UserMenuButton = new Lang.Class({
 | 
			
		||||
        this._session.RebootRemote();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    shutdown: function() {
 | 
			
		||||
        this._session.ShutdownRemote();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    suspend: function() {
 | 
			
		||||
        if (!this._haveSuspend)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        // Ensure we only suspend after locking the screen
 | 
			
		||||
        if (this._screenSaverSettings.get_boolean(LOCK_ENABLED_KEY)) {
 | 
			
		||||
            let tmpId = Main.screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
 | 
			
		||||
                Main.screenShield.disconnect(tmpId);
 | 
			
		||||
 | 
			
		||||
                this._loginManager.suspend();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            this.menu.close(BoxPointer.PopupAnimation.NONE);
 | 
			
		||||
            Main.screenShield.lock(true);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._loginManager.suspend();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hibernate: function() {
 | 
			
		||||
        if (!this._haveHibernate)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        // Ensure we only suspend after locking the screen
 | 
			
		||||
        if (this._screenSaverSettings.get_boolean(LOCK_ENABLED_KEY)) {
 | 
			
		||||
            let tmpId = Main.screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
 | 
			
		||||
                Main.screenShield.disconnect(tmpId);
 | 
			
		||||
 | 
			
		||||
                this._loginManager.hibernate();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            this.menu.close(BoxPointer.PopupAnimation.NONE);
 | 
			
		||||
            Main.screenShield.lock(true);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._loginManager.hibernate();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onSuspendOrPowerOffActivate: function() {
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
 | 
			
		||||
        if (this._haveShutdown &&
 | 
			
		||||
            this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
 | 
			
		||||
            this._session.ShutdownRemote();
 | 
			
		||||
            this.shutdown();
 | 
			
		||||
        } else {
 | 
			
		||||
            if (this._screenSaverSettings.get_boolean(LOCK_ENABLED_KEY)) {
 | 
			
		||||
                let tmpId = Main.screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
 | 
			
		||||
                    Main.screenShield.disconnect(tmpId);
 | 
			
		||||
 | 
			
		||||
                    this._loginManager.suspend();
 | 
			
		||||
                }));
 | 
			
		||||
 | 
			
		||||
                this.menu.close(BoxPointer.PopupAnimation.NONE);
 | 
			
		||||
                Main.screenShield.lock(true);
 | 
			
		||||
            } else {
 | 
			
		||||
                this._loginManager.suspend();
 | 
			
		||||
            }
 | 
			
		||||
            this.suspend();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ const AltTab = imports.ui.altTab;
 | 
			
		||||
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
 | 
			
		||||
const WINDOW_ANIMATION_TIME = 0.25;
 | 
			
		||||
@@ -101,32 +102,32 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
 | 
			
		||||
 | 
			
		||||
        this._workspaceSwitcherPopup = null;
 | 
			
		||||
        Meta.keybindings_set_custom_handler('switch-to-workspace-left',
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-switch-to-workspace-left',
 | 
			
		||||
                                            Util.wrapKeybinding(Lang.bind(this, this._showWorkspaceSwitcher), true));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-switch-to-workspace-right',
 | 
			
		||||
                                            Util.wrapKeybinding(Lang.bind(this, this._showWorkspaceSwitcher), true));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-switch-to-workspace-up',
 | 
			
		||||
                                            Util.wrapKeybinding(Lang.bind(this, this._showWorkspaceSwitcher), true));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-switch-to-workspace-down',
 | 
			
		||||
                                            Util.wrapKeybinding(Lang.bind(this, this._showWorkspaceSwitcher), true));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-move-to-workspace-left',
 | 
			
		||||
                                            Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('switch-to-workspace-right',
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-move-to-workspace-right',
 | 
			
		||||
                                            Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('switch-to-workspace-up',
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-move-to-workspace-up',
 | 
			
		||||
                                            Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('switch-to-workspace-down',
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-move-to-workspace-down',
 | 
			
		||||
                                            Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('move-to-workspace-left',
 | 
			
		||||
                                            Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('move-to-workspace-right',
 | 
			
		||||
                                            Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('move-to-workspace-up',
 | 
			
		||||
                                            Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('move-to-workspace-down',
 | 
			
		||||
                                            Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('switch-windows',
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-switch-windows',
 | 
			
		||||
                                            Lang.bind(this, this._startAppSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('switch-group',
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-switch-group',
 | 
			
		||||
                                            Lang.bind(this, this._startAppSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('switch-windows-backward',
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-switch-windows-backward',
 | 
			
		||||
                                            Lang.bind(this, this._startAppSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('switch-group-backward',
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-switch-group-backward',
 | 
			
		||||
                                            Lang.bind(this, this._startAppSwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('switch-panels',
 | 
			
		||||
                                            Lang.bind(this, this._startA11ySwitcher));
 | 
			
		||||
        Meta.keybindings_set_custom_handler('internal-keybinding-switch-panels',
 | 
			
		||||
                                            Util.wrapKeybinding(Lang.bind(this, this._startA11ySwitcher), true));
 | 
			
		||||
        global.display.add_keybinding('open-application-menu',
 | 
			
		||||
                                      new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
 | 
			
		||||
                                      Meta.KeyBindingFlags.NONE,
 | 
			
		||||
@@ -552,30 +553,32 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
 | 
			
		||||
        if (!tabPopup.show(backwards, binding.get_name(), binding.get_mask()))
 | 
			
		||||
            tabPopup.destroy();
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _startA11ySwitcher : function(display, screen, window, binding) {
 | 
			
		||||
        let modifiers = binding.get_modifiers();
 | 
			
		||||
        let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
 | 
			
		||||
        Main.ctrlAltTabManager.popup(backwards, binding.get_mask());
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _openAppMenu : function(display, screen, window, event, binding) {
 | 
			
		||||
        Main.panel.openAppMenu();
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showWorkspaceSwitcher : function(display, screen, window, binding) {
 | 
			
		||||
        if (screen.n_workspaces == 1)
 | 
			
		||||
            return;
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        let [action,,,direction] = binding.get_name().split('-');
 | 
			
		||||
        let [,,action,,,direction] = binding.get_name().split('-');
 | 
			
		||||
        let direction = Meta.MotionDirection[direction.toUpperCase()];
 | 
			
		||||
        let newWs;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if (direction != Meta.MotionDirection.UP &&
 | 
			
		||||
            direction != Meta.MotionDirection.DOWN)
 | 
			
		||||
            return;
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (action == 'switch')
 | 
			
		||||
            newWs = this.actionMoveWorkspace(direction);
 | 
			
		||||
@@ -591,6 +594,8 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
            }
 | 
			
		||||
            this._workspaceSwitcherPopup.display(direction, newWs.index());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    actionMoveWorkspace: function(direction) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user