This problem only happens in urxvt as far as I know and it is only a problem if I disable OpenGL. I am using AwesomeWM on Debian Buster/Sid? and I am using xpra version 2.1 revision r16525, but I have seen this for a while. If I disable OpenGL and open a urxvt window, the whole window will refuse to repaint until I resize the window, which apparently triggers a refresh. Thus I cannot see what I am typing or the output of anything unless I constantly keep resizing the window. No other applications are affected (that I am aware of). I enabled logging for x11
and have attached the log here (truncated for the relevant part).
Log output
Since the screen updates are getting through with opengl enabled, it's very likely that the server is sending them in a timely manner and that it is the client that is somehow failing to either update its back buffer or failing to ask the local X11 server to repaint the window. Does the window refresh if you use the "refresh" menu entry in xpra's system tray?
Please include the "-d paint" client log. (small sample is enough) Please also try running the client with:
XPRA_REPAINT_ALL=1
xpra attach ...
XPRA_USE_CAIRO_BACKING=1
xpra attach ...
XPRA_REPAINT_ALL
and XPRA_USE_CAIRO_BACKING
did not work
compton
(a standalone compositor)
Another interesting observation (not sure if it's related). If I try running xpra control :470 refresh
, it errors out with
server returned error code 127 error processing control command: full_quality_refresh() takes at most 2 arguments (3 given)
if I don't have OpenGL enabled (it works fine if I enable OpenGL - presumably it's calling different methods?). Looking at the log, I get:
Traceback (most recent call last): File "/usr/lib/python2.7/dist-packages/xpra/server/server_core.py", line 1158, in process_control_command v = command.run(*args[1:]) File "/usr/lib/python2.7/dist-packages/xpra/server/control_command.py", line 67, in run return super(ArgsControlCommand, self).run(*args) File "/usr/lib/python2.7/dist-packages/xpra/server/control_command.py", line 32, in run return self.do_run(*args) File "/usr/lib/python2.7/dist-packages/xpra/server/server_base.py", line 1799, in control_command_refresh ws.full_quality_refresh(window, {}) TypeError: full_quality_refresh() takes at most 2 arguments (3 given)
Relevant portion with all debugging enabled
The fact that even the cairo backend fails to repaint is very suspicious.
I think your window manager is up to no good.
The full_quality_refresh
bug has been fixed in r16565 - thanks for pointing that out! (and FYI: the message would have been exactly the same with or without opengl enabled)
Please attach the client "-d paint" log output, not the server's.
I get a message that there are no loggers matching paint
That's because there aren't any - it's a client logger.
Are you sure you tried those environment switches on the client?
Yes, I used those environment variables when calling xpra attach
. I didn't realize that xpra control
controls the server (in retrospect, it should have been obvious). I'm attaching a portion of the client log now - I think it's the right portion, but I'm not sure.
client debug output
Even weirder. If I e.g. start mutt
on an xpra display within the same terminal emulator, it works fine. If I then spawn an emacsclient
from within that, that fails to repaint. Something really odd is going on. I'll attach the debug output from mutt
since that may prove to be instructive.
[edit] That's interesting. It seems mutt
doesn't generate any refresh events - I presume ncurses handles the redrawing or something...
Nothing suspicious there, you're getting your screen updates through the mmap channel:
draw_region(0, 0, 1360, 732, mmap, 1 bytes, 4080, {'rgb_format': 'RGB'}, \ [<function record_decode_time at 0x7f0578784f50>, <function after_draw_refresh at 0x7f0560917938>])
And then we fire the callbacks, in particular:
after_draw_refresh(True, ) 1360x732 at 0x0 encoding=mmap, options={'encoding': 'mmap', 'rgb_format': 'RGB'}
This will call gtk.Widget.queue_draw_area - the documentation says: the window will receive expose events for the union of all regions that have been invalidated.
This should therefore cause the X11 server to call the window's do_expose_event
method to repaint what had been invalidated.
Please try the "-d events" switch client side to see if those events come through.
2017-07-30 11:15:47,657 on_realize(ClientWindow(5)) gdk window=<gtk.gdk.Window object at 0x7f917055aaa0 (GdkWindow at 0x5455b1db40)> 2017-07-30 11:15:47,673 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f9170554378: GDK_CONFIGURE x=0, y=0, width=1366, height=768>) OR=False, iconified=False 2017-07-30 11:15:47,674 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f9170554378: GDK_CONFIGURE x=0, y=0, width=1366, height=768>) OR=False, iconified=False 2017-07-30 11:15:47,678 do_expose_event(<gtk.gdk.Event at 0x7f9170554378: GDK_EXPOSE area=[0, 0, 1366, 768]>) area=gtk.gdk.Rectangle(0, 0, 1366, 768) 2017-07-30 11:15:48,560 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f9170554378: GDK_CONFIGURE x=0, y=20, width=1366, height=748>) OR=False, iconified=False 2017-07-30 11:15:48,561 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f9170554378: GDK_CONFIGURE x=0, y=20, width=1366, height=748>) OR=False, iconified=False 2017-07-30 11:15:48,571 do_expose_event(<gtk.gdk.Event at 0x7f9170554378: GDK_EXPOSE area=[0, 0, 1360, 748]>) area=gtk.gdk.Rectangle(0, 0, 1360, 748) 2017-07-30 11:15:48,804 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f9170554378: GDK_CONFIGURE x=0, y=0, width=1366, height=768>) OR=False, iconified=False 2017-07-30 11:15:48,811 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f9170554378: GDK_CONFIGURE x=0, y=0, width=1366, height=768>) OR=False, iconified=False 2017-07-30 11:15:48,814 do_expose_event(<gtk.gdk.Event at 0x7f9170554378: GDK_EXPOSE area=[0, 0, 1366, 768]>) area=gtk.gdk.Rectangle(0, 0, 1366, 768) 2017-07-30 11:15:56,197 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f91705543c8: GDK_CONFIGURE x=0, y=20, width=1366, height=748>) OR=False, iconified=False 2017-07-30 11:15:56,198 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f91705543c8: GDK_CONFIGURE x=0, y=20, width=1366, height=748>) OR=False, iconified=False 2017-07-30 11:15:56,207 do_expose_event(<gtk.gdk.Event at 0x7f91705543c8: GDK_EXPOSE area=[0, 0, 1360, 748]>) area=gtk.gdk.Rectangle(0, 0, 1360, 748) 2017-07-30 11:15:57,232 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f91705543c8: GDK_CONFIGURE x=0, y=0, width=1366, height=768>) OR=False, iconified=False 2017-07-30 11:15:57,233 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f91705543c8: GDK_CONFIGURE x=0, y=0, width=1366, height=768>) OR=False, iconified=False 2017-07-30 11:15:57,240 do_expose_event(<gtk.gdk.Event at 0x7f91705543c8: GDK_EXPOSE area=[0, 0, 1366, 768]>) area=gtk.gdk.Rectangle(0, 0, 1366, 768) 2017-07-30 11:16:06,127 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f9170554378: GDK_CONFIGURE x=0, y=20, width=1366, height=748>) OR=False, iconified=False 2017-07-30 11:16:06,129 ClientWindow(5).do_configure_event(<gtk.gdk.Event at 0x7f9170554378: GDK_CONFIGURE x=0, y=20, width=1366, height=748>) OR=False, iconified=False
The only expose events shown in the log sample follow the window resize (configure event). My guess is that your window manager is unhelpfully intercepting the expose events. Not much we can do about this.
Hmm okay I'll post a bug report in AwesomeWM's bug tracker. Thanks!
If I am right, this may workaround the issue in your window manager:
--- xpra/client/client_window_base.py (revision 16553) +++ xpra/client/client_window_base.py (working copy) @@ -589,7 +589,13 @@ rect = 0, 0, w, h else: rect = self._client.srect(x, y, width, height) - self.idle_add(self.queue_draw, *rect) + #self.idle_add(self.queue_draw, *rect) + from xpra.util import AdHocStruct + event = AdHocStruct() + from gtk.gdk import Rectangle + w, h = self.get_size() + event.area = Rectangle(0, 0, w, h) + self.do_expose_event(event) #only register this callback if we actually need it: if backing.draw_needs_refresh: callbacks.append(after_draw_refresh)
This mimics the missing expose event.
Another thing worth trying:
--- xpra/client/gtk2/gtk2_window_base.py (revision 16553) +++ xpra/client/gtk2/gtk2_window_base.py (working copy) @@ -405,7 +405,7 @@ def queue_draw(self, x, y, width, height): window = self.get_window() if window: - window.invalidate_rect(gdk.Rectangle(x, y, width, height), False) + window.invalidate_rect(gdk.Rectangle(x, y, width, height), True) else: log.warn("ignoring draw received for a window which is not realized yet!")
(this one would make more sense)
Your first fix worked! I wonder how common this is...if it's common enough, it may be worth it to keep this as the default?
This is not "fixed": the first fix cannot be merged as it is (it only confirms that the expose events are not being generated because of your window manager), the second fix could be merged, please try that one.
Unfortunately the second fix did not work.
The patch below uses a better place to fix things. Only penalizing non-compositing window managers with the workaround - but since you reported that running a compositor didn't help, this would not fix all cases either.
--- xpra/client/gtk2/gtk2_window_base.py (revision 16553) +++ xpra/client/gtk2/gtk2_window_base.py (working copy) @@ -22,7 +22,7 @@ from xpra.client.gtk_base.gtk_client_window_base import GTKClientWindowBase, HAS_X11_BINDINGS from xpra.gtk_common.gtk_util import WINDOW_NAME_TO_HINT, WINDOW_EVENT_MASK, BUTTON_MASK from xpra.gtk_common.gobject_util import one_arg_signal -from xpra.util import WORKSPACE_UNSET, WORKSPACE_NAMES, csv, envbool, envint +from xpra.util import WORKSPACE_UNSET, WORKSPACE_NAMES, csv, envbool, envint, AdHocStruct from xpra.os_util import strtobytes @@ -404,10 +404,18 @@ def queue_draw(self, x, y, width, height): window = self.get_window() - if window: - window.invalidate_rect(gdk.Rectangle(x, y, width, height), False) + if not window: + log.warn("ignoring draw received for a window which is not realized yet!") + return + rect = gdk.Rectangle(x, y, width, height) + if self.is_composited(): + window.invalidate_rect(rect, False) else: - log.warn("ignoring draw received for a window which is not realized yet!") + #draw directly (bad) to workaround buggy window managers: + #see: https://github.com/Xpra-org/xpra/issues/1610 + event = AdHocStruct() + event.area = rect + self.do_expose_event(event) def do_expose_event(self, event): #cannot use self
I will probably close this ticket as wontfix. The paint code in xpra is very very well tested and works with GTK2, GTK3, on 40+ platforms (including things as varied as macos, win32, bsd, etc). This is also the only recommended way of painting the screen in all the GTK documentation.
Something in your window manager is swallowing those important expose events and we shouldn't be trying to workaround that.
Based on the upstream ticket: Depth=32 not redrawn correctly (CopyArea has no effect).
Interestingly, the latest patch happened to work in my case. I have absolutely no idea what's going on as the fix suggested in the upstream ticket did not work.
Based on the upstream ticket (see comment:16), there seems to be an issue in awesome - fixed in newer versions, but not fixed in Debian (...) Either a missing configure notify: size_hints_honor issue #1340
So I am closing this ticket as invalid.
I've partially merged the workaround in r16571: we can enable "immediate paint" mode using XPRA_FORCE_IMMEDIATE_PAINT=1
, which could be useful for testing / debugging in the future, or as a workaround for those stuck with buggy versions of awesome.
this ticket has been moved to: https://github.com/Xpra-org/xpra/issues/1610