New architecture : create & update works, signals and remove doesn't

This commit is contained in:
Grégory Soutadé 2020-11-03 16:59:27 +01:00
parent 8032ce0245
commit 5458908603
2 changed files with 219 additions and 157 deletions

View File

@ -70,7 +70,8 @@ Example
You can test it with command line : You can test it with command line :
gdbus call --session --dest org.gnome.Shell --object-path /com/soutade/GenericMonitor --method com.soutade.GenericMonitor.notify '{"group":"new","items":[{"name":"first","text":"Hello","style":"color:green"}]}' gdbus call --session --dest org.gnome.Shell --object-path /com/soutade/GenericMonitor --method com.soutade.GenericMonitor.notify '{"group":"new","items":[{"name":"first","text":"Hello","style":"color:green","popup":{"items":{"picture":{"path":"/tmp/cat2.jpg"}}}}]}'
gdbus call --session --dest org.gnome.Shell --object-path /com/soutade/GenericMonitor --method com.soutade.GenericMonitor.deleteGroups '{"groups":["new"]}' gdbus call --session --dest org.gnome.Shell --object-path /com/soutade/GenericMonitor --method com.soutade.GenericMonitor.deleteGroups '{"groups":["new"]}'
Python example is available Python example is available

View File

@ -20,82 +20,47 @@
// https://github.com/bananenfisch/RecentItems/blob/master/extension.js // https://github.com/bananenfisch/RecentItems/blob/master/extension.js
// https://github.com/julio641742/gnome-shell-extension-reference/blob/master/tutorials/POPUPMENU-EXTENSION.md // https://github.com/julio641742/gnome-shell-extension-reference/blob/master/tutorials/POPUPMENU-EXTENSION.md
// https://gjs-docs.gnome.org/st10~1.0_api/st.widget // https://gjs-docs.gnome.org/st10~1.0_api/st.widget
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/master/js/ui/panelMenu.js
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/master/js/ui/popupMenu.js
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 Lang = imports.lang;
const GLib = imports.gi.GLib const GLib = imports.gi.GLib
const Main = imports.ui.main; const Main = imports.ui.main;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const PanelMenu = imports.ui.panelMenu; const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu; const PopupMenu = imports.ui.popupMenu;
const GObject = imports.gi.GObject; const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Pixbuf = imports.gi.GdkPixbuf; const Pixbuf = imports.gi.GdkPixbuf;
const Cogl = imports.gi.Cogl; const Cogl = imports.gi.Cogl;
function hash_get(hash, key, default_value)
{
if (hash.hasOwnProperty(key))
return hash[key];
return default_value;
}
var MyPopupMenuItem = GObject.registerClass({ var MyPopupMenuItem = GObject.registerClass({
GTypeName: "MyPopupMenuItem" GTypeName: "MyPopupMenuItem"
}, },
class MyPopupMenuItem extends PopupMenu.PopupBaseMenuItem { class MyPopupMenuItem extends PopupMenu.PopupBaseMenuItem {
_init(gicon, text, params) { _init(widgets, params) {
super._init(params); super._init(params);
this.box = new St.BoxLayout({ style_class: 'popup-combobox-item' }); this.box = new St.BoxLayout({ style_class: 'popup-combobox-item' });
this.box.set_vertical(true); this.box.set_vertical(true);
this._img = new clutter.Image();
let initial_pixbuf = Pixbuf.Pixbuf.new_from_file('/tmp/cat2.jpg');
this._img.set_data(initial_pixbuf.get_pixels(),
initial_pixbuf.get_has_alpha() ? Cogl.PixelFormat.RGBA_8888
: Cogl.PixelFormat.RGB_888,
initial_pixbuf.get_width(),
initial_pixbuf.get_height(),
initial_pixbuf.get_rowstride());
this._icon = new clutter.Actor();
this._icon.set_content(this._img);
this._icon.set_size(150,//initial_pixbuf.get_width(),
300);//initial_pixbuf.get_height());
this.box.add(this._icon);
// if (gicon) for (let widgetIndex in widgets)
// this.icon = new St.Icon({ gicon: gicon, style_class: 'popup-menu-icon' }); this.box.add(widgets[widgetIndex]);
// else
// this.icon = new St.Icon({ icon_name: 'edit-clear-symbolic', icon_size: 22 });
// this.box.add(this._icon); this.add_child(this.box);
this.label = new St.Label({ text: " " + text }); }
this.box.add(this.label);
this.add_child(this.box);
}
}); });
var RecentItems = GObject.registerClass({
GTypeName: "RecentItems"
},
class RecentItems extends PanelMenu.Button {
_init() {
super._init(0.0);
this.connect('enter-event', this._onEnter.bind(this));
this.connect('leave-event', this._onLeave.bind(this));
this._iconActor = new St.Icon({ icon_name: 'document-open-recent-symbolic', style_class: 'system-status-icon' });
this.actor.add_actor(this._iconActor);
this.actor.add_style_class_name('panel-status-button');
Main.panel.addToStatusArea('recent-items', this);
let menuItem = new MyPopupMenuItem('', 'hello', {});
this.menu.addMenuItem(menuItem);
}
_onEnter() {
this.menu.open(true);
}
_onLeave() {
this.menu.close();
}
});
var MonitorWidget = GObject.registerClass({ var MonitorWidget = GObject.registerClass({
GTypeName: "MonitorWidget" GTypeName: "MonitorWidget"
}, },
@ -109,7 +74,10 @@ class MonitorWidget extends PanelMenu.Button {
if (item.hasOwnProperty('icon')) if (item.hasOwnProperty('icon'))
{ {
this.icon = this._createIcon(icon, iconStyle); if (typeof(item['icon']) === "string")
this.icon = this._createIconOld(item);
else
this.icon = this._createIcon(item['icon']);
this.add_child(this.icon); this.add_child(this.icon);
} }
else else
@ -117,7 +85,10 @@ class MonitorWidget extends PanelMenu.Button {
if (item.hasOwnProperty('text')) if (item.hasOwnProperty('text'))
{ {
this.widget = this._createText(text, style); if (typeof(item['text']) === "string")
this.widget = this._createTextOld(item);
else
this.widget = this._createText(item['text']);
this.add_child(this.widget); this.add_child(this.widget);
} }
else else
@ -126,35 +97,11 @@ class MonitorWidget extends PanelMenu.Button {
if (item.hasOwnProperty('popup')) if (item.hasOwnProperty('popup'))
this._createPopup(item['popup']); this._createPopup(item['popup']);
if (item.hasOwnProperty('on-click')) this.onClick = hash_get(item, 'on-click', '');
onClick = item['on-click']; this.onEnter = hash_get(item, 'on-enter', '');
let box = 'center'; this.onLeave = hash_get(item, 'on-leave', '');
if (item.hasOwnProperty('box'))
box = item['box'];
this.onClick = onClick; let box = hash_get(item, 'box', 'center');
switch(box) {
case 'left':
this.box = Main.panel._leftBox;
break;
case 'right':
this.box = Main.panel._rigthBox;
break;
default:
case 'center':
this.box = Main.panel._centerBox;
break;
}
// Don't know why, _rightBox seems undefined on shell 3.36 !!
if (this.box === undefined) {
log(`${box} box is undefined, falling back to center one`);
this.box = Main.panel._centerBox;
}
let menuItem = new MyPopupMenuItem('', 'hello', {});
this.menu.addMenuItem(menuItem);
this.connect('enter-event', this._onEnter.bind(this)); this.connect('enter-event', this._onEnter.bind(this));
this.connect('leave-event', this._onLeave.bind(this)); this.connect('leave-event', this._onLeave.bind(this));
@ -170,29 +117,117 @@ class MonitorWidget extends PanelMenu.Button {
this.menu.close(); this.menu.close();
} }
_createText(text, style) { _createPopup(item) {
this.style = style; if (!item.hasOwnProperty('items')) {
if (text === '') { return null;
}
let widgets = [];
let widget;
for (let itemIndex in item['items']) {
switch(itemIndex)
{
case 'text':
widget = this._createText(item['items'][itemIndex]);
break;
case 'picture':
widget = this._createPicture(item['items'][itemIndex]);
break
}
if (widget !== null)
widgets.push(widget);
}
if (widgets.length > 0) {
this.menuItem = new MyPopupMenuItem(widgets, {});
this.menu.addMenuItem(this.menuItem);
return this.menuItem;
}
return null;
}
_createTextOld(item) {
var item_values = {};
item_values = {'text':item['text']};
if (item.hasOwnProperty('style'))
item_values['style'] = item['style'];
return this._createText(item_values);
}
_createText(item) {
if (!item.hasOwnProperty('text'))
throw new Error("Text must have a \'text\' value");
let style = hash_get(item, 'style', '');
this.textProperties = item;
if (item['text'] === '') {
return null; return null;
} else { } else {
widget = new St.Button({ label: text }); let widget = new St.Button({ label: item['text'] });
widget.set_style(this.style); widget.set_style(style);
return widget; return widget;
} }
} }
_createIcon(icon, style) { _createIconOld(item) {
this.iconStyle = style; var item_values = {};
if (icon === '') { item_values = {'path':item['icon']};
if (item.hasOwnProperty('iconStyle'))
item_values['style'] = item['iconStyle'];
return this._createIcon(item_values);
}
_createIcon(item) {
if (!item.hasOwnProperty('path'))
throw new Error("Icon must have a \'path\' value");
let style = hash_get(item, 'style', '');
this.iconProperties = item;
if (item['path'] === '') {
return null; return null;
} else { } else {
let gicon = Gio.icon_new_for_string(icon); let gicon = Gio.icon_new_for_string(item['path']);
gicon = new St.Icon({ gicon }); gicon = new St.Icon({ gicon });
gicon.set_style(this.iconStyle); gicon.set_style(style);
return gicon; return gicon;
} }
} }
_createPicture(item) {
if (!item.hasOwnProperty('path'))
throw new Error("picture must have a \'path\' value");
let width = hash_get(item, 'width', -1);
let height = hash_get(item, 'height', -1);
if (typeof(width) === "string")
width = parseInt(width, 10);
if (typeof(heigth) === "string")
heigth = parseInt(heigth, 10);
let img = new Clutter.Image();
let initial_pixbuf = Pixbuf.Pixbuf.new_from_file(item['path']);
img.set_data(initial_pixbuf.get_pixels(),
initial_pixbuf.get_has_alpha() ? Cogl.PixelFormat.RGBA_8888
: Cogl.PixelFormat.RGB_888,
initial_pixbuf.get_width(),
initial_pixbuf.get_height(),
initial_pixbuf.get_rowstride());
let picture = new Clutter.Actor();
picture.set_content(img);
picture.set_size((width != -1)?width:initial_pixbuf.get_width(),
(height != -1)?height:initial_pixbuf.get_height());
return picture;
}
removeFromBox() { removeFromBox() {
if (this.widget) if (this.widget)
this.box.remove_child(this.widget); this.box.remove_child(this.widget);
@ -200,39 +235,85 @@ class MonitorWidget extends PanelMenu.Button {
this.box.remove_child(this.icon); this.box.remove_child(this.icon);
} }
update(text, style, icon, iconStyle) { update(item) {
let prevWidget = this.widget; let prevWidget = this.widget;
let prevIcon = this.icon; let prevIcon = this.icon;
if (text !== '') { if (item.hasOwnProperty('text'))
if (!this.widget) { {
this._createText(text, style); let text = '';
this.box.insert_child_above(this.widget, this.icon); let style = '';
} else { if (typeof(item['text']) === "string") {
this.widget.label = text; text = hash_get(item, 'text', '');
style = hash_get(item, 'style', '');
} else {
let textValues = item['text'];
text = hash_get(textValues, 'text', '');
style = hash_get(textValues, 'style', '');
}
if (text !== '') {
if (!this.widget) {
if (typeof(item['text']) === "string")
this.widget = this._createTextOld(item);
else
this.widget = this._createText(item['text']);
this.insert_child_above(this.widget, this.icon);
} else {
this.widget.label = text;
}
}
if (style !== '' && this.widget) {
this.widget.set_style(style);
} }
} }
if (style !== '' && this.widget) { if (item.hasOwnProperty('icon'))
this.style = style; {
this.widget.set_style(this.style); let icon = '';
let style = '';
if (typeof(item['icon']) === "string") {
icon = hash_get(item, 'icon', '');
style = hash_get(item, 'iconStyle', '');
} else {
let iconValues = item['icon'];
icon = hash_get(iconValues, 'path', '');
style = hash_get(textValues, 'style', '');
}
if (icon !== '') {
if (typeof(item['icon']) === "string")
this.icon = this._createIconOld(item);
else
this.icon = this._createIcon(item['icon']);
}
if (prevIcon) {
this.insert_child_above(this.icon, prevIcon);
this.remove_child(prevIcon);
//delete prevIcon;
} else
this.insert_child_before(this.icon, prevWidget);
if (style !== '' && this.icon) {
this.icon.set_style(style);
}
} }
if (icon !== '') { if (item.hasOwnProperty('popup'))
this._createIcon(icon, iconStyle); {
if (prevIcon) if (this.menuItem) {
this.box.insert_child_above(this.icon, prevIcon); this.menu.removeAll();
else //delete this.menuItem;
this.box.insert_child_before(this.icon, prevWidget); }
}
if (iconStyle !== '' && this.icon) { this._createPopup(item['popup']);
this.iconStyle = style; }
this.icon.set_style(this.iconStyle);
}
if (prevIcon && icon !== '') this.onClick = hash_get(item, 'on-click', this.onClick);
this.box.remove_child(prevIcon); this.onEnter = hash_get(item, 'on-enter', this.onEnter);
this.onLeave = hash_get(item, 'on-leave', this.onLeave);
} }
}); });
@ -266,7 +347,7 @@ class GenericMonitorDBUS {
constructor() { constructor() {
this.monitor_groups = {}; this.monitor_groups = {};
this.actor_clicked = {}; this.actor_clicked = {};
this.clutterSettings = clutter.Settings.get_default(); this.ClutterSettings = Clutter.Settings.get_default();
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');
this._dbusImpl.emit_signal('onActivate', null); this._dbusImpl.emit_signal('onActivate', null);
@ -363,7 +444,7 @@ class GenericMonitorDBUS {
clickItem['nbClicks'] = 1; clickItem['nbClicks'] = 1;
clickItem['button'] = event.get_button(); clickItem['button'] = event.get_button();
this.actor_clicked[actorName] = clickItem; this.actor_clicked[actorName] = clickItem;
Mainloop.timeout_add(this.clutterSettings['double-click-time'], Mainloop.timeout_add(this.ClutterSettings['double-click-time'],
Lang.bind(this, this._doClickCallback)); Lang.bind(this, this._doClickCallback));
} else { } else {
this.actor_clicked[actorName]['nbClicks'] = 2; this.actor_clicked[actorName]['nbClicks'] = 2;
@ -388,49 +469,29 @@ class GenericMonitorDBUS {
for (let itemIndex in parameters['items']) { for (let itemIndex in parameters['items']) {
let item = parameters['items'][itemIndex]; let item = parameters['items'][itemIndex];
let style = '';
if (item.hasOwnProperty('style'))
style = item['style'];
let text = '';
if (item.hasOwnProperty('text'))
text = item['text'];
let icon = '';
if (item.hasOwnProperty('icon'))
icon = item['icon'];
let iconStyle = '';
if (item.hasOwnProperty('icon-style'))
iconStyle = item['icon-style'];
let onClick = '';
if (item.hasOwnProperty('on-click'))
onClick = item['on-click'];
let box = 'center';
if (item.hasOwnProperty('box'))
box = item['box'];
let monitorWidget = this._getItemFromGroup(group, item['name']); let monitorWidget = this._getItemFromGroup(group, item['name']);
let lastWidget = null;
// New widget // New widget
if (monitorWidget === null) { if (monitorWidget === null) {
lastWidget = group.length - 1; let lastWidget = group.length - 1;
monitorWidget = new MonitorWidget(item, groupName, lastWidget); monitorWidget = new MonitorWidget(item, groupName, lastWidget);
group.push(monitorWidget); group.push(monitorWidget);
// Connect signals // Connect signals
if (onClick !== '') { // if (onClick !== '') {
if (monitorWidget.widget) // if (monitorWidget.widget)
monitorWidget.widget.set_reactive(true); // monitorWidget.widget.set_reactive(true);
monitorWidget.widget.connect( // monitorWidget.widget.connect(
'button-release-event', Lang.bind(this, this._clicked) // 'button-release-event', Lang.bind(this, this._clicked)
); // );
if (monitorWidget.icon) { // if (monitorWidget.icon) {
monitorWidget.icon.set_reactive(true); // monitorWidget.icon.set_reactive(true);
monitorWidget.icon.connect( // monitorWidget.icon.connect(
'button-release-event', Lang.bind(this, this._clicked) // 'button-release-event', Lang.bind(this, this._clicked)
); // );
} // }
} // }
} else { } else {
monitorWidget.update(text, style, icon, iconStyle); monitorWidget.update(item);
} }
} }
} }