Compare commits
	
		
			2 Commits
		
	
	
		
			wip/jimmac
			...
			wip/pad-os
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f9693d3a2b | ||
| 
						 | 
					dc280ef2ad | 
@@ -35,6 +35,7 @@ endif
 | 
			
		||||
 | 
			
		||||
introspectiondir = $(datadir)/dbus-1/interfaces
 | 
			
		||||
introspection_DATA =				\
 | 
			
		||||
	org.gnome.Shell.PadOsd.xml		\
 | 
			
		||||
	org.gnome.Shell.Screencast.xml		\
 | 
			
		||||
	org.gnome.Shell.Screenshot.xml		\
 | 
			
		||||
	org.gnome.ShellSearchProvider.xml	\
 | 
			
		||||
@@ -114,6 +115,7 @@ EXTRA_DIST =						\
 | 
			
		||||
	$(convert_DATA)					\
 | 
			
		||||
	$(keys_in_files)				\
 | 
			
		||||
	$(dist_theme_files)				\
 | 
			
		||||
	pad-osd.css					\
 | 
			
		||||
	perf-background.xml.in				\
 | 
			
		||||
	org.gnome.Shell.PortalHelper.desktop.in		\
 | 
			
		||||
	org.gnome.Shell.PortalHelper.service.in		\
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@
 | 
			
		||||
    <file>no-events.svg</file>
 | 
			
		||||
    <file>no-notifications.svg</file>
 | 
			
		||||
    <file>noise-texture.png</file>
 | 
			
		||||
    <file>pad-osd.css</file>
 | 
			
		||||
    <file>page-indicator-active.svg</file>
 | 
			
		||||
    <file>page-indicator-inactive.svg</file>
 | 
			
		||||
    <file>page-indicator-checked.svg</file>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								data/org.gnome.Shell.PadOsd.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								data/org.gnome.Shell.PadOsd.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
<!DOCTYPE node PUBLIC
 | 
			
		||||
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
 | 
			
		||||
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
 | 
			
		||||
<node>
 | 
			
		||||
 | 
			
		||||
  <!--
 | 
			
		||||
      org.gnome.Shell.PadOSD:
 | 
			
		||||
      @short_description: Pad OSD interface
 | 
			
		||||
 | 
			
		||||
      The interface used to show button map OSD on pad devices.
 | 
			
		||||
  -->
 | 
			
		||||
  <interface name='org.gnome.Shell.Wacom.PadOsd'>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
        Show:
 | 
			
		||||
        @device_node: device node file, usually in /dev/input/...
 | 
			
		||||
        @edition_mode: whether toggling edition mode on when showing
 | 
			
		||||
 | 
			
		||||
        Shows the pad button map OSD for the requested device, the OSD
 | 
			
		||||
	will be shown according the current device settings (output
 | 
			
		||||
	mapping, left handed mode, ...)
 | 
			
		||||
    -->
 | 
			
		||||
    <method name='Show'>
 | 
			
		||||
      <arg name='device_node' direction='in' type='o'/>
 | 
			
		||||
      <arg name='edition_mode' direction='in' type='b'/>
 | 
			
		||||
    </method>
 | 
			
		||||
  </interface>
 | 
			
		||||
</node>
 | 
			
		||||
@@ -562,6 +562,10 @@ StScrollBar {
 | 
			
		||||
    background-color: #eeeeec;
 | 
			
		||||
    border-radius: 0.3em; }
 | 
			
		||||
 | 
			
		||||
.pad-osd-window {
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* App Switcher */
 | 
			
		||||
.switcher-popup {
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								data/theme/pad-osd.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								data/theme/pad-osd.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
.Leader {
 | 
			
		||||
    stroke-width: .5 !important;
 | 
			
		||||
    stroke: #535353;
 | 
			
		||||
    fill: none !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Button {
 | 
			
		||||
    stroke-width: .25;
 | 
			
		||||
    stroke: #ededed;
 | 
			
		||||
    fill: #ededed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Ring {
 | 
			
		||||
    stroke-width: .5 !important;
 | 
			
		||||
    stroke: #535353 !important;
 | 
			
		||||
    fill: none !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.Label {
 | 
			
		||||
    stroke: none !important;
 | 
			
		||||
    stroke-width: .1 !important;
 | 
			
		||||
    font-size: .1 !important;
 | 
			
		||||
    fill: transparent !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.TouchStrip, .TouchRing {
 | 
			
		||||
    stroke-width: .1 !important;
 | 
			
		||||
    stroke: #ededed !important;
 | 
			
		||||
    fill: #535353 !important;
 | 
			
		||||
}
 | 
			
		||||
@@ -72,6 +72,7 @@
 | 
			
		||||
    <file>ui/osdMonitorLabeler.js</file>
 | 
			
		||||
    <file>ui/overview.js</file>
 | 
			
		||||
    <file>ui/overviewControls.js</file>
 | 
			
		||||
    <file>ui/padOsd.js</file>
 | 
			
		||||
    <file>ui/panel.js</file>
 | 
			
		||||
    <file>ui/panelMenu.js</file>
 | 
			
		||||
    <file>ui/pointerWatcher.js</file>
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const OsdWindow = imports.ui.osdWindow;
 | 
			
		||||
const OsdMonitorLabeler = imports.ui.osdMonitorLabeler;
 | 
			
		||||
const Overview = imports.ui.overview;
 | 
			
		||||
const PadOsd = imports.ui.padOsd;
 | 
			
		||||
const Panel = imports.ui.panel;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const RunDialog = imports.ui.runDialog;
 | 
			
		||||
@@ -61,6 +62,7 @@ let screenShield = null;
 | 
			
		||||
let notificationDaemon = null;
 | 
			
		||||
let windowAttentionHandler = null;
 | 
			
		||||
let ctrlAltTabManager = null;
 | 
			
		||||
let padOsdService = null;
 | 
			
		||||
let osdWindowManager = null;
 | 
			
		||||
let osdMonitorLabeler = null;
 | 
			
		||||
let sessionMode = null;
 | 
			
		||||
@@ -155,6 +157,7 @@ function _initializeUI() {
 | 
			
		||||
    // working until it's updated.
 | 
			
		||||
    uiGroup = layoutManager.uiGroup;
 | 
			
		||||
 | 
			
		||||
    padOsdService = new PadOsd.PadOsdService();
 | 
			
		||||
    screencastService = new Screencast.ScreencastService();
 | 
			
		||||
    xdndHandler = new XdndHandler.XdndHandler();
 | 
			
		||||
    ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										733
									
								
								js/ui/padOsd.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										733
									
								
								js/ui/padOsd.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,733 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Rsvg = imports.gi.Rsvg;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GDesktopEnums = imports.gi.GDesktopEnums;
 | 
			
		||||
const Atk = imports.gi.Atk;
 | 
			
		||||
const Cairo = imports.cairo;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
const Layout = imports.ui.layout;
 | 
			
		||||
 | 
			
		||||
const ACTIVE_COLOR = "#729fcf";
 | 
			
		||||
 | 
			
		||||
const LTR = 0;
 | 
			
		||||
const RTL = 1;
 | 
			
		||||
 | 
			
		||||
const CW = 0;
 | 
			
		||||
const CCW = 1;
 | 
			
		||||
 | 
			
		||||
const UP = 0;
 | 
			
		||||
const DOWN = 1;
 | 
			
		||||
 | 
			
		||||
const KeybindingEntry = new Lang.Class({
 | 
			
		||||
    Name: 'KeybindingEntry',
 | 
			
		||||
 | 
			
		||||
    _init: function () {
 | 
			
		||||
        this.actor = new St.Entry({ hint_text: _('New shortcut...'),
 | 
			
		||||
                                    width: 120 });
 | 
			
		||||
        this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this.destroy));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCapturedEvent: function (actor, event) {
 | 
			
		||||
        if (event.type() == Clutter.EventType.KEY_PRESS) {
 | 
			
		||||
            if (GLib.unichar_isprint(event.get_key_unicode())) {
 | 
			
		||||
                let str = Gtk.accelerator_name_with_keycode(null,
 | 
			
		||||
                                                            event.get_key_symbol(),
 | 
			
		||||
                                                            event.get_key_code(),
 | 
			
		||||
                                                            event.get_state());
 | 
			
		||||
                this.actor.set_text(str);
 | 
			
		||||
                this.emit('keybinding', str);
 | 
			
		||||
            }
 | 
			
		||||
            return Clutter.EVENT_STOP;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function () {
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(KeybindingEntry.prototype);
 | 
			
		||||
 | 
			
		||||
const ActionComboBox = new Lang.Class({
 | 
			
		||||
    Name: 'ActionComboBox',
 | 
			
		||||
 | 
			
		||||
    _init: function () {
 | 
			
		||||
        this.actor = new St.Button({ style_class: 'button' });
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onButtonClicked));
 | 
			
		||||
        this.actor.set_toggle_mode(true);
 | 
			
		||||
 | 
			
		||||
        let boxLayout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.HORIZONTAL,
 | 
			
		||||
                                                spacing: 6 });
 | 
			
		||||
        let box = new St.Widget({ layout_manager: boxLayout });
 | 
			
		||||
        this.actor.set_child(box);
 | 
			
		||||
 | 
			
		||||
        this._label = new St.Label({ width: 150 });
 | 
			
		||||
        box.add_child(this._label)
 | 
			
		||||
 | 
			
		||||
        let arrow = new St.Icon({ style_class: 'popup-menu-arrow',
 | 
			
		||||
                                  icon_name: 'pan-down-symbolic',
 | 
			
		||||
                                  accessible_role: Atk.Role.ARROW,
 | 
			
		||||
                                  y_expand: true,
 | 
			
		||||
                                  y_align: Clutter.ActorAlign.CENTER });
 | 
			
		||||
        box.add_child(arrow);
 | 
			
		||||
 | 
			
		||||
        /* Order matches GDesktopPadButtonAction enum */
 | 
			
		||||
        this._actions = [_('Application defined'),
 | 
			
		||||
                         _('Show on-screen help'),
 | 
			
		||||
                         _('Switch monitor'),
 | 
			
		||||
                         _('Assign keystroke')];
 | 
			
		||||
 | 
			
		||||
        this._editMenu = new PopupMenu.PopupMenu(this.actor, 0, St.Side.TOP);
 | 
			
		||||
        this._editMenu.connect('menu-closed', Lang.bind(this, function() { this.actor.set_checked(false); }));
 | 
			
		||||
        this._editMenu.actor.hide();
 | 
			
		||||
        Main.uiGroup.add_actor(this._editMenu.actor);
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._actions.length; i++) {
 | 
			
		||||
            let str = this._actions[i];
 | 
			
		||||
            let action = i;
 | 
			
		||||
            this._editMenu.addAction(str, Lang.bind(this, function() { this._onActionSelected(action) }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.setAction(GDesktopEnums.PadButtonAction.NONE);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onActionSelected: function (action) {
 | 
			
		||||
        this.setAction(action);
 | 
			
		||||
        this.popdown();
 | 
			
		||||
        this.emit('action', action);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setAction: function (action) {
 | 
			
		||||
        this._label.set_text(this._actions[action]);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    popup: function () {
 | 
			
		||||
        this._editMenu.open(true);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    popdown: function () {
 | 
			
		||||
        this._editMenu.close(true);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onButtonClicked: function () {
 | 
			
		||||
        if (this.actor.get_checked())
 | 
			
		||||
            this.popup();
 | 
			
		||||
        else
 | 
			
		||||
            this.popdown();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ActionComboBox.prototype);
 | 
			
		||||
 | 
			
		||||
const ActionEditor = new Lang.Class({
 | 
			
		||||
    Name: 'ActionEditor',
 | 
			
		||||
 | 
			
		||||
    _init: function () {
 | 
			
		||||
        let boxLayout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.HORIZONTAL,
 | 
			
		||||
                                                spacing: 12 });
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Widget({ layout_manager: boxLayout });
 | 
			
		||||
 | 
			
		||||
        this._actionComboBox = new ActionComboBox();
 | 
			
		||||
        this._actionComboBox.connect('action', Lang.bind(this, this._onActionSelected));
 | 
			
		||||
        this.actor.add_actor(this._actionComboBox.actor);
 | 
			
		||||
 | 
			
		||||
        this._keybindingEdit = new KeybindingEntry();
 | 
			
		||||
        this._keybindingEdit.connect('keybinding', Lang.bind(this, this._onKeybindingEdited));
 | 
			
		||||
        this._keybindingEdit.actor.hide();
 | 
			
		||||
        this.actor.add_actor(this._keybindingEdit.actor);
 | 
			
		||||
 | 
			
		||||
        this._doneButton = new St.Button ({ label: _('Done'),
 | 
			
		||||
                                            width: 100,
 | 
			
		||||
                                            style_class: 'button'});
 | 
			
		||||
        this._doneButton.connect('clicked', Lang.bind(this, this._onEditingDone));
 | 
			
		||||
        this.actor.add_actor(this._doneButton);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setSettings: function (settings) {
 | 
			
		||||
        this._buttonSettings = settings;
 | 
			
		||||
 | 
			
		||||
        this._currentAction = this._buttonSettings.get_enum('action');
 | 
			
		||||
        this._currentKeybinding = this._buttonSettings.get_string('keybinding');
 | 
			
		||||
        this._actionComboBox.setAction (this._currentAction);
 | 
			
		||||
 | 
			
		||||
        if (this._currentAction == GDesktopEnums.PadButtonAction.KEYBINDING) {
 | 
			
		||||
            this._keybindingEdit.actor.set_text(this._currentKeybinding);
 | 
			
		||||
            this._keybindingEdit.actor.show();
 | 
			
		||||
        } else {
 | 
			
		||||
            this._keybindingEdit.actor.hide();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    close: function() {
 | 
			
		||||
        this._actionComboBox.popdown();
 | 
			
		||||
        this.actor.hide();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeybindingEdited: function (entry, keybinding) {
 | 
			
		||||
        this._currentKeybinding = keybinding;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onActionSelected: function (menu, action) {
 | 
			
		||||
        this._currentAction = action;
 | 
			
		||||
 | 
			
		||||
        if (action == GDesktopEnums.PadButtonAction.KEYBINDING) {
 | 
			
		||||
            this._keybindingEdit.actor.show();
 | 
			
		||||
            this._keybindingEdit.actor.grab_key_focus();
 | 
			
		||||
        } else {
 | 
			
		||||
            this._keybindingEdit.actor.hide();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _storeSettings: function () {
 | 
			
		||||
        if (!this._buttonSettings)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let keybinding = null;
 | 
			
		||||
 | 
			
		||||
        if (this._currentAction == GDesktopEnums.PadButtonAction.KEYBINDING)
 | 
			
		||||
            keybinding = this._currentKeybinding;
 | 
			
		||||
 | 
			
		||||
        this._buttonSettings.set_enum('action', this._currentAction);
 | 
			
		||||
 | 
			
		||||
        if (keybinding)
 | 
			
		||||
            this._buttonSettings.set_string('keybinding', keybinding);
 | 
			
		||||
        else
 | 
			
		||||
            this._buttonSettings.reset('keybinding');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onEditingDone: function () {
 | 
			
		||||
        this._storeSettings();
 | 
			
		||||
        this.close();
 | 
			
		||||
        this.emit ('done');
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ActionEditor.prototype);
 | 
			
		||||
 | 
			
		||||
const PadDiagram = new Lang.Class({
 | 
			
		||||
    Name: 'PadDiagram',
 | 
			
		||||
    Extends: St.DrawingArea,
 | 
			
		||||
 | 
			
		||||
    _init: function (imagePath, leftHanded) {
 | 
			
		||||
        this.parent();
 | 
			
		||||
 | 
			
		||||
        let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/pad-osd.css');
 | 
			
		||||
        let [success, css, etag] = file.load_contents(null);
 | 
			
		||||
        this._css = css;
 | 
			
		||||
 | 
			
		||||
        let originalHandle = Rsvg.Handle.new_from_file(imagePath);
 | 
			
		||||
        let dimensions = originalHandle.get_dimensions();
 | 
			
		||||
        this._imageWidth = dimensions.width;
 | 
			
		||||
        this._imageHeight = dimensions.height;
 | 
			
		||||
 | 
			
		||||
        this._activeButtons = [];
 | 
			
		||||
        this._imagePath = imagePath;
 | 
			
		||||
        this._handle = this._composeStyledDiagram();
 | 
			
		||||
        this.connect('repaint', Lang.bind(this, this._repaint));
 | 
			
		||||
        this.connect('notify::size', Lang.bind(this, this._updateScale));
 | 
			
		||||
        this._leftHanded = leftHanded;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _wrappingSvgHeader: function () {
 | 
			
		||||
        return ('<?xml version="1.0" encoding="UTF-8" standalone="no"?>' +
 | 
			
		||||
                '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" ' +
 | 
			
		||||
                'xmlns:xi="http://www.w3.org/2001/XInclude" ' +
 | 
			
		||||
                'width="' + this._imageWidth + '" height="' + this._imageHeight + '"> ' +
 | 
			
		||||
                '<style type="text/css">');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _wrappingSvgFooter: function () {
 | 
			
		||||
        return ('</style>' +
 | 
			
		||||
                '<xi:include href="' + this._imagePath + '" />' +
 | 
			
		||||
                '</svg>');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _cssString: function () {
 | 
			
		||||
        let css = this._css;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._activeButtons.length; i++) {
 | 
			
		||||
            let ch = String.fromCharCode('A'.charCodeAt() + this._activeButtons[i]);
 | 
			
		||||
            css += ('.' + ch + ' { ' +
 | 
			
		||||
	            '  stroke: ' + ACTIVE_COLOR + ' !important; ' +
 | 
			
		||||
                    '  fill: ' + ACTIVE_COLOR + ' !important; ' +
 | 
			
		||||
                    '} ');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return css;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _composeStyledDiagram: function () {
 | 
			
		||||
        let svgData = '';
 | 
			
		||||
 | 
			
		||||
        if (!GLib.file_test(this._imagePath, GLib.FileTest.EXISTS))
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        svgData += this._wrappingSvgHeader();
 | 
			
		||||
        svgData += this._cssString();
 | 
			
		||||
        svgData += this._wrappingSvgFooter();
 | 
			
		||||
 | 
			
		||||
        let handle = new Rsvg.Handle();
 | 
			
		||||
        handle.set_base_uri (GLib.path_get_dirname (this._imagePath));
 | 
			
		||||
        handle.write(svgData);
 | 
			
		||||
        handle.close();
 | 
			
		||||
 | 
			
		||||
        return handle;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateScale: function () {
 | 
			
		||||
        let [width, height] = this.get_size();
 | 
			
		||||
        let dimensions = this._handle.get_dimensions ();
 | 
			
		||||
        let scaleX = width / dimensions.width;
 | 
			
		||||
        let scaleY = height / dimensions.height;
 | 
			
		||||
        this._scale = Math.min(scaleX, scaleY);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _repaint: function (area) {
 | 
			
		||||
        if (this._handle == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let [width, height] = area.get_surface_size();
 | 
			
		||||
        let dimensions = this._handle.get_dimensions ();
 | 
			
		||||
        let cr = this.get_context();
 | 
			
		||||
 | 
			
		||||
        if (this._scale == null)
 | 
			
		||||
            this._updateScale();
 | 
			
		||||
 | 
			
		||||
        cr.save();
 | 
			
		||||
        cr.translate (width/2, height/2);
 | 
			
		||||
        cr.scale (this._scale, this._scale);
 | 
			
		||||
        if (this._leftHanded)
 | 
			
		||||
            cr.rotate(Math.PI);
 | 
			
		||||
        cr.translate (-dimensions.width/2, -dimensions.height/2);
 | 
			
		||||
        this._handle.render_cairo(cr);
 | 
			
		||||
        cr.restore();
 | 
			
		||||
        cr.$dispose();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _transformPoint: function (x, y) {
 | 
			
		||||
        if (this._handle == null || this._scale == null)
 | 
			
		||||
            return [x, y];
 | 
			
		||||
 | 
			
		||||
        // I miss Cairo.Matrix
 | 
			
		||||
        let [width, height] = this.get_size();
 | 
			
		||||
        let dimensions = this._handle.get_dimensions ();
 | 
			
		||||
        x = x * this._scale + width / 2 - dimensions.width / 2 * this._scale;
 | 
			
		||||
        y = y * this._scale + height / 2 - dimensions.height / 2 * this._scale;;
 | 
			
		||||
        return [Math.round(x), Math.round(y)];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getItemLabelCoords: function (labelName, leaderName) {
 | 
			
		||||
        if (this._handle == null)
 | 
			
		||||
            return [false];
 | 
			
		||||
 | 
			
		||||
        let leaderPos, leaderSize, pos;
 | 
			
		||||
        let found, direction;
 | 
			
		||||
 | 
			
		||||
        [found, pos] = this._handle.get_position_sub('#' + labelName);
 | 
			
		||||
        if (!found)
 | 
			
		||||
            return [false];
 | 
			
		||||
 | 
			
		||||
        [found, leaderPos] = this._handle.get_position_sub('#' + leaderName);
 | 
			
		||||
        [found, leaderSize] = this._handle.get_dimensions_sub('#' + leaderName);
 | 
			
		||||
        if (!found)
 | 
			
		||||
            return [false];
 | 
			
		||||
 | 
			
		||||
        if (pos.x > leaderPos.x + leaderSize.width)
 | 
			
		||||
            direction = LTR;
 | 
			
		||||
        else
 | 
			
		||||
            direction = RTL;
 | 
			
		||||
 | 
			
		||||
        if (this._leftHanded) {
 | 
			
		||||
            direction = 1 - direction;
 | 
			
		||||
            pos.x = this._imageWidth - pos.x;
 | 
			
		||||
            pos.y = this._imageHeight - pos.y;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let [x, y] = this._transformPoint(pos.x, pos.y)
 | 
			
		||||
 | 
			
		||||
        return [true, x, y, direction];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getButtonLabelCoords: function (button) {
 | 
			
		||||
        let ch = String.fromCharCode('A'.charCodeAt() + button);
 | 
			
		||||
        let labelName = 'Label' + ch;
 | 
			
		||||
        let leaderName = 'Leader' + ch;
 | 
			
		||||
 | 
			
		||||
        return this._getItemLabelCoords(labelName, leaderName);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getRingLabelCoords: function (number, dir) {
 | 
			
		||||
        let numStr = number > 0 ? number.toString() : '';
 | 
			
		||||
        let dirStr = dir == CW ? 'CW' : 'CCW';
 | 
			
		||||
        let labelName = 'LabelRing' + numStr + dirStr;
 | 
			
		||||
        let leaderName = 'LeaderRing' + numStr + dirStr;
 | 
			
		||||
 | 
			
		||||
        return this._getItemLabelCoords(labelName, leaderName);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getStripLabelCoords: function (number, dir) {
 | 
			
		||||
        let numStr = number > 0 ? (number + 1).toString() : '';
 | 
			
		||||
        let dirStr = dir == UP ? 'Up' : 'Down';
 | 
			
		||||
        let labelName = 'LabelStrip' + numStr + dirStr;
 | 
			
		||||
        let leaderName = 'LeaderStrip' + numStr + dirStr;
 | 
			
		||||
 | 
			
		||||
        return this._getItemLabelCoords(labelName, leaderName);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _invalidateSvg: function () {
 | 
			
		||||
        if (this._handle == null)
 | 
			
		||||
            return;
 | 
			
		||||
        this._handle = this._composeStyledDiagram();
 | 
			
		||||
        this.queue_repaint();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateButton: function (button) {
 | 
			
		||||
        this._activeButtons.push(button);
 | 
			
		||||
        this._invalidateSvg ();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    deactivateButton: function (button) {
 | 
			
		||||
        for (let i = 0; i < this._activeButtons.length; i++) {
 | 
			
		||||
            if (this._activeButtons[i] == button)
 | 
			
		||||
                this._activeButtons.splice(i, 1);
 | 
			
		||||
        }
 | 
			
		||||
        this._invalidateSvg ();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const PadOsd = new Lang.Class({
 | 
			
		||||
    Name: 'PadOsd',
 | 
			
		||||
 | 
			
		||||
    _init: function (padDevice, settings, imagePath, editionMode, monitorIndex) {
 | 
			
		||||
        this.padDevice = padDevice;
 | 
			
		||||
        this._settings = settings;
 | 
			
		||||
        this._imagePath = imagePath;
 | 
			
		||||
        this._editionMode = editionMode;
 | 
			
		||||
        this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
 | 
			
		||||
 | 
			
		||||
        this.actor = new Shell.GenericContainer({ style_class: 'pad-osd-window',
 | 
			
		||||
                                                   reactive: true,
 | 
			
		||||
                                                   x: 0,
 | 
			
		||||
                                                   y: 0,
 | 
			
		||||
                                                   width: global.screen_width,
 | 
			
		||||
                                                   height: global.screen_height });
 | 
			
		||||
        this.actor.connect('allocate', Lang.bind(this, this._allocate));
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this.destroy));
 | 
			
		||||
        Main.uiGroup.add_actor(this.actor);
 | 
			
		||||
 | 
			
		||||
        this._monitorIndex = monitorIndex;
 | 
			
		||||
        let constraint = new Layout.MonitorConstraint({ index: monitorIndex });
 | 
			
		||||
        this.actor.add_constraint(constraint);
 | 
			
		||||
 | 
			
		||||
        this._padDiagram = new PadDiagram(this._imagePath, settings.get_boolean('left-handed'));
 | 
			
		||||
        this.actor.add_actor(this._padDiagram);
 | 
			
		||||
 | 
			
		||||
        this._buttonBox = new St.Widget({ layout_manager: new Clutter.BinLayout(),
 | 
			
		||||
                                          x_expand: true,
 | 
			
		||||
                                          x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                          y_align: Clutter.ActorAlign.CENTER });
 | 
			
		||||
        this._editButton = new St.Button({ label: _('Edit...'),
 | 
			
		||||
                                           style_class: 'button',
 | 
			
		||||
                                           can_focus: true,
 | 
			
		||||
                                           x_expand: true });
 | 
			
		||||
        this._editButton.connect('clicked', Lang.bind(this, function () { this.setEditionMode(true) }));
 | 
			
		||||
        this._buttonBox.add_actor(this._editButton);
 | 
			
		||||
        this.actor.add_actor(this._buttonBox);
 | 
			
		||||
 | 
			
		||||
        let boxLayout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.VERTICAL });
 | 
			
		||||
        this._labelBox = new St.Widget({ layout_manager: boxLayout,
 | 
			
		||||
                                         x_expand: true,
 | 
			
		||||
                                         x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                         y_align: Clutter.ActorAlign.CENTER });
 | 
			
		||||
        this._titleLabel = new St.Label();
 | 
			
		||||
        this._titleLabel.clutter_text.set_markup('<span size="larger"><b>' + padDevice.get_device_name() + '</b></span>');
 | 
			
		||||
        this._labelBox.add_actor(this._titleLabel);
 | 
			
		||||
 | 
			
		||||
        this._tipLabel = new St.Label();
 | 
			
		||||
        this._labelBox.add_actor(this._tipLabel);
 | 
			
		||||
        this.actor.add_actor(this._labelBox);
 | 
			
		||||
 | 
			
		||||
        this._actionEditor = new ActionEditor();
 | 
			
		||||
        this._actionEditor.connect ('done', Lang.bind(this, this._endButtonActionEdition));
 | 
			
		||||
        this.actor.add_actor(this._actionEditor.actor);
 | 
			
		||||
 | 
			
		||||
        this._labels = [];
 | 
			
		||||
        this._ringLabels = [];
 | 
			
		||||
        this._stripLabels = [];
 | 
			
		||||
 | 
			
		||||
        // FIXME: Fix num buttons.
 | 
			
		||||
        let i = 0;
 | 
			
		||||
        for (i = 0; i < 50; i++) {
 | 
			
		||||
            let [found, x, y, direction] = this._padDiagram.getButtonLabelCoords(i);
 | 
			
		||||
            if (!found)
 | 
			
		||||
                break;
 | 
			
		||||
            let label = this._createLabel(i, Meta.PadActionType.BUTTON);
 | 
			
		||||
            this._labels.push(label);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < padDevice.get_n_rings(); i++) {
 | 
			
		||||
            let [found, x, y, direction] = this._padDiagram.getRingLabelCoords(i, CW);
 | 
			
		||||
            let [found2, x2, y2, direction2] = this._padDiagram.getRingLabelCoords(i, CCW);
 | 
			
		||||
            if (!found || !found2)
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            let label1 = this._createLabel(i, Meta.PadActionType.RING);
 | 
			
		||||
            let label2 = this._createLabel(i, Meta.PadActionType.RING);
 | 
			
		||||
            this._ringLabels.push([label1, label2]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < padDevice.get_n_strips(); i++) {
 | 
			
		||||
            let [found, x, y, direction] = this._padDiagram.getStripLabelCoords(i, UP);
 | 
			
		||||
            let [found2, x2, y2, direction2] = this._padDiagram.getStripLabelCoords(i, DOWN);
 | 
			
		||||
            if (!found || !found2)
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            let label1 = this._createLabel(i, Meta.PadActionType.STRIP);
 | 
			
		||||
            let label2 = this._createLabel(i, Meta.PadActionType.STRIP);
 | 
			
		||||
            this._stripLabels.push([label1, label2]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._syncEditionMode();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createLabel: function (number, type) {
 | 
			
		||||
        let str = global.display.get_pad_action_label(this.padDevice, type, number);
 | 
			
		||||
        let label = new St.Label({ text: str ? str : _('None') });
 | 
			
		||||
        this.actor.add_actor(label);
 | 
			
		||||
 | 
			
		||||
        return label;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocateChild: function (child, x, y, direction, box) {
 | 
			
		||||
        let [prefHeight, natHeight] = child.get_preferred_height (-1);
 | 
			
		||||
        let [prefWidth, natWidth] = child.get_preferred_width (natHeight);
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
 | 
			
		||||
        natWidth = Math.min(natWidth, 250);
 | 
			
		||||
 | 
			
		||||
        if (direction == LTR) {
 | 
			
		||||
            childBox.x1 = x + box.x1;
 | 
			
		||||
            childBox.x2 = x + box.x1 + natWidth;
 | 
			
		||||
        } else {
 | 
			
		||||
            childBox.x1 = x + box.x1 - natWidth;
 | 
			
		||||
            childBox.x2 = x + box.x1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        childBox.y1 = y + box.y1 - natHeight / 2;
 | 
			
		||||
        childBox.y2 = y + box.y1 + natHeight / 2;
 | 
			
		||||
        child.allocate(childBox, 0);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocate: function (actor, box, flags) {
 | 
			
		||||
        let [prefLabelHeight, natLabelHeight] = this._labelBox.get_preferred_height(box.x2 - box.x1);
 | 
			
		||||
        let buttonY = Math.max((box.y2 - box.y1) * 3 / 4 + box.y1, (box.y2 - box.y1) - 100);
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
        let diagramBox = new Clutter.ActorBox();
 | 
			
		||||
 | 
			
		||||
        diagramBox.x1 = box.x1;
 | 
			
		||||
        diagramBox.x2 = box.x2;
 | 
			
		||||
        diagramBox.y1 = prefLabelHeight;
 | 
			
		||||
        diagramBox.y2 = buttonY;
 | 
			
		||||
        this._padDiagram.allocate(diagramBox, flags);
 | 
			
		||||
 | 
			
		||||
        childBox.x1 = box.x1;
 | 
			
		||||
        childBox.x2 = box.x2;
 | 
			
		||||
        childBox.y1 = buttonY;
 | 
			
		||||
        childBox.y2 = box.y2;
 | 
			
		||||
        this._buttonBox.allocate(childBox, flags);
 | 
			
		||||
 | 
			
		||||
        childBox.y1 = 0;
 | 
			
		||||
        childBox.y2 = prefLabelHeight;
 | 
			
		||||
        this._labelBox.allocate(childBox, flags);
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._labels.length; i++) {
 | 
			
		||||
            let label = this._labels[i];
 | 
			
		||||
            let [found, x, y, direction] = this._padDiagram.getButtonLabelCoords(i);
 | 
			
		||||
            this._allocateChild(label, x, y, direction, diagramBox);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._ringLabels.length; i++) {
 | 
			
		||||
            let [label1, label2] = this._ringLabels[i];
 | 
			
		||||
 | 
			
		||||
            let [found, x, y, direction] = this._padDiagram.getRingLabelCoords(i, CW);
 | 
			
		||||
            this._allocateChild(label1, x, y, direction, diagramBox);
 | 
			
		||||
 | 
			
		||||
            [found, x, y, direction] = this._padDiagram.getRingLabelCoords(i, CCW);
 | 
			
		||||
            this._allocateChild(label2, x, y, direction, diagramBox);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._stripLabels.length; i++) {
 | 
			
		||||
            let [label1, label2] = this._stripLabels[i];
 | 
			
		||||
 | 
			
		||||
            let [found, x, y, direction] = this._padDiagram.getStripLabelCoords(i, UP);
 | 
			
		||||
            this._allocateChild(label1, x, y, direction, diagramBox);
 | 
			
		||||
 | 
			
		||||
            [found, x, y, direction] = this._padDiagram.getStripLabelCoords(i, DOWN);
 | 
			
		||||
            this._allocateChild(label2, x, y, direction, diagramBox);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._editingButtonAction != null) {
 | 
			
		||||
            let [found, x, y, direction] = this._padDiagram.getButtonLabelCoords(this._editingButtonAction);
 | 
			
		||||
            this._allocateChild(this._actionEditor.actor, x, y, direction, diagramBox);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCapturedEvent : function (actor, event) {
 | 
			
		||||
        if (event.type() == Clutter.EventType.PAD_BUTTON_PRESS &&
 | 
			
		||||
            event.get_source_device() == this.padDevice) {
 | 
			
		||||
            this._padDiagram.activateButton(event.get_button());
 | 
			
		||||
 | 
			
		||||
            if (this._editionMode)
 | 
			
		||||
                this._startButtonActionEdition(event.get_button());
 | 
			
		||||
            return Clutter.EVENT_STOP;
 | 
			
		||||
        } else if (event.type() == Clutter.EventType.PAD_BUTTON_RELEASE &&
 | 
			
		||||
                   event.get_source_device() == this.padDevice) {
 | 
			
		||||
            this._padDiagram.deactivateButton(event.get_button());
 | 
			
		||||
            return Clutter.EVENT_STOP;
 | 
			
		||||
        } else if (event.type() == Clutter.EventType.KEY_PRESS &&
 | 
			
		||||
                   (!this._editionMode || event.get_key_symbol() == Clutter.Escape)) {
 | 
			
		||||
            if (this._editingButtonAction != null)
 | 
			
		||||
                this._endButtonActionEdition();
 | 
			
		||||
            else
 | 
			
		||||
                this.destroy();
 | 
			
		||||
            return Clutter.EVENT_STOP;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _syncEditionMode: function () {
 | 
			
		||||
        this._editButton.set_reactive(!this._editionMode);
 | 
			
		||||
        this._editButton.save_easing_state();
 | 
			
		||||
        this._editButton.set_easing_duration(200);
 | 
			
		||||
        this._editButton.set_opacity(this._editionMode ? 128 : 255);
 | 
			
		||||
        this._editButton.restore_easing_state();
 | 
			
		||||
 | 
			
		||||
        let title;
 | 
			
		||||
 | 
			
		||||
        if (this._editionMode) {
 | 
			
		||||
            title = _('Press a button to configure');
 | 
			
		||||
            this._tipLabel.set_text (_("Press Esc to exit"));
 | 
			
		||||
        } else {
 | 
			
		||||
            title = this.padDevice.get_device_name();
 | 
			
		||||
            this._tipLabel.set_text (_("Press any key to exit"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._titleLabel.clutter_text.set_markup('<span size="larger"><b>' + title + '</b></span>');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _endButtonActionEdition: function () {
 | 
			
		||||
        this._actionEditor.close();
 | 
			
		||||
 | 
			
		||||
        if (this._editingButtonAction != null) {
 | 
			
		||||
            // Update and show the label
 | 
			
		||||
            let str = global.display.get_pad_action_label(this.padDevice,
 | 
			
		||||
                                                          Meta.PadActionType.BUTTON,
 | 
			
		||||
                                                          this._editingButtonAction);
 | 
			
		||||
            this._labels[this._editingButtonAction].set_text(str ? str : _('None'));
 | 
			
		||||
 | 
			
		||||
            this._labels[this._editingButtonAction].show();
 | 
			
		||||
            this._editingButtonAction = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._editedButtonSettings = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _startButtonActionEdition: function (button) {
 | 
			
		||||
        if (this._editingButtonAction == button)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._endButtonActionEdition();
 | 
			
		||||
        this._editingButtonAction = button;
 | 
			
		||||
 | 
			
		||||
        this._labels[this._editingButtonAction].hide();
 | 
			
		||||
        this._actionEditor.actor.show();
 | 
			
		||||
        this.actor.queue_relayout();
 | 
			
		||||
 | 
			
		||||
        let ch = String.fromCharCode('A'.charCodeAt() + button);
 | 
			
		||||
        let settingsPath = this._settings.path + "button" + ch + '/';
 | 
			
		||||
        this._editedButtonSettings = Gio.Settings.new_with_path('org.gnome.desktop.peripherals.tablet.pad-button',
 | 
			
		||||
                                                                settingsPath);
 | 
			
		||||
        this._actionEditor.setSettings (this._editedButtonSettings);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setEditionMode: function (editionMode) {
 | 
			
		||||
        if (this._editionMode == editionMode)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._editionMode = editionMode;
 | 
			
		||||
        this._syncEditionMode();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function () {
 | 
			
		||||
        this._actionEditor.close();
 | 
			
		||||
 | 
			
		||||
        if (this._capturedEventId != 0) {
 | 
			
		||||
            global.stage.disconnect(this._capturedEventId);
 | 
			
		||||
            this._capturedEventId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.actor) {
 | 
			
		||||
            let actor = this.actor;
 | 
			
		||||
            this.actor = null;
 | 
			
		||||
            actor.destroy();
 | 
			
		||||
            this.emit('closed');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(PadOsd.prototype);
 | 
			
		||||
 | 
			
		||||
const PadOsdIface = '<node> \
 | 
			
		||||
<interface name="org.gnome.Shell.Wacom.PadOsd"> \
 | 
			
		||||
<method name="Show"> \
 | 
			
		||||
    <arg name="device_node" direction="in" type="o"/> \
 | 
			
		||||
    <arg name="edition_mode" direction="in" type="b"/> \
 | 
			
		||||
</method> \
 | 
			
		||||
</interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
 | 
			
		||||
const PadOsdService = new Lang.Class({
 | 
			
		||||
    Name: 'PadOsdService',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(PadOsdIface, this);
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Wacom');
 | 
			
		||||
        Gio.DBus.session.own_name('org.gnome.Shell.Wacom.PadOsd', Gio.BusNameOwnerFlags.REPLACE, null, null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    ShowAsync: function(params, invocation) {
 | 
			
		||||
        let [deviceNode, editionMode] = params;
 | 
			
		||||
        let deviceManager = Clutter.DeviceManager.get_default();
 | 
			
		||||
        let devices = deviceManager.list_devices();
 | 
			
		||||
        let padDevice = null;
 | 
			
		||||
 | 
			
		||||
        devices.forEach(Lang.bind(this, function(device) {
 | 
			
		||||
            if (deviceNode == device.get_device_node())
 | 
			
		||||
                padDevice = device;
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        if (padDevice == null ||
 | 
			
		||||
            padDevice.get_device_type() != Clutter.InputDeviceType.PAD_DEVICE) {
 | 
			
		||||
            invocation.return_error_literal(Gio.IOErrorEnum,
 | 
			
		||||
                                            Gio.IOErrorEnum.CANCELLED,
 | 
			
		||||
                                            "Invalid params");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        global.display.request_pad_osd(padDevice, editionMode);
 | 
			
		||||
        invocation.return_value(null);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(PadOsdService.prototype);
 | 
			
		||||
@@ -17,6 +17,7 @@ const Main = imports.ui.main;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const WindowMenu = imports.ui.windowMenu;
 | 
			
		||||
const PadOsd = imports.ui.padOsd;
 | 
			
		||||
 | 
			
		||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
 | 
			
		||||
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
 | 
			
		||||
@@ -915,6 +916,7 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
                           Lang.bind(this, this._toggleCalendar));
 | 
			
		||||
 | 
			
		||||
        global.display.connect('show-resize-popup', Lang.bind(this, this._showResizePopup));
 | 
			
		||||
        global.display.connect('show-pad-osd', Lang.bind(this, this._showPadOsd));
 | 
			
		||||
 | 
			
		||||
        Main.overview.connect('showing', Lang.bind(this, function() {
 | 
			
		||||
            for (let i = 0; i < this._dimmedWindows.length; i++)
 | 
			
		||||
@@ -944,7 +946,19 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        gesture = new AppSwitchAction();
 | 
			
		||||
        gesture.connect('activated', Lang.bind(this, this._switchApp));
 | 
			
		||||
        global.stage.add_action(gesture);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showPadOsd: function (display, device, settings, imagePath, editionMode, monitorIndex) {
 | 
			
		||||
        if (this._currentPadOsd != null) {
 | 
			
		||||
            if (this._currentPadOsd.padDevice == device)
 | 
			
		||||
                this._currentPadOsd.destroy();
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._currentPadOsd = new PadOsd.PadOsd(device, settings, imagePath, editionMode, monitorIndex);
 | 
			
		||||
        this._currentPadOsd.connect('closed', Lang.bind(this, function() { this._currentPadOsd = null }));
 | 
			
		||||
 | 
			
		||||
        return this._currentPadOsd.actor;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actionSwitchWorkspace: function(action, direction) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user