Skip to content

Commit

Permalink
#803 / #1688:
Browse files Browse the repository at this point in the history
* augment the timeout notification so users can cancel it using an action
* support showing the timeout in the gtk notifier (show for all notifications with a timeout shorter than 60s)

git-svn-id: https://xpra.org/svn/Xpra/trunk@18200 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Jan 30, 2018
1 parent f417ea2 commit d23356a
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 26 deletions.
16 changes: 8 additions & 8 deletions src/xpra/gtk_common/gtk_notifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ def get_origin_x(self):
def get_origin_y(self):
return self.y

def show_notify(self, dbus_id, tray, nid, app_name, replaces_nid, app_icon, summary, body, actions, hints, expire_timeout, icon):
self.new_popup(nid, summary, body, actions, icon)
def show_notify(self, dbus_id, tray, nid, app_name, replaces_nid, app_icon, summary, body, actions, hints, timeout, icon):
self.new_popup(nid, summary, body, actions, icon, timeout, timeout>0 and timeout<=600)

def new_popup(self, nid, summary, body, actions, icon):
def new_popup(self, nid, summary, body, actions, icon, timeout=10, show_timeout=False):
"""Create a new Popup instance."""
if len(self._notify_stack) == self.max_popups:
oldest = self._notify_stack[0]
Expand All @@ -121,7 +121,7 @@ def new_popup(self, nid, summary, body, actions, icon):
loader.write(img_data, len(img_data))
loader.close()
image = loader.get_pixbuf()
popup = Popup(self, nid, summary, body, actions, image=image)
popup = Popup(self, nid, summary, body, actions, image=image, timeout=timeout, show_timeout=show_timeout)
self._notify_stack.append(popup)
self._offset += self._notify_stack[-1].h
return popup
Expand All @@ -146,8 +146,8 @@ def popup_action(self, nid, action_id):


class Popup(gtk.Window):
def __init__(self, stack, nid, title, message, actions, image):
log("Popup%s", (stack, nid, title, message, actions, image))
def __init__(self, stack, nid, title, message, actions, image, timeout=5, show_timeout=False):
log("Popup%s", (stack, nid, title, message, actions, image, timeout, show_timeout))
self.stack = stack
self.nid = nid
gtk.Window.__init__(self)
Expand Down Expand Up @@ -201,7 +201,7 @@ def __init__(self, stack, nid, title, message, actions, image):
self.counter = gtk.Label()
self.counter.set_alignment(1, 1)
self.counter.set_padding(3, 3)
self.timeout = stack.timeout
self.timeout = timeout

body_box.pack_start(self.message, True, False, 5)
body_box.pack_end(self.counter, False, False, 5)
Expand All @@ -224,7 +224,7 @@ def __init__(self, stack, nid, title, message, actions, image):
self.message.modify_fg(STATE_NORMAL, stack.fg_color)
self.header.modify_fg(STATE_NORMAL, stack.fg_color)
self.counter.modify_fg(STATE_NORMAL, stack.fg_color)
self.show_timeout = stack.show_timeout
self.show_timeout = show_timeout
self.hover = False
self.show_all()
self.w, self.h = get_preferred_size(self)
Expand Down
20 changes: 13 additions & 7 deletions src/xpra/notifications/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.

import os.path
from xpra.os_util import BytesIOClass
from xpra.log import Logger
log = Logger("dbus", "notify")

XPRA_NOTIFICATIONS_OFFSET = 2**31
XPRA_BANDWIDTH_NOTIFICATION_ID = XPRA_NOTIFICATIONS_OFFSET+1
XPRA_IDLE_NOTIFICATION_ID = XPRA_NOTIFICATIONS_OFFSET+2


def parse_image_data(data):
try:
Expand All @@ -29,13 +34,14 @@ def parse_image_data(data):
return None

def parse_image_path(path):
try:
from PIL import Image
img = Image.open(path)
return image_data(img)
except Exception as e:
log.error("Error parsing image path '%s' for notification:", path)
log.error(" %s", e)
if os.path.exists(path):
try:
from PIL import Image
img = Image.open(path)
return image_data(img)
except Exception as e:
log.error("Error parsing image path '%s' for notification:", path)
log.error(" %s", e)
return None

def image_data(img):
Expand Down
31 changes: 24 additions & 7 deletions src/xpra/server/server_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
notifylog = Logger("notify")
httplog = Logger("http")
bandwidthlog = Logger("bandwidth")
timeoutlog = Logger("timeout")

from xpra.platform.features import COMMAND_SIGNALS, CLIPBOARDS
from xpra.keyboard.mask import DEFAULT_MODIFIER_MEANINGS
Expand All @@ -46,7 +47,7 @@
from xpra.net.bytestreams import set_socket_timeout
from xpra.platform import get_username
from xpra.platform.paths import get_icon_filename, get_icon_dir
from xpra.notifications.common import parse_image_path
from xpra.notifications.common import parse_image_path, XPRA_IDLE_NOTIFICATION_ID
from xpra.child_reaper import reaper_cleanup
from xpra.scripts.config import parse_bool_or_int, parse_bool, FALSE_OPTIONS, TRUE_OPTIONS
from xpra.scripts.main import sound_option, parse_env
Expand Down Expand Up @@ -517,6 +518,7 @@ def _process_notification_action(self, proto, packet):
nid, action_key = packet[1:3]
ss = self._server_sources.get(proto)
assert ss
ss.user_event()
try:
#special client callback notification:
client_callback = ss.notification_callbacks.pop(nid)
Expand Down Expand Up @@ -1193,17 +1195,33 @@ def is_timedout(self, protocol):


def idle_timeout_cb(self, source):
log("idle_timeout_cb(%s)", source)
timeoutlog("idle_timeout_cb(%s)", source)
p = source.protocol
if p:
self.disconnect_client(p, IDLE_TIMEOUT)

def idle_grace_timeout_cb(self, source):
log("idle_grace_timeout_cb(%s)", source)
timeout_nid = 2**16 + 2**8 + 1
source.notify(0, timeout_nid, "xpra", 0, "", "This Xpra session will timeout soon", "Activate one of the windows to avoid this timeout", [], {}, 10, "")
timeoutlog("idle_grace_timeout_cb(%s)", source)
nid = XPRA_IDLE_NOTIFICATION_ID
actions = ["cancel", "Cancel Timeout"]
user_icon = os.path.join(get_icon_dir(), "timer.png")
icon = parse_image_path(user_icon) or ()
def idle_notification_action(nid, action_id):
timeoutlog("idle_notification_action(%i, %s)", nid, action_id)
if action_id=="cancel":
source.user_event()
source.no_idle()
if self.session_name!="Xpra":
summary = "The Xpra session %s" % self.session_name
else:
summary = "Xpra session"
summary += " is about to timeout"
body = "Unless this session sees some activity,\n" + \
"it will be terminated soon."
source.notify("", nid, "Xpra", 0, "", summary, body, actions, {}, source.idle_grace_duration, icon, user_callback=idle_notification_action)
source.go_idle()


def _log_disconnect(self, proto, *args):
#skip logging of disconnection events for server sources
#we have tagged during hello ("info_request", "exit_request", etc..)
Expand Down Expand Up @@ -1398,8 +1416,7 @@ def notify_new_user(self, ss):
if self.notifications_forwarder:
dbus_id = self.notifications_forwarder.dbus_id
user_icon = os.path.join(get_icon_dir(), "user.png")
if os.path.exists(user_icon):
icon = parse_image_path(user_icon)
icon = parse_image_path(user_icon) or ()
title = "User '%s' connected to the session" % (ss.name or ss.username or ss.uuid)
body = "\n".join(ss.get_connect_info())
for s in self._server_sources.values():
Expand Down
10 changes: 6 additions & 4 deletions src/xpra/server/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from xpra.make_thread import start_thread
from xpra.os_util import platform_name, Queue, get_machine_id, get_user_uuid, monotonic_time, BytesIOClass, strtobytes, bytestostr, WIN32, POSIX
from xpra.server.background_worker import add_work_item
from xpra.notifications.common import XPRA_BANDWIDTH_NOTIFICATION_ID
from xpra.platform.paths import get_icon_dir
from xpra.util import csv, std, typedict, updict, flatten_dict, notypedict, get_screen_info, envint, envbool, AtomicInteger, \
CLIENT_PING_TIMEOUT, WORKSPACE_UNSET, DEFAULT_METADATA_SUPPORTED
Expand Down Expand Up @@ -282,6 +283,8 @@ def __init__(self, protocol, disconnect_cb, idle_add, timeout_add, source_remove
self.idle_timeout = idle_timeout
self.idle_timeout_cb = idle_timeout_cb
self.idle_grace_timeout_cb = idle_grace_timeout_cb
#grace duration is at least 10 seconds:
self.idle_grace_duration = max(10, int(self.idle_timeout*(100-GRACE_PERCENT)//100))
self.idle_timer = None
self.idle_grace_timer = None
self.schedule_idle_grace_timeout()
Expand Down Expand Up @@ -714,9 +717,8 @@ def schedule_idle_grace_timeout(self):
self.source_remove(self.idle_grace_timer)
self.idle_grace_timer = None
if self.idle_timeout>0 and not self.is_closed():
#grace timer is 90% of real timer:
grace = int(self.idle_timeout*1000*GRACE_PERCENT/100)
self.idle_grace_timer = self.timeout_add(grace, self.idle_grace_timedout)
grace = self.idle_timeout - self.idle_grace_duration
self.idle_grace_timer = self.timeout_add(max(0, int(grace*1000)), self.idle_grace_timedout)

def idle_grace_timedout(self):
self.idle_grace_timer = None
Expand Down Expand Up @@ -2524,7 +2526,7 @@ def record_congestion_event(self, source, late_pct=0, send_speed=0):
if count>CONGESTION_WARNING_EVENT_COUNT:
self.bandwidth_warning_time = now
dbus_id = ""
nid = 2**31
nid = XPRA_BANDWIDTH_NOTIFICATION_ID
summary = "Network Performance Issue"
body = "Your network connection is struggling to keep up,\n" + \
"consider lowering the bandwidth limit,\n" + \
Expand Down

0 comments on commit d23356a

Please sign in to comment.