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# This file is part of Xpra. 

2# Copyright (C) 2019-2020 Antoine Martin <antoine@xpra.org> 

3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

4# later version. See the file COPYING for details. 

5 

6from gi.repository import GLib 

7 

8from xpra.clipboard.clipboard_core import ClipboardProtocolHelperCore 

9from xpra.util import repr_ellipsized, ellipsizer, envint, engs 

10from xpra.log import Logger 

11from xpra.platform.features import CLIPBOARD_GREEDY 

12 

13log = Logger("clipboard") 

14 

15CONVERT_TIMEOUT = envint("XPRA_CLIPBOARD_CONVERT_TIMEOUT", 100) 

16REMOTE_TIMEOUT = envint("XPRA_CLIPBOARD_REMOTE_TIMEOUT", 1500) 

17assert 0<CONVERT_TIMEOUT<5000 

18assert 0<REMOTE_TIMEOUT<5000 

19 

20 

21class ClipboardTimeoutHelper(ClipboardProtocolHelperCore): 

22 

23 #a clipboard superclass that handles timeouts 

24 def __init__(self, send_packet_cb, progress_cb=None, **kwargs): 

25 super().__init__(send_packet_cb, progress_cb, **kwargs) 

26 self._clipboard_outstanding_requests = {} 

27 

28 def cleanup(self): 

29 #reply to outstanding requests with "no data": 

30 for request_id in tuple(self._clipboard_outstanding_requests.keys()): 

31 self._clipboard_got_contents(request_id) 

32 self._clipboard_outstanding_requests = {} 

33 ClipboardProtocolHelperCore.cleanup(self) 

34 

35 def make_proxy(self, selection): 

36 raise NotImplementedError() 

37 

38 def _get_proxy(self, selection): 

39 proxy = self._clipboard_proxies.get(selection) 

40 if not proxy: 

41 log.warn("Warning: no clipboard proxy for '%s'", selection) 

42 return None 

43 return proxy 

44 

45 def set_want_targets_client(self, want_targets): 

46 super().set_want_targets_client(want_targets) 

47 #pass it on to the ClipboardProxy instances: 

48 for proxy in self._clipboard_proxies.values(): 

49 proxy.set_want_targets(want_targets) 

50 

51 

52 ############################################################################ 

53 # network methods for communicating with the remote clipboard: 

54 ############################################################################ 

55 def _send_clipboard_token_handler(self, proxy, packet_data=()): 

56 if log.is_debug_enabled(): 

57 log("_send_clipboard_token_handler(%s, %s)", proxy, repr_ellipsized(packet_data)) 

58 remote = self.local_to_remote(proxy._selection) 

59 packet = ["clipboard-token", remote] 

60 if packet_data: 

61 #append 'TARGETS' unchanged: 

62 packet.append(packet_data[0]) 

63 #if present, the next element is the target data, 

64 #which we have to convert to wire format: 

65 if len(packet_data)>=2: 

66 target, dtype, dformat, data = packet_data[1] 

67 wire_encoding, wire_data = self._munge_raw_selection_to_wire(target, dtype, dformat, data) 

68 if wire_encoding: 

69 wire_data = self._may_compress(dtype, dformat, wire_data) 

70 if wire_data: 

71 packet += [target, dtype, dformat, wire_encoding, wire_data] 

72 claim = proxy._can_send 

73 packet += [claim, CLIPBOARD_GREEDY] 

74 log("send_clipboard_token_handler %s to %s", proxy._selection, remote) 

75 self.send(*packet) 

76 

77 def _send_clipboard_request_handler(self, proxy, selection, target): 

78 log("send_clipboard_request_handler%s", (proxy, selection, target)) 

79 request_id = self._clipboard_request_counter 

80 self._clipboard_request_counter += 1 

81 remote = self.local_to_remote(selection) 

82 log("send_clipboard_request %s to %s, id=%s", selection, remote, request_id) 

83 timer = GLib.timeout_add(REMOTE_TIMEOUT, self.timeout_request, request_id, selection, target) 

84 self._clipboard_outstanding_requests[request_id] = (timer, selection, target) 

85 self.progress() 

86 self.send("clipboard-request", request_id, remote, target) 

87 

88 def timeout_request(self, request_id, selection, target): 

89 try: 

90 selection, target = self._clipboard_outstanding_requests.pop(request_id)[1:] 

91 except KeyError: 

92 log.warn("Warning: clipboard request id %i not found", request_id) 

93 log.warn(" selection=%s, target=%s", selection, target) 

94 return 

95 finally: 

96 self.progress() 

97 log.warn("Warning: remote clipboard request timed out") 

98 log.warn(" request id %i, selection=%s, target=%s", request_id, selection, target) 

99 proxy = self._get_proxy(selection) 

100 if proxy: 

101 proxy.got_contents(target) 

102 

103 def _clipboard_got_contents(self, request_id, dtype=None, dformat=None, data=None): 

104 try: 

105 timer, selection, target = self._clipboard_outstanding_requests.pop(request_id) 

106 except KeyError: 

107 log.warn("Warning: request id %i not found", request_id) 

108 log.warn(" already timed out or duplicate reply") 

109 return 

110 finally: 

111 self.progress() 

112 GLib.source_remove(timer) 

113 proxy = self._get_proxy(selection) 

114 log("clipboard got contents%s: proxy=%s for selection=%s", 

115 (request_id, dtype, dformat, ellipsizer(data)), proxy, selection) 

116 if proxy: 

117 proxy.got_contents(target, dtype, dformat, data) 

118 

119 def client_reset(self): 

120 super().client_reset() 

121 #timeout all pending requests 

122 cor = self._clipboard_outstanding_requests 

123 if cor: 

124 log.info("cancelling %i clipboard request%s", len(cor), engs(cor)) 

125 self._clipboard_outstanding_requests = {} 

126 for request_id in cor: 

127 self._clipboard_got_contents(request_id)