Hi all,
I'm writing a scenario with nitpicker where I want to support pop-ups e.g. for asking the user's password.
I made a simple GUI app with a textbox that pops up and disappears when required. However, whenever this popup appears I want nitpicker to immediately change focus to this popup and put it in front of all other nitpicker clients and windows. Now the behaviour is either "click", "transient" or "none", meaning the focus is only given when the user clicks on the window, or never.
This is a problem since if some other untrusted app is running in the background, the user could type in his password immediately when the pop-up appears, and the input is then directed to the app instead of the popup itself, allowing the untrusted app to read the password. The only way the user could enter the password correctly at the moment is by clicking on the pop-up before typing.
One solution would be handling the focus via a focus report-rom, however when the pop-up is not there I want nitpicker to use its default behaviour (together with the window manager) so that it focuses windows when they are clicked. Reimplementing this default behaviour so it produces the report in this case seems quite ugly.
Do you have any ideas what I could try to do to achieve the desired behaviour?
From nitpicker's readme:
The focus ROM is expected to have a 'label' attribute with the value
set to the label of the to-be focused client. When using an external focus policy, domains configured as "click" are internally handled like "transient" focusable domains. It is up to the external focus policy component to make a new focus permanent by providing an updated "focus" ROM."
What if I want to switch between an external and internal focus policy based on which apps are running? Do you think it is easiest to extend nitpicker to have a focus="always" attribute that always focuses a certain client whenever it is up? Or to write a separate complicated focus policy component responsible for all focusing?
Hi Boris,
I made a simple GUI app with a textbox that pops up and disappears when required. However, whenever this popup appears I want nitpicker to immediately change focus to this popup and put it in front of all other nitpicker clients and windows. Now the behaviour is either "click", "transient" or "none", meaning the focus is only given when the user clicks on the window, or never.
I had to solved this exact problem in the Sculpt scenario where the control panel "Leitzentrale" should always have the keyboard focus while activated. Otherwise, the regular nitpicker focus policy should be in place. I hope that my solution works equally well for your scenario:
Please have a look at the combination of the 'nit_user_focus' and 'nit_focus' components in the sculpt.run script [1]. The former captures the state of the regular nitpicker focus. The latter overrides the former whenever the Leitzentrale is enabled.
[1] https://github.com/nfeske/genode/blob/sculpt/repos/gems/run/sculpt.run
Cheers Norman
Hi,
I have implemented a scenario with nit_user_focus similar to the one you described below. For such scenarios this works fine.
However, the scenario I want to make is a little bit more complicated. I would like to hear your opinion on this.
On one end I have the login popup that behaves a bit like the leitzentrale from sculpt. When it is up, it always gets the focus through the rom_filter rule. So far, so good.
However, on the user end I am using the window manager. All the user applications' nitpicker sessions are routed to the wm. Windows can be maximized or not maximized. The maximized state might be toggled with buttons or keys or it might be fixed.
Also, I want applications that have just started to be focused and put on top of the window stack immediately. For this I and Martijn made some changes in the layouter such that if the layouter gets a new focus_request ROM update, it will try to bring the requested window to the top and focus it. The request is then generated by our launcher component. This also works fine.
However, the nit_focus component does not really do what we want here. This can be illustrated with the following example.
- We have three GUI components: the login screen which should always be focused; a noux window and a virtualbox window, all of which are in maximized state.
1. Initially, the login screen is focused and shown since it is up. I login and it disappears.
2. I start the noux component. Now the noux component is visible, though it does not have the focus yet as it is not clicked and nit_focus has not produced a report. The focus_request from the layouter is not applied since the window manager is not in control of the currently focused nitpicker session (which is none).
3. I click on the noux window. Now it is both visible and focused.
4. Now I start virtualbox. Because noux is a client of the wm, the focus_request is applied and our hack made sure the new window is immediately visible and focused.
5. Now I lock the screen. The login screen pops up again and is focused.
6. I login again. the VM is still the top window and is visible now. However, the focus is back to the last clicked component, which is noux. I am an uncaring end-user and type in my password for the trusted VM and hit enter. My password is now entered in noux, as it had the focus. Now suppose it is not noux but an untrusted/possibly compromised VM connected to the internet.
Now what causes this issue is the fact that I wanted there to be other ways besides clicking to bring a window to the front. In fact, it would be nice if the window manager was always in charge if the login screen is not up. So I tried removing the nit_focus component and hardcoding the focus attribute to be "wm -> " in case the login screen isn't up. It seemed to me that this might solve point 2 (since the focus now belongs to wm) and point 6 (since the wm is in charge and automatically focuses the hovered window). However, the focus_request does not seem to do anything now and no window ever gets the focus, even if clicked. I do not really understand how this works. Can you give an explanation?
One thing I could do is let the launcher also generate a focus report focusing the last started application whenever it starts. However, this would mean it needs to keep track of the window stacking order and focusing besides the wm/layouter, as switching focus no longer works. This does not sound like a good direction to me.
Ideally I want the focus of windows to be decided by the wm/layouter, but also have the possibility for an external component to bring certain windows to the top and focus them without the need of a user click. Do you have any ideas for how to accomplish this?
Hi Boris,
On 08.02.2018 14:28, Boris Mulder wrote:
I have implemented a scenario with nit_user_focus similar to the one you described below. For such scenarios this works fine.
However, the scenario I want to make is a little bit more complicated. I would like to hear your opinion on this.
On one end I have the login popup that behaves a bit like the leitzentrale from sculpt. When it is up, it always gets the focus through the rom_filter rule. So far, so good.
However, on the user end I am using the window manager. All the user applications' nitpicker sessions are routed to the wm. Windows can be maximized or not maximized. The maximized state might be toggled with buttons or keys or it might be fixed.
Also, I want applications that have just started to be focused and put on top of the window stack immediately. For this I and Martijn made some changes in the layouter such that if the layouter gets a new focus_request ROM update, it will try to bring the requested window to the top and focus it. The request is then generated by our launcher component. This also works fine.
That sounds all as intended.
However, the nit_focus component does not really do what we want here. This can be illustrated with the following example.
- We have three GUI components: the login screen which should always be
focused; a noux window and a virtualbox window, all of which are in maximized state.
- Initially, the login screen is focused and shown since it is up. I
login and it disappears.
- I start the noux component. Now the noux component is visible, though
it does not have the focus yet as it is not clicked and nit_focus has not produced a report. The focus_request from the layouter is not applied since the window manager is not in control of the currently focused nitpicker session (which is none).
I click on the noux window. Now it is both visible and focused.
Now I start virtualbox. Because noux is a client of the wm, the
focus_request is applied and our hack made sure the new window is immediately visible and focused.
Now I lock the screen. The login screen pops up again and is focused.
I login again. the VM is still the top window and is visible now.
However, the focus is back to the last clicked component, which is noux. I am an uncaring end-user and type in my password for the trusted VM and hit enter. My password is now entered in noux, as it had the focus. Now suppose it is not noux but an untrusted/possibly compromised VM connected to the internet.
Now what causes this issue is the fact that I wanted there to be other ways besides clicking to bring a window to the front. In fact, it would be nice if the window manager was always in charge if the login screen is not up. So I tried removing the nit_focus component and hardcoding the focus attribute to be "wm -> " in case the login screen isn't up. It seemed to me that this might solve point 2 (since the focus now belongs to wm) and point 6 (since the wm is in charge and automatically focuses the hovered window). However, the focus_request does not seem to do anything now and no window ever gets the focus, even if clicked. I do not really understand how this works. Can you give an explanation?
In the sculpt scenario, the nitpicker focus is actually defined by a cascade of ROM filters.
The 'nit_user_focus' component represents the focus defined by the window manager (the layouter actually). This is the 'nit_focus' binary. In contrast, the 'nit_focus' component is a ROM filter that takes the output of the 'nit_user_focus' and generates the real nitpicker focus. This ROM filter is the point where the global override of the window-manager's policy happens. Admittedly, the naming is a bit ambiguous since the 'nit_focus' component does not use the 'nit_focus' binary.
That said, since I integrated the wm in the Sculpt scenario last week, I encountered a few focus-related complications. In particular, there apparently are situation where the window manager takes the focus away from the leitzentrale. This is a bug in nitpicker that must be fixed.
Furthermore, I think that the current nitpicker interface for passing the focus between sessions needs to be improved. It immediately triggers an action (which depends on conditions such as whether the calling session has the current focus or not) but if the condition is not satisfied, focus-change action gets lost. I plan to change this interface such that a client will be able to specify the session label it likes to yield its focus to. This is will be not an event but a state. Regardless of when the client becomes focused, this focus-yield information will come into effect.
One thing I could do is let the launcher also generate a focus report focusing the last started application whenever it starts. However, this would mean it needs to keep track of the window stacking order and focusing besides the wm/layouter, as switching focus no longer works. This does not sound like a good direction to me.
I agree. This is the responsibility of the layouter, not the launcher.
Ideally I want the focus of windows to be decided by the wm/layouter, but also have the possibility for an external component to bring certain windows to the top and focus them without the need of a user click. Do you have any ideas for how to accomplish this?
Since the layouter is the arbitrator of the focus, but you still want to consider the wishes of an external component, it would be natural to let the layouter listen to these wishes and consider this information for its decision. Hence, you would need an interface to let the layouter know these wishes. Still, the layouter's stays in the position to take the ultimate decision. I have no suggestion of how such an interface should look like. Ideally, it would be a state presented via a ROM module.
Cheers Norman
Hi Norman,
Thanks for your reply.
Furthermore, I think that the current nitpicker interface for passing the focus between sessions needs to be improved. It immediately triggers an action (which depends on conditions such as whether the calling session has the current focus or not) but if the condition is not satisfied, focus-change action gets lost. I plan to change this interface such that a client will be able to specify the session label it likes to yield its focus to. This is will be not an event but a state. Regardless of when the client becomes focused, this focus-yield information will come into effect.
That might make implementing features such as mine easier!
Since the layouter is the arbitrator of the focus, but you still want to consider the wishes of an external component, it would be natural to let the layouter listen to these wishes and consider this information for its decision. Hence, you would need an interface to let the layouter know these wishes. Still, the layouter's stays in the position to take the ultimate decision. I have no suggestion of how such an interface should look like. Ideally, it would be a state presented via a ROM module.
Actually that is what I am trying to do now, and it sort of works for bringing other sessions to the front.
However, the problem here is that the nit_focus component only checks the clicked session, not the ones brought to the front externally.
Ideally I want the focus of windows to be decided by the wm/layouter, but also have the possibility for an external component to bring certain windows to the top and focus them without the need of a user click.
So we need to have another nit_focus like component (or an extension of the existing one) that bases its output on some report generated by the layouter. The layouter should generate a report with the label of the current window on top of the stack, and this new component generates the focus report accordingly. With rom_filters this can then be integrated into the scenario the same way as with nit_focus. Whenever another window is put to the front, either by clicking or through the new external report, the layouter should update its own report with the top window. Then the nit_focus component can update its focus report in turn.
One option would be using the "focus" report of the layouter together with the window_list or window_layout report.
In this case, since the wm lives above the runtime init, the report generated by the new nit_focus would need to have a label_prefix appended, e.g. the window list reports label "noux -> nit_fb -> " whereas nitpicker wants to see "runtime -> wm -> noux -> nit_fb -> ". This depends on your scenario so should be configurable.
What do you think of this direction? Worth integrating into Genode?
Hi Boris,
On 08.02.2018 16:20, Boris Mulder wrote:
So we need to have another nit_focus like component (or an extension of the existing one) that bases its output on some report generated by the layouter.
exactly! The sole purpose of the nit_focus component is to be replaced. :-) With less than 50 lines of code, it showcases the implementation of the policy that was formerly built-in in nitpicker. Since I moved this policy to this external component, we can do anything we want by replacing it.
The layouter should generate a report with the label of the current window on top of the stack, and this new component generates the focus report accordingly. With rom_filters this can then be integrated into the scenario the same way as with nit_focus. Whenever another window is put to the front, either by clicking or through the new external report, the layouter should update its own report with the top window. Then the nit_focus component can update its focus report in turn.
Yes.
One option would be using the "focus" report of the layouter together with the window_list or window_layout report.
In this case, since the wm lives above the runtime init, the report generated by the new nit_focus would need to have a label_prefix appended, e.g. the window list reports label "noux -> nit_fb -> " whereas nitpicker wants to see "runtime -> wm -> noux -> nit_fb -> ". This depends on your scenario so should be configurable.
What do you think of this direction? Worth integrating into Genode?
It is exactly the direction I want to go. The externalized nit_focus component was just a stepping stone.
Still, my remark about the nitpicker-focus handover between sessions holds because such a mechanism is needed regardless of the layouter's / nit_focus policy, e.g., for implementing dialogs with menus or sub-dialogs.
Cheers Norman
Well, I adapted the nit_focus to use the window_layout report instead of the clicked report, and it works like a charm.
Thanks for your response! If you want the source to save some work later, I do not mind sharing it.
Boris
On 08-02-18 17:43, Norman Feske wrote:
Hi Boris,
On 08.02.2018 16:20, Boris Mulder wrote:
So we need to have another nit_focus like component (or an extension of the existing one) that bases its output on some report generated by the layouter.
exactly! The sole purpose of the nit_focus component is to be replaced. :-) With less than 50 lines of code, it showcases the implementation of the policy that was formerly built-in in nitpicker. Since I moved this policy to this external component, we can do anything we want by replacing it.
The layouter should generate a report with the label of the current window on top of the stack, and this new component generates the focus report accordingly. With rom_filters this can then be integrated into the scenario the same way as with nit_focus. Whenever another window is put to the front, either by clicking or through the new external report, the layouter should update its own report with the top window. Then the nit_focus component can update its focus report in turn.
Yes.
One option would be using the "focus" report of the layouter together with the window_list or window_layout report.
In this case, since the wm lives above the runtime init, the report generated by the new nit_focus would need to have a label_prefix appended, e.g. the window list reports label "noux -> nit_fb -> " whereas nitpicker wants to see "runtime -> wm -> noux -> nit_fb -> ". This depends on your scenario so should be configurable.
What do you think of this direction? Worth integrating into Genode?
It is exactly the direction I want to go. The externalized nit_focus component was just a stepping stone.
Still, my remark about the nitpicker-focus handover between sessions holds because such a mechanism is needed regardless of the layouter's / nit_focus policy, e.g., for implementing dialogs with menus or sub-dialogs.
Cheers Norman