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#!/usr/bin/env python 

2# This file is part of Xpra. 

3# Copyright (C) 2018, 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 

7import sys 

8import os.path 

9from io import BytesIO 

10from math import cos, sin 

11 

12from xpra.util import typedict, envint, AdHocStruct, AtomicInteger, iround 

13from xpra.os_util import WIN32 

14from xpra.log import Logger 

15from xpra.platform.paths import get_icon_filename 

16 

17log = Logger("opengl", "paint") 

18 

19 

20def get_gl_client_window_module(force_enable=False): 

21 log("get_gl_client_window_module()") 

22 try: 

23 from xpra.client.gl.gtk3 import nativegl_client_window 

24 except ImportError as e: 

25 log("cannot import opengl window module", exc_info=True) 

26 log.warn("Warning: cannot import native OpenGL module") 

27 log.warn(" %s", e) 

28 return {}, None 

29 opengl_props = nativegl_client_window.check_support(force_enable) 

30 log("check_support(%s)=%s", force_enable, opengl_props) 

31 if opengl_props: 

32 return opengl_props, nativegl_client_window 

33 return {}, None 

34 

35def noop(*_args): 

36 pass 

37def no_scaling(*args): 

38 if len(args)==1: 

39 return args[0] 

40 return args 

41def get_None(*_args): 

42 return None 

43def no_idle_add(fn, *args, **kwargs): 

44 fn(*args, **kwargs) 

45def no_timeout_add(*_args, **_kwargs): 

46 raise Exception("timeout_add should not have been called") 

47def no_source_remove(*_args, **_kwargs): 

48 raise Exception("source_remove should not have been called") 

49 

50class FakeClient(AdHocStruct): 

51 def __init__(self): 

52 self.sp = self.sx = self.sy = self.srect = no_scaling 

53 self.cx = self.cy = no_scaling 

54 self.xscale = self.yscale = 1 

55 self.server_window_decorations = True 

56 self.mmap_enabled = False 

57 self.mmap = None 

58 self.readonly = False 

59 self.encoding_defaults = {} 

60 self.get_window_frame_sizes = get_None 

61 self._focused = None 

62 self.request_frame_extents = noop 

63 self.server_window_states = () 

64 self.server_window_frame_extents = False 

65 self.server_readonly = False 

66 self.server_pointer = False 

67 self.update_focus = noop 

68 self.handle_key_action = noop 

69 self.idle_add = no_idle_add 

70 self.timeout_add = no_timeout_add 

71 self.source_remove = no_source_remove 

72 

73 def send(self, *args): 

74 log("send%s", args) 

75 def get_current_modifiers(self): 

76 return () 

77 def get_mouse_position(self): 

78 return 0, 0 

79 def server_ok(self): 

80 return True 

81 def mask_to_names(self, *_args): 

82 return () 

83 

84def test_gl_client_window(gl_client_window_class, max_window_size=(1024, 1024), pixel_depth=24, show=False): 

85 #try to render using a temporary window: 

86 draw_result = {} 

87 window = None 

88 try: 

89 x, y = -100, -100 

90 if show: 

91 x, y = 100, 100 

92 w, h = 250, 250 

93 from xpra.codecs.loader import load_codec 

94 load_codec("dec_pillow") 

95 from xpra.client.window_border import WindowBorder 

96 border = WindowBorder() 

97 default_cursor_data = None 

98 noclient = FakeClient() 

99 #test with alpha, but not on win32 

100 #because we can't do alpha on win32 with opengl 

101 metadata = typedict({b"has-alpha" : not WIN32}) 

102 class NoHeaderGLClientWindow(gl_client_window_class): 

103 def add_header_bar(self): 

104 pass 

105 def schedule_recheck_focus(self): 

106 pass 

107 window = NoHeaderGLClientWindow(noclient, None, None, 2**32-1, x, y, w, h, w, h, 

108 metadata, False, typedict({}), 

109 border, max_window_size, default_cursor_data, pixel_depth) 

110 window_backing = window._backing 

111 window_backing.idle_add = no_idle_add 

112 window_backing.timeout_add = no_timeout_add 

113 window_backing.source_remove = no_source_remove 

114 window.realize() 

115 window_backing.paint_screen = True 

116 pixel_format = "BGRX" 

117 bpp = len(pixel_format) 

118 options = typedict({"pixel_format" : pixel_format}) 

119 stride = bpp*w 

120 coding = "rgb32" 

121 widget = window_backing._backing 

122 widget.realize() 

123 def paint_callback(success, message=""): 

124 log("paint_callback(%s, %s)", success, message) 

125 draw_result["success"] = success 

126 if message: 

127 draw_result["message"] = message.replace("\n", " ") 

128 log("OpenGL: testing draw on %s widget %s with %s : %s", window, widget, coding, pixel_format) 

129 pix = AtomicInteger(0x7f) 

130 REPAINT_DELAY = envint("XPRA_REPAINT_DELAY", int(show)*16) 

131 gl_icon = get_icon_filename("opengl", ext="png") 

132 icon_data = None 

133 if os.path.exists(gl_icon): 

134 from PIL import Image 

135 img = Image.open(gl_icon) 

136 img.load() 

137 icon_w, icon_h = img.size 

138 icon_stride = icon_w * 4 

139 noalpha = Image.new("RGB", img.size, (255, 255, 255)) 

140 noalpha.paste(img, mask=img.split()[3]) # 3 is the alpha channel 

141 buf = BytesIO() 

142 noalpha.save(buf, format="JPEG") 

143 icon_data = buf.getvalue() 

144 buf.close() 

145 icon_format = "jpeg" 

146 if not icon_data: 

147 icon_w = 32 

148 icon_h = 32 

149 icon_stride = icon_w * 4 

150 icon_data = bytes([0])*icon_stride*icon_h 

151 icon_format = "rgb32" 

152 def draw(): 

153 v = pix.increase() 

154 img_data = bytes([v % 256]*stride*h) 

155 options["flush"] = 1 

156 window.draw_region(0, 0, w, h, coding, img_data, stride, v, options, [paint_callback]) 

157 options["flush"] = 0 

158 mx = w//2-icon_w//2 

159 my = h//2-icon_h//2 

160 x = iround(mx*(1+sin(v/100))) 

161 y = iround(my*(1+cos(v/100))) 

162 window.draw_region(x, y, icon_w, icon_h, icon_format, icon_data, icon_stride, v, options, [paint_callback]) 

163 return REPAINT_DELAY>0 

164 #the paint code is actually synchronous here, 

165 #so we can check the present_fbo() result: 

166 if show: 

167 widget.show() 

168 window.show() 

169 from gi.repository import Gtk, GLib 

170 def window_close_event(*_args): 

171 Gtk.main_quit() 

172 noclient.window_close_event = window_close_event 

173 GLib.timeout_add(REPAINT_DELAY, draw) 

174 Gtk.main() 

175 else: 

176 draw() 

177 if window_backing.last_present_fbo_error: 

178 return { 

179 "success" : False, 

180 "message" : "failed to present FBO on screen: %s" % window_backing.last_present_fbo_error 

181 } 

182 finally: 

183 if window: 

184 window.destroy() 

185 log("test_gl_client_window(..) draw_result=%s", draw_result) 

186 return draw_result 

187 

188 

189 

190def main(): 

191 try: 

192 opengl_props, gl_client_window_module = get_gl_client_window_module(True) 

193 log("do_run_glcheck() opengl_props=%s, gl_client_window_module=%s", opengl_props, gl_client_window_module) 

194 gl_client_window_class = gl_client_window_module.GLClientWindow 

195 pixel_depth = 0 

196 log("do_run_glcheck() gl_client_window_class=%s, pixel_depth=%s", gl_client_window_class, pixel_depth) 

197 #if pixel_depth not in (0, 16, 24, 30) and pixel_depth<32: 

198 # pixel_depth = 0 

199 draw_result = test_gl_client_window(gl_client_window_class, pixel_depth=pixel_depth, show=True) 

200 success = draw_result.pop("success", False) 

201 opengl_props.update(draw_result) 

202 if not success: 

203 opengl_props["safe"] = False 

204 return 0 

205 except Exception: 

206 log("do_run_glcheck(..)", exc_info=True) 

207 return 1 

208 

209if __name__ == "__main__": 

210 r = main() 

211 sys.exit(r)