Gnome SHELL Generic Monitor

Gnome SHELL Generic Monitor Git Source Tree

Root/examples/genericmonitor.py

1#
2# This program is free software: you can redistribute it and/or modify
3# it under the terms of the GNU General Public License as published by
4# the Free Software Foundation, either version 3 of the License, or
5# (at your option) any later version.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <https://www.gnu.org/licenses/>.
14#
15
16import json
17import dbus
18from dbus.mainloop.glib import DBusGMainLoop
19import gi
20gi.require_version('Gst', '1.0')
21from gi.repository import GObject, GLib, Gst
22
23#
24# DBUS interface
25#
26class GenericMonitor:
27 """
28 Class that manage DBUS communication with GNOME generic monitor addon.
29 You have to subclass it
30 """
31
32 def setupMonitor(self):
33 """ Setup DBUS stuff (equivalent to constructor) """
34 self._activated = True
35 self._encoder = json.JSONEncoder()
36 self._dbus_interface = 'com.soutade.GenericMonitor'
37
38 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
39 self._dbus = dbus.SessionBus()
40
41 self.systray_proxy = self._dbus.get_object('org.gnome.Shell', '/com/soutade/GenericMonitor')
42
43 self.add_signal_receiver(self.onClick, 'onClick')
44 self.add_signal_receiver(self.onDblClick, 'onDblClick')
45 self.add_signal_receiver(self.onRightClick, 'onRightClick')
46 self.add_signal_receiver(self.onRightDblClick, 'onRightDblClick')
47 self.add_signal_receiver(self.onScrollUp, 'onScrollUp')
48 self.add_signal_receiver(self.onScrollDown, 'onScrollDown')
49 self.add_signal_receiver(self.onEnter, 'onEnter')
50 self.add_signal_receiver(self.onLeave, 'onLeave')
51
52 self.add_signal_receiver(self.onActivate, 'onActivate')
53 self.add_signal_receiver(self.onDeactivate, 'onDeactivate')
54
55 def runMainLoop(self):
56 """ Start infinite loop that allows to send and receive events and functions """
57 self._mainLoop = GLib.MainLoop()
58 self._mainLoop.run()
59
60 def stopMainLoop(self):
61 """ Stop infinite main loop """
62 self._mainLoop.quit()
63
64 # Generic Monitor functions
65 def notify(self, group):
66 """ Send notify() function
67 Parameters
68 ----------
69 group : GenericMonitorGroup
70 group to notify
71 """
72 if self._activated:
73 if type(group) == GenericMonitorGroup:
74 group = group.getValues()
75 self.systray_proxy.notify(self._encoder.encode(group), dbus_interface=self._dbus_interface)
76
77 def deleteItems(self, items):
78 """ Send deleteItems() function
79 Parameters
80 ----------
81 items : list of str (<itemName>@<groupName>)
82 items to delete
83 """
84 if self._activated:
85 items = {'items':items}
86 self.systray_proxy.deleteItems(self._encoder.encode(items), dbus_interface=self._dbus_interface)
87
88 def deleteGroups(self, groups):
89 """ Send deleteGroups() function
90 Parameters
91 ----------
92 groups : list of str (<groupName>)
93 groups to delete
94 """
95 if self._activated:
96 groups = {'groups':groups}
97 self.systray_proxy.deleteGroups(self._encoder.encode(groups), dbus_interface=self._dbus_interface)
98
99 def openPopup(self, item):
100 """ Send openPopup() function
101 Parameters
102 ----------
103 item : str (<itemName>@<groupName>)
104 Open popup (if there is one) of item
105 """
106 if self._activated:
107 item = {'item':item}
108 self.systray_proxy.openPopup(self._encoder.encode(item), dbus_interface=self._dbus_interface)
109
110 def closePopup(self, item):
111 """ Send closePopup() function
112 Parameters
113 ----------
114 item : str (<itemName>@<groupName>)
115 Close popup (if there is one) of item
116 """
117 if self._activated:
118 item = {'item':item}
119 self.systray_proxy.closePopup(self._encoder.encode(item), dbus_interface=self._dbus_interface)
120
121 def togglePopup(self, item):
122 """ Send togglePopup() function
123 Parameters
124 ----------
125 item : str (<itemName>@<groupName>)
126 Toggle popup (if there is one) of item
127 """
128 if self._activated:
129 item = {'item':item}
130 self.systray_proxy.togglePopup(self._encoder.encode(item), dbus_interface=self._dbus_interface)
131
132 # Generic Monitor signals
133 def onClick(self, sender):
134 """ onClick event
135 Parameters
136 ----------
137 sender : str (<itemName>@<groupName>)
138 Sender which event has been raised
139 """
140 pass
141
142 def onRightClick(self, sender):
143 """ onRightClick event
144 Parameters
145 ----------
146 sender : str (<itemName>@<groupName>)
147 Sender which event has been raised
148 """
149 pass
150
151 def onDblClick(self, sender):
152 """ onDblClick event
153 Parameters
154 ----------
155 sender : str (<itemName>@<groupName>)
156 Sender which event has been raised
157 """
158 pass
159
160 def onRightDblClick(self, sender):
161 """ onRightDblClick event
162 Parameters
163 ----------
164 sender : str (<itemName>@<groupName>)
165 Sender which event has been raised
166 """
167 pass
168
169 def onEnter(self, sender):
170 """ onEnter event (mouse enter in item)
171 Parameters
172 ----------
173 sender : str (<itemName>@<groupName>)
174 Sender which event has been raised
175 """
176 pass
177
178 def onLeave(self, sender):
179 """ onLeave event (mouse leave item)
180 Parameters
181 ----------
182 sender : str (<itemName>@<groupName>)
183 Sender which event has been raised
184 """
185 pass
186
187 def onScrollUp(self, sender):
188 """ onScrollUp event
189 Parameters
190 ----------
191 sender : str (<itemName>@<groupName>)
192 Sender which event has been raised
193 """
194 pass
195
196 def onScrollDown(self, sender):
197 """ onScrollDown event
198 Parameters
199 ----------
200 sender : str (<itemName>@<groupName>)
201 Sender which event has been raised
202 """
203 pass
204
205 def onActivate(self):
206 """ onActivate event (addon activated)
207 """
208 self._activated = True
209
210 def onDeactivate(self):
211 """ onDeactivate event (addon deactivated)
212 """
213 self._activated = False
214
215 # DBUS method
216 """ Add callback when DBUS signal is raised
217 Parameters
218 ----------
219 callback : function
220 Callback raised on DBUS signal
221 signalName : str
222 Name of DBUS signal
223 interface : str
224 Name of DBUS interface
225 """
226 def add_signal_receiver(self, callback, signalName, interface=None):
227 if not interface:
228 interface = self._dbus_interface
229 self._dbus.add_signal_receiver(callback, signalName, interface)
230
231
232#
233# Item stuff
234#
235class GenericMonitorGenericWidget:
236 """ Generic widget class, parent of all widgets
237 """
238 def __init__(self, style='', name='', signals={}):
239 """
240 Parameters
241 ----------
242 name : str, optional
243 Widget name
244 signals : dictionary, optional
245 Dictionary of signals and their action
246 """
247 self.valuesToMap = ['name', 'style']
248 self.mapValues = {}
249 self.mapName = ''
250 self.style = style
251 self.name = name
252 self.signals = signals
253
254 def setStyle(self, style):
255 self.style = style
256
257 def _toMap(self):
258 """ Return dictionary of class elements to send to addon
259 """
260 self.mapValues = {}
261 for p in self.valuesToMap:
262 if self.__dict__[p]:
263 self.mapValues[p] = self.__dict__[p]
264 for (name, value) in self.signals.items():
265 self.mapValues[name] = value
266 return {self.mapName:self.mapValues}
267
268class GenericMonitorTextWidget(GenericMonitorGenericWidget):
269 """ Text widget
270 """
271 def __init__(self, text, style='', name='', signals={}):
272 """
273 Parameters
274 ----------
275 text : str
276 Text to display
277 style : str, optional
278 CSS style
279 name : str, optional
280 Widget name
281 signals : dictionary, optional
282 Dictionary of signals and their action
283 """
284 super().__init__(style, name, signals)
285 self.valuesToMap += ['text']
286 self.mapName = 'text'
287
288 self.text = text
289
290 def setText(self, text):
291 self.text = text
292
293class GenericMonitorIconWidget(GenericMonitorGenericWidget):
294 """ Icon widget
295 """
296 def __init__(self, path, style=''):
297 """
298 Parameters
299 ----------
300 path : str
301 Icon path
302 style : str, optional
303 CSS style
304 """
305 super().__init__(style=style)
306 self.valuesToMap += ['path']
307 self.mapName = 'icon'
308
309 self.path = path
310 self.style = style
311
312 def setPath(self, path):
313 self.path = path
314
315
316class GenericMonitorPictureWidget(GenericMonitorGenericWidget):
317 """ Picture widget
318 """
319 def __init__(self, path, style='', width=-1, height=-1, name='', signals={}):
320 """
321 Parameters
322 ----------
323 path : str
324 Picture path
325 style : str, optional
326 CSS style
327 width : int, optional
328 Width of displayed picture (-1 for default width)
329 height : int, optional
330 Width of displayed picture (-1 for default width)
331 name : str, optional
332 Widget name
333 signals : dictionary, optional
334 Dictionary of signals and their action
335 """
336
337 super().__init__(style, name, signals)
338 self.valuesToMap += ['path', 'width', 'height']
339 self.mapName = 'picture'
340 self.path = path
341
342 self.width = width
343 self.height = height
344
345 def setPath(self, path):
346 self.path = path
347
348 def setWidth(self, width):
349 self.width = width
350
351 def setHeight(self, height):
352 self.height = height
353
354class GenericMonitorPopup(GenericMonitorGenericWidget):
355 """ Popup of current item
356 """
357 def __init__(self, items):
358 """
359 Parameters
360 ----------
361 items : list of GenericMonitorTextWidget and GenericMonitorPictureWidget
362 List of items (text or picture)
363 """
364 self.valuesToMap = ('items',)
365 self.mapName = 'popup'
366
367 self.items = items
368
369 def _toMap(self):
370 self.mapValues = {}
371 self.mapValues['items'] = []
372 for item in self.items:
373 self.mapValues['items'] += [item._toMap()]
374 return {self.mapName:self.mapValues}
375
376 def clear(self):
377 """ Clear items list
378 """
379 self.items = []
380
381 def setItems(self, items):
382 self.items = items
383
384class GenericMonitorItem:
385 """ Addon item that will be displayed in status bar
386 """
387 def __init__(self, name, items=[], signals={}, popup=None, box='center'):
388 """
389 Parameters
390 ----------
391 name : str
392 Item name
393 items : list of GenericMonitorTextWidget and GenericMonitorIconWidget, optional
394 List of items (text or icon)
395 signals : dictionary, optional
396 Dictionary of signals and their action
397 "on-click" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
398 "on-dblclick" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
399 "on-rightclick" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
400 "on-rightdblclick" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
401 "on-click" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
402 "on-enter" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
403 "on-leave" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
404 "on-scroll" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
405 popup : GenericMonitorPopup, optional
406 Popup to be displayed
407 box : str, optional
408 Box were to put items : left, center (default), or right
409 """
410 self.name = name
411 self.items = items
412 self.signals = signals
413 self.popup = popup
414 self.box = box
415 self.group = ''
416
417 self._checkValues()
418
419 def _checkValues(self):
420 if not self.name:
421 raise ValueError('Need a name')
422 if len(self.items) > 2:
423 raise ValueError('Maximum 2 items can be displayed')
424 for (name, value) in self.signals.items():
425 if not name in ('on-click', 'on-dblclick', 'on-rightclick', 'on-rightdblclick',
426 'on-enter', 'on-leave', 'on-scroll'):
427 raise ValueError('Invalid signal name ' + name)
428 if not value in ('signal', 'delete', 'open-popup', 'close-popup', 'toggle-popup'):
429 raise ValueError('Invalid signal value ' + value)
430 for item in self.items:
431 if not isinstance(item, GenericMonitorGenericWidget):
432 raise ValueError('Invalid item ' + item)
433 if self.popup and not isinstance(self.popup, GenericMonitorPopup):
434 raise ValueError('Invalid popup object')
435 if self.box and not self.box in ('left', 'center', 'right'):
436 raise ValueError('Invalid box value')
437
438 def setGroup(self, group):
439 """ Set current group (automatically done when added in a group)
440 Parameters
441 ----------
442 group : str
443 Group name
444 """
445 self.group = group
446
447 def getName(self):
448 return self.name
449
450 def getFullName(self):
451 """ return full name used by addon
452 """
453 return '%s@%s' % (self.name, self.group)
454
455 def _toMap(self):
456 myMap = {}
457 for p in ('name', 'box'):
458 if self.__dict__[p]:
459 myMap[p] = self.__dict__[p]
460 for item in self.items:
461 item._toMap()
462 myMap[item.mapName] = item.mapValues
463 if self.popup:
464 self.popup._toMap()
465 myMap['popup'] = self.popup.mapValues
466 for (name, value) in self.signals.items():
467 myMap[name] = value
468 return [myMap]
469
470class GenericMonitorGroup:
471 """ Group of items
472 """
473 def __init__(self, name, items=[]):
474 """
475 Parameters
476 ----------
477 name : str
478 Group name
479 items : list of GenericMonitorItem, optional
480 List of items
481 """
482 self.name = name
483 self.items = []
484 if type(items) != list:
485 self.addItem(items)
486 else:
487 self.addItems(items)
488
489 def addItem(self, item):
490 """ Add item into the groupw
491 Parameters
492 ----------
493 item : GenericMonitorItem
494 Item to add
495 """
496 item.setGroup(self.name)
497 self.items.append(item)
498
499 def addItems(self, items):
500 """ Add items into the group
501 Parameters
502 ----------
503 items : list of GenericMonitorItem
504 Items to add
505 """
506 for item in items:
507 self.addItem(item)
508
509 def clear(self):
510 """ Clear items list
511 """
512 for item in items:
513 item.setGroup('')
514 self.items = []
515
516 def getValues(self):
517 """ Returns group and its items in addon format
518 """
519 res = {'group': self.name, 'items':[]}
520 for item in self.items:
521 res['items'] += item._toMap()
522 return res
523
524 def __str__(self):
525 return str(self.getValues())

Archive Download this file

Branches

Tags