Add onClick feature
This commit is contained in:
		
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							@@ -25,6 +25,7 @@ All functions read JSON formatted parameters
 | 
				
			|||||||
      "group": "groupname",
 | 
					      "group": "groupname",
 | 
				
			||||||
      // style and icon-style are optional
 | 
					      // style and icon-style are optional
 | 
				
			||||||
      // item can have text and/or icon
 | 
					      // item can have text and/or icon
 | 
				
			||||||
 | 
					      // item can have click action "signal" or "delete"
 | 
				
			||||||
      "items": [
 | 
					      "items": [
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
	      "name":"",
 | 
						      "name":"",
 | 
				
			||||||
@@ -32,6 +33,7 @@ All functions read JSON formatted parameters
 | 
				
			|||||||
              "style":"",
 | 
					              "style":"",
 | 
				
			||||||
              "icon-style":"",
 | 
					              "icon-style":"",
 | 
				
			||||||
	      "icon":"",
 | 
						      "icon":"",
 | 
				
			||||||
 | 
						      "on-click":"",
 | 
				
			||||||
          }, ...
 | 
					          }, ...
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -48,6 +50,15 @@ All functions read JSON formatted parameters
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When text/icon is clicked and on-click parameter is set to "signal", 
 | 
				
			||||||
 | 
					extension emit one of the following signals :
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * onClick
 | 
				
			||||||
 | 
					  * onRightClick
 | 
				
			||||||
 | 
					  * onDblClick
 | 
				
			||||||
 | 
					  * onRightDblClick
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example
 | 
					Example
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								dbus.xml
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								dbus.xml
									
									
									
									
									
								
							@@ -8,4 +8,16 @@
 | 
				
			|||||||
  <method name="deleteGroups">
 | 
					  <method name="deleteGroups">
 | 
				
			||||||
    <arg type="s" direction="in" />
 | 
					    <arg type="s" direction="in" />
 | 
				
			||||||
  </method>
 | 
					  </method>
 | 
				
			||||||
 | 
					  <signal name="onClick">
 | 
				
			||||||
 | 
					    <arg type="s" direction="out" />
 | 
				
			||||||
 | 
					  </signal>
 | 
				
			||||||
 | 
					  <signal name="onRightClick">
 | 
				
			||||||
 | 
					    <arg type="s" direction="out" />
 | 
				
			||||||
 | 
					  </signal>
 | 
				
			||||||
 | 
					  <signal name="onDblClick">
 | 
				
			||||||
 | 
					    <arg type="s" direction="out" />
 | 
				
			||||||
 | 
					  </signal>
 | 
				
			||||||
 | 
					  <signal name="onRightDblClick">
 | 
				
			||||||
 | 
					    <arg type="s" direction="out" />
 | 
				
			||||||
 | 
					  </signal>
 | 
				
			||||||
</interface>
 | 
					</interface>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										116
									
								
								extension.js
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								extension.js
									
									
									
									
									
								
							@@ -20,14 +20,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const St = imports.gi.St;
 | 
					const St = imports.gi.St;
 | 
				
			||||||
const Gio = imports.gi.Gio;
 | 
					const Gio = imports.gi.Gio;
 | 
				
			||||||
 | 
					const Lang = imports.lang;
 | 
				
			||||||
 | 
					const GLib = imports.gi.GLib
 | 
				
			||||||
const Main = imports.ui.main;
 | 
					const Main = imports.ui.main;
 | 
				
			||||||
 | 
					const Mainloop = imports.mainloop;
 | 
				
			||||||
 | 
					const clutter = imports.gi.Clutter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MonitorWidget {
 | 
					class MonitorWidget {
 | 
				
			||||||
    constructor(name, group, text, style, icon, iconStyle) {
 | 
					    constructor(name, group, text, style, icon, iconStyle, onClick) {
 | 
				
			||||||
        this.name = name;
 | 
					        this.name = name;
 | 
				
			||||||
        this.group = group;
 | 
					        this.group = group;
 | 
				
			||||||
        this._createIcon(icon, iconStyle);
 | 
					        this._createIcon(icon, iconStyle);
 | 
				
			||||||
        this._createText(text, style);
 | 
					        this._createText(text, style);
 | 
				
			||||||
 | 
					        this.onClick = onClick;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _createText(text, style) {
 | 
					    _createText(text, style) {
 | 
				
			||||||
@@ -100,6 +105,8 @@ function loadInterfaceXml(filename) {
 | 
				
			|||||||
class GenericMonitorDBUS {
 | 
					class GenericMonitorDBUS {
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        this.monitor_groups = {};
 | 
					        this.monitor_groups = {};
 | 
				
			||||||
 | 
					        this.actor_clicked = {};
 | 
				
			||||||
 | 
					        this.clutterSettings = clutter.Settings.get_default();
 | 
				
			||||||
        this.box = Main.panel._centerBox;
 | 
					        this.box = Main.panel._centerBox;
 | 
				
			||||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(loadInterfaceXml('dbus.xml'), this);
 | 
					        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(loadInterfaceXml('dbus.xml'), this);
 | 
				
			||||||
        this._dbusImpl.export(Gio.DBus.session, '/com/soutade/GenericMonitor');
 | 
					        this._dbusImpl.export(Gio.DBus.session, '/com/soutade/GenericMonitor');
 | 
				
			||||||
@@ -118,6 +125,10 @@ class GenericMonitorDBUS {
 | 
				
			|||||||
                throw new Error('No name defined for item');
 | 
					                throw new Error('No name defined for item');
 | 
				
			||||||
            if (!item.hasOwnProperty('text') && !item.hasOwnProperty('icon'))
 | 
					            if (!item.hasOwnProperty('text') && !item.hasOwnProperty('icon'))
 | 
				
			||||||
                throw new Error('No text not icon defined for item');
 | 
					                throw new Error('No text not icon defined for item');
 | 
				
			||||||
 | 
					            if (item.hasOwnProperty('on-click')) {
 | 
				
			||||||
 | 
					                if (item['on-click'] !== 'signal' && item['on-click'] !== 'delete')
 | 
				
			||||||
 | 
					                    throw new Error('Invalid on-click value');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,6 +142,73 @@ class GenericMonitorDBUS {
 | 
				
			|||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _doClickCallback() {
 | 
				
			||||||
 | 
					        for(let itemIndex in this.actor_clicked) {
 | 
				
			||||||
 | 
					            let item = this.actor_clicked[itemIndex];
 | 
				
			||||||
 | 
					            let right = '';
 | 
				
			||||||
 | 
					            let nbClicks = '';
 | 
				
			||||||
 | 
					            if (item['button'] == 3)
 | 
				
			||||||
 | 
					                right = 'Right';
 | 
				
			||||||
 | 
					            if (item['nbClicks'] > 1)
 | 
				
			||||||
 | 
					                nbClicks = 'Dbl';
 | 
				
			||||||
 | 
					            let signalName = 'on' + right + nbClicks + 'Click';
 | 
				
			||||||
 | 
					            this._dbusImpl.emit_signal(signalName, GLib.Variant.new('(s)',[item['name']]));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.actor_clicked = {}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _actorToMonitorWidget(actor) {
 | 
				
			||||||
 | 
					        for (let groupName in this.monitor_groups) {
 | 
				
			||||||
 | 
					            let group = this.monitor_groups[groupName];
 | 
				
			||||||
 | 
					            for (let itemIndex in group) {
 | 
				
			||||||
 | 
					                let item = group[itemIndex];
 | 
				
			||||||
 | 
					                if (item.widget === actor ||
 | 
				
			||||||
 | 
					                    item.icon === actor)
 | 
				
			||||||
 | 
					                    return [groupName, item];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _removeFromArray(array, value) {
 | 
				
			||||||
 | 
					        for(let i=0; i<array.length; i++) {
 | 
				
			||||||
 | 
					            if (array[i] === value) {
 | 
				
			||||||
 | 
					                array.splice(i, 1);
 | 
				
			||||||
 | 
					                if (array === null)
 | 
				
			||||||
 | 
					                    array = [];
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return array;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					// https://stackoverflow.com/questions/50100546/how-do-i-detect-clicks-on-the-gnome-appmenu
 | 
				
			||||||
 | 
					    _clicked(actor, event) {
 | 
				
			||||||
 | 
					        let result = this._actorToMonitorWidget(actor);
 | 
				
			||||||
 | 
					        if (result === null)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let groupName = result[0];
 | 
				
			||||||
 | 
					        let monitorWidget = result[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (monitorWidget.onClick == 'signal') {
 | 
				
			||||||
 | 
					            let actorName = monitorWidget.name + '@' + groupName;
 | 
				
			||||||
 | 
					            if (!this.actor_clicked.hasOwnProperty(actorName)) {
 | 
				
			||||||
 | 
					                let clickItem = {};
 | 
				
			||||||
 | 
					                clickItem['name'] = actorName;
 | 
				
			||||||
 | 
					                clickItem['nbClicks'] = 1;
 | 
				
			||||||
 | 
					                clickItem['button'] = event.get_button();
 | 
				
			||||||
 | 
					                this.actor_clicked[actorName] = clickItem;
 | 
				
			||||||
 | 
					                Mainloop.timeout_add(this.clutterSettings['double-click-time'],
 | 
				
			||||||
 | 
					                                     Lang.bind(this, this._doClickCallback));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.actor_clicked[actorName]['nbClicks'] = 2;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (monitorWidget.onClick == 'delete') {
 | 
				
			||||||
 | 
					            this.deleteItem(monitorWidget, groupName);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    notify(str) {
 | 
					    notify(str) {
 | 
				
			||||||
        let parameters = JSON.parse(str);
 | 
					        let parameters = JSON.parse(str);
 | 
				
			||||||
        this._checkParmeters(parameters);
 | 
					        this._checkParmeters(parameters);
 | 
				
			||||||
@@ -158,13 +236,16 @@ class GenericMonitorDBUS {
 | 
				
			|||||||
            let iconStyle = '';
 | 
					            let iconStyle = '';
 | 
				
			||||||
            if (item.hasOwnProperty('icon-style'))
 | 
					            if (item.hasOwnProperty('icon-style'))
 | 
				
			||||||
                iconStyle = item['icon-style'];
 | 
					                iconStyle = item['icon-style'];
 | 
				
			||||||
 | 
					            let onClick = '';
 | 
				
			||||||
 | 
					            if (item.hasOwnProperty('on-click'))
 | 
				
			||||||
 | 
					                onClick = item['on-click'];
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            let monitorWidget = this._getItemFromGroup(group, item['name']);
 | 
					            let monitorWidget = this._getItemFromGroup(group, item['name']);
 | 
				
			||||||
            let lastWidget = null;
 | 
					            let lastWidget = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // New widget
 | 
					            // New widget
 | 
				
			||||||
            if (monitorWidget === null) {
 | 
					            if (monitorWidget === null) {
 | 
				
			||||||
                monitorWidget = new MonitorWidget(item['name'], groupName, text, style, icon, iconStyle);
 | 
					                monitorWidget = new MonitorWidget(item['name'], groupName, text, style, icon, iconStyle, onClick);
 | 
				
			||||||
                if (group.length)
 | 
					                if (group.length)
 | 
				
			||||||
                    lastWidget = group[group.length - 1].widget;
 | 
					                    lastWidget = group[group.length - 1].widget;
 | 
				
			||||||
                group.push(monitorWidget);
 | 
					                group.push(monitorWidget);
 | 
				
			||||||
@@ -175,6 +256,20 @@ class GenericMonitorDBUS {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                if (monitorWidget.widget)
 | 
					                if (monitorWidget.widget)
 | 
				
			||||||
                    this.box.insert_child_above(monitorWidget.widget, lastWidget);
 | 
					                    this.box.insert_child_above(monitorWidget.widget, lastWidget);
 | 
				
			||||||
 | 
					                // Connect signals
 | 
				
			||||||
 | 
					                if (onClick !== '') {
 | 
				
			||||||
 | 
					                    if (monitorWidget.widget)
 | 
				
			||||||
 | 
					                        monitorWidget.widget.set_reactive(true);
 | 
				
			||||||
 | 
					                        monitorWidget.widget.connect(
 | 
				
			||||||
 | 
					                            'button-release-event', Lang.bind(this, this._clicked)
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                    if (monitorWidget.icon) {
 | 
				
			||||||
 | 
					                        monitorWidget.icon.set_reactive(true);
 | 
				
			||||||
 | 
					                        monitorWidget.icon.connect(
 | 
				
			||||||
 | 
					                            'button-release-event', Lang.bind(this, this._clicked)
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                let prevWidget = monitorWidget.widget;
 | 
					                let prevWidget = monitorWidget.widget;
 | 
				
			||||||
                let prevIcon = monitorWidget.icon;
 | 
					                let prevIcon = monitorWidget.icon;
 | 
				
			||||||
@@ -201,6 +296,16 @@ class GenericMonitorDBUS {
 | 
				
			|||||||
            this.box.remove_child(item.icon);
 | 
					            this.box.remove_child(item.icon);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    deleteItem(item, groupName) {
 | 
				
			||||||
 | 
					        let group = this.monitor_groups[groupName];
 | 
				
			||||||
 | 
					        this._removeItemFromBox(item);
 | 
				
			||||||
 | 
					        group = this._removeFromArray(group, item);
 | 
				
			||||||
 | 
					        if (group.length === 0)
 | 
				
			||||||
 | 
					            delete this.monitor_groups[groupName];
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            this.monitor_groups = group;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    deleteItems(str) {
 | 
					    deleteItems(str) {
 | 
				
			||||||
        let parameters = JSON.parse(str);
 | 
					        let parameters = JSON.parse(str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -219,10 +324,7 @@ class GenericMonitorDBUS {
 | 
				
			|||||||
            let group = this.monitor_groups[groupName];
 | 
					            let group = this.monitor_groups[groupName];
 | 
				
			||||||
            let item = this._getItemFromGroup(group, itemName);
 | 
					            let item = this._getItemFromGroup(group, itemName);
 | 
				
			||||||
            if (item !== null) {
 | 
					            if (item !== null) {
 | 
				
			||||||
                this._removeItemFromBox(item);
 | 
					                this.deleteItem(item, groupName);
 | 
				
			||||||
                delete group[item['name']];
 | 
					 | 
				
			||||||
                if (group.length === 0)
 | 
					 | 
				
			||||||
                    delete this.monitor_groups[groupName];
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "uuid": "generic-monitor@gnome-shell-extensions",
 | 
					    "uuid": "generic-monitor@gnome-shell-extensions",
 | 
				
			||||||
    "name": "Generic Monitor",
 | 
					    "name": "Generic Monitor",
 | 
				
			||||||
    "description": "Generic monitor using DBUS",
 | 
					    "description": "Display text & icon on systray using DBUS",
 | 
				
			||||||
    "version": "1",
 | 
					    "version": "2",
 | 
				
			||||||
    "shell-version": [
 | 
					    "shell-version": [
 | 
				
			||||||
	"3.34"
 | 
						"3.34"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user