Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Sync and Clone from EventsLoop. Add EventsLoopProxy. #191

Merged
merged 20 commits into from
Jun 21, 2017

Conversation

mitchmindtree
Copy link
Contributor

This commit only updates the top-level API to get some early feedback.
None of the platform-specific code has been updated yet. I'm hoping to
get around to this over the next couple days however if someone more
familiar with the windows backend would like to do a PR against this
fork that would be a great help.

Closes #187.

This commit only updates the top-level API to get some early feedback.
None of the platform-specific code has been updated yet. I'm hoping to
get around to this over the next couple days however if someone more
familiar with the windows backend would like to do a PR against this
fork that would be a great help.

Closes rust-windowing#187.
X11 and Wayland implementations are now half implemented, however both
still do not correctly break from the inner blocking event dispatch
functions when `wakeup` is called, which they should do.
@mitchmindtree
Copy link
Contributor Author

The wayland backend is now implemented and the x11 implementation is halfway there.

@mitchmindtree
Copy link
Contributor Author

OK I believe all backends have been implemented now!

windows, android and iOS are still using the gen_api_transition! macro, so I updated the macro for those backends.

This should now be ready for review.

@mitchmindtree mitchmindtree changed the title [WIP] Remove Sync and Clone from EventsLoop. Add EventsLoopProxy. Remove Sync and Clone from EventsLoop. Add EventsLoopProxy. May 31, 2017
@elinorbgr
Copy link
Contributor

General design question, as the eventsloop is no longer intended to be shared and we have a proxy, wouldn't it make sense to:

  • move the interrupt method to the proxy too ?
  • make dispatch_events and run_forever take &mut self as argument, rather than &self ?

Doing both of this could simplify greatly the internal implementation (it'd possibly remove a few synchronisation/locking primitives in the wayland backend, for example), while not really changing the ergonomics of the eventsloop.

Given this PR is a breaking change any way...

@mitchmindtree
Copy link
Contributor Author

mitchmindtree commented May 31, 2017

@vberger the ability to interrupt should only really be needed by the EventsLoop itself. See #187 for the discussion around the semantic difference between interrupt() and wakeup().

Now that you mention it though, I agree that both run_forever and poll_events should take &mut self instead. However, this would mean that self.interrupt() could not be called within the given user callback to cause run_forever to break (which is its only purpose after this PR). Perhaps instead of having an interrupt method, the run_forever user callback should return whether or not the loop should continue, e.g.

pub enum ControlFlow {
    Continue,
    Complete,
}

Or something along these lines? That way run_forever and poll_events should be able to take &mut self and interrupt() could be removed.

@mitchmindtree
Copy link
Contributor Author

@tomaka what are your thoughts on my previous comment ^ ? I'm happy to go ahead and make the change, but it would be nice to get some feedback before going ahead as the change will take a bit of time to implement across all backends.

This removes the need for the EventsLoop::interrupt method by inroducing
a ControlFlow type. This new type is to be returned by the user's
callback and indicates whether the `EventsLoop` should continue waiting
for events or break from the loop.

Only the wayland, x11 and api_transition backends have been updated so
far, and only the wayland backend has actually been tested.
@Ralith
Copy link
Contributor

Ralith commented Jun 3, 2017

+1 for &mut self; that would make the X11 backend noticably simpler.

@mitchmindtree
Copy link
Contributor Author

OK I had some time tonight and went ahead with the extra changes. The general gist is:

  1. Change poll_events and run_forever to take &mut self
  2. Remove EventsLoop::interrupt in favour of having the EventsLoop::run_forever user callback return a new ControlFlow type.

I'm happy to roll this back to 38856b1 if folks would prefer to make this change in a future PR, however I think it makes sense to include it along with the removal of Sync. I personally think the change looks pretty nice, though I'm open to any suggestions/tweaks/feedback - e.g. there might be a better name than ControlFlow.

All backends have been updated and seem to work fine, though there is probably room for simplification in some backends (certainly in x11 as you mention @Ralith).

This is ready for review.


let mut control_flow = ControlFlow::Continue;

if self.pending_wakeup.load(atomic::Ordering::Relaxed) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the wakeup system implemented here cause xlib.XNextEvent to return? Unless I'm missing something, this implementation of wakeup does not cause a blocked loop to advance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pending_wakeup flag is only an indicator of whether or not wakeup has been called on an EventsLoopProxy. It is EventsLoopProxy::wakeup itself that should cause the next event function to return, though I could certainly be wrong on this - IIRC, I took this code from the old WindowProxy::wakeup method.

If you're on x11, you can test if this is working or not by running the included proxy.rs example. If it needs fiixing, please feel free to submit a PR to my fork, or let me know how I can go about fixing it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my, I'm so sorry. I didn't look at this as thoroughly as I should have when making this comment. I didn't see originally that the actual event loop bump was moved rather than deleted.

};

unsafe {
(display.xlib.XSendEvent)(display.display, self.root, 0, 0, mem::transmute(&mut xev));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recall trying to implement this at some point using self.root as the window and missing some wakeup events. I'll test again with your branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I just tested this on X11 and you are right, this does not seem to cause xlib.XNextEvent to stop blocking at all (in the proxy.rs example). That said, I can't help but wonder if this code ever worked for the old WindowProxy code either.

I'm not very familiar with the X11 backend but will see if I can get to the bottom of this. In the meantime, do you have any ideas on why this might not be working?

@mitchmindtree
Copy link
Contributor Author

mitchmindtree commented Jun 17, 2017

@jwilm you were right wrt root not working as the target for the wakeup event. To fix this, I created a dummy, InputOnly window (owned by the EventsLoop) with the sole purpose of receiving the wakeup events and it seems to work nicely! Tested on Arch+Gnome+X11.

@mitchmindtree
Copy link
Contributor Author

@tomaka would you mind sharing your thoughts on this?

@jwilm
Copy link
Contributor

jwilm commented Jun 17, 2017

@mitchmindtree Have you considered making the wakeup method accept a WindowId? This makes it possible to know specifically which window is being woken up, and it removes the need for a phantom window for wake ups. This was previously supported before EventsLoop became a thing.

@mitchmindtree
Copy link
Contributor Author

mitchmindtree commented Jun 17, 2017

I'm personally not sure that it should be winit's job to do anything beyond waking up the event loop for a few reasons:

  1. In its simplest form, the functionality that we need from winit (that users cannot implement efficiently in a cross-platform way otherwise) is a way to stop blocking on run_forever.
  2. Often the act of waking the EventsLoop has nothing to do with a particular WindowId. E.g. In my own code, I imagine having to specify a WindowId will feel more like a hinderance, as I normally just want to awaken the events loop to complete the program or to render some pending graphics that I just pushed to a channel that is already associated with the window(s) I want to draw to.
  3. When they are needed, associating WindowIds with wakeups is trivial to implement in user code.

This was previously supported before EventsLoop became a thing.

Before EventsLoop, having multiple windows was a total mess on most platforms and there was no over-arching concept of a single stream of events. The only way to block on all events was by producing a WaitEvents iterator from each Window one at a time, and the only way to wake up these loops was by producing a WindowProxy for each Window. There was no way around waking up a specific window, as the only way to receive events was by producing iterators from each individual window. This is no longer the case as we do now have a single stream of events in the form of an EventsLoop, of which WindowEvents are a subset of all Events that might occur.

What are your thoughts on this @jwilm?

@jwilm
Copy link
Contributor

jwilm commented Jun 18, 2017

Thanks for the perspective @mitchmindtree. Sounds like you've done the right thing!

src/lib.rs Outdated
/// Continue looping and waiting for events.
Continue,
/// Exit from the event loop.
Complete,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this variant be Break instead of Complete to mirror the normal control flow keywords?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call! I've just added a commit that makes this change.

@jwilm
Copy link
Contributor

jwilm commented Jun 20, 2017

I really like this change set. Would love to see it land soon :)

Copy link
Contributor

@Ralith Ralith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes to the X11 backend look good to me, and I am strongly in favor of the API changes.

@tomaka
Copy link
Contributor

tomaka commented Jun 21, 2017

R+, thanks!

@tomaka tomaka merged commit a08347e into rust-windowing:master Jun 21, 2017
@mitchmindtree mitchmindtree deleted the remove_sync branch June 21, 2017 09:11
mitchmindtree added a commit to mitchmindtree/winit that referenced this pull request Jun 24, 2017
Includes:

- Recent removal of sync (breaking change) rust-windowing#191.
- Wayland fixes: rust-windowing#190, rust-windowing#188, rust-windowing#181
- X11 fixes: rust-windowing#174, rust-windowing#178,
tmfink pushed a commit to tmfink/winit that referenced this pull request Jan 5, 2022
This opens the door to caching tiles at different zoom levels (issue rust-windowing#191).
madsmtm pushed a commit to madsmtm/winit that referenced this pull request Jun 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants