Compare commits

..

26 Commits

Author SHA1 Message Date
soutade e291b79f2c Update metadata.json with Gnome Shell 48.5 2025-11-17 22:58:39 +01:00
Christian-Fritz b4af852a0f Fix formatting in README 2025-07-05 18:10:38 +02:00
soutade 6aa9f15d70 Update extension for GNOME 48 2025-03-31 15:14:59 +02:00
soutade ca11b0e175 Version 15 2024-08-31 16:36:07 +02:00
soutade d0e8f0cde5 Code review from JustPerfection 2024-08-31 13:58:43 +02:00
soutade 66d79cc804 Update for Gnome Shell 45+ 2024-08-29 20:46:21 +02:00
soutade 3ed3394a33 Update metadata.json with Gnome Shell 44 2023-09-25 19:14:35 +02:00
soutade 7cd668af14 Count number of threads instead of unread messages in gmail example 2022-11-20 21:01:41 +01:00
soutade 5690307c63 Update Gmail access with OAuth 2 2022-11-20 20:00:34 +01:00
soutade b1feb004e8 Update metadata.json 2022-10-28 17:20:14 +02:00
soutade 73021a25a1 Update README 2022-10-28 08:09:34 +02:00
soutade 4c73986596 Updates for GNOME 43 2022-10-27 17:54:37 +02:00
soutade d3665f2ff0 Quick update for GNOME 42. There is still some issues with menu. 2022-04-10 14:21:53 +02:00
soutade 00fb6120c9 Update README.md and version to be aligned on Gnome store version 2022-01-07 08:35:13 +01:00
soutade 02d3e8b72a Remove timer resource during SignalMgt destructor 2022-01-06 09:52:11 +01:00
soutade 78254a550e Update support for version 41 in metadata 2022-01-06 09:14:55 +01:00
soutade 7a5f506c23 Remove use of deprecated "lang" package 2021-10-01 09:02:34 +02:00
soutade 1d3328f71e Update support for version 40 in metadata 2021-09-30 16:33:06 +02:00
soutade 45d0cc9d11 Use WeakMap to store objects as key and rename MonitorWidget signals field into signalManager to avoid confusions 2021-09-30 16:32:26 +02:00
soutade 4d6fe82790 Update version 2021-02-02 07:04:45 +01:00
soutade 9943a9075f Popup text must be labels not buttons 2021-01-31 20:18:11 +01:00
soutade 83609b58ab After linter pass 2021-01-29 09:15:40 +01:00
soutade b85ff4a782 Update examples 2021-01-28 10:34:18 +01:00
soutade 30bfc796b9 Update README 2021-01-28 10:34:18 +01:00
soutade 35e34b52f2 Move signal management into external class. It allows to handle signals for popup nested elements. 2021-01-28 10:34:17 +01:00
soutade 1b4430c3ac Update README 2020-11-28 12:14:48 +01:00
9 changed files with 663 additions and 459 deletions
+54 -23
View File
@@ -7,10 +7,17 @@ This GNOME Shell Extension aims to display information to center box. Using DBUS
Installation Installation
------------ ------------
Install it from https://extensions.gnome.org/extension/2826/generic-monitor/
OR
Create a symbolic link from your _.local_ directory and enable extension Create a symbolic link from your _.local_ directory and enable extension
ln -s $PWD/generic-monitor@gnome-shell-extensions/ ~/.local/share/gnome-shell/extensions/ ```bash
gnome-extensions enable generic-monitor@gnome-shell-extensions ln -s $PWD/generic-monitor@gnome-shell-extensions/ ~/.local/share/gnome-shell/extensions/
gnome-extensions enable generic-monitor@gnome-shell-extensions
```
Restart GNOME Restart GNOME
@@ -20,6 +27,7 @@ DBUS protocol
All functions read JSON formatted parameters All functions read JSON formatted parameters
```js
notify(): notify():
{ {
"group": "groupname", "group": "groupname",
@@ -60,41 +68,54 @@ All functions read JSON formatted parameters
{ {
"item": "<itemName>@<groupName>" "item": "<itemName>@<groupName>"
} }
```
DBUS object DBUS object
=========== ===========
<text_object> is defined as : <text_object> is defined as:
```js
"text" : { "text" : {
"name" : "" // Optional, used with popup nested element
<signals_description>, // Optional, used with popup nested element
"text" : "Text to be displayed", "text" : "Text to be displayed",
"style" : "CSS style to be applied", // Optional "style" : "CSS style to be applied", // Optional
} }
```
<icon_object> is defined as : <icon_object> is defined as:
```js
"icon" : { "icon" : {
"path" : "Icon path", "path" : "Icon path",
"style" : "CSS style to be applied", // Optional "style" : "CSS style to be applied", // Optional
} }
```
<picture_object> is defined as : <picture_object> is defined as:
```js
"picture" : { "picture" : {
"name" : "" // Optional, used with popup nested element
<signals_description>, // Optional, used with popup nested element
"path" : "Icon path", "path" : "Icon path",
"width" : XXX, // Optional : Force width in pixels, can be -1 for defaut value "width" : XXX, // Optional : Force width in pixels, can be -1 for defaut value
"height" : XXX, // Optional : Force height in pixels, can be -1 for defaut value "height" : XXX, // Optional : Force height in pixels, can be -1 for defaut value
} }
```
<popup_object is defuned as : <popup_object> is defined as:
```js
"popup" : { "popup" : {
"items": [<text_objects> and/or <picture_objects>] "items": [<text_objects> and/or <picture_objects>]
} }
```
Signals description Signals description
=================== ===================
Signals can be : Signals can be :
```js
"on-click" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"] "on-click" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
"on-dblclick" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"] "on-dblclick" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
"on-rightclick" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"] "on-rightclick" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
@@ -102,17 +123,18 @@ Signals can be :
"on-enter" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"] "on-enter" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
"on-leave" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"] "on-leave" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
"on-scroll" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"] "on-scroll" : ["signal"|"delete"|"open-popup"|"close-popup"|"toggle-popup"]
```
Targets : Targets :
* signal : emit a signal to desktop application * signal : Emit a signal to desktop application
* delete : Delete item * delete : Delete item
* open-popup : Open the popup if there is one * open-popup : Open the popup if there is one
* close-popup : Close the popup if there is one * close-popup : Close the popup if there is one
* toggle-popup : Toggle (open/close) the popup if there is one * toggle-popup : Toggle (open/close) the popup if there is one
Signal names emit when action "signal" is specified : Signal names emit when action "signal" is specified:
* onClick * onClick
* onDblClick * onDblClick
@@ -123,9 +145,11 @@ Signal names emit when action "signal" is specified :
* onScrollUp * onScrollUp
* onScrollDown * onScrollDown
Each signal is sent with one parameter : "<itemName>@<groupName>" Each signal is sent with one parameter: "<itemName>@<groupName>"
For popup nested elements, parameter is "<nestedName>@<itemName>@<groupName>"
where nestedName can be empty if not defined by user
Other signals are available when extension is activated/deactivated : Other signals are available when extension is activated/deactivated:
* onActivate * onActivate
* onDeactivate * onDeactivate
@@ -134,13 +158,17 @@ Other signals are available when extension is activated/deactivated :
Example 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","on-click":"toggle-popup","text":"Hello","style":"color:green","popup":{"items":[{"picture":{"path":"/tmp/cat2.jpg"}}]}}]}' ```bash
# Create new group and add items
gdbus call --session --dest org.gnome.Shell --object-path /com/soutade/GenericMonitor --method com.soutade.GenericMonitor.notify '{"group":"new","items":[{"name":"first","on-click":"toggle-popup","text":{"text":"Hello","style":"color:green"},"popup":{"items":[{"picture":{"path":"/tmp/cat.jpg"}}]}}]}'
gdbus call --session --dest org.gnome.Shell --object-path /com/soutade/GenericMonitor --method com.soutade.GenericMonitor.deleteGroups '{"groups":["new"]}' # Delete group
gdbus call --session --dest org.gnome.Shell --object-path /com/soutade/GenericMonitor --method com.soutade.GenericMonitor.deleteGroups '{"groups":["new"]}'
```
Python examples is available Python examples are available @ https://indefero.soutade.fr/p/genericmonitor/source/tree/master/examples
Development Development
@@ -148,12 +176,15 @@ Development
After doing code update, you can test it within a nested window. In other cases you have to restart GNOME. After doing code update, you can test it within a nested window. In other cases you have to restart GNOME.
dbus-run-session -- gnome-shell --nested [--wayland] ```bash
dbus-run-session -- gnome-shell --nested [--wayland]
```
To see log & errors : To see log & errors:
journalctl /usr/bin/gnome-shell
```bash
journalctl /usr/bin/gnome-shell
```
Licence Licence
------- -------
+14 -14
View File
@@ -1,47 +1,47 @@
<interface name="com.soutade.GenericMonitor"> <interface name="com.soutade.GenericMonitor">
<!-- Functions --> <!-- Functions -->
<method name="notify"> <method name="notify">
<arg type="s" direction="in" /> <arg name="parameters" type="s" direction="in" />
</method> </method>
<method name="deleteItems"> <method name="deleteItems">
<arg type="s" direction="in" /> <arg name="items" type="s" direction="in" />
</method> </method>
<method name="deleteGroups"> <method name="deleteGroups">
<arg type="s" direction="in" /> <arg name="groups" type="s" direction="in" />
</method> </method>
<method name="openPopup"> <method name="openPopup">
<arg type="s" direction="in" /> <arg name="popup" type="s" direction="in" />
</method> </method>
<method name="closePopup"> <method name="closePopup">
<arg type="s" direction="in" /> <arg name="popup" type="s" direction="in" />
</method> </method>
<method name="togglePopup"> <method name="togglePopup">
<arg type="s" direction="in" /> <arg name="popup" type="s" direction="in" />
</method> </method>
<!-- Events --> <!-- Events -->
<signal name="onClick"> <signal name="onClick">
<arg type="s" direction="out" /> <arg name="fullName" type="s" direction="out" />
</signal> </signal>
<signal name="onRightClick"> <signal name="onRightClick">
<arg type="s" direction="out" /> <arg name="fullName" type="s" direction="out" />
</signal> </signal>
<signal name="onDblClick"> <signal name="onDblClick">
<arg type="s" direction="out" /> <arg name="fullName" type="s" direction="out" />
</signal> </signal>
<signal name="onRightDblClick"> <signal name="onRightDblClick">
<arg type="s" direction="out" /> <arg name="fullName" type="s" direction="out" />
</signal> </signal>
<signal name="onScrollUp"> <signal name="onScrollUp">
<arg type="s" direction="out" /> <arg name="fullName" type="s" direction="out" />
</signal> </signal>
<signal name="onScrollDown"> <signal name="onScrollDown">
<arg type="s" direction="out" /> <arg name="fullName" type="s" direction="out" />
</signal> </signal>
<signal name="onEnter"> <signal name="onEnter">
<arg type="s" direction="out" /> <arg name="fullName" type="s" direction="out" />
</signal> </signal>
<signal name="onLeave"> <signal name="onLeave">
<arg type="s" direction="out" /> <arg name="fullName" type="s" direction="out" />
</signal> </signal>
<!-- Activate/Deactivate signals --> <!-- Activate/Deactivate signals -->
<signal name="onActivate"> <signal name="onActivate">
+39 -16
View File
@@ -235,10 +235,24 @@ class GenericMonitor:
class GenericMonitorGenericWidget: class GenericMonitorGenericWidget:
""" Generic widget class, parent of all widgets """ Generic widget class, parent of all widgets
""" """
def __init__(self): def __init__(self, style='', name='', signals={}):
self.valuesToMap = [] """
Parameters
----------
name : str, optional
Widget name
signals : dictionary, optional
Dictionary of signals and their action
"""
self.valuesToMap = ['name', 'style']
self.mapValues = {} self.mapValues = {}
self.mapName = '' self.mapName = ''
self.style = style
self.name = name
self.signals = signals
def setStyle(self, style):
self.style = style
def _toMap(self): def _toMap(self):
""" Return dictionary of class elements to send to addon """ Return dictionary of class elements to send to addon
@@ -247,12 +261,14 @@ class GenericMonitorGenericWidget:
for p in self.valuesToMap: for p in self.valuesToMap:
if self.__dict__[p]: if self.__dict__[p]:
self.mapValues[p] = self.__dict__[p] self.mapValues[p] = self.__dict__[p]
for (name, value) in self.signals.items():
self.mapValues[name] = value
return {self.mapName:self.mapValues} return {self.mapName:self.mapValues}
class GenericMonitorTextWidget(GenericMonitorGenericWidget): class GenericMonitorTextWidget(GenericMonitorGenericWidget):
""" Text widget """ Text widget
""" """
def __init__(self, text, style=''): def __init__(self, text, style='', name='', signals={}):
""" """
Parameters Parameters
---------- ----------
@@ -260,19 +276,20 @@ class GenericMonitorTextWidget(GenericMonitorGenericWidget):
Text to display Text to display
style : str, optional style : str, optional
CSS style CSS style
name : str, optional
Widget name
signals : dictionary, optional
Dictionary of signals and their action
""" """
self.valuesToMap = ('text', 'style') super().__init__(style, name, signals)
self.valuesToMap += ['text']
self.mapName = 'text' self.mapName = 'text'
self.text = text self.text = text
self.style = style
def setText(self, text): def setText(self, text):
self.text = text self.text = text
def setStyle(self, style):
self.style = style
class GenericMonitorIconWidget(GenericMonitorGenericWidget): class GenericMonitorIconWidget(GenericMonitorGenericWidget):
""" Icon widget """ Icon widget
""" """
@@ -285,7 +302,8 @@ class GenericMonitorIconWidget(GenericMonitorGenericWidget):
style : str, optional style : str, optional
CSS style CSS style
""" """
self.valuesToMap = ('path', 'style') super().__init__(style=style)
self.valuesToMap += ['path']
self.mapName = 'icon' self.mapName = 'icon'
self.path = path self.path = path
@@ -294,14 +312,11 @@ class GenericMonitorIconWidget(GenericMonitorGenericWidget):
def setPath(self, path): def setPath(self, path):
self.path = path self.path = path
def setStyle(self, style):
self.style = style
class GenericMonitorPictureWidget(GenericMonitorGenericWidget):
class GenericMonitorPictureWidget(GenericMonitorIconWidget):
""" Picture widget """ Picture widget
""" """
def __init__(self, path, style='', width=-1, height=-1): def __init__(self, path, style='', width=-1, height=-1, name='', signals={}):
""" """
Parameters Parameters
---------- ----------
@@ -313,15 +328,23 @@ class GenericMonitorPictureWidget(GenericMonitorIconWidget):
Width of displayed picture (-1 for default width) Width of displayed picture (-1 for default width)
height : int, optional height : int, optional
Width of displayed picture (-1 for default width) Width of displayed picture (-1 for default width)
name : str, optional
Widget name
signals : dictionary, optional
Dictionary of signals and their action
""" """
super().__init__(path, style) super().__init__(style, name, signals)
self.valuesToMap = ('path', 'style', 'width', 'height') self.valuesToMap += ['path', 'width', 'height']
self.mapName = 'picture' self.mapName = 'picture'
self.path = path
self.width = width self.width = width
self.height = height self.height = height
def setPath(self, path):
self.path = path
def setWidth(self, width): def setWidth(self, width):
self.width = width self.width = width
+85
View File
@@ -0,0 +1,85 @@
#
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Setup : https://developers.google.com/gmail/api/quickstart/python
# Need to have credentials.json were you call main script
#
# File imported from https://github.com/googleworkspace/python-samples/blob/main/gmail/quickstart/quickstart.py
#
from __future__ import print_function
import os.path
import json
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
creds = None
def _initCreds():
global creds
if creds: return
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('./token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
data = {}
data['refresh_token'] = creds.refresh_token
data['client_id'] = creds.client_id
data['client_secret'] = creds.client_secret
data['token_uri'] = creds.token_uri
data['id_token'] = creds.id_token
token.write(json.dumps(data))
def getUnreadMails():
"""
Get number of unread threads (that may contain multiple messages)
"""
_initCreds()
service = build('gmail', 'v1', credentials=creds)
pageToken = ''
threads = set()
while True:
results = service.users().messages().list(userId='me', labelIds=['UNREAD'],\
includeSpamTrash=False, pageToken=pageToken)\
.execute()
if not 'messages' in results.keys(): continue
threads = threads.union(set([k['threadId'] for k in results['messages']]))
# Loop over all result pages (100 results per page by default)
pageToken = results.get('nextPageToken', '')
if not pageToken: break
return len(threads)
+10 -20
View File
@@ -23,11 +23,11 @@ import time
import requests import requests
from requests.auth import HTTPBasicAuth from requests.auth import HTTPBasicAuth
import xml.dom.minidom import xml.dom.minidom
import getpass
from threading import Thread from threading import Thread
from signal import signal, SIGINT from signal import signal, SIGINT
import sys import sys
from genericmonitor import * from genericmonitor import *
from gmail import getUnreadMails
PURPLE_CONV_UPDATE_UNSEEN = 4 PURPLE_CONV_UPDATE_UNSEEN = 4
PURPLE_MESSAGE_SEND = 0 PURPLE_MESSAGE_SEND = 0
@@ -59,31 +59,23 @@ class PidginConversation:
class EventThread(Thread,GenericMonitor): class EventThread(Thread,GenericMonitor):
SLEEP_TIME = 30 SLEEP_TIME = 30
MAIL_ADDRESS='XXX@gmail.com'
def stop(self): def stop(self):
self._stopLoop = True self._stopLoop = True
self.stopMainLoop() self.stopMainLoop()
def _getMail(self): def _getMail(self):
address = "https://mail.google.com/mail/feed/atom"
auth = HTTPBasicAuth(self.MAIL_ADDRESS, self._mail_password)
req = requests.get(address, auth=auth)
text = '' text = ''
style = '' style = ''
if req.status_code == requests.codes.ok: try:
dom = xml.dom.minidom.parseString(req.text) nb_messages = getUnreadMails()
try: if nb_messages == 1:
nb_messages = int(dom.getElementsByTagName('fullcount')[0].firstChild.nodeValue) text = '1 msg'
if nb_messages == 1: elif nb_messages > 1:
text = '1 msg' text = '%d msgs' % (nb_messages)
elif nb_messages > 1: style = 'color:white'
text = '%d msgs' % (nb_messages) except Exception as e:
style = 'color:white' text = str(e)
except Exception as e:
text = str(e)
else:
text = 'Mail error %d' % (req.status_code)
self.mailWidget.setText(text) self.mailWidget.setText(text)
self.mailWidget.setStyle(style) self.mailWidget.setStyle(style)
@@ -103,8 +95,6 @@ class EventThread(Thread,GenericMonitor):
self.add_signal_receiver(self.pidginMessageWrote, 'WroteChatMsg', 'im.pidgin.purple.PurpleInterface') self.add_signal_receiver(self.pidginMessageWrote, 'WroteChatMsg', 'im.pidgin.purple.PurpleInterface')
self.add_signal_receiver(self.pidginConversationUpdated, 'ConversationUpdated', 'im.pidgin.purple.PurpleInterface') self.add_signal_receiver(self.pidginConversationUpdated, 'ConversationUpdated', 'im.pidgin.purple.PurpleInterface')
self._mail_password = getpass.getpass('Enter password for address %s: ' % (self.MAIL_ADDRESS))
self.mailWidget = GenericMonitorTextWidget('') self.mailWidget = GenericMonitorTextWidget('')
mailItem = GenericMonitorItem('mail', [self.mailWidget]) mailItem = GenericMonitorItem('mail', [self.mailWidget])
self.mailGroup = GenericMonitorGroup('Mail', [mailItem]) self.mailGroup = GenericMonitorGroup('Mail', [mailItem])
+10 -8
View File
@@ -19,6 +19,7 @@
Display random picture from unsplash.com in a popup Display random picture from unsplash.com in a popup
* Click : open/close popup * Click : open/close popup
* Popup item click : display who clicked
* ScrollUp/ScrollDown/Double click : display next picture * ScrollUp/ScrollDown/Double click : display next picture
* Right click : exit * Right click : exit
''' '''
@@ -42,20 +43,17 @@ class PicturePopup(GenericMonitor):
self.runMainLoop() self.runMainLoop()
def display_next_img(self): def display_next_img(self):
filedata = urllib.request.urlopen('https://source.unsplash.com/random') filedata = urllib.request.urlopen('https://picsum.photos/500/500')
# Get redirected URL without parameters
url = filedata.url.split('?')[0]
filedata = urllib.request.urlopen(url + '?fit=max&width=500&height=500')
datatowrite = filedata.read() datatowrite = filedata.read()
with open('/tmp/cat2.jpg', 'wb') as f: with open('/tmp/cat2.jpg', 'wb') as f:
f.write(datatowrite) f.write(datatowrite)
widget = GenericMonitorTextWidget('#%d' % self.imgs_idx, 'color:purple') widget = GenericMonitorTextWidget('#%d' % self.imgs_idx, 'color:purple')
url_widget = GenericMonitorTextWidget(url, 'color:white;font-weight:bold') url_widget = GenericMonitorTextWidget('random_pic', 'color:white;font-weight:bold', signals={'on-click':'signal'}) # No name here
picture_widget = GenericMonitorPictureWidget('/tmp/cat2.jpg') picture_widget = GenericMonitorPictureWidget('/tmp/cat2.jpg', name='NestedWidget', signals={'on-click':'signal'})
popup = GenericMonitorPopup([url_widget, picture_widget]) popup = GenericMonitorPopup([url_widget, picture_widget])
signals = { signals = {
'on-click':'toggle-popup', 'on-click':'toggle-popup',
# Could also use this behavior # Could also use this behavior [bugged since GNOME 42]
# 'on-enter':'open-popup', # 'on-enter':'open-popup',
# 'on-leave':'close-popup', # 'on-leave':'close-popup',
'on-dblclick':'signal', 'on-dblclick':'signal',
@@ -68,7 +66,11 @@ class PicturePopup(GenericMonitor):
self.imgs_idx += 1 self.imgs_idx += 1
def _forMe(self, sender): def _forMe(self, sender):
return sender == self.item.getFullName() return str(sender).endswith(self.item.getFullName())
def onClick(self, sender):
if not self._forMe(sender): return
print('Click from {}'.format(sender))
def _onScroll(self, sender): def _onScroll(self, sender):
if not self._forMe(sender): return if not self._forMe(sender): return
+1 -1
View File
@@ -65,7 +65,7 @@ class TimerThread(Thread,GenericMonitor):
self._stopLoop = False self._stopLoop = False
self.textWidget = GenericMonitorTextWidget('') self.textWidget = GenericMonitorTextWidget('')
signals = {'on-click':'signal'} signals = {'on-click':'signal','on-dblclick':'signal','on-rightclick':'signal'}
self.monitorItem = GenericMonitorItem('timer', [self.textWidget], signals, box='right') self.monitorItem = GenericMonitorItem('timer', [self.textWidget], signals, box='right')
self.monitorGroup = GenericMonitorGroup('Timer', self.monitorItem) self.monitorGroup = GenericMonitorGroup('Timer', self.monitorItem)
+444 -370
View File
File diff suppressed because it is too large Load Diff
+4 -5
View File
@@ -2,11 +2,10 @@
"uuid": "generic-monitor@gnome-shell-extensions", "uuid": "generic-monitor@gnome-shell-extensions",
"name": "Generic Monitor", "name": "Generic Monitor",
"description": "Display text & icon on systray using DBUS", "description": "Display text & icon on systray using DBUS",
"version": "3", "version": "18",
"shell-version": [ "shell-version": [
"3.38", "48",
"3.36", "48.5"
"3.34"
], ],
"url": "http://indefero.soutade.fr/p/genericmonitor" "url": "https://forge.soutade.fr/soutade/GnomeShellGenericMonitor"
} }