nitpicker: Support for session-focus management

This patch introduces a focus-management facility to the nitpicker
session interface. As a side effect of this change, we remove the notion
of a "focused view". There can only be a "focused session". This makes
sense because input is directed to sessions, not views.

Issue #1168
This commit is contained in:
Norman Feske 2014-06-04 15:58:49 +02:00
parent d22cddd1e8
commit 24869bd3ff
12 changed files with 231 additions and 185 deletions

View File

@ -25,26 +25,29 @@ struct Nitpicker::Session_client : public Genode::Rpc_client<Session>
explicit Session_client(Session_capability session) explicit Session_client(Session_capability session)
: Rpc_client<Session>(session) { } : Rpc_client<Session>(session) { }
Framebuffer::Session_capability framebuffer_session() { Framebuffer::Session_capability framebuffer_session() override {
return call<Rpc_framebuffer_session>(); } return call<Rpc_framebuffer_session>(); }
Input::Session_capability input_session() { Input::Session_capability input_session() override {
return call<Rpc_input_session>(); } return call<Rpc_input_session>(); }
View_capability create_view(View_capability parent = View_capability()) { View_capability create_view(View_capability parent = View_capability()) override {
return call<Rpc_create_view>(parent); } return call<Rpc_create_view>(parent); }
void destroy_view(View_capability view) { void destroy_view(View_capability view) override {
call<Rpc_destroy_view>(view); } call<Rpc_destroy_view>(view); }
int background(View_capability view) { int background(View_capability view) override {
return call<Rpc_background>(view); } return call<Rpc_background>(view); }
Framebuffer::Mode mode() { Framebuffer::Mode mode() override {
return call<Rpc_mode>(); } return call<Rpc_mode>(); }
void buffer(Framebuffer::Mode mode, bool alpha) { void buffer(Framebuffer::Mode mode, bool alpha) override {
call<Rpc_buffer>(mode, alpha); } call<Rpc_buffer>(mode, alpha); }
void focus(Nitpicker::Session_capability session) override {
call<Rpc_focus>(session); }
}; };
#endif /* _INCLUDE__NITPICKER_SESSION__CLIENT_H_ */ #endif /* _INCLUDE__NITPICKER_SESSION__CLIENT_H_ */

View File

@ -85,6 +85,20 @@ struct Nitpicker::Session : Genode::Session
*/ */
virtual void buffer(Framebuffer::Mode mode, bool use_alpha) = 0; virtual void buffer(Framebuffer::Mode mode, bool use_alpha) = 0;
/**
* Set focused session
*
* Normally, the focused session is defined by the user by clicking on a
* view. The 'focus' function allows a client to set the focus without user
* action. However, the change of the focus is performed only is the
* currently focused session belongs to a child or the same process as the
* called session. This relationship is checked by comparing the session
* labels of the currently focused session and the caller. This way, a
* common parent can manage the focus among its child processes. But a
* session cannot steal the focus from an unrelated session.
*/
virtual void focus(Genode::Capability<Session> focused) = 0;
/** /**
* Return number of bytes needed for virtual framebuffer of specified size * Return number of bytes needed for virtual framebuffer of specified size
*/ */
@ -108,12 +122,13 @@ struct Nitpicker::Session : Genode::Session
GENODE_RPC(Rpc_destroy_view, void, destroy_view, View_capability); GENODE_RPC(Rpc_destroy_view, void, destroy_view, View_capability);
GENODE_RPC(Rpc_background, int, background, View_capability); GENODE_RPC(Rpc_background, int, background, View_capability);
GENODE_RPC(Rpc_mode, Framebuffer::Mode, mode); GENODE_RPC(Rpc_mode, Framebuffer::Mode, mode);
GENODE_RPC(Rpc_focus, void, focus, Genode::Capability<Session>);
GENODE_RPC_THROW(Rpc_buffer, void, buffer, GENODE_TYPE_LIST(Out_of_metadata), GENODE_RPC_THROW(Rpc_buffer, void, buffer, GENODE_TYPE_LIST(Out_of_metadata),
Framebuffer::Mode, bool); Framebuffer::Mode, bool);
GENODE_RPC_INTERFACE(Rpc_framebuffer_session, Rpc_input_session, GENODE_RPC_INTERFACE(Rpc_framebuffer_session, Rpc_input_session,
Rpc_create_view, Rpc_destroy_view, Rpc_background, Rpc_create_view, Rpc_destroy_view, Rpc_background,
Rpc_mode, Rpc_buffer); Rpc_mode, Rpc_buffer, Rpc_focus);
}; };
#endif /* _INCLUDE__NITPICKER_SESSION__NITPICKER_SESSION_H_ */ #endif /* _INCLUDE__NITPICKER_SESSION__NITPICKER_SESSION_H_ */

View File

@ -216,33 +216,33 @@ namespace Nitpicker {
** Nitpicker session interface ** ** Nitpicker session interface **
*********************************/ *********************************/
Framebuffer::Session_capability framebuffer_session() Framebuffer::Session_capability framebuffer_session() override
{ {
return _nitpicker.framebuffer_session(); return _nitpicker.framebuffer_session();
} }
Input::Session_capability input_session() Input::Session_capability input_session() override
{ {
return _proxy_input_cap; return _proxy_input_cap;
} }
View_capability create_view(View_capability) View_capability create_view(View_capability) override
{ {
return _proxy_view_cap; return _proxy_view_cap;
} }
void destroy_view(View_capability view) void destroy_view(View_capability view) override
{ {
_nitpicker.destroy_view(_nitpicker_view); _nitpicker.destroy_view(_nitpicker_view);
} }
int background(View_capability view) int background(View_capability view) override
{ {
/* not forwarding to real nitpicker session */ /* not forwarding to real nitpicker session */
return 0; return 0;
} }
Framebuffer::Mode mode() Framebuffer::Mode mode() override
{ {
int mode_width = (_max_width > -1) ? int mode_width = (_max_width > -1) ?
_max_width : _max_width :
@ -256,11 +256,13 @@ namespace Nitpicker {
_nitpicker.mode().format()); _nitpicker.mode().format());
} }
void buffer(Framebuffer::Mode mode, bool use_alpha) void buffer(Framebuffer::Mode mode, bool use_alpha) override
{ {
_nitpicker.buffer(mode, use_alpha); _nitpicker.buffer(mode, use_alpha);
} }
void focus(Capability<Session>) override { }
/********************************** /**********************************
** Input::Transformer interface ** ** Input::Transformer interface **

View File

@ -100,9 +100,8 @@ class Chunky_menubar : public Texture<PT>,
Color(r / 4, g / 4, b / 4)); Color(r / 4, g / 4, b / 4));
/* draw label */ /* draw label */
draw_label(_canvas, view_rect.center(label_size(session_label.string(), draw_label(_canvas, view_rect.center(label_size(session_label.string(), "")),
view_title.string())), session_label.string(), session_label.string(), WHITE, "", session_color);
WHITE, view_title.string(), session_color);
} }
using Menubar::state; using Menubar::state;

View File

@ -456,6 +456,8 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
View_stack &_view_stack; View_stack &_view_stack;
Mode &_mode;
List<View_component> _view_list; List<View_component> _view_list;
/* capabilities for sub sessions */ /* capabilities for sub sessions */
@ -487,6 +489,38 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
_buffer_size = 0; _buffer_size = 0;
} }
bool _focus_change_permitted() const
{
::Session * const focused_session = _mode.focused_session();
/*
* If no session is focused, we allow any client to assign it. This
* is useful for programs such as an initial login window that
* should receive input events without prior manual selection via
* the mouse.
*
* In principle, a client could steal the focus during time between
* a currently focused session gets closed and before the user
* manually picks a new session. However, in practice, the focus
* policy during application startup and exit is managed by a
* window manager that sits between nitpicker and the application.
*/
if (!focused_session)
return true;
/*
* Check if the currently focused session label belongs to a
* session subordinated to the caller, i.e., it originated from
* a child of the caller or from the same process. This is the
* case if the first part of the focused session label is
* identical to the caller's label.
*/
char const * const focused_label = focused_session->label().string();
char const * const caller_label = label().string();
return strcmp(focused_label, caller_label, Genode::strlen(caller_label)) == 0;
}
public: public:
/** /**
@ -494,6 +528,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
*/ */
Session_component(Session_label const &label, Session_component(Session_label const &label,
View_stack &view_stack, View_stack &view_stack,
Mode &mode,
Rpc_entrypoint &ep, Rpc_entrypoint &ep,
Framebuffer::Session &framebuffer, Framebuffer::Session &framebuffer,
int v_offset, int v_offset,
@ -506,7 +541,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
_buffer_alloc(&buffer_alloc, ram_quota), _buffer_alloc(&buffer_alloc, ram_quota),
_framebuffer(framebuffer), _framebuffer(framebuffer),
_framebuffer_session_component(view_stack, *this, framebuffer, *this), _framebuffer_session_component(view_stack, *this, framebuffer, *this),
_ep(ep), _view_stack(view_stack), _ep(ep), _view_stack(view_stack), _mode(mode),
_framebuffer_session_cap(_ep.manage(&_framebuffer_session_component)), _framebuffer_session_cap(_ep.manage(&_framebuffer_session_component)),
_input_session_cap(_ep.manage(&_input_session_component)), _input_session_cap(_ep.manage(&_input_session_component)),
_provides_default_bg(provides_default_bg) _provides_default_bg(provides_default_bg)
@ -560,13 +595,13 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
** Nitpicker session interface ** ** Nitpicker session interface **
*********************************/ *********************************/
Framebuffer::Session_capability framebuffer_session() { Framebuffer::Session_capability framebuffer_session() override {
return _framebuffer_session_cap; } return _framebuffer_session_cap; }
Input::Session_capability input_session() { Input::Session_capability input_session() override {
return _input_session_cap; } return _input_session_cap; }
View_capability create_view(View_capability parent_cap) View_capability create_view(View_capability parent_cap) override
{ {
/* lookup parent view */ /* lookup parent view */
View_component *parent_view = View_component *parent_view =
@ -590,7 +625,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
return _ep.manage(view); return _ep.manage(view);
} }
void destroy_view(View_capability view_cap) void destroy_view(View_capability view_cap) override
{ {
View_component *vc = dynamic_cast<View_component *>(_ep.lookup_and_lock(view_cap)); View_component *vc = dynamic_cast<View_component *>(_ep.lookup_and_lock(view_cap));
if (!vc) return; if (!vc) return;
@ -601,7 +636,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
destroy(env()->heap(), vc); destroy(env()->heap(), vc);
} }
int background(View_capability view_cap) int background(View_capability view_cap) override
{ {
if (_provides_default_bg) { if (_provides_default_bg) {
Object_pool<View_component>::Guard vc(_ep.lookup_and_lock(view_cap)); Object_pool<View_component>::Guard vc(_ep.lookup_and_lock(view_cap));
@ -623,7 +658,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
return 0; return 0;
} }
Framebuffer::Mode mode() Framebuffer::Mode mode() override
{ {
unsigned const width = _framebuffer.mode().width(); unsigned const width = _framebuffer.mode().width();
unsigned const height = _framebuffer.mode().height() unsigned const height = _framebuffer.mode().height()
@ -633,7 +668,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
_framebuffer.mode().format()); _framebuffer.mode().format());
} }
void buffer(Framebuffer::Mode mode, bool use_alpha) void buffer(Framebuffer::Mode mode, bool use_alpha) override
{ {
/* check if the session quota suffices for the specified mode */ /* check if the session quota suffices for the specified mode */
if (_buffer_alloc.quota() < ram_quota(mode, use_alpha)) if (_buffer_alloc.quota() < ram_quota(mode, use_alpha))
@ -642,6 +677,28 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
_framebuffer_session_component.notify_mode_change(mode, use_alpha); _framebuffer_session_component.notify_mode_change(mode, use_alpha);
} }
void focus(Genode::Capability<Nitpicker::Session> session_cap) override
{
/* check permission by comparing session labels */
if (!_focus_change_permitted()) {
PWRN("unauthorized focus change requesed by %s", label().string());
return;
}
/* prevent focus changes during drag operations */
if (_mode.drag())
return;
/* lookup targeted session object */
Session_component * const session =
session_cap.valid() ? dynamic_cast<Session_component *>(_ep.lookup_and_lock(session_cap)) : 0;
_mode.focused_session(session);
if (session)
session->release();
}
/******************************* /*******************************
** Buffer_provider interface ** ** Buffer_provider interface **
@ -684,6 +741,7 @@ class Nitpicker::Root : public Genode::Root_component<Session_component>
Global_keys &_global_keys; Global_keys &_global_keys;
Framebuffer::Mode _scr_mode; Framebuffer::Mode _scr_mode;
View_stack &_view_stack; View_stack &_view_stack;
Mode &_mode;
Framebuffer::Session &_framebuffer; Framebuffer::Session &_framebuffer;
int _default_v_offset; int _default_v_offset;
@ -712,7 +770,7 @@ class Nitpicker::Root : public Genode::Root_component<Session_component>
bool const provides_default_bg = (strcmp(label.string(), "backdrop") == 0); bool const provides_default_bg = (strcmp(label.string(), "backdrop") == 0);
Session_component *session = new (md_alloc()) Session_component *session = new (md_alloc())
Session_component(Session_label(args), _view_stack, *ep(), Session_component(Session_label(args), _view_stack, _mode, *ep(),
_framebuffer, v_offset, provides_default_bg, _framebuffer, v_offset, provides_default_bg,
stay_top, *md_alloc(), unused_quota); stay_top, *md_alloc(), unused_quota);
@ -733,6 +791,7 @@ class Nitpicker::Root : public Genode::Root_component<Session_component>
{ {
_session_list.remove(session); _session_list.remove(session);
_global_keys.apply_config(_session_list); _global_keys.apply_config(_session_list);
_mode.forget(*session);
destroy(md_alloc(), session); destroy(md_alloc(), session);
} }
@ -744,13 +803,13 @@ class Nitpicker::Root : public Genode::Root_component<Session_component>
*/ */
Root(Session_list &session_list, Global_keys &global_keys, Root(Session_list &session_list, Global_keys &global_keys,
Rpc_entrypoint &session_ep, View_stack &view_stack, Rpc_entrypoint &session_ep, View_stack &view_stack,
Allocator &md_alloc, Mode &mode, Allocator &md_alloc,
Framebuffer::Session &framebuffer, Framebuffer::Session &framebuffer,
int default_v_offset) int default_v_offset)
: :
Root_component<Session_component>(&session_ep, &md_alloc), Root_component<Session_component>(&session_ep, &md_alloc),
_session_list(session_list), _global_keys(global_keys), _session_list(session_list), _global_keys(global_keys),
_view_stack(view_stack), _view_stack(view_stack), _mode(mode),
_framebuffer(framebuffer), _framebuffer(framebuffer),
_default_v_offset(default_v_offset) _default_v_offset(default_v_offset)
{ } { }
@ -843,7 +902,8 @@ struct Nitpicker::Main
Genode::Sliced_heap sliced_heap = { env()->ram_session(), env()->rm_session() }; Genode::Sliced_heap sliced_heap = { env()->ram_session(), env()->rm_session() };
Root<PT> np_root = { session_list, global_keys, ep.rpc_ep(), user_state, Root<PT> np_root = { session_list, global_keys, ep.rpc_ep(), user_state,
sliced_heap, framebuffer, Framebuffer_screen::MENUBAR_HEIGHT }; user_state, sliced_heap, framebuffer,
Framebuffer_screen::MENUBAR_HEIGHT };
Genode::Reporter pointer_reporter = { "pointer" }; Genode::Reporter pointer_reporter = { "pointer" };
@ -874,7 +934,7 @@ struct Nitpicker::Main
{ {
// tmp_fb = &framebuffer; // tmp_fb = &framebuffer;
fb_screen->menubar.state(Menubar_state(user_state, "", "", BLACK)); fb_screen->menubar.state(Menubar_state(user_state, "", BLACK));
user_state.default_background(background); user_state.default_background(background);
user_state.stack(mouse_cursor); user_state.stack(mouse_cursor);

View File

@ -21,15 +21,12 @@
struct Menubar_state struct Menubar_state
{ {
Genode::String<128> session_label; Genode::String<128> session_label;
Genode::String<128> view_title;
Mode mode; Mode mode;
Color session_color; Color session_color;
Menubar_state(Mode mode, char const *session_label, Menubar_state(Mode mode, char const *session_label, Color session_color)
char const *view_title, Color session_color)
: :
session_label(session_label), view_title(view_title), session_label(session_label), mode(mode), session_color(session_color)
mode(mode), session_color(session_color)
{ } { }
Menubar_state() : session_color(BLACK) { } Menubar_state() : session_color(BLACK) { }

View File

@ -14,26 +14,26 @@
#ifndef _MODE_H_ #ifndef _MODE_H_
#define _MODE_H_ #define _MODE_H_
class View; class Session;
class Canvas_base;
class Mode class Mode
{ {
private: private:
bool _xray; bool _xray = false;
bool _kill; bool _kill = false;
/* /*
* Last clicked view. This view is receiving keyboard input, except * Number of currently pressed keys.
* for global keys. * This counter is used to determine if the user
* is dragging an item.
*/ */
View const *_focused_view; unsigned _key_cnt = 0;
Session *_focused_session = nullptr;
public: public:
Mode(): _xray(false), _kill(false), _focused_view(0) { }
virtual ~Mode() { } virtual ~Mode() { }
/** /**
@ -42,20 +42,30 @@ class Mode
bool xray() const { return _xray; } bool xray() const { return _xray; }
bool kill() const { return _kill; } bool kill() const { return _kill; }
bool flat() const { return !_xray && !_kill; } bool flat() const { return !_xray && !_kill; }
bool drag() const { return _key_cnt > 0; }
void leave_kill() { _kill = false; } void leave_kill() { _kill = false; }
void toggle_kill() { _kill = !_kill; } void toggle_kill() { _kill = !_kill; }
void toggle_xray() { _xray = !_xray; } void toggle_xray() { _xray = !_xray; }
View const *focused_view() const { return _focused_view; } void inc_key_cnt() { _key_cnt++; }
void dec_key_cnt() { _key_cnt--; }
void focused_view(View const *view) { _focused_view = view; } bool has_key_cnt(unsigned cnt) const { return cnt == _key_cnt; }
Session *focused_session() { return _focused_session; }
virtual void focused_session(Session *session) { _focused_session = session; }
bool is_focused(Session const &session) const { return &session == _focused_session; }
/** /**
* Discard all references to specified view * Discard all references to specified view
*/ */
virtual void forget(View const &v) { virtual void forget(Session const &session)
if (&v == _focused_view) _focused_view = 0; } {
if (is_focused(session)) _focused_session = nullptr;
}
}; };
#endif #endif

View File

@ -37,12 +37,24 @@ static inline bool _mouse_button(Keycode keycode) {
User_state::User_state(Global_keys &global_keys, Area view_stack_size, Menubar &menubar) User_state::User_state(Global_keys &global_keys, Area view_stack_size, Menubar &menubar)
: :
View_stack(view_stack_size, *this), _global_keys(global_keys), _key_cnt(0), View_stack(view_stack_size, *this), _global_keys(global_keys), _menubar(menubar)
_menubar(menubar), _pointed_view(0), _input_receiver(0),
_global_key_sequence(false)
{ } { }
void User_state::_update_all()
{
Menubar_state state(*this, "", BLACK);
if (_input_receiver)
state = Menubar_state(*this,
_input_receiver->label().string(),
_input_receiver->color());
_menubar.state(state);
update_all_views();
}
void User_state::handle_event(Input::Event ev) void User_state::handle_event(Input::Event ev)
{ {
Input::Keycode const keycode = ev.keycode(); Input::Keycode const keycode = ev.keycode();
@ -77,22 +89,22 @@ void User_state::handle_event(Input::Event ev)
_mouse_pos = Point(ax, ay); _mouse_pos = Point(ax, ay);
/* count keys */ /* count keys */
if (type == Event::PRESS) _key_cnt++; if (type == Event::PRESS) Mode::inc_key_cnt();
if (type == Event::RELEASE && _key_cnt > 0) _key_cnt--; if (type == Event::RELEASE && Mode::drag()) Mode::dec_key_cnt();
View const * const pointed_view = find_view(_mouse_pos); View const * const pointed_view = find_view(_mouse_pos);
Session * const pointed_session = pointed_view ? &pointed_view->session() : 0;
/* /*
* Deliver a leave event if pointed-to session changed * Deliver a leave event if pointed-to session changed
*/ */
if (pointed_view && _pointed_view && if (_pointed_session && (pointed_session != _pointed_session)) {
!pointed_view->same_session_as(*_pointed_view)) {
Input::Event leave_ev(Input::Event::LEAVE, 0, ax, ay, 0, 0); Input::Event leave_ev(Input::Event::LEAVE, 0, ax, ay, 0, 0);
_pointed_view->session().submit_input_event(leave_ev); _pointed_session->submit_input_event(leave_ev);
} }
_pointed_view = pointed_view; _pointed_session = pointed_session;
/** /**
* Guard that, when 'enabled' is set to true, performs a whole-screen * Guard that, when 'enabled' is set to true, performs a whole-screen
@ -101,96 +113,63 @@ void User_state::handle_event(Input::Event ev)
struct Update_all_guard struct Update_all_guard
{ {
User_state &user_state; User_state &user_state;
bool update_menubar = false; bool update = false;
bool update_views = false;
char const *menu_title = "";
Update_all_guard(User_state &user_state) Update_all_guard(User_state &user_state)
: user_state(user_state) { } : user_state(user_state) { }
~Update_all_guard() ~Update_all_guard()
{ {
Menubar_state state(user_state, "", "", BLACK); if (update)
user_state._update_all();
if (user_state._input_receiver)
state = Menubar_state(user_state,
user_state._input_receiver->label().string(),
menu_title,
user_state._input_receiver->color());
if (update_menubar)
user_state._menubar.state(state);
if (update_menubar || update_views)
user_state.update_all_views();
} }
} update_all_guard(*this); } update_all_guard(*this);
/* /*
* Handle start of a key sequence * Handle start of a key sequence
*/ */
if (type == Event::PRESS && _key_cnt == 1) { if (type == Event::PRESS && Mode::has_key_cnt(1)) {
/* /*
* Detect mouse press event in kill mode, used to select the session * Detect mouse press event in kill mode, used to select the session
* to lock out. * to lock out.
*/ */
if (kill() && keycode == Input::BTN_LEFT) { if (kill() && keycode == Input::BTN_LEFT) {
if (pointed_view) if (_pointed_session)
lock_out_session(pointed_view->session()); lock_out_session(*_pointed_session);
/* leave kill mode */ /* leave kill mode */
update_all_guard.update_menubar = true; update_all_guard.update = true;
update_all_guard.update_views = true;
Mode::leave_kill(); Mode::leave_kill();
return; return;
} }
/* update focused view */ /* update focused session */
if (pointed_view != focused_view() && _mouse_button(keycode)) { if (pointed_session != Mode::focused_session() && _mouse_button(keycode)) {
bool const focus_stays_in_session = update_all_guard.update = true;
focused_view() && pointed_view &&
focused_view()->belongs_to(pointed_view->session());
/* /*
* Update the whole screen when the focus change results in * Notify both the old focused session and the new one.
* changing the focus to another session.
*/ */
if (flat() && !focus_stays_in_session) { if (Mode::focused_session()) {
update_all_guard.update_menubar = true; Input::Event unfocus_ev(Input::Event::FOCUS, 0, ax, ay, 0, 0);
update_all_guard.update_views = true; Mode::focused_session()->submit_input_event(unfocus_ev);
} }
/* if (_pointed_session) {
* Notify both the old focussed session and the new one. Input::Event focus_ev(Input::Event::FOCUS, 1, ax, ay, 0, 0);
*/ pointed_session->submit_input_event(focus_ev);
if (!focus_stays_in_session) {
if (focused_view()) {
Input::Event unfocus_ev(Input::Event::FOCUS, 0, ax, ay, 0, 0);
focused_view()->session().submit_input_event(unfocus_ev);
}
if (pointed_view) {
Input::Event focus_ev(Input::Event::FOCUS, 1, ax, ay, 0, 0);
pointed_view->session().submit_input_event(focus_ev);
}
} }
update_all_guard.update_menubar = true; focused_session(_pointed_session);
if (!flat() || !focused_view() || !pointed_view)
update_all_guard.update_views = true;
focused_view(pointed_view);
} }
/* /*
* If there exists a global rule for the pressed key, set the * If there exists a global rule for the pressed key, set the
* corresponding session as receiver of the input stream until the key * corresponding session as receiver of the input stream until the key
* count reaches zero. Otherwise, the input stream is directed to the * count reaches zero. Otherwise, the input stream is directed to the
* pointed-at view. * pointed-at session.
* *
* If we deliver a global key sequence, we temporarily change the focus * If we deliver a global key sequence, we temporarily change the focus
* to the global receiver. To reflect that change, we need to update * to the global receiver. To reflect that change, we need to update
@ -198,20 +177,17 @@ void User_state::handle_event(Input::Event ev)
*/ */
Session * const global_receiver = _global_keys.global_receiver(keycode); Session * const global_receiver = _global_keys.global_receiver(keycode);
if (global_receiver) { if (global_receiver) {
_global_key_sequence = true; _global_key_sequence = true;
_input_receiver = global_receiver; _input_receiver = global_receiver;
update_all_guard.menu_title = ""; update_all_guard.update = true;
update_all_guard.update_menubar = true;
update_all_guard.update_views = true;
} }
/* /*
* No global rule matched, so the input stream gets directed to the * No global rule matched, so the input stream gets directed to the
* focused view or refers to a built-in operation. * focused session or refers to a built-in operation.
*/ */
if (!global_receiver && focused_view()) { if (!global_receiver) {
_input_receiver = &focused_view()->session(); _input_receiver = Mode::focused_session();
update_all_guard.menu_title = focused_view()->title();
} }
/* /*
@ -220,13 +196,14 @@ void User_state::handle_event(Input::Event ev)
*/ */
if (_global_keys.is_operation_key(keycode)) { if (_global_keys.is_operation_key(keycode)) {
if (_global_keys.is_kill_key(keycode)) Mode::toggle_kill(); if (_global_keys.is_kill_key(keycode)) {
Mode::toggle_kill();
_input_receiver = 0;
}
if (_global_keys.is_xray_key(keycode)) Mode::toggle_xray(); if (_global_keys.is_xray_key(keycode)) Mode::toggle_xray();
update_all_guard.update_menubar = true; update_all_guard.update = true;
update_all_guard.update_views = true;
_input_receiver = 0;
} }
} }
@ -237,22 +214,22 @@ void User_state::handle_event(Input::Event ev)
if (type == Event::MOTION || type == Event::WHEEL) { if (type == Event::MOTION || type == Event::WHEEL) {
if (_key_cnt == 0) { if (Mode::has_key_cnt(0)) {
/* /*
* In flat mode, we deliver motion events to the session of * In flat mode, we deliver motion events to the pointed-at
* the pointed view. In xray mode, we deliver motion * session. In xray mode, we deliver motion events only to the
* events only to the session with the focused view. * focused session.
*/ */
if (flat() || (xray() && focused_view() == pointed_view)) if (flat() || (xray() && Mode::focused_session() == pointed_session))
if (pointed_view) if (pointed_session)
pointed_view->session().submit_input_event(ev); pointed_session->submit_input_event(ev);
} else if (_input_receiver) } else if (_input_receiver)
_input_receiver->submit_input_event(ev); _input_receiver->submit_input_event(ev);
} }
/* deliver press/release event to session with focused view */ /* deliver press/release event to focused session */
if (type == Event::PRESS || type == Event::RELEASE) if (type == Event::PRESS || type == Event::RELEASE)
if (_input_receiver) if (_input_receiver)
_input_receiver->submit_input_event(ev); _input_receiver->submit_input_event(ev);
@ -260,13 +237,11 @@ void User_state::handle_event(Input::Event ev)
/* /*
* Detect end of global key sequence * Detect end of global key sequence
*/ */
if (ev.type() == Event::RELEASE && _key_cnt == 0 && _global_key_sequence) { if (ev.type() == Event::RELEASE && Mode::has_key_cnt(0) && _global_key_sequence) {
_input_receiver = focused_view() ? &focused_view()->session() : 0; _input_receiver = Mode::focused_session();
update_all_guard.menu_title = focused_view() ? focused_view()->title() : ""; update_all_guard.update = true;
update_all_guard.update_menubar = true;
update_all_guard.update_views = true;
_global_key_sequence = false; _global_key_sequence = false;
} }
@ -277,17 +252,23 @@ void User_state::handle_event(Input::Event ev)
** Mode interface ** ** Mode interface **
********************/ ********************/
void User_state::forget(View const &view) void User_state::forget(Session const &session)
{ {
if (focused_view() == &view) { Mode::forget(session);
Mode::forget(view);
_menubar.state(Menubar_state(*this, "", "", BLACK));
update_all_views();
}
if (_input_receiver && view.belongs_to(*_input_receiver))
_input_receiver = 0;
if (_pointed_view == &view) if (_pointed_session == &session) {
_pointed_view = find_view(_mouse_pos); View * const pointed_view = find_view(_mouse_pos);
_pointed_session = pointed_view ? &pointed_view->session() : nullptr;
}
} }
void User_state::focused_session(Session *session)
{
Mode::focused_session(session);
if (!_global_key_sequence)
_input_receiver = session;
_update_all();
}

View File

@ -32,17 +32,10 @@ class User_state : public Mode, public View_stack
*/ */
Global_keys &_global_keys; Global_keys &_global_keys;
/*
* Number of currently pressed keys.
* This counter is used to determine if the user
* is dragging an item.
*/
unsigned _key_cnt;
/* /*
* Menubar to display trusted labeling information * Menubar to display trusted labeling information
* according to the current Mitpicker mode and the * according to the current Mitpicker mode and the
* focused view. * focused session.
*/ */
Menubar &_menubar; Menubar &_menubar;
@ -52,19 +45,21 @@ class User_state : public Mode, public View_stack
Point _mouse_pos; Point _mouse_pos;
/* /*
* Currently pointed-at view * Currently pointed-at session
*/ */
View const *_pointed_view; Session *_pointed_session = nullptr;
/* /*
* Session that receives the current stream of input events * Session that receives the current stream of input events
*/ */
Session *_input_receiver; Session *_input_receiver = nullptr;
/* /*
* True while a global key sequence is processed * True while a global key sequence is processed
*/ */
bool _global_key_sequence; bool _global_key_sequence = false;
void _update_all();
public: public:
@ -89,7 +84,8 @@ class User_state : public Mode, public View_stack
/** /**
* Mode interface * Mode interface
*/ */
void forget(View const &) override; void forget(Session const &) override;
void focused_session(Session *) override;
}; };
#endif #endif

View File

@ -80,8 +80,7 @@ void View::frame(Canvas_base &canvas, Mode const &mode) const
void View::draw(Canvas_base &canvas, Mode const &mode) const void View::draw(Canvas_base &canvas, Mode const &mode) const
{ {
/* is this the currently focused view? */ /* is this the currently focused view? */
bool const view_is_focused = mode.focused_view() bool const session_is_focused = mode.is_focused(_session);
&& mode.focused_view()->belongs_to(_session);
Color const frame_color = _session.color(); Color const frame_color = _session.color();
@ -89,7 +88,7 @@ void View::draw(Canvas_base &canvas, Mode const &mode) const
* Use dimming in x-ray and kill mode, but do not dim the focused view in * Use dimming in x-ray and kill mode, but do not dim the focused view in
* x-ray mode. * x-ray mode.
*/ */
Texture_painter::Mode const op = mode.flat() || (mode.xray() && view_is_focused) Texture_painter::Mode const op = mode.flat() || (mode.xray() && session_is_focused)
? Texture_painter::SOLID : Texture_painter::MIXED; ? Texture_painter::SOLID : Texture_painter::MIXED;
Rect const view_rect = abs_geometry(); Rect const view_rect = abs_geometry();

View File

@ -140,11 +140,7 @@ class View : public Same_buffer_list_elem,
*/ */
virtual int frame_size(Mode const &mode) const virtual int frame_size(Mode const &mode) const
{ {
if (mode.focused_view() return mode.is_focused(_session) ? 5 : 3;
&& mode.focused_view()->belongs_to(_session))
return 5;
return 3;
} }
/** /**

View File

@ -40,11 +40,10 @@ static View const *last_stay_top_view(View const *view)
template <typename VIEW> template <typename VIEW>
VIEW *View_stack::_next_view(VIEW &view) const VIEW *View_stack::_next_view(VIEW &view) const
{ {
Session * const active_session = _mode.focused_view() ? Session * const focused_session = _mode.focused_session();
&_mode.focused_view()->session() : 0;
View * const active_background = active_session ? View * const active_background = focused_session ?
active_session->background() : 0; focused_session->background() : 0;
for (VIEW *next_view = &view; ;) { for (VIEW *next_view = &view; ;) {
@ -298,16 +297,5 @@ void View_stack::remove_view(View const &view, bool redraw)
/* exclude view from view stack */ /* exclude view from view stack */
_views.remove(&view); _views.remove(&view);
/*
* Reset focused and pointed-at view if necessary
*
* Thus must be done after calling '_views.remove' because the new focused
* pointer is determined by traversing the view stack. If the to-be-removed
* view would still be there, we would re-assign the old pointed-to view as
* the current one, resulting in a dangling pointer right after the view
* gets destructed by the caller of 'removed_view'.
*/
_mode.forget(view);
_dirty_rect.mark_as_dirty(rect); _dirty_rect.mark_as_dirty(rect);
} }