Overhaul persistent tooltip position #9979

* directly show at correct position
* honor multi-monitor boundaries
* hide on focus-out (e.g. switch desktops with visible
  tooltip left it visible)
* remove unused `set_center_alignment` API
This commit is contained in:
Robin Gareus 2025-08-17 02:54:03 +02:00
parent 6b79d4ab98
commit a83c83aef6
No known key found for this signature in database
GPG key ID: A090BCE02CF57F04
2 changed files with 69 additions and 36 deletions

View file

@ -38,7 +38,6 @@ class LIBGTKMM2EXT_API PersistentTooltip : public sigc::trackable
void set_tip (std::string); void set_tip (std::string);
void set_font (Pango::FontDescription font); void set_font (Pango::FontDescription font);
void set_center_alignment (bool align_to_center);
virtual bool dragging () const; virtual bool dragging () const;
static void set_tooltips_enabled (bool en) { _tooltips_enabled = en; } static void set_tooltips_enabled (bool en) { _tooltips_enabled = en; }
@ -47,6 +46,7 @@ class LIBGTKMM2EXT_API PersistentTooltip : public sigc::trackable
private: private:
static bool _tooltips_enabled; static bool _tooltips_enabled;
static unsigned int _tooltip_timeout; static unsigned int _tooltip_timeout;
void update_position ();
bool timeout (); bool timeout ();
void show (); void show ();
void hide (); void hide ();
@ -54,6 +54,8 @@ class LIBGTKMM2EXT_API PersistentTooltip : public sigc::trackable
bool leave (GdkEventCrossing *); bool leave (GdkEventCrossing *);
bool press (GdkEventButton *); bool press (GdkEventButton *);
bool release (GdkEventButton *); bool release (GdkEventButton *);
void realized ();
bool parent_focus_out (GdkEventFocus *);
/** The widget that we are providing a tooltip for */ /** The widget that we are providing a tooltip for */
Gtk::Widget* _target; Gtk::Widget* _target;
@ -74,7 +76,6 @@ class LIBGTKMM2EXT_API PersistentTooltip : public sigc::trackable
/** The tip text */ /** The tip text */
std::string _tip; std::string _tip;
Pango::FontDescription _font; Pango::FontDescription _font;
bool _align_to_center;
int _margin_y; int _margin_y;
}; };

View file

@ -37,7 +37,6 @@ PersistentTooltip::PersistentTooltip (Gtk::Widget* target, bool draggable, int
, _label (0) , _label (0)
, _draggable (draggable) , _draggable (draggable)
, _maybe_dragging (false) , _maybe_dragging (false)
, _align_to_center (true)
, _margin_y (margin_y) , _margin_y (margin_y)
{ {
target->signal_enter_notify_event().connect (sigc::mem_fun (*this, &PersistentTooltip::enter), false); target->signal_enter_notify_event().connect (sigc::mem_fun (*this, &PersistentTooltip::enter), false);
@ -80,6 +79,14 @@ PersistentTooltip::leave (GdkEventCrossing *)
return false; return false;
} }
bool
PersistentTooltip::parent_focus_out (GdkEventFocus*)
{
_timeout.disconnect ();
hide ();
return false;
}
bool bool
PersistentTooltip::press (GdkEventButton* ev) PersistentTooltip::press (GdkEventButton* ev)
{ {
@ -126,6 +133,7 @@ PersistentTooltip::show ()
_window->set_name (X_("ContrastingPopup")); _window->set_name (X_("ContrastingPopup"));
_window->set_position (WIN_POS_MOUSE); _window->set_position (WIN_POS_MOUSE);
_window->set_decorated (false); _window->set_decorated (false);
_window->signal_realize().connect (mem_fun (this, &PersistentTooltip::realized));
_label = manage (new Label); _label = manage (new Label);
_label->modify_font (_font); _label->modify_font (_font);
@ -138,39 +146,69 @@ PersistentTooltip::show ()
Gtk::Window* tlw = dynamic_cast<Gtk::Window*> (_target->get_toplevel ()); Gtk::Window* tlw = dynamic_cast<Gtk::Window*> (_target->get_toplevel ());
if (tlw) { if (tlw) {
_window->set_transient_for (*tlw); _window->set_transient_for (*tlw);
_window->signal_focus_out_event ().connect (sigc::mem_fun (*this, &PersistentTooltip::parent_focus_out));
} }
} }
set_tip (_tip); set_tip (_tip);
if (!_window->get_visible ()) { if (_window->is_realized ()) {
int rx, ry; update_position ();
int sw = gdk_screen_width ();
_target->get_window()->get_origin (rx, ry);
/* the window needs to be realized first
* for _window->get_width() to be correct.
*/
if (sw < rx + _window->get_width()) {
/* right edge of window would be off the right edge of
the screen, so don't show it in the usual place.
*/
rx = sw - _window->get_width();
_window->move (rx, ry + _target->get_height() + _margin_y);
} else {
if (_align_to_center) {
_window->move (rx + (_target->get_width () - _window->get_width ()) / 2, ry + _target->get_height());
} else {
_window->move (rx, ry + _target->get_height());
}
}
_window->present ();
} }
if (!_window->get_visible ()) {
_window->present ();
}
}
void
PersistentTooltip::update_position ()
{
int tgt_x, tgt_y;
int tgt_w = _target->get_width ();
int tgt_h = _target->get_height ();
_target->get_window()->get_origin (tgt_x, tgt_y);
GdkScreen* screen = gtk_widget_get_screen (GTK_WIDGET(_window->gobj()));
GdkRectangle monitor;
gint monitor_num = gdk_screen_get_monitor_at_point (screen, tgt_x, tgt_y + tgt_h / 2);
gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
int w = _window->get_width ();
int h = _window->get_height ();
int left = tgt_x + (tgt_w - w) / 2;
int right = left + w;
int top = tgt_y + tgt_h + _margin_y;
int bottom = top + h;
int sw = monitor.x + monitor.width;
if (right > sw) {
/* right edge of window would be off the right edge of
* the screen, so don't show it in the usual place.
*/
left = sw - w;
} else if (left < monitor.x) {
/* ditto for the left edge */
left = monitor.x;
}
if (bottom > monitor.y + monitor.height) {
/* don't show tooltop across screens */
top = tgt_y - h - _margin_y - 1;
}
_window->move (left, top);
}
void
PersistentTooltip::realized ()
{
update_position ();
} }
void void
@ -192,9 +230,3 @@ PersistentTooltip::set_font (Pango::FontDescription font)
_label->modify_font (_font); _label->modify_font (_font);
} }
} }
void
PersistentTooltip::set_center_alignment (bool align_to_center)
{
_align_to_center = align_to_center;
}