Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/client/gl/window_backend.py : 73%
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.
7import sys
8import os.path
9from io import BytesIO
10from math import cos, sin
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
17log = Logger("opengl", "paint")
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
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")
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
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 ()
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
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
209if __name__ == "__main__":
210 r = main()
211 sys.exit(r)