replaced appinstance with GtkApplication
This commit is contained in:
parent
b01636e05d
commit
85efe92d30
|
@ -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)
|
|
|
@ -39,37 +39,31 @@ def _parse_arguments():
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
def _run(args):
|
def main():
|
||||||
|
_require('pyudev', 'python-pyudev')
|
||||||
|
_require('gi.repository', 'python-gi')
|
||||||
|
_require('gi.repository.Gtk', 'gir1.2-gtk-3.0')
|
||||||
|
_parse_arguments()
|
||||||
|
|
||||||
|
# handle ^C in console
|
||||||
|
import signal
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
|
||||||
|
try:
|
||||||
import solaar.ui as ui
|
import solaar.ui as ui
|
||||||
ui.init()
|
ui.init()
|
||||||
|
|
||||||
import solaar.listener as listener
|
import solaar.listener as listener
|
||||||
listener.setup_scanner(ui.status_changed, ui.error_dialog)
|
listener.setup_scanner(ui.status_changed, ui.error_dialog)
|
||||||
|
|
||||||
listener.start_all()
|
listener.start_all()
|
||||||
|
|
||||||
# main UI event loop
|
# main UI event loop
|
||||||
ui.run_loop()
|
ui.run_loop()
|
||||||
ui.destroy()
|
|
||||||
|
|
||||||
listener.stop_all()
|
listener.stop_all()
|
||||||
|
except Exception as e:
|
||||||
|
import sys
|
||||||
def main():
|
sys.exit("%s: error: %s" % (NAME.lower(), e))
|
||||||
_require('pyudev', 'python-pyudev')
|
|
||||||
_require('gi.repository', 'python-gi')
|
|
||||||
_require('gi.repository.Gtk', 'gir1.2-gtk-3.0')
|
|
||||||
args = _parse_arguments()
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -5,13 +5,37 @@
|
||||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
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__)
|
_log = getLogger(__name__)
|
||||||
del getLogger
|
del getLogger
|
||||||
|
|
||||||
from gi.repository import GLib, Gtk
|
from gi.repository import GLib, Gtk
|
||||||
GLib.threads_init()
|
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):
|
def _error_dialog(reason, object):
|
||||||
_log.error("error: %s %s", reason, object)
|
_log.error("error: %s %s", reason, object)
|
||||||
|
@ -67,7 +91,7 @@ def _process_async_queue():
|
||||||
if function:
|
if function:
|
||||||
function(*args, **kwargs)
|
function(*args, **kwargs)
|
||||||
if _log.isEnabledFor(_DEBUG):
|
if _log.isEnabledFor(_DEBUG):
|
||||||
_log.debug("stopped %s", t.name)
|
_log.debug("stopped")
|
||||||
|
|
||||||
_queue_processor = Thread(name='AsyncUI', target=_process_async_queue)
|
_queue_processor = Thread(name='AsyncUI', target=_process_async_queue)
|
||||||
_queue_processor.daemon = True
|
_queue_processor.daemon = True
|
||||||
|
@ -80,7 +104,6 @@ def async(function, *args, **kwargs):
|
||||||
task = (function, args, kwargs)
|
task = (function, args, kwargs)
|
||||||
_task_queue.put(task)
|
_task_queue.put(task)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -89,21 +112,32 @@ from . import notify, tray, window
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
notify.init()
|
notify.init()
|
||||||
tray.init()
|
tray.init(lambda _ignore: window.destroy())
|
||||||
window.init()
|
window.init()
|
||||||
|
|
||||||
def run_loop():
|
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():
|
def _shutdown(app):
|
||||||
# stop the async UI processor
|
# stop the async UI processor
|
||||||
_queue_processor.alive = False
|
_queue_processor.alive = False
|
||||||
async(None)
|
async(None)
|
||||||
|
|
||||||
tray.destroy()
|
tray.destroy()
|
||||||
window.destroy()
|
|
||||||
notify.uninit()
|
notify.uninit()
|
||||||
|
|
||||||
|
application.connect('activate', _activate)
|
||||||
|
application.connect('shutdown', _shutdown)
|
||||||
|
application.run(None)
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
from logitech.unifying_receiver.status import ALERT
|
from logitech.unifying_receiver.status import ALERT
|
||||||
def _status_changed(device, alert, reason):
|
def _status_changed(device, alert, reason):
|
||||||
|
|
|
@ -30,7 +30,7 @@ _RECEIVER_SEPARATOR = ('~', None, None, None)
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
def _create_menu():
|
def _create_menu(quit_handler):
|
||||||
menu = Gtk.Menu()
|
menu = Gtk.Menu()
|
||||||
|
|
||||||
# per-device menu entries will be generated as-needed
|
# per-device menu entries will be generated as-needed
|
||||||
|
@ -42,7 +42,7 @@ def _create_menu():
|
||||||
|
|
||||||
from .action import about, make
|
from .action import about, make
|
||||||
menu.append(about.create_menu_item())
|
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
|
del about, make
|
||||||
|
|
||||||
menu.show_all()
|
menu.show_all()
|
||||||
|
@ -424,10 +424,10 @@ _devices_info = []
|
||||||
_menu = None
|
_menu = None
|
||||||
_icon = None
|
_icon = None
|
||||||
|
|
||||||
def init():
|
def init(_quit_handler):
|
||||||
global _menu, _icon
|
global _menu, _icon
|
||||||
assert _menu is None
|
assert _menu is None
|
||||||
_menu = _create_menu()
|
_menu = _create_menu(_quit_handler)
|
||||||
assert _icon is None
|
assert _icon is None
|
||||||
_icon = _create(_menu)
|
_icon = _create(_menu)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ Name=Solaar
|
||||||
Comment=Logitech Unifying Receiver peripherals manager
|
Comment=Logitech Unifying Receiver peripherals manager
|
||||||
Exec=solaar
|
Exec=solaar
|
||||||
Icon=solaar
|
Icon=solaar
|
||||||
StartupNotify=false
|
StartupNotify=true
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Keywords=logitech;unifying;receiver;mouse;keyboard;
|
Keywords=logitech;unifying;receiver;mouse;keyboard;
|
||||||
|
|
Loading…
Reference in New Issue