Skip to content

Commit

Permalink
#3473 pre-map windows capability
Browse files Browse the repository at this point in the history
the opengl backend needed a way to wait until the drawing area is realized so that it can generate an opengl context
  • Loading branch information
totaam committed Feb 22, 2022
1 parent bb41849 commit 9ec3dd5
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 2 deletions.
31 changes: 31 additions & 0 deletions xpra/client/gl/gtk3/gl_drawing_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

class GLDrawingArea(GLWindowBackingBase):

def __init__(self, wid : int, window_alpha : bool, pixel_depth : int=0):
self.on_realize_cb = []
super().__init__(wid, window_alpha, pixel_depth)

def __repr__(self):
return "GLDrawingArea(%s, %s, %s)" % (self.wid, self.size, self.pixel_format)

Expand All @@ -33,6 +37,7 @@ def is_double_buffered(self):

def init_backing(self):
da = Gtk.DrawingArea()
da.connect_after("realize", self.on_realize)
#da.connect('configure_event', self.on_configure_event)
#da.connect('draw', self.on_draw)
#double-buffering is enabled by default anyway, so this is redundant:
Expand All @@ -42,6 +47,32 @@ def init_backing(self):
da.show()
self._backing = da

def on_realize(self, *args):
onrcb = self.on_realize_cb
log("GLDrawingArea.on_realize%s callbacks=%s", args, onrcb)
self.on_realize_cb = []
gl_context = self.gl_context()
with gl_context:
for x, args in onrcb:
try:
x(gl_context, *args)
except Exception:
log.error("Error calling realize callback %s", x, exc_info=True)

def with_gl_context(self, cb, *args):
da = self._backing
if da and da.get_mapped():
gl_context = self.gl_context()
if gl_context:
with gl_context:
cb(gl_context, *args)
else:
cb(None, *args)
else:
log("GLDrawingArea.with_gl_context delayed: %s%s", cb, args)
self.on_realize_cb.append((cb, args))


def get_bit_depth(self, pixel_depth=0):
return pixel_depth or self.context.get_bit_depth() or 24

Expand Down
2 changes: 2 additions & 0 deletions xpra/client/mixins/window_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
MOUSE_SCROLL_SQRT_SCALE = envbool("XPRA_MOUSE_SCROLL_SQRT_SCALE", OSX)
MOUSE_SCROLL_MULTIPLIER = envint("XPRA_MOUSE_SCROLL_MULTIPLIER", 100)

PRE_MAP = envbool("XPRA_PRE_MAP_WINDOWS", True)

DRAW_TYPES = {bytes : "bytes", str : "bytes", tuple : "arrays", list : "arrays"}

Expand Down Expand Up @@ -339,6 +340,7 @@ def get_window_caps(self) -> dict:
"min-size" : self.min_window_size,
"max-size" : self.max_window_size,
"restack" : True,
"pre-map" : PRE_MAP,
}


Expand Down
4 changes: 4 additions & 0 deletions xpra/server/source/windows_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def init_state(self):
self.window_min_size = 0, 0
self.window_max_size = 0, 0
self.window_restack = False
self.window_pre_map = False
self.system_tray = False
self.metadata_supported = ()

Expand Down Expand Up @@ -146,6 +147,7 @@ def parse_client_caps(self, c):
self.window_min_size = c.inttupleget("window.min-size", (0, 0))
self.window_max_size = c.inttupleget("window.max-size", (0, 0))
self.window_restack = c.boolget("window.restack", False)
self.window_pre_map = c.boolget("window.pre-map", False)
log("cursors=%s (encodings=%s), bell=%s",
self.send_cursors, self.cursor_encodings, self.send_bell)
#window filters:
Expand All @@ -169,6 +171,8 @@ def get_info(self) -> dict:
"bell" : self.send_bell,
"system-tray" : self.system_tray,
"suspended" : self.suspended,
"restack" : self.window_restack,
"pre-map" : self.window_pre_map,
}
wsize = info.setdefault("window-size", {})
wsize.update({
Expand Down
17 changes: 15 additions & 2 deletions xpra/x11/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
SHARING_SYNC_SIZE = envbool("XPRA_SHARING_SYNC_SIZE", True)
CLAMP_WINDOW_TO_ROOT = envbool("XPRA_CLAMP_WINDOW_TO_ROOT", False)
ALWAYS_RAISE_WINDOW = envbool("XPRA_ALWAYS_RAISE_WINDOW", False)
PRE_MAP = envbool("XPRA_PRE_MAP_WINDOWS", True)

WINDOW_SIGNALS = os.environ.get("XPRA_WINDOW_SIGNALS", "SIGINT,SIGTERM,SIGQUIT,SIGCONT,SIGUSR1,SIGUSR2").split(",")

Expand Down Expand Up @@ -636,6 +637,18 @@ def _add_new_window(self, window):
self._desktop_manager.add_window(window, x, y, w, h)
window.managed_connect("notify::geometry", self._window_resized_signaled)
self._send_new_window_packet(window)
if PRE_MAP:
#pre-map the window if any client supports this,
#so we can send the pixel data immediately after:
sources = tuple(filter(lambda source : getattr(source, "window_pre_map", False), self._server_sources.values()))
if sources:
wid = self._window_to_id.get(window)
log("pre-mapping window %i for %s", wid, sources)
self._desktop_manager.configure_window(window, x, y, w, h)
self._desktop_manager.show_window(window)
for s in sources:
s.map_window(wid, window, (x, y, w, h))
self.schedule_configure_damage(wid, 0)


def _window_resized_signaled(self, window, *args):
Expand Down Expand Up @@ -1108,7 +1121,7 @@ def _process_configure_window(self, proto, packet):
if damage:
self.schedule_configure_damage(wid)

def schedule_configure_damage(self, wid):
def schedule_configure_damage(self, wid, delay=CONFIGURE_DAMAGE_RATE):
#rate-limit the damage events
timer = self.configure_damage_timers.get(wid)
if timer:
Expand All @@ -1118,7 +1131,7 @@ def damage():
window = self._lookup_window(wid)
if window and window.is_managed():
self.refresh_window(window)
self.configure_damage_timers[wid] = self.timeout_add(CONFIGURE_DAMAGE_RATE, damage)
self.configure_damage_timers[wid] = self.timeout_add(delay, damage)

def cancel_configure_damage(self, wid):
timer = self.configure_damage_timers.pop(wid, None)
Expand Down

0 comments on commit 9ec3dd5

Please sign in to comment.