-
Notifications
You must be signed in to change notification settings - Fork 568
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Some comments on the X11 platform #1045
Comments
Thanks a lot for going through the trouble of giving us some feedback! Some of the points I personally already know, while others points are news. In both cases it's great to have some of this written down. I'll also give some replies to a few points below. Regarding the white flash and not setting the background white, that's probably related indeed. Windows had the same issue which was fixed in #915. Regarding the draw scheduling, the Regarding Regarding resource leaks during application quit - yes this is about cleanup in druid-shell Rust code, not X11 resources per se. Regarding |
I did the
I think we might not be, actually... (I opened up an issue on |
BTW, the initial commit of this (by me) was a super huge hack to see if we could get something else in the Rust ecosystem working. Code that I submitted is definitely not production-ready -- the expectation was that it would be improved over time -- but it's nice to have the list of stuff that's wrong! :) |
#989 fixed a number of these, so I checked them off |
I wanted to chime in here, to thank both Charles for getting the platform started, and psychon for giving constructive feedback. There's a lot of knowledge there, and it should serve as a useful guide for our corps of volunteers who are working on this. And of course to jneem for working to improve it :) |
Thanks for getting it started, @crsaracco! I never would have written an x11 backend from scratch, but now that it's here I'm having a lot of fun (and learning a lot, too) tinkering with it. |
Related-to: linebender#1045 Signed-off-by: Uli Schlachter <psychon@znc.in>
Related-to: #1045 Signed-off-by: Uli Schlachter <psychon@znc.in>
Hi,
I cam across Druid via https://www.reddit.com/r/rust/comments/h9z66n/changelog_for_druid_06_updated_from_05_two_weeks/. The changelog then links to a couple of things which then lead to more issues. I feel like I provide some useful input and hence I am opening this issue. I will try to add things to the already existing issues where applicable.
#599 (comment)
https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/window.rs#L182
You are telling the X11 server to fill any exposed area with white before sending an expose event. I'd recommend just removing this line. The default background is None, which means that the server just sends an Expose event without drawing anything beforehand.
This makes no sense to me. X11 windows must have at least a size of 1x1. Sounds like a weird interaction with your WM, but I am not really sure what is going on.
You seem to have figured out
WM_PROTOCOLS
already. Anyway, I recommend reading EWMH and scrolling through the table of contents of ICCCM (I have never read all of ICCCM myself, I think).#599 (comment)
I recommend looking at double-buffering. With cairo, this is as simple as
cairo_surface_create_similar
(this is the C function) on the surface. Internally, this creates an X11 pixmap (if called on an X11 surface) and sets this up as a cairo surface. You can then draw to this surface and only copy your finished drawing to the X11 window.If you are already doing double-buffering: Sorry for missing that part of the code.
cairo_surface_flush()
where necessary, right? (Necessary = the drawing should actually be sent to the X11 server now.)#475
I have no clue about druid, but please tell me that you are only doing this if there is an active animation. I saw some screenshot of a calculator somewhere and that does not look like something that needs to be redrawn many times per second...?
#475
You basically need to write your own main loop. The usual low-level X11 libraries that I have seen do not provide one for you. x11rb falls into this category.
Actually, you already wrote a very simple main loop, but so far it can only handle X11 events and nothing else:
https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/application.rs#L271-L286
As an example on how a very simple version of this might look at, I recommend looking at (the main ingredient is
poll_with_timeout
): https://github.com/psychon/x11rb/blob/a6bd1453fd8e931394b9b1f2185fad48b7cca5fe/examples/xclock_utc.rs.Basically:
poll_for_event()
to handle all the events that were read from the socket to the X11 server.This related to #934 and #935. I haven't written this to either of them since it does not completely fit with either of them.
In case you have the luxury of ignoring thread, the above works. In this case, you can also add a single call to
xcb_flush()
(well,connection.flush()
) at the end of the main loop iteration. That way, you do not have to flush anywhere else (assuming your forbid functions that take a long time to return, but that would completely block your main loop and so I guess you do).If you have to support threads: Don't.
If you still have to support threads: The Qt guys have not found a correct way to handle events in the main thread while other threads might also use the X11 connection. Their solution is to spawn a thread which always calls
xcb_wait_for_event()
in a loop and sends the result to the thread that runs the main loop (...via some Qt-internal mechanism that I know nothing about).I also took a look at the code in https://github.com/xi-editor/druid/tree/master/druid-shell/src/platform/x11.
https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/application.rs#L224
I recommend only handling the last MotionNotify event in a series of events. If the X11 server generated these events faster than you can handle them, your application may lag behind more and more.
E.g. imagine a program that shows a cross at the current mouse position while it is inside of its window (just for the sake of argument). This program sleeps for a second after drawing its content (also just for the sake of argument). When the mouse cursor moves across the window, one can now see the old mouse positions to be drawn with a lot of delay. I hope this description makes sense.
A simple way to avoid this is to keep a "pending"
MotionNotify
event around while processing events. If a newerMotionNotify
event comes in, the pending one is simply discarded. Some things, e.g. "mouse left the window" depend on the order of events and in this case the pending event would be handled.Perhaps some code can explain this better than my weird explanation above:
https://github.com/awesomeWM/awesome/blob/e7113d7191e37c5b0faedccff6caf82d8e0bd77c/awesome.c#L392-L425
https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/application.rs#L296-L297
Huh? Can someone tell me more about this? The X11 server automatically destroys all your resources when you close the connection (unless you use the
SetCloseDownMode
request and specify something else to happen).Or is this about something like an
Rc
cycle, i.e. a leak inside of the Rust program?https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/keycodes.rs
This looks so simple. You should keep it at that version of the code. :-)
https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/window.rs#L94-L140
https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/window.rs#L460-L471
_NET_WM_NAME
property. It has typeUTF8_STRING
. I actually do not know how to decodeSTRING
properties correctly, but just the fact that X11 is older than Unicode makes this scary.https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/window.rs#L293
.finish()
your cairo surface before destroying the underlying window. Most likely, it makes no difference, but in the cases where it makes a difference, it saves you some X11 errors.https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/window.rs#L260
https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/window.rs#L333-L354
SendEvent
request. It just forwards its content. Why do you need this to go through the X11 server instead of handling this internally?Edit: Found an explanation at fe13219#diff-31f2e83ba4096702ec15dea2f88c18edR336-R339
In this case I would say: Why not use your "soon existing" idle infrastructure instead? That would still save a round-trip to the server.
https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/application.rs#L175-L182
count
member.count == 0
indicates that this is the last expose event for now.https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/window.rs#L358-L360
ConfigureNotify
events when the size changes. That would avoid one round-trip to the X11 server.https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/window.rs#L433
Edit: Actually, I was wrong. ICCCM says that what you are doing here is fine.
https://github.com/xi-editor/druid/blob/d810d30b95da52b3ca89efe63bd3b88b15b5a42b/druid-shell/src/platform/x11/window.rs#L443
SetInputFocus
withCurrentTime
. Never ever may anything do that. Welcome to "X11 is mechanism, not policy".WM_CLASS
. Also,WM_CLIENT_MACHINE
andWM_COMMAND
would be "nice to have". Oh and_NET_WM_PID
(from EWMH, not ICCCM) is also a nice-to-have.WindowHandle::set_cursor
), I recommend taking a look at https://docs.rs/x11rb/0.6.0/x11rb/cursor/index.htmlFeel free to ping me as @psychon with questions in the future on other issues. There is certainly a lot that I do not know, but perhaps there are also bits and pieces that I can help with.
Edit:
The text was updated successfully, but these errors were encountered: