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
window. add close button interceptor to react on the window closing before anything is done #1180
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the idea of ‘WillClose’ is to allow vetoing then perhaps it could be named more accordingly?
The glfw implementation seems complex - does it need a ‘closing’ bool and a goroutine? Isn’t it a case of calling the Function to verify, then continuing if ok? If the code was rearranged to exit early the diff could be much smaller.
Also why is the gomobile driver a no-op? Should we not be able to veto closing windows there?
Yes, the main benefit is to get the place to prevent the window closing, but there could be different cases where onClose is too late because window is already closed. I took name from the original discussion and if you see there's better option just write it. closing yes it should be there, otherwise it's possible to get several handlers running that can create races. For example if you build my example and try to close the window several times without this protection it will show several confirmation dialogs. Simple function call without goroutine is ok for a plain go code but using ShowConfirm in the handler is taking the app to a deadlock (checked on linux and windows). I'll keep old closed as doClose to simplify the diff The only reason of no-op is i'm not sure how to check that case. I'll add the code there as well |
|
Isn’t the race condition that requires ‘closing’ only present because of the goroutine? If a confirm is required I would |
I had no issues with the goroutine present but every time i've tried to remove it i'm experiencing a deadlock. The easiest way to see the |
Isn't the deadlock related to the example code which blocks waiting for the interface to do something? By moving to a goroutine you add the need to check for concurrent runs. Maybe this relates to the design - "WillClose" sounds like a notification or event but really it's supporting, or requiring, a long blocking wait whilst the user is asked of something. This is counter to how other callbacks are setup whereby they use the event thread and blocking would be a bad idea. |
Thinking out loud a simpler design might require that if WillClose is set then the developer must call Window.Close() if that is what they want? That way threading is not required as the dialog callback can simply call that method if appropriate... |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few inline comments, it looks cleaner but would like a third opinion
I think it looks cleaner this way - but perhaps others could feed in? |
closing this PR to reopen and get additional commit after recent guthub issues |
one of the text selection tests failed on one node, not sure it's related:
|
I have restarted in case it was a temporary fault |
internal/driver/glfw/window.go
Outdated
@@ -404,6 +409,13 @@ func (w *window) Close() { | |||
w.closed(w.viewport) | |||
} | |||
|
|||
func (w *window) DoClose() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need that to be exported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, the idea is that user should explicitly close the window in this new handler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO a difference between Close()
and DoClose()
isn't clear intuitively. I would stick with TryClose()
and onCloseTry
naming scheme. @andydotxyz What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DoClose is expected to close window without additional checks so TryClose is exactly opposite name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that what I meant. Don't these names look more intuitive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@RustamGamidov Can you do as @andydotxyz suggests, i.e. rename willClose
into onCloseIntercept
, SetWillClose()
into SetCloseIntercept()
and get rid of DoClose()
? Then the only thing that will remain is an approve from another contributor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah... made it if i understood the idea. I'm just confused with how many things are moved to the client code like checking for deadlocks or loops. Especially because there was a comment regarding possible loop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should not be neccessary to do any checking for loops or deadlocks in client code. The simplicity we are looking for is simplicity for the developers using the API.
They should not have to worry about threading at all, that is one of our design principles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then i believe onCloseIntercepted should be called in goroutine like it was initially but it probably worth to wait for comments from other repo owners because we already used our arguments and most likely we'll stuck arguing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if perhaps the event queue is the right place to put it? Just launching goroutines to work around possible deadlocks seems like it's not fixing the underlying issue? We used to do that with button taps and key presses and it caused a jumble of out-of-order events, so we don't do that any more.
same test failed on the same node as far as i remember that still looks not related
btw, locally on win10 i'm experiencing not stable clipboard test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the when-to-check-intercept logic is reversed in this latest version, which is probably why you are seeing loops?
So I think my feeling on this is - I like the style of WillClose with a return boolean. The Intercept requiring the dev to call Close() is a little confusing/not obvious in my opinion. However - WillClose is probably the wrong name and the name of that Method will need to be revisited. On the flip side the implementation will be easier/cleaner with Intercept - as WillClose will have to involve some goroutines etc... So there is a trade off either way. I will be happy going with what the majority decides. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that I quite like the intercept behaviour that the PR implements currently. It looks like the example isn't updated though.
window.Close() should be called explicitly to close the window
to keep Close for the programmatic closing with pre-checks to break the pre-checks loop without status variable
be aware client code should close the window, check for loops and ensure there are locks
… window tests are deleted because
fixed the example and rebased over the current develop |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me. Thanks for rebasing and updating the example 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great and is very close :) two comments inline that I think were missed from earlier discussion threads.
Last thought - in previous version there were tests, is it possible to re-add testing to this version?
internal/driver/glfw/window.go
Outdated
if w.onClosed != nil { | ||
w.queueEvent(w.onClosed) | ||
if w.onCloseIntercepted != nil { | ||
w.onCloseIntercepted() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Earlier you mentioned that this could block - should it be passed to w.queueEvent
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i've tried that, and it's not helping unfortunately
i can do this to follow the pattern
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you confirm what the issue is please?
Looking at the example above I can't help but feel the channel should not be needed - just calling Window.Close()
in the callback should work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the issue is not reacting ShowConfirm
Yes, it's solved with removing the channel with and without using queueEvent
. Changed the example accordingly
window.go
Outdated
@@ -64,6 +64,9 @@ type Window interface { | |||
// SetOnClosed sets a function that runs when the window is closed. | |||
SetOnClosed(func()) | |||
|
|||
// SetCloseIntercept sets a function that runs instead of closing if defined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a "." to this, and add another line instructing people to call Close()
to confirm window closure?
i don't see the way how to do this as the current solution is catching window manager closing only that is private |
no specific reason for that just following the pattern to decrease deadlock chance
quite unlikely related to the PR |
But from tests you can call private methods... |
oh indeed! missed they are in the same package |
ci failed on one of the nodes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great thanks so much for getting this the whole way
@okratitan I think that @toaster and I are happy here, can you approve the latest version too please? |
Many thanks, this will be in 1.4 release later this year. |
🙏 thanks a lot for all your patience and comments! That was the long way! |
Description:
adding wrapper to closing handler so that we can react on the window closing before the window is destroyed.
for example it can serve window closing confirmation
Fixes #467
Checklist:
Where applicable:
example: