From 85efe92d304743043aa896bd5d110be384c12fc8 Mon Sep 17 00:00:00 2001 From: Daniel Pavel Date: Tue, 9 Jul 2013 17:52:07 +0200 Subject: [PATCH] replaced appinstance with GtkApplication --- lib/solaar/appinstance.py | 67 ------------------------------- lib/solaar/gtk.py | 44 +++++++++----------- lib/solaar/ui/__init__.py | 58 ++++++++++++++++++++------ lib/solaar/ui/tray.py | 8 ++-- share/applications/solaar.desktop | 2 +- 5 files changed, 70 insertions(+), 109 deletions(-) delete mode 100644 lib/solaar/appinstance.py diff --git a/lib/solaar/appinstance.py b/lib/solaar/appinstance.py deleted file mode 100644 index fe46bf3f..00000000 --- a/lib/solaar/appinstance.py +++ /dev/null @@ -1,67 +0,0 @@ -# -# -# - -from __future__ import absolute_import, division, print_function, unicode_literals - -# -# -# - -import fcntl as _fcntl -import os.path as _path -import os as _os - -from solaar import NAME -_program = NAME.lower() -del NAME - -from logging import getLogger, DEBUG as _DEBUG -_log = getLogger(__name__) -del getLogger - - -def check(): - """Select a file lock location and try to acquire it. - Suitable locations are $XDG_RUNTIME_DIR, /run/lock, /var/lock, and $TMPDIR. - The first one found and writable is used. - """ - # ensure no more than a single instance runs at a time - lock_fd = None - for p in _os.environ.get('XDG_RUNTIME_DIR'), '/run/lock', '/var/lock', _os.environ.get('TMPDIR', '/tmp'): - # pick the first temporary writable folder - if p and _path.isdir(p) and _os.access(p, _os.W_OK): - lock_path = _path.join(p, _program + '.single-instance.' + str(_os.getuid())) - try: - lock_fd = open(lock_path, 'wb') - if _log.isEnabledFor(_DEBUG): - _log.debug("single-instance lock file is %s", lock_path) - break - except: - pass - - if lock_fd: - try: - _fcntl.flock(lock_fd, _fcntl.LOCK_EX | _fcntl.LOCK_NB) - if _log.isEnabledFor(_DEBUG): - _log.debug("acquired single-instance lock %s", lock_fd) - return lock_fd - except IOError as e: - if e.errno == 11: - _log.warn("lock file is busy, %s already running: %s", _program, e) - import sys - sys.exit(_program + ": error: already running") - else: - raise - else: - import sys - print (_program + ": warning: no suitable location for the lockfile found; ignoring", file=sys.stderr) - - -def close(lock_fd): - """Release a file lock.""" - if lock_fd: - _fcntl.flock(lock_fd, _fcntl.LOCK_UN) - lock_fd.close() - if _log.isEnabledFor(_DEBUG): - _log.debug("released single-instance lock %s", lock_fd) diff --git a/lib/solaar/gtk.py b/lib/solaar/gtk.py index ee06f421..8adf706d 100644 --- a/lib/solaar/gtk.py +++ b/lib/solaar/gtk.py @@ -39,37 +39,31 @@ def _parse_arguments(): return args -def _run(args): - import solaar.ui as ui - ui.init() - - import solaar.listener as listener - listener.setup_scanner(ui.status_changed, ui.error_dialog) - - listener.start_all() - - # main UI event loop - ui.run_loop() - ui.destroy() - - listener.stop_all() - - def main(): _require('pyudev', 'python-pyudev') _require('gi.repository', 'python-gi') _require('gi.repository.Gtk', 'gir1.2-gtk-3.0') - args = _parse_arguments() + _parse_arguments() + + # handle ^C in console + import signal + signal.signal(signal.SIGINT, signal.SIG_DFL) - from . import appinstance - appid = appinstance.check() try: - # handle ^C in console - import signal - signal.signal(signal.SIGINT, signal.SIG_DFL) - _run(args) - finally: - appinstance.close(appid) + import solaar.ui as ui + ui.init() + + import solaar.listener as listener + listener.setup_scanner(ui.status_changed, ui.error_dialog) + listener.start_all() + + # main UI event loop + ui.run_loop() + + listener.stop_all() + except Exception as e: + import sys + sys.exit("%s: error: %s" % (NAME.lower(), e)) if __name__ == '__main__': diff --git a/lib/solaar/ui/__init__.py b/lib/solaar/ui/__init__.py index 9c2e1ae8..f44e7b63 100644 --- a/lib/solaar/ui/__init__.py +++ b/lib/solaar/ui/__init__.py @@ -5,13 +5,37 @@ from __future__ import absolute_import, division, print_function, unicode_literals -from logging import getLogger, DEBUG as _DEBUG +from logging import getLogger, DEBUG as _DEBUG, INFO as _INFO _log = getLogger(__name__) del getLogger from gi.repository import GLib, Gtk GLib.threads_init() +# +# +# + +def _init_application(): + app = Gtk.Application.new('io.github.pwr.solaar', 0) + registered = app.register(None) + if _log.isEnabledFor(_INFO): + _log.info("application %s, registered %s", app.get_dbus_object_path(), registered) + # assert registered, "failed to register unique application %s" % app + + # if there is already a running instance, bail out + if app.get_is_remote(): + # pop up the window in the other instance + app.activate() + raise Exception("already running") + + return app + +application = _init_application() + +# +# +# def _error_dialog(reason, object): _log.error("error: %s %s", reason, object) @@ -67,7 +91,7 @@ def _process_async_queue(): if function: function(*args, **kwargs) if _log.isEnabledFor(_DEBUG): - _log.debug("stopped %s", t.name) + _log.debug("stopped") _queue_processor = Thread(name='AsyncUI', target=_process_async_queue) _queue_processor.daemon = True @@ -80,7 +104,6 @@ def async(function, *args, **kwargs): task = (function, args, kwargs) _task_queue.put(task) - # # # @@ -89,21 +112,32 @@ from . import notify, tray, window def init(): notify.init() - tray.init() + tray.init(lambda _ignore: window.destroy()) window.init() def run_loop(): - Gtk.main() + def _activate(app): + assert app == application + if app.get_windows(): + window.popup() + else: + app.add_window(window._window) -def destroy(): - # stop the async UI processor - _queue_processor.alive = False - async(None) + def _shutdown(app): + # stop the async UI processor + _queue_processor.alive = False + async(None) - tray.destroy() - window.destroy() - notify.uninit() + tray.destroy() + notify.uninit() + application.connect('activate', _activate) + application.connect('shutdown', _shutdown) + application.run(None) + +# +# +# from logitech.unifying_receiver.status import ALERT def _status_changed(device, alert, reason): diff --git a/lib/solaar/ui/tray.py b/lib/solaar/ui/tray.py index ca4ec655..3d9fd7fb 100644 --- a/lib/solaar/ui/tray.py +++ b/lib/solaar/ui/tray.py @@ -30,7 +30,7 @@ _RECEIVER_SEPARATOR = ('~', None, None, None) # # -def _create_menu(): +def _create_menu(quit_handler): menu = Gtk.Menu() # per-device menu entries will be generated as-needed @@ -42,7 +42,7 @@ def _create_menu(): from .action import about, make menu.append(about.create_menu_item()) - menu.append(make('application-exit', 'Quit', Gtk.main_quit).create_menu_item()) + menu.append(make('application-exit', 'Quit', quit_handler).create_menu_item()) del about, make menu.show_all() @@ -424,10 +424,10 @@ _devices_info = [] _menu = None _icon = None -def init(): +def init(_quit_handler): global _menu, _icon assert _menu is None - _menu = _create_menu() + _menu = _create_menu(_quit_handler) assert _icon is None _icon = _create(_menu) diff --git a/share/applications/solaar.desktop b/share/applications/solaar.desktop index 0363f59a..a5584065 100644 --- a/share/applications/solaar.desktop +++ b/share/applications/solaar.desktop @@ -3,7 +3,7 @@ Name=Solaar Comment=Logitech Unifying Receiver peripherals manager Exec=solaar Icon=solaar -StartupNotify=false +StartupNotify=true Terminal=false Type=Application Keywords=logitech;unifying;receiver;mouse;keyboard;