-
-
Notifications
You must be signed in to change notification settings - Fork 180
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#1761: move notification client code to its own module
git-svn-id: https://xpra.org/svn/Xpra/trunk@18514 3bb7dfac-3a0b-4e04-842a-767bc560f471
- Loading branch information
Showing
4 changed files
with
187 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
# This file is part of Xpra. | ||
# Copyright (C) 2010-2018 Antoine Martin <antoine@devloop.org.uk> | ||
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any | ||
# later version. See the file COPYING for details. | ||
|
||
from xpra.log import Logger | ||
log = Logger("notify") | ||
|
||
|
||
from xpra.platform.paths import get_icon_filename | ||
from xpra.platform.gui import get_native_notifier_classes | ||
from xpra.os_util import bytestostr | ||
from xpra.util import envbool, repr_ellipsized, make_instance | ||
|
||
|
||
NATIVE_NOTIFIER = envbool("XPRA_NATIVE_NOTIFIER", True) | ||
|
||
|
||
""" | ||
Utility superclass for clients that handle notifications | ||
""" | ||
class NotificationClient(object): | ||
|
||
def __init__(self): | ||
self.client_supports_notifications = False | ||
self.notifications_enabled = False | ||
self.notifier = None | ||
self.tray = None | ||
|
||
def init(self, opts): | ||
""" initialize variables from configuration """ | ||
self.client_supports_notifications = opts.notifications | ||
|
||
def init_ui(self): | ||
log("client_supports_notifications=%s", self.client_supports_notifications) | ||
if self.client_supports_notifications: | ||
self.notifier = self.make_notifier() | ||
log("using notifier=%s", self.notifier) | ||
self.client_supports_notifications = self.notifier is not None | ||
|
||
|
||
def cleanup(self): | ||
n = self.notifier | ||
log("NotificationClient.cleanup() notifier=%s", n) | ||
if n: | ||
self.notifier = None | ||
try: | ||
n.cleanup() | ||
except: | ||
log.error("Error on notifier cleanup", exc_info=True) | ||
|
||
|
||
def parse_server_capabilities(self): | ||
c = self.server_capabilities | ||
self.server_notifications = c.boolget("notifications") | ||
self.server_notifications_close = c.boolget("notifications.close") | ||
self.server_notifications_actions = c.boolget("notifications.actions") | ||
self.notifications_enabled = self.client_supports_notifications | ||
|
||
def get_notifications_caps(self): | ||
return { | ||
"" : self.client_supports_notifications, | ||
"close" : self.client_supports_notifications, | ||
"actions" : self.client_supports_notifications and self.notifier and self.notifier.handles_actions, | ||
} | ||
|
||
def init_authenticated_packet_handlers(self): | ||
self.set_packet_handlers(self._ui_packet_handlers, { | ||
"notify_show": self._process_notify_show, | ||
"notify_close": self._process_notify_close, | ||
}) | ||
|
||
def make_notifier(self): | ||
nc = self.get_notifier_classes() | ||
log("make_notifier() notifier classes: %s", nc) | ||
return make_instance(nc, self.notification_closed, self.notification_action) | ||
|
||
def notification_closed(self, nid, reason=3, text=""): | ||
log("notification_closed(%i, %i, %s) server notification.close=%s", nid, reason, text, self.server_notifications_close) | ||
if self.server_notifications_close: | ||
self.send("notification-close", nid, reason, text) | ||
|
||
def notification_action(self, nid, action_id): | ||
log("notification_action(%i, %s) server notifications.actions=%s", nid, action_id, self.server_notifications_actions) | ||
if self.server_notifications_actions: | ||
self.send("notification-action", nid, action_id) | ||
|
||
def get_notifier_classes(self): | ||
#subclasses will generally add their toolkit specific variants | ||
#by overriding this method | ||
#use the native ones first: | ||
if not NATIVE_NOTIFIER: | ||
return [] | ||
return get_native_notifier_classes() | ||
|
||
def may_notify(self, nid, summary, body, actions=[], hints={}, expire_timeout=10*1000, icon_name=None): | ||
log("may_notify%s client_supports_notifications=%s, notifier=%s", (nid, summary, body, actions, hints, expire_timeout, icon_name), self.client_supports_notifications, self.notifier) | ||
n = self.notifier | ||
if not self.client_supports_notifications or not n: | ||
return | ||
try: | ||
from xpra.notifications.common import parse_image_path | ||
icon_filename = get_icon_filename(icon_name) | ||
icon = parse_image_path(icon_filename) | ||
n.show_notify("", self.tray, nid, "Xpra", nid, "", summary, body, actions, hints, expire_timeout, icon) | ||
except Exception as e: | ||
log("failed to show notification", exc_info=True) | ||
log.error("Error: cannot show notification") | ||
log.error(" '%s'", summary) | ||
log.error(" %s", e) | ||
|
||
def _process_notify_show(self, packet): | ||
if not self.notifications_enabled: | ||
log("process_notify_show: ignoring packet, notifications are disabled") | ||
return | ||
self._ui_event() | ||
dbus_id, nid, app_name, replaces_nid, app_icon, summary, body, expire_timeout = packet[1:9] | ||
icon, actions, hints = None, [], {} | ||
if len(packet)>=10: | ||
icon = packet[9] | ||
if len(packet)>=12: | ||
actions, hints = packet[10], packet[11] | ||
#note: if the server doesn't support notification forwarding, | ||
#it can still send us the messages (via xpra control or the dbus interface) | ||
log("_process_notify_show(%s) notifier=%s, server_notifications=%s", repr_ellipsized(str(packet)), self.notifier, self.server_notifications) | ||
log("notification actions=%s, hints=%s", actions, hints) | ||
assert self.notifier | ||
#this one of the few places where we actually do care about character encoding: | ||
try: | ||
summary = summary.decode("utf8") | ||
except: | ||
summary = bytestostr(summary) | ||
try: | ||
body = body.decode("utf8") | ||
except: | ||
body = bytestostr(body) | ||
app_name = bytestostr(app_name) | ||
tray = self.get_tray_window(app_name, hints) | ||
log("get_tray_window(%s)=%s", app_name, tray) | ||
self.notifier.show_notify(dbus_id, tray, nid, app_name, replaces_nid, app_icon, summary, body, actions, hints, expire_timeout, icon) | ||
|
||
def _process_notify_close(self, packet): | ||
if not self.notifications_enabled: | ||
return | ||
assert self.notifier | ||
nid = packet[1] | ||
log("_process_notify_close(%s)", nid) | ||
self.notifier.close_notify(nid) | ||
|
||
def get_tray_window(self, _app_name, _hints): | ||
#overriden in subclass to use the correct window if we can find it | ||
return self.tray |
Oops, something went wrong.