-
Notifications
You must be signed in to change notification settings - Fork 20
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
fix: mini-frame is slow in Windows #9
base: master
Are you sure you want to change the base?
Conversation
a3687e3
to
e4fc024
Compare
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.
Thanks! I've left a few comments that should be addresses before this gets merged.
((and (frame-live-p mini-frame-frame) | ||
(frame-visible-p mini-frame-frame)) | ||
(mini-frame--display fn args)) |
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's here for the case when enable-recursive-minibuffers
is t
.
M-x
C-x 5 o
M-x
C-g
Focus should stay in mini-frame. With this changes mini-frame is closed.
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.
Fixed
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.
But why this block must be removed at all? Is this Windows specific? Can you please provide receipt for issue that this removal is fixing?
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.
What this block doing is just call bare mini-frame--display
without any additional setup + cleanup.
That can be quite dangerous.
For example when I tried it on Windows, once the minibuffer some how got into visible state, and the focus is removed. Since we never run the cleanup code for it, it will just stays visible there forever.
This could be true even for other platform too.
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.
What this block doing is just call bare
mini-frame--display
without any additional setup + cleanup.
That can be quite dangerous.
But mini-frame is visible. This mean that cleanup is set already and all what we want frommini-frame--display
is maybe to update size and position of mini-frame.
For example when I tried it on Windows, once the minibuffer some how got into visible state, and the focus is removed. Since we never run the cleanup code for it, it will just stays visible there forever.
This could be true even for other platform too.
I'll check it on Windows.
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.
But mini-frame is visible. This mean that cleanup is set already and all what we want from
mini-frame--display
is maybe to update size and position of mini-frame.
Let me clarify it more.
I found out one of the reason in Windows (or it may affect other GUI system) that some time the mini frame may get behind the main frame.
In that case the mini frame still show up as visible but user cannot see it.
Worse, I observe that when I'm using swiper
, once the mini frame got behind main frame, the user will not be able to move away from mini frame without using mouse.
The reason may be because the mini frame is still visible (actually hidden since it's behind the main frame), so when we try to quit it, there is no cleanup code to be run to reassign the input focus.
To recover from the issue of mini frame get behind main frame, one easy solution is to just hide mini frame every time we enter it (except recursive entering). That will make sure we start it with a fresh z-order once it went wrong. However, because of that, we will need the frame cleanup code for the your mentioned block, since basically we're going to show the mini frame again.
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.
Worse, I observe that when I'm using
swiper
, once the mini frame got behind main frame, the user will not be able to move away from mini frame without using mouse.
C-x 5 0
may help.
Can confirm. When ivy-mode
is active or after M-x swiper
mini-frame has visibility
frame parameter set to t
but it's not visible, e.g.:
M-x swiper
C-g
M-: (frame-parameter mini-frame-frame 'visibility)
I'll look further.
mini-frame.el
Outdated
(select-frame-set-input-focus mini-frame-selected-frame)) | ||
(make-frame-invisible mini-frame-completions-frame) | ||
(modify-frame-parameters mini-frame-completions-frame '((parent-frame)))) | ||
(if (frame-live-p mini-frame-selected-frame) |
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 the mini-frame-selected-frame
variable is really needed. Maybe set focus to (frame-parameter mini-frame-frame 'parent-frame)
will be enough.
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, I've removed all of mini-frame-selected-frame
now.
mini-frame.el
Outdated
;; (if (eq system-type 'windows-nt) | ||
;; FIXME sometime buffer is not visible on windows | ||
;; (delete-frame mini-frame-frame) |
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 no need to keep commented code.
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.
Removed
36151c3
to
117bc09
Compare
(when (frame-live-p mini-frame-completions-frame) | ||
(make-frame-invisible mini-frame-completions-frame) | ||
(modify-frame-parameters mini-frame-completions-frame '((parent-frame)))) | ||
(if (frame-parameter mini-frame-frame 'parent-frame) |
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.
In which case parent-frame
parameter of mini-frame
will be nil
here?
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.
As in the description, when I hide the mini-frame
, I also detach its parent from it.
The purpose of that is to make sure mini-frame
is not being destroyed when parent frame is gone.
For example, you open another frame M-x make-frame
or using emacsclient
to connect to server. At that time, if mini-frame
is used inside the new frame, and you close the new frame after that, mini-frame
will be gone with the new frame.
With this change, it's prevented, so we don't need to create new mini-frame
again
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 understand that.
But I mean this particular place (line 319). We are only going to hide mini-frame, so it is visible and it's parent-frame
is not nil
, right?
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 see, Since this part is in unwind
form, I assume anything may happens.
For example, the mini-frame
is dead, thus the frame-parent
parameter is returned as nil
.
In that case it will go to else code bellow and try to find another root frame to set focus to. So we don't accidently lost the input focus in some unreachable place.
((and (frame-live-p mini-frame-frame) | ||
(frame-visible-p mini-frame-frame)) | ||
(mini-frame--display fn args)) |
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.
What this block doing is just call bare
mini-frame--display
without any additional setup + cleanup.
That can be quite dangerous.
But mini-frame is visible. This mean that cleanup is set already and all what we want frommini-frame--display
is maybe to update size and position of mini-frame.
For example when I tried it on Windows, once the minibuffer some how got into visible state, and the focus is removed. Since we never run the cleanup code for it, it will just stays visible there forever.
This could be true even for other platform too.
I'll check it on Windows.
;; trying to find an alternate frame to return the focus | ||
(when-let (fr (cl-find-if-not | ||
(lambda (fr) | ||
(or (equal fr mini-frame-completions-frame) | ||
(equal fr mini-frame-frame) | ||
(frame-parameter fr 'parent-frame))) | ||
(frame-list))) | ||
(select-frame-set-input-focus fr))) |
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 (other-frame)
be used here to simplify the code?
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.
Since we're going to detach mini-frame-completions-frame
and mini-frame-frame
to nil
parent, (other-frame)
may just return them back. So I need this to find the first frame that's not the mini frame.
@muffinmad Is there any chance this can be merged? |
@kiennq Sorry for delay. Haven't enough time lately to find out the reason of such behavior on Windows, but your PR is on my list. |
@kiennq Please check recent master version. Mini-frame is not deleted on Windows now. |
When I update
|
To reproduce the same error:
Solutions:
|
Using
mini-frame
under Windows is slow, mostly due to it has to create new child frame every timemini-frame
is invoked.When I read the FIXME, it seems that in Windows, child frame can easily being display under the current frame, thus make the child frame not displayable problem.
In this PR I've tried to tackle this, produced quite contended result for Windows.
z-group
to defaultmini-frame-frame
parametersmini-frame-read-from-minibuffer
, unify the condition of last two conditions, since both of them requires calling to(mini-frame--display fn args)
. And that function requires properly set up of hooks, variables and cleanups.mini-frame
if visible before displaying it in Windows. This is done to make suremini-frame
restart its z order and will not be hidden under parent frame.The change log may seems a lot, but all is done to ensure mini frame on Windows can be displayed quickly.
I've tested it with
swiper
, that seems to make mini frame goes to weird state every time we type + not select the result. With this fix the issue is resolved.