diff --git a/repos/gems/sculpt/leitzentrale/default b/repos/gems/sculpt/leitzentrale/default
index c8f5f7632a..d4b6001af7 100644
--- a/repos/gems/sculpt/leitzentrale/default
+++ b/repos/gems/sculpt/leitzentrale/default
@@ -87,6 +87,7 @@
+
@@ -116,6 +117,7 @@
+
@@ -133,7 +135,7 @@
report="manager -> panel_dialog"/>
-
@@ -240,6 +242,7 @@
+
diff --git a/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h b/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h
index f0063b9f2f..55bfe34691 100644
--- a/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h
+++ b/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h
@@ -63,7 +63,7 @@ class Dialog::Distant_runtime : Noncopyable
Top_level_dialog::Name _hovered_dialog { };
Sculpt::Rom_handler _hover_rom {
- _env, "hover", *this, &Distant_runtime::_handle_hover };
+ _env, "menu_hover", *this, &Distant_runtime::_handle_hover };
void _handle_hover(Xml_node const &);
diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc
index c7133a4989..79f995c6d3 100644
--- a/repos/gems/src/app/sculpt_manager/main.cc
+++ b/repos/gems/src/app/sculpt_manager/main.cc
@@ -762,12 +762,35 @@ struct Sculpt::Main : Input_event_handler,
Rom_handler _nitpicker_hover_handler {
_env, "nitpicker_hover", *this, &Main::_handle_nitpicker_hover };
+ Rom_handler _hover_handler {
+ _env, "hover", *this, &Main::_handle_hover };
+
Expanding_reporter _gui_fb_config { _env, "config", "gui_fb_config" };
Constructible _pointer_pos { };
Fb_connectors::Name _hovered_display { };
+ void _handle_hover(Xml_node const &hover)
+ {
+ using Label = String<128>;
+
+ Label label { hover.attribute_value("label", Label()) };
+ Label suffix { "popup_dialog" };
+
+ _popup_hovered = false;
+ if (label.length() >= suffix.length()) {
+ size_t const offset = label.length() - suffix.length();
+
+ if (!strcmp(label.string() + offset, suffix.string()))
+ _popup_hovered = true;
+ }
+
+ _hover_seq_number = { hover.attribute_value("seq_number", 0U) };
+
+ _try_handle_click();
+ }
+
void _handle_nitpicker_hover(Xml_node const &hover)
{
if (hover.has_attribute("xpos"))
@@ -942,7 +965,11 @@ struct Sculpt::Main : Input_event_handler,
/* used to prevent closing the popup immediatedly after opened */
Input::Seq_number _popup_opened_seq_number { };
+ /* used to correlate clicks and hover reports */
+ Input::Seq_number _hover_seq_number { };
Input::Seq_number _clicked_seq_number { };
+ Input::Seq_number _last_clicked_seq_number { };
+ bool _popup_hovered { false };
/**
* Input_event_handler interface
@@ -962,23 +989,11 @@ struct Sculpt::Main : Input_event_handler,
* Detect clicks outside the popup dialog (for closing it)
*/
if (ev.key_press(Input::BTN_LEFT) || ev.touch()) {
-
_clicked_seq_number = _global_input_seq_number;
-
- bool const popup_opened =
- (_popup_opened_seq_number.value == _clicked_seq_number.value);
-
- bool const popup_hovered =
- _popup_dialog.if_hovered([&] (Hovered_at const &) { return true; });
-
- if (!popup_hovered && !popup_opened) {
- if (_popup.state == Popup::VISIBLE) {
- _close_popup_dialog();
- discard_construction();
- }
- }
+ _try_handle_click();
}
+
bool need_generate_dialog = false;
ev.handle_press([&] (Input::Keycode, Codepoint code) {
@@ -1156,6 +1171,27 @@ struct Sculpt::Main : Input_event_handler,
_update_window_layout();
}
+ void _try_handle_click()
+ {
+ /* skip if already handled */
+ if (_last_clicked_seq_number.value == _clicked_seq_number.value)
+ return;
+
+ /* wait for hover to be updated */
+ if (_clicked_seq_number.value != _hover_seq_number.value)
+ return;
+
+ _last_clicked_seq_number = _clicked_seq_number;
+
+ bool const popup_opened =
+ (_popup_opened_seq_number.value == _clicked_seq_number.value);
+
+ if ((_popup.state == Popup::VISIBLE) && !_popup_hovered && !popup_opened) {
+ _close_popup_dialog();
+ discard_construction();
+ }
+ }
+
void _refresh_panel_and_window_layout()
{
_panel_dialog.refresh();
diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc
index f1a24ad859..66d77af7b5 100644
--- a/repos/os/src/server/nitpicker/main.cc
+++ b/repos/os/src/server/nitpicker/main.cc
@@ -960,7 +960,7 @@ void Nitpicker::Main::handle_input_events(User_state::Input_batch batch)
_view_stack.update_all_views();
}
- if (result.hover_changed)
+ if (result.hover_changed || result.last_seq_changed)
_hover_count++;
/* report mouse-position updates */
diff --git a/repos/os/src/server/nitpicker/user_state.cc b/repos/os/src/server/nitpicker/user_state.cc
index 91ceb57af1..61c68a1555 100644
--- a/repos/os/src/server/nitpicker/user_state.cc
+++ b/repos/os/src/server/nitpicker/user_state.cc
@@ -342,6 +342,8 @@ User_state::handle_input_events(Input_batch batch)
View_owner const * const old_input_receiver = _input_receiver;
View_owner const * const old_last_clicked = _last_clicked;
unsigned const old_clicked_count = _clicked_count;
+ unsigned const old_seq_number = _last_seq_number.constructed()
+ ? _last_seq_number->value : 0;
bool button_activity = false;
@@ -424,6 +426,9 @@ User_state::handle_input_events(Input_batch batch)
[&] (Nowhere) { return _pointer.ok(); });
};
+ bool const last_seq_changed = _last_seq_number.constructed()
+ && _last_seq_number->value != old_seq_number;
+
return {
.hover_changed = _hovered != old_hovered,
.focus_changed = (_focused != old_focused) ||
@@ -432,7 +437,8 @@ User_state::handle_input_events(Input_batch batch)
.button_activity = button_activity,
.motion_activity = pointer_changed() || touch_occurred,
.key_pressed = _key_pressed(),
- .last_clicked_changed = last_clicked_changed
+ .last_clicked_changed = last_clicked_changed,
+ .last_seq_changed = last_seq_changed
};
}
@@ -460,6 +466,9 @@ void User_state::report_hovered_view_owner(Xml_generator &xml, bool active) cons
_hovered->report(xml);
if (active) xml.attribute("active", "yes");
+
+ if (_last_seq_number.constructed())
+ xml.attribute("seq_number", _last_seq_number->value);
}
diff --git a/repos/os/src/server/nitpicker/user_state.h b/repos/os/src/server/nitpicker/user_state.h
index 5e688b849f..2296aba7fc 100644
--- a/repos/os/src/server/nitpicker/user_state.h
+++ b/repos/os/src/server/nitpicker/user_state.h
@@ -252,6 +252,7 @@ class Nitpicker::User_state
bool const motion_activity;
bool const key_pressed;
bool const last_clicked_changed;
+ bool const last_seq_changed;
};
Handle_input_result handle_input_events(Input_batch);