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) 2017-2019 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#pylint: disable-msg=E1101 

7 

8from xpra.util import csv 

9from xpra.os_util import POSIX, OSX, bytestostr 

10from xpra.server.rfb.rfb_const import RFBEncoding, RFB_KEYNAMES 

11from xpra.server.rfb.rfb_protocol import RFBProtocol 

12from xpra.server.rfb.rfb_source import RFBSource 

13from xpra.server import server_features 

14from xpra.scripts.config import parse_bool, parse_number 

15from xpra.log import Logger 

16 

17log = Logger("rfb") 

18 

19 

20""" 

21 Adds RFB packet handler to a server. 

22""" 

23class RFBServer: 

24 

25 def __init__(self): 

26 self._window_to_id = {} 

27 self._rfb_upgrade = 0 

28 self.readonly = False 

29 self.rfb_buttons = 0 

30 self.x11_keycodes_for_keysym = {} 

31 if POSIX and not OSX: 

32 from xpra.x11.bindings.keyboard_bindings import X11KeyboardBindings #@UnresolvedImport 

33 self.X11Keyboard = X11KeyboardBindings() 

34 

35 def init(self, opts): 

36 if not parse_bool("rfb-upgrade", opts.rfb_upgrade): 

37 self._rfb_upgrade = 0 

38 else: 

39 self._rfb_upgrade = parse_number(int, "rfb-upgrade", opts.rfb_upgrade, 0) 

40 log("init(..) rfb-upgrade=%i", self._rfb_upgrade) 

41 

42 

43 def _get_rfb_desktop_model(self): 

44 models = tuple(self._window_to_id.keys()) 

45 if not models: 

46 log.error("RFB: no window models to export, dropping connection") 

47 return None 

48 if len(models)!=1: 

49 log.error("RFB can only handle a single desktop window, found %i", len(self._window_to_id)) 

50 return None 

51 return models[0] 

52 

53 def _get_rfb_desktop_wid(self): 

54 ids = tuple(self._window_to_id.values()) 

55 if len(ids)!=1: 

56 log.error("RFB can only handle a single desktop window, found %i", len(self._window_to_id)) 

57 return None 

58 return ids[0] 

59 

60 

61 def handle_rfb_connection(self, conn): 

62 model = self._get_rfb_desktop_model() 

63 if not model: 

64 conn.close() 

65 return 

66 def rfb_protocol_class(conn): 

67 auths = self.make_authenticators("rfb", "rfb", conn) 

68 assert len(auths)<=1, "rfb does not support multiple authentication modules" 

69 auth = None 

70 if len(auths)==1: 

71 auth = auths[0] 

72 return RFBProtocol(self, conn, auth, 

73 self.process_rfb_packet, self.get_rfb_pixelformat, self.session_name or "Xpra Server") 

74 p = self.do_make_protocol("rfb", conn, {}, rfb_protocol_class) 

75 p.send_protocol_handshake() 

76 

77 def process_rfb_packet(self, proto, packet): 

78 #log("RFB packet: '%s'", packet) 

79 fn_name = "_process_rfb_%s" % bytestostr(packet[0]).replace("-", "_") 

80 fn = getattr(self, fn_name, None) 

81 if not fn: 

82 log.warn("Warning: no RFB handler for %s", fn_name) 

83 return 

84 self.idle_add(fn, proto, packet) 

85 

86 

87 def get_rfb_pixelformat(self): 

88 model = self._get_rfb_desktop_model() 

89 w, h = model.get_dimensions() 

90 #w, h, bpp, depth, bigendian, truecolor, rmax, gmax, bmax, rshift, bshift, gshift 

91 return w, h, 32, 32, False, True, 255, 255, 255, 16, 8, 0 

92 

93 def _process_rfb_invalid(self, proto, packet): 

94 self.disconnect_protocol(proto, "invalid packet: %s" % (packet[1:])) 

95 

96 def _process_rfb_connection_lost(self, proto, packet): 

97 self._process_connection_lost(proto, packet) 

98 

99 def _process_rfb_authenticated(self, proto, _packet): 

100 model = self._get_rfb_desktop_model() 

101 if not model: 

102 proto.close() 

103 return 

104 self.accept_protocol(proto) 

105 #use blocking sockets from now on: 

106 from xpra.net.bytestreams import set_socket_timeout 

107 set_socket_timeout(proto._conn, None) 

108 accepted, share_count, disconnected = self.handle_sharing(proto, share=proto.share) 

109 log("rfb handle sharing: accepted=%s, share count=%s, disconnected=%s", accepted, share_count, disconnected) 

110 if not accepted: 

111 return 

112 source = RFBSource(proto, proto.share) 

113 if server_features.input_devices: 

114 source.keyboard_config = self.get_keyboard_config() 

115 self.set_keymap(source) 

116 self._server_sources[proto] = source 

117 w, h = model.get_dimensions() 

118 source.damage(self._window_to_id[model], model, 0, 0, w, h) 

119 #ugly weak dependency, 

120 #shadow servers need to be told to start the refresh timer: 

121 start_refresh = getattr(self, "start_refresh", None) 

122 if start_refresh: 

123 for wid in tuple(self._window_to_id.values()): 

124 start_refresh(wid) #pylint: disable=not-callable 

125 

126 def _process_rfb_PointerEvent(self, _proto, packet): 

127 if not server_features.input_devices or self.readonly: 

128 return 

129 buttons, x, y = packet[1:4] 

130 wid = self._get_rfb_desktop_wid() 

131 self._move_pointer(wid, (x, y)) 

132 if buttons!=self.rfb_buttons: 

133 #figure out which buttons have changed: 

134 for button in range(8): 

135 mask = 2**button 

136 if buttons & mask != self.rfb_buttons & mask: 

137 pressed = bool(buttons & mask) 

138 self.button_action((x, y), 1+button, pressed, -1) 

139 self.rfb_buttons = buttons 

140 

141 def _process_rfb_KeyEvent(self, proto, packet): 

142 if not server_features.input_devices or self.readonly: 

143 return 

144 source = self.get_server_source(proto) 

145 if not source: 

146 return 

147 pressed, p1, p2, key = packet[1:5] 

148 wid = self._get_rfb_desktop_wid() 

149 keyname = RFB_KEYNAMES.get(key) 

150 if not keyname: 

151 if 0<key<255: 

152 keyname = chr(key) 

153 elif self.X11Keyboard: 

154 keyname = self.X11Keyboard.keysym_str(key) 

155 if not keyname: 

156 log.warn("rfb unknown KeyEvent: %s, %i, %i, %#x", pressed, p1, p2, key) 

157 return 

158 modifiers = [] 

159 keyval = 0 

160 keycode, group = source.keyboard_config.get_keycode(0, keyname, pressed, modifiers, 0, keyname, 0) 

161 log("rfb keycode(%s)=%s, %s", keyname, keycode, group) 

162 if keycode: 

163 is_mod = source.keyboard_config.is_modifier(keycode) 

164 self._handle_key(wid, bool(pressed), keyname, keyval, keycode, modifiers, is_mod, True) 

165 

166 def _process_rfb_SetEncodings(self, _proto, packet): 

167 n, encodings = packet[2:4] 

168 known_encodings = [RFBEncoding.ENCODING_STR.get(x) for x in encodings if x in RFBEncoding.ENCODING_STR] 

169 log("%i encodings: %s", n, csv(known_encodings)) 

170 unknown_encodings = [x for x in encodings if x not in RFBEncoding.ENCODING_STR] 

171 if unknown_encodings: 

172 log("%i unknown encodings: %s", len(unknown_encodings), csv(unknown_encodings)) 

173 

174 def _process_rfb_SetPixelFormat(self, _proto, packet): 

175 log("RFB: SetPixelFormat %s", packet) 

176 #w, h, bpp, depth, bigendian, truecolor, rmax, gmax, bmax, rshift, bshift, gshift = packet 

177 

178 def _process_rfb_FramebufferUpdateRequest(self, _proto, packet): 

179 #pressed, _, _, keycode = packet[1:5] 

180 inc, x, y, w, h = packet[1:6] 

181 log("RFB: FramebufferUpdateRequest inc=%s, geometry=%s", inc, (x, y, w, h)) 

182 if not inc: 

183 model = self._get_rfb_desktop_model() 

184 self.refresh_window_area(model, x, y, w, h) 

185 

186 def _process_rfb_ClientCutText(self, _proto, packet): 

187 #l = packet[4] 

188 text = packet[5] 

189 log("got rfb clipboard text: %r", text)