#19 [svn 576] xrandr handling does not work

closed-fixed
nobody
None
5
2012-01-27
2012-01-21
John Doe
No

BACKGROUND: I am on a 1280x1024 monitor. Xorg and all of its components are the newest versions. JWM is configured to have an auto-hiding taskbar across the bottom of the screen.

SCENARIO 1: I start X with no special command line, which results in the native resolution (1280x1024). In a terminal, I enter "xrandr -s 800x600". The screen goes black for half a second, then comes back with 800x600 resolution. I move the mouse pointer to the bottom of the screen, expecting that the taskbar will pop up. But no taskbar shows. Other than that everything works as normal, I can move all windows, and a mouse-click on the desktop brings up JWM's desktop menu.

SCENARIO 2: I add the line "xrandr -s 800x600" to .xinitrc, immediately before the line "jwm". Then I start X. It comes up with 800x600 resolution and the taskbar pops up at the bottom, just as expected. Now I enter "xrandr -s 1280x1024" in a terminal. The screen goes black for half a second, then comes back with the requested resolution. But: JWM continues to use the old, smaller resolution -- it uses the top-left rectangle of the screen that (by eye-balling) corresponds to 800x600 pixels. The taskbar is visible all of the time at the bottom of that rectangle, and also has that rectangle's width. Moving the mouse pointer over the taskbar makes the taskbar pop up at that place. Everything else works as expected, except that all new windows are placed initially within the top-left rectangle (but I can move them outside afterwards).

REPLICABLE: for me, always, 100%. But note that a success report has been given here:

http://bkhome.org/blog/?viewDetailed=02646

REMEDIES: None. According to the changelog, the window manager should handle the changed screen resolution all by itself, but it doesn't. Manually running "jwm -reload" or "jwm -restart" in a terminal doesn't help, either.

PROBLEM ANALYSIS: After the above observations, I instrumented JWM with a few debug statements. These lead me to the following conclusions. On startup, JWM reads in the screen resolution in the function "OpenConnection" in main.c. This function is called once, at program start, and then never again. That is important: "OpenConnection" is called from "StartupConnection" which is *outside* the main loop (!!!). When a RandR event reaches the event handler ("WaitForEvent" in event.c), JWM does all shutdown/startup steps that are handled inside the main loop in main.c. Re-reading the screen resolution isn't inside the main loop (it is outside), and therefore never takes place. Therefore, the running window manager continues to use the old resolution. -- You may now argue that "OpenConnection" is also called when restart / reload / exit events are sent to the desktop with the "SendJWMMessage" function (also in main.c), and that the new screen resolution must be read in when this function is called. To this I answer that "SendJWMMessage" is never called by the running window manager. Instead, it is only called from secondary copies of the program, for example when I manually run "jwm -restart" in a terminal. This secondary copy then does in fact know about the new screen resolution for the split second that it runs, but it does not transfer this information to the running window manager.

I readily admit that I may overlook something.

Discussion

  • John Doe

    John Doe - 2012-01-22

    FWIW, I have now tried it on a netbook with a native 800x480 screen resolution, this time using a non-autohiding vertical taskbar on the right-hand screen edge. Switching between the native resolution and a resolution of 640x480 replicates the reported effects in both scenarios analogously.

     
  • Joe Wingbermuehle

    Thanks for your assessment, I think you're right. I've checked in a change that should fix the problem (revision 577 or 329).

     
  • John Doe

    John Doe - 2012-01-22

    Thanks. Additional tests suggest that the svn-577 changes are necessary, but not sufficient. I have uploaded two small patches to show that.

    The first patch, "jwm-577-xrandr_debugstatements.patch", adds debug statements whenever JWM re-reads the screen resolution. They produce output on program startup, and afterwards each time I change the screen resolution with xrandr. That is good, and shows that JWM actually receives and handles all xrandr events. However, although the debug statements fire each time I change the screen resolution, they always output the original resolution from when JWM was first started. That means, JWM svn-577 still relies on old values that are stored "somewhere" (probably in the X server).

    That is where the second patch comes in, "jwm-577-xrandr_restart_connection.patch". It checks whether we are doing the first initialization or a repeated one, and if it is a repeated one, then it closes and reopens the connection. With this second patch, changing the screen resolution with xrandr now works for me, in both of the scenarios (increasing as well as decreasing the resolution). The task bar then comes up at the correct place after the resolution change.

    I must of course warn that the patches are PROOF-OF-CONCEPT code, not production code. Using the second patch to make xrandr work, exposes problems in other programs (for example, conky does not move itself to a different place after the screen resolution has changed), and the font sizes are sometimes unexpected after a screen resolution change. Most importantly, the second patch may give unexpected results depending on whether the X server was started with the "-reset", "-noreset", or "-terminate" parameters. However, the basic principle behind the second patch ("the connection to the server must be closed and re-opened") seems sound.

     
  • Joe Wingbermuehle

    I checked in another change that might fix it. Now it gets he screen width/height out of the XRR event rather than trying to get them from Xlib (somewhat surprising that Xlib is caching those values when it shouldn't be, I'd say that's a bug in Xlib).
    Anyway, these changes are in revision 578 (330).
    Thanks for for your help!

     
  • John Doe

    John Doe - 2012-01-23

    Elegant, but alas that did not change things: The old resolution is still stored somewhere, and used.

    General test conditions: I am on the computer with the larger monitor and use xrandr in a terminal to switch repeatedly between 1280x1024 and 800x600 resolution. I compiled and tried svn 578 in two different ways:

    1) ./configure --prefix=/usr --sysconfdir=/etc/jwm --enable-debug --disable-xinerama

    2) ./configure --prefix=/usr --sysconfdir=/etc/jwm --enable-debug

    The first way leads to the results that I described initially: after switching to the smaller resolution and then back to the larger one, the taskbar appears at the bottom of an invisible 800x600 rectangle (top-left), and has only that rectangle's width (ca. 800 pixels). On mouse-over, the taskbar pops up and down "in place" (i.e., where it is).

    The second way leads to a taskbar that appears at the same Y-position as above (ca. 600 pixels from top), but this time, it fills the whole screen width. Further, on mouse-over, it "jumps" to the bottom of the (now larger) screen, and when I move the mouse away, it "jumps" back.

    From my (seriously limited) knowledge of the JWM source code, this makes no sense at all. But my empirical observations are correct, I do not make this up. In any case, it seems to me that there are various buffers in the X system that do not all get properly flushed during an xrandr event, unless the connection is closed and then reopened (which is of course not acceptable for general use). I am out of ideas at the moment.

     
  • John Doe

    John Doe - 2012-01-25

    Alright, we may be getting somewhere. Joe, the svn 578 change was almost good, but it has one problem: event->width and event->height are the width and height from the point in time when the event was generated, and these are no longer the same when the event is finally received. At least on my machines is that so. When I switch, say, from 1280x1024 to 800x600 pixels resolution, then event->width is 1280, and event->height is 1024. That is easy to show by adding a line like

    Debug("HandleRandrEvent: event->width x event->height = %d x %d", event->width, event->height);

    inside the handler. At least on my computers, it shows the *old* screen resolution, not the *new* one.

    I have rewritten the handler a bit such that it does not rely on event->width and event->height, but actually determines the current root window size with XGetWindowAttributes. Extending the debug statements like this:

    Debug("HandleRandrEvent: event->width x event->height = %d x %d", event->width, event->height);
    Debug("HandleRandrEvent: attrs->width x attrs->height = %d x %d", a->width, a->height);

    confirms that we get, within the *same* event, both the old screen resolution (in event->width and event->height) and the new resolution (in attrs->width and attrs->height).

    The good news first: If I update JWM's global variables "rootWidth" and "rootHeight" from these manually determined attributes, then the resolution switching works beautifully. I can switch between 1280x1024, 800x600, and 640x480 for as long as I want -- the (autohiding) taskbar is always positioned correctly and works as it should.

    Now the not-so-good news. The original svn-578 code (plus a debug statement) yielded *one* RandR event per resolution switch. For switching from 1280x1024 to 800x600, it looked like this:

    DEBUG: main.c[120]: debug mode started
    DEBUG: shape extension enabled
    DEBUG: render extension enabled
    DEBUG: randr extension enabled
    DEBUG: Unknown event type: 34
    DEBUG: HandleRandrEvent: event->width x event->height = 1280 x 1024
    DEBUG: Unknown event type: 100

    With the new code, I get *three* RandR events for a single resolution switch, looking like this:

    DEBUG: main.c[120]: debug mode started
    DEBUG: shape extension enabled
    DEBUG: render extension enabled
    DEBUG: randr extension enabled
    DEBUG: Unknown event type: 34
    DEBUG: HandleRandrEvent: event->width x event->height = 1280 x 1024
    DEBUG: HandleRandrEvent: attrs->width x attrs->height = 800 x 600
    DEBUG: Unknown event type: 100
    DEBUG: HandleRandrEvent: event->width x event->height = 800 x 600
    DEBUG: HandleRandrEvent: attrs->width x attrs->height = 800 x 600
    DEBUG: Unknown event type: 100
    DEBUG: HandleRandrEvent: event->width x event->height = 800 x 600
    DEBUG: HandleRandrEvent: attrs->width x attrs->height = 800 x 600
    DEBUG: Unknown event type: 100

    I don't know where the extra two events come from. The xrandr(3) man page at http://www.xfree86.org/current/Xrandr.3.html says: "Clients must call back into Xlib using XRRUpdateConfiguration when screen configuration change notify events are generated (or root window configuration changes occur, to update Xlib's view of the resolution, size, rotation, reflection or subpixel order." I have done that, but I still get the two extra events. So for the moment I must accept the extra events, and can only make sure that only the first of them (not: all of them) triggers a restart of the window manager.

    My changes are attached as a patch ("follow-up-to-svn578.patch"). My main hope is that people watching this thread will try it out and give feedback on whether it works on their machines, or not.

     
  • John Doe

    John Doe - 2012-01-26

    The resizing worked nicely, but when I tried to rotate in addition, I was back to square one. At some point I realized that this is all overkill. The XRandR extension has been developed to work *transparently* for its users (such as window managers). For example, the window manager must be able to respond when the screen changes from "wide but not high" to "high but not wide." But the window manager need not care (or even know) whether this change comes from a left-rotation, or from a right-rotation, or from some other reason. These details are already taken care of by XRandR -- transparently. In fact, there is a trivial solution to make both resizing and rotating reliable with very, very little effort (just a few source code lines). I submitted an extensively tested patch here:

    http://sourceforge.net/tracker/?func=detail&aid=3480156&group_id=157836&atid=805418

    Hopefully it's a solved problem now.

     
  • Joe Wingbermuehle

    Nice catch!
    I removed the support for RandR in revision 579 (331) and added the ConfigureNotify function as in your patch.
    Thanks!

     
  • John Doe

    John Doe - 2012-01-27

    I repeated the test script that came with the patch (each resolution X each rotation) on the Pentium4, and happily confirm that revision 579 passes flawlessly. Thanks a lot!

     
  • Joe Wingbermuehle

    • status: open --> closed-fixed
     

Log in to post a comment.