Hide keyboard shortcuts

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. 

6 

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 

11 

12log = Logger("timeout") 

13 

14GRACE_PERCENT = envint("XPRA_GRACE_PERCENT", 90) 

15 

16 

17class IdleMixin(StubSourceMixin): 

18 

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) 

24 

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 

31 

32 def init_from(self, _protocol, server): 

33 self.idle_timeout = server.idle_timeout 

34 

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 

42 

43 def cleanup(self): 

44 self.cancel_idle_grace_timeout() 

45 self.cancel_idle_timeout() 

46 

47 def get_info(self) -> dict: 

48 return { 

49 "idle_time" : int(monotonic_time()-self.last_user_event), 

50 "idle" : self.idle, 

51 } 

52 

53 

54 def parse_client_caps(self, _c : typedict): 

55 #start the timer 

56 self.schedule_idle_grace_timeout() 

57 self.schedule_idle_timeout() 

58 

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) 

70 

71 

72 def cancel_idle_timeout(self): 

73 it = self.idle_timer 

74 if it: 

75 self.idle_timer = None 

76 self.source_remove(it) 

77 

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) 

82 

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) 

88 

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) 

95 

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() 

120 

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() 

125 

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()