Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/server/source/idle_mixin.py : 83%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2# This file is part of Xpra.
3# Copyright (C) 2010-2020 Antoine Martin <antoine@xpra.org>
4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
5# later version. See the file COPYING for details.
7from xpra.util import envint, typedict, IDLE_TIMEOUT, XPRA_IDLE_NOTIFICATION_ID
8from xpra.os_util import monotonic_time
9from xpra.server.source.stub_source_mixin import StubSourceMixin
10from xpra.log import Logger
12log = Logger("timeout")
14GRACE_PERCENT = envint("XPRA_GRACE_PERCENT", 90)
17class IdleMixin(StubSourceMixin):
19 @classmethod
20 def is_needed(cls, caps : typedict) -> bool:
21 #the 'keyboard' and 'mouse' capability were only added in v4,
22 #so we have to enable the mixin by default:
23 return caps.boolget("keyboard", True) or caps.boolget("mouse", True) or caps.boolget("windows", False)
25 def __init__(self):
26 self.idle_timeout = 0
27 #duplicated from clientconnection:
28 self.notification_callbacks = {}
29 self.send_notifications = False
30 self.send_notifications_actions = False
32 def init_from(self, _protocol, server):
33 self.idle_timeout = server.idle_timeout
35 def init_state(self):
36 self.last_user_event = monotonic_time()
37 #grace duration is at least 10 seconds:
38 self.idle_grace_duration = max(10, int(self.idle_timeout*(100-GRACE_PERCENT)//100))
39 self.idle = False
40 self.idle_timer = None
41 self.idle_grace_timer = None
43 def cleanup(self):
44 self.cancel_idle_grace_timeout()
45 self.cancel_idle_timeout()
47 def get_info(self) -> dict:
48 return {
49 "idle_time" : int(monotonic_time()-self.last_user_event),
50 "idle" : self.idle,
51 }
54 def parse_client_caps(self, _c : typedict):
55 #start the timer
56 self.schedule_idle_grace_timeout()
57 self.schedule_idle_timeout()
59 def user_event(self):
60 log("user_event()")
61 self.last_user_event = monotonic_time()
62 self.cancel_idle_grace_timeout()
63 self.schedule_idle_grace_timeout()
64 self.cancel_idle_timeout()
65 self.schedule_idle_timeout()
66 if self.idle:
67 self.no_idle()
68 if self.notification_callbacks.pop(XPRA_IDLE_NOTIFICATION_ID, None):
69 self.notify_close(XPRA_IDLE_NOTIFICATION_ID)
72 def cancel_idle_timeout(self):
73 it = self.idle_timer
74 if it:
75 self.idle_timer = None
76 self.source_remove(it)
78 def schedule_idle_timeout(self):
79 log("schedule_idle_timeout() idle_timer=%s, idle_timeout=%s", self.idle_timer, self.idle_timeout)
80 if self.idle_timeout>0:
81 self.idle_timer = self.timeout_add(self.idle_timeout*1000, self.idle_timedout)
83 def cancel_idle_grace_timeout(self):
84 igt = self.idle_grace_timer
85 if igt:
86 self.idle_grace_timer = None
87 self.source_remove(igt)
89 def schedule_idle_grace_timeout(self):
90 log("schedule_idle_grace_timeout() grace timer=%s, idle_timeout=%s", self.idle_grace_timer, self.idle_timeout)
91 if self.idle_timeout>0 and not self.is_closed():
92 grace = self.idle_timeout - self.idle_grace_duration
93 self.idle_grace_timer = self.timeout_add(max(0, int(grace*1000)), self.idle_grace_timedout)
94 log("schedule_idle_grace_timeout() timer=%s due in %i seconds", self.idle_grace_timer, grace)
96 def idle_grace_timedout(self):
97 self.idle_grace_timer = None
98 log("idle_grace_timedout()")
99 if not self.send_notifications:
100 #not much we can do!
101 return
102 #notify the user, giving him a chance to cancel the timeout:
103 nid = XPRA_IDLE_NOTIFICATION_ID
104 if nid in self.notification_callbacks:
105 return
106 actions = ()
107 if self.send_notifications_actions:
108 actions = ("cancel", "Cancel Timeout")
109 if self.session_name!="Xpra":
110 summary = "The Xpra session %s" % self.session_name
111 else:
112 summary = "Xpra session"
113 summary += " is about to timeout"
114 body = "Unless this session sees some activity,\n" + \
115 "it will be terminated soon."
116 self.may_notify(nid, summary, body,
117 actions, {}, expire_timeout=10*1000,
118 icon_name="timer", user_callback=self.idle_notification_action)
119 self.go_idle()
121 def idle_notification_action(self, nid, action_id):
122 log("idle_notification_action(%i, %s)", nid, action_id)
123 if action_id=="cancel":
124 self.user_event()
126 def idle_timedout(self):
127 self.idle_timer = None
128 p = self.protocol
129 log("idle_timedout() protocol=%s", p)
130 if p:
131 self.disconnect(IDLE_TIMEOUT)
132 if not self.is_closed():
133 self.schedule_idle_timeout()