xpra icon
Bug tracker and wiki

Opened 3 months ago

Closed 3 months ago

#1610 closed defect (invalid)

Repaint problems in urxvt

Reported by: chaanakya Owned by: chaanakya
Priority: major Milestone: 2.2
Component: client Version: trunk
Keywords: Cc:

Description (last modified by Antoine Martin)

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).

Attachments (3)

:470_trunc.log (109.2 KB) - added by chaanakya 3 months ago.
Log output
:470_debug_all.log (91.4 KB) - added by chaanakya 3 months ago.
Relevant portion with all debugging enabled
:470_client.log (6.4 KB) - added by chaanakya 3 months ago.
client debug output

Download all attachments as: .zip

Change History (21)

Changed 3 months ago by chaanakya

Attachment: :470_trunc.log added

Log output

comment:1 Changed 3 months ago by Antoine Martin

Description: modified (diff)
Owner: changed from Antoine Martin to chaanakya

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 ...
  • a different window manager

comment:2 Changed 3 months ago by chaanakya

  • XPRA_REPAINT_ALL and XPRA_USE_CAIRO_BACKING did not work
  • Using "Refresh" from the menu did not work
  • Interestingly, this does work under Enlightenment. I thought it may have to do with compositing, but I don't see any change when I run compton (a standalone compositor)
  • I get a message that there are no loggers matching paint, so I enabled all debugging instead and uploaded the relevant portion. I switch to the window, trigger a full refresh, and switch out of the window.

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)
Last edited 3 months ago by chaanakya (previous) (diff)

Changed 3 months ago by chaanakya

Attachment: :470_debug_all.log added

Relevant portion with all debugging enabled

comment:3 Changed 3 months ago by Antoine Martin

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?

comment:4 Changed 3 months ago by chaanakya

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.

Changed 3 months ago by chaanakya

Attachment: :470_client.log added

client debug output

comment:5 Changed 3 months ago by chaanakya

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...

Last edited 3 months ago by chaanakya (previous) (diff)

comment:6 Changed 3 months ago by Antoine Martin

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.

comment:7 Changed 3 months ago by chaanakya

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

comment:8 Changed 3 months ago by Antoine Martin

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.

comment:9 Changed 3 months ago by chaanakya

Hmm okay I'll post a bug report in AwesomeWM's bug tracker. Thanks!

comment:10 Changed 3 months ago by Antoine Martin

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)

Last edited 3 months ago by Antoine Martin (previous) (diff)

comment:11 Changed 3 months ago by chaanakya

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?

comment:12 Changed 3 months ago by chaanakya

Resolution: fixed
Status: newclosed

comment:13 Changed 3 months ago by Antoine Martin

Resolution: fixed
Status: closedreopened

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.

comment:14 Changed 3 months ago by chaanakya

Unfortunately the second fix did not work.

comment:15 Changed 3 months ago by Antoine Martin

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: http://xpra.org/trac/ticket/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.

Last edited 3 months ago by Antoine Martin (previous) (diff)

comment:16 Changed 3 months ago by Antoine Martin

Based on the upstream ticket: awesome + xpra + urxvt issue and some IRC discussions, this may be related to this bug in the Xorg server: Depth=32 not redrawn correctly (CopyArea has no effect).

comment:17 Changed 3 months ago by chaanakya

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.

comment:18 Changed 3 months ago by Antoine Martin

Resolution: invalid
Status: reopenedclosed

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: Reply on configurerequest even if geometry is the same, or some problem with size hints (less likely): 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.

Note: See TracTickets for help on using tickets.