2013-01-11 16:32:08 +00:00
|
|
|
|
/* GTK - The GIMP Toolkit
|
2019-04-29 03:25:37 +00:00
|
|
|
|
* Copyright (C) 2019 Red Hat, Inc.
|
|
|
|
|
*
|
|
|
|
|
* Authors:
|
|
|
|
|
* - Matthias Clasen <mclasen@redhat.com>
|
2013-01-11 16:32:08 +00:00
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-11-13 14:11:21 +00:00
|
|
|
|
/**
|
|
|
|
|
* SECTION:gtkpopover
|
|
|
|
|
* @Short_description: Context dependent bubbles
|
|
|
|
|
* @Title: GtkPopover
|
2013-01-11 16:32:08 +00:00
|
|
|
|
*
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* GtkPopover is a bubble-like context window, primarily meant to
|
|
|
|
|
* provide context-dependent information or options. Popovers are
|
2020-02-24 12:21:46 +00:00
|
|
|
|
* attached to a widget, set with gtk_widget_set_parent(). By
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* default they will point to the whole widget area, although this
|
|
|
|
|
* behavior can be changed through gtk_popover_set_pointing_to().
|
2013-01-11 16:32:08 +00:00
|
|
|
|
*
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* The position of a popover relative to the widget it is attached to
|
|
|
|
|
* can also be changed through gtk_popover_set_position().
|
|
|
|
|
*
|
2019-12-30 00:44:31 +00:00
|
|
|
|
* By default, #GtkPopover performs a grab, in order to ensure input events
|
|
|
|
|
* get redirected to it while it is shown, and also so the popover is dismissed
|
|
|
|
|
* in the expected situations (clicks outside the popover, or the Escape key
|
|
|
|
|
* being pressed). If no such modal behavior is desired on a popover,
|
|
|
|
|
* gtk_popover_set_autohide() may be called on it to tweak its behavior.
|
2014-01-22 15:26:13 +00:00
|
|
|
|
*
|
2014-04-26 18:38:07 +00:00
|
|
|
|
* ## GtkPopover as menu replacement
|
|
|
|
|
*
|
2019-12-30 00:44:31 +00:00
|
|
|
|
* GtkPopover is often used to replace menus. The best was to do this
|
|
|
|
|
* is to use the #GtkPopoverMenu subclass which supports being populated
|
|
|
|
|
* from a #GMenuModel with gtk_popover_menu_new_from_model().
|
2014-04-26 18:38:07 +00:00
|
|
|
|
*
|
|
|
|
|
* |[
|
|
|
|
|
* <section>
|
|
|
|
|
* <attribute name="display-hint">horizontal-buttons</attribute>
|
|
|
|
|
* <item>
|
|
|
|
|
* <attribute name="label">Cut</attribute>
|
|
|
|
|
* <attribute name="action">app.cut</attribute>
|
|
|
|
|
* <attribute name="verb-icon">edit-cut-symbolic</attribute>
|
|
|
|
|
* </item>
|
|
|
|
|
* <item>
|
|
|
|
|
* <attribute name="label">Copy</attribute>
|
|
|
|
|
* <attribute name="action">app.copy</attribute>
|
|
|
|
|
* <attribute name="verb-icon">edit-copy-symbolic</attribute>
|
|
|
|
|
* </item>
|
|
|
|
|
* <item>
|
|
|
|
|
* <attribute name="label">Paste</attribute>
|
|
|
|
|
* <attribute name="action">app.paste</attribute>
|
|
|
|
|
* <attribute name="verb-icon">edit-paste-symbolic</attribute>
|
|
|
|
|
* </item>
|
|
|
|
|
* </section>
|
|
|
|
|
* ]|
|
|
|
|
|
*
|
2015-11-02 17:53:57 +00:00
|
|
|
|
* # CSS nodes
|
|
|
|
|
*
|
2017-07-08 10:04:44 +00:00
|
|
|
|
* |[<!-- language="plain" -->
|
2019-06-07 17:05:48 +00:00
|
|
|
|
* popover[.menu]
|
2017-07-08 10:04:44 +00:00
|
|
|
|
* ├── arrow
|
2019-06-07 17:05:48 +00:00
|
|
|
|
* ╰── contents.background
|
2017-07-08 10:04:44 +00:00
|
|
|
|
* ╰── <child>
|
|
|
|
|
* ]|
|
|
|
|
|
*
|
2019-06-07 17:05:48 +00:00
|
|
|
|
* The contents child node always gets the .background style class and
|
|
|
|
|
* the popover itself gets the .menu style class if the popover is
|
2019-12-30 00:44:31 +00:00
|
|
|
|
* menu-like (i.e. #GtkPopoverMenu).
|
2015-11-02 17:53:57 +00:00
|
|
|
|
*
|
2019-12-30 00:44:31 +00:00
|
|
|
|
* Particular uses of GtkPopover, such as touch selection popups or magnifiers
|
|
|
|
|
* in #GtkEntry or #GtkTextView get style classes like .touch-selection or .magnifier
|
|
|
|
|
* to differentiate from plain popovers.
|
2015-10-30 14:08:18 +00:00
|
|
|
|
*
|
2019-06-07 17:05:48 +00:00
|
|
|
|
* When styling a popover directly, the popover node should usually
|
2021-02-14 16:14:23 +00:00
|
|
|
|
* not have any background. The visible part of the popover can have a shadow.
|
|
|
|
|
* To specify it in CSS, set the box-shadow of the contents node.
|
2017-07-08 10:04:44 +00:00
|
|
|
|
*
|
|
|
|
|
* Note that, in order to accomplish appropriate arrow visuals, #GtkPopover uses
|
2019-12-30 00:44:31 +00:00
|
|
|
|
* custom drawing for the arrow node. This makes it possible for the arrow to
|
|
|
|
|
* change its shape dynamically, but it also limits the possibilities of styling
|
|
|
|
|
* it using CSS. In particular, the arrow gets drawn over the content node's
|
2021-02-14 16:14:23 +00:00
|
|
|
|
* shadow border so they look like one shape, which means that the border width
|
|
|
|
|
* of the content node and the arrow node should be the same. The arrow also does
|
2019-12-30 00:44:31 +00:00
|
|
|
|
* not support any border shape other than solid, no border-radius, only one
|
|
|
|
|
* border width (border-bottom-width is used) and no box-shadow.
|
2013-01-11 16:32:08 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
2018-02-08 23:42:38 +00:00
|
|
|
|
|
2014-08-01 15:38:42 +00:00
|
|
|
|
#include "gtkpopoverprivate.h"
|
2019-08-27 08:28:29 +00:00
|
|
|
|
#include "gtkpopovermenuprivate.h"
|
2019-04-29 03:25:37 +00:00
|
|
|
|
#include "gtknative.h"
|
|
|
|
|
#include "gtkwidgetprivate.h"
|
|
|
|
|
#include "gtkeventcontrollerkey.h"
|
2020-03-24 16:45:43 +00:00
|
|
|
|
#include "gtkeventcontrollerfocus.h"
|
2019-10-25 08:36:29 +00:00
|
|
|
|
#include "gtkbinlayout.h"
|
2019-04-29 03:25:37 +00:00
|
|
|
|
#include "gtkenums.h"
|
|
|
|
|
#include "gtktypebuiltins.h"
|
2021-02-17 04:47:20 +00:00
|
|
|
|
#include "gtkpopovercontentprivate.h"
|
2018-02-08 23:42:38 +00:00
|
|
|
|
#include "gtkintl.h"
|
|
|
|
|
#include "gtkprivate.h"
|
2019-04-29 03:25:37 +00:00
|
|
|
|
#include "gtkmain.h"
|
2018-02-08 23:42:38 +00:00
|
|
|
|
#include "gtkstack.h"
|
2019-06-10 03:10:13 +00:00
|
|
|
|
#include "gtkmenusectionboxprivate.h"
|
2019-04-29 03:25:37 +00:00
|
|
|
|
#include "gdk/gdkeventsprivate.h"
|
|
|
|
|
#include "gtkpointerfocusprivate.h"
|
2020-01-18 16:48:30 +00:00
|
|
|
|
#include "gtkcsscolorvalueprivate.h"
|
2019-05-05 23:53:02 +00:00
|
|
|
|
#include "gtksnapshot.h"
|
2020-03-24 03:04:06 +00:00
|
|
|
|
#include "gtkshortcutmanager.h"
|
2020-05-02 02:35:31 +00:00
|
|
|
|
#include "gtkbuildable.h"
|
2020-05-06 17:56:27 +00:00
|
|
|
|
#include "gtktooltipprivate.h"
|
2020-05-16 05:20:50 +00:00
|
|
|
|
#include "gtkcssboxesimplprivate.h"
|
2020-08-13 23:21:05 +00:00
|
|
|
|
#include "gtknativeprivate.h"
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
|
|
|
|
#include "gtkrender.h"
|
|
|
|
|
#include "gtkstylecontextprivate.h"
|
|
|
|
|
#include "gtkroundedboxprivate.h"
|
|
|
|
|
#include "gsk/gskroundedrectprivate.h"
|
2021-02-01 00:26:33 +00:00
|
|
|
|
#include "gtkcssshadowvalueprivate.h"
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2020-03-24 16:45:43 +00:00
|
|
|
|
#define MNEMONICS_DELAY 300 /* ms */
|
|
|
|
|
|
2019-05-05 23:53:02 +00:00
|
|
|
|
#define TAIL_GAP_WIDTH 24
|
|
|
|
|
#define TAIL_HEIGHT 12
|
|
|
|
|
|
|
|
|
|
#define POS_IS_VERTICAL(p) ((p) == GTK_POS_TOP || (p) == GTK_POS_BOTTOM)
|
2019-04-29 03:25:37 +00:00
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
GdkSurface *surface;
|
|
|
|
|
GskRenderer *renderer;
|
|
|
|
|
GtkWidget *default_widget;
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GdkRectangle pointing_to;
|
|
|
|
|
gboolean has_pointing_to;
|
|
|
|
|
guint surface_transform_changed_cb;
|
|
|
|
|
GtkPositionType position;
|
2019-05-19 23:46:56 +00:00
|
|
|
|
gboolean autohide;
|
2019-05-22 00:42:07 +00:00
|
|
|
|
gboolean has_arrow;
|
2020-03-24 16:29:26 +00:00
|
|
|
|
gboolean mnemonics_visible;
|
2020-03-24 16:45:43 +00:00
|
|
|
|
gboolean disable_auto_mnemonics;
|
2020-10-13 12:26:41 +00:00
|
|
|
|
gboolean cascade_popdown;
|
2020-03-24 16:45:43 +00:00
|
|
|
|
|
2020-08-08 00:06:08 +00:00
|
|
|
|
int x_offset;
|
|
|
|
|
int y_offset;
|
|
|
|
|
|
2020-03-24 16:45:43 +00:00
|
|
|
|
guint mnemonics_display_timeout_id;
|
2016-12-13 20:00:28 +00:00
|
|
|
|
|
2020-05-02 02:35:31 +00:00
|
|
|
|
GtkWidget *child;
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkWidget *contents_widget;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
GtkCssNode *arrow_node;
|
2019-05-25 23:11:30 +00:00
|
|
|
|
GskRenderNode *arrow_render_node;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2020-02-16 11:59:24 +00:00
|
|
|
|
GdkPopupLayout *layout;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
GdkRectangle final_rect;
|
|
|
|
|
GtkPositionType final_position;
|
2019-04-29 03:25:37 +00:00
|
|
|
|
} GtkPopoverPrivate;
|
2014-10-20 17:10:52 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
enum {
|
|
|
|
|
CLOSED,
|
2019-06-12 16:54:57 +00:00
|
|
|
|
ACTIVATE_DEFAULT,
|
2019-04-29 03:25:37 +00:00
|
|
|
|
LAST_SIGNAL
|
|
|
|
|
};
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
|
|
|
|
enum {
|
2020-02-24 12:21:46 +00:00
|
|
|
|
PROP_POINTING_TO = 1,
|
2014-01-10 11:04:17 +00:00
|
|
|
|
PROP_POSITION,
|
2019-05-19 23:46:56 +00:00
|
|
|
|
PROP_AUTOHIDE,
|
2019-04-28 16:54:02 +00:00
|
|
|
|
PROP_DEFAULT_WIDGET,
|
2019-05-22 00:42:07 +00:00
|
|
|
|
PROP_HAS_ARROW,
|
2020-03-24 16:29:26 +00:00
|
|
|
|
PROP_MNEMONICS_VISIBLE,
|
2020-05-01 22:24:15 +00:00
|
|
|
|
PROP_CHILD,
|
2020-10-13 12:26:41 +00:00
|
|
|
|
PROP_CASCADE_POPDOWN,
|
2015-12-02 06:03:35 +00:00
|
|
|
|
NUM_PROPERTIES
|
2013-01-11 16:32:08 +00:00
|
|
|
|
};
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
static GParamSpec *properties[NUM_PROPERTIES] = { NULL };
|
2014-02-06 14:30:55 +00:00
|
|
|
|
|
2020-05-02 02:35:31 +00:00
|
|
|
|
static void gtk_popover_buildable_init (GtkBuildableIface *iface);
|
|
|
|
|
|
2020-03-24 03:04:06 +00:00
|
|
|
|
static void gtk_popover_shortcut_manager_interface_init (GtkShortcutManagerInterface *iface);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
static void gtk_popover_native_interface_init (GtkNativeInterface *iface);
|
2015-01-09 15:10:29 +00:00
|
|
|
|
|
2020-05-02 02:35:31 +00:00
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (GtkPopover, gtk_popover, GTK_TYPE_WIDGET,
|
2019-04-29 03:25:37 +00:00
|
|
|
|
G_ADD_PRIVATE (GtkPopover)
|
2020-05-02 02:35:31 +00:00
|
|
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
|
|
|
|
|
gtk_popover_buildable_init)
|
2020-03-24 03:04:06 +00:00
|
|
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_SHORTCUT_MANAGER,
|
|
|
|
|
gtk_popover_shortcut_manager_interface_init)
|
2019-04-29 03:25:37 +00:00
|
|
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_NATIVE,
|
|
|
|
|
gtk_popover_native_interface_init))
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
popover: Fix memory management of popovers
Popovers are strange in the sense that they aren't attached to a
parent directly, they rely on the relative_to widget so the toplevel
is shared, and when they have a parent, it is the toplevel itself,
not relative_to. This also means that there are conditions where the
popover loses it's parent, so they must survive unparenting.
The previous code would be floating the last reference as soon as the
parent is gone, but it was non-obvious who'd own that reference. So
fix this situation by granting the ownership of popovers to their
relative_to widget, an extra reference may be held by the toplevel
when the popover has a parent, but the popover object will be
guaranteed to be alive as long as the parent lives.
This way, memory management of popovers is as hidden from the user
as regular widgets within containers are, users are free to call
gtk_widget_destroy() on a popover, but it'd eventually become
destructed when relative_to is.
2014-01-09 16:21:43 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
static GdkSurface *
|
|
|
|
|
gtk_popover_native_get_surface (GtkNative *native)
|
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = GTK_POPOVER (native);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2013-11-12 15:55:23 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
return priv->surface;
|
|
|
|
|
}
|
2016-09-28 17:53:10 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
static GskRenderer *
|
|
|
|
|
gtk_popover_native_get_renderer (GtkNative *native)
|
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = GTK_POPOVER (native);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
return priv->renderer;
|
|
|
|
|
}
|
2017-07-08 10:04:44 +00:00
|
|
|
|
|
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_native_get_surface_transform (GtkNative *native,
|
2020-05-17 21:08:01 +00:00
|
|
|
|
double *x,
|
|
|
|
|
double *y)
|
2017-07-08 10:04:44 +00:00
|
|
|
|
{
|
2020-05-16 05:20:50 +00:00
|
|
|
|
GtkCssBoxes css_boxes;
|
|
|
|
|
const graphene_rect_t *margin_rect;
|
2020-01-18 16:48:30 +00:00
|
|
|
|
|
2020-05-16 05:20:50 +00:00
|
|
|
|
gtk_css_boxes_init (&css_boxes, GTK_WIDGET (native));
|
|
|
|
|
margin_rect = gtk_css_boxes_get_margin_rect (&css_boxes);
|
|
|
|
|
|
|
|
|
|
*x = - margin_rect->origin.x;
|
|
|
|
|
*y = - margin_rect->origin.y;
|
2017-07-08 10:04:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-16 11:59:24 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
is_gravity_facing_north (GdkGravity gravity)
|
|
|
|
|
{
|
|
|
|
|
switch (gravity)
|
|
|
|
|
{
|
|
|
|
|
case GDK_GRAVITY_NORTH_EAST:
|
|
|
|
|
case GDK_GRAVITY_NORTH:
|
|
|
|
|
case GDK_GRAVITY_NORTH_WEST:
|
|
|
|
|
case GDK_GRAVITY_STATIC:
|
|
|
|
|
return TRUE;
|
|
|
|
|
case GDK_GRAVITY_SOUTH_WEST:
|
|
|
|
|
case GDK_GRAVITY_WEST:
|
|
|
|
|
case GDK_GRAVITY_SOUTH_EAST:
|
|
|
|
|
case GDK_GRAVITY_EAST:
|
|
|
|
|
case GDK_GRAVITY_CENTER:
|
|
|
|
|
case GDK_GRAVITY_SOUTH:
|
|
|
|
|
return FALSE;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
is_gravity_facing_south (GdkGravity gravity)
|
|
|
|
|
{
|
|
|
|
|
switch (gravity)
|
|
|
|
|
{
|
|
|
|
|
case GDK_GRAVITY_SOUTH_WEST:
|
|
|
|
|
case GDK_GRAVITY_SOUTH_EAST:
|
|
|
|
|
case GDK_GRAVITY_SOUTH:
|
|
|
|
|
return TRUE;
|
|
|
|
|
case GDK_GRAVITY_NORTH_EAST:
|
|
|
|
|
case GDK_GRAVITY_NORTH:
|
|
|
|
|
case GDK_GRAVITY_NORTH_WEST:
|
|
|
|
|
case GDK_GRAVITY_STATIC:
|
|
|
|
|
case GDK_GRAVITY_WEST:
|
|
|
|
|
case GDK_GRAVITY_EAST:
|
|
|
|
|
case GDK_GRAVITY_CENTER:
|
|
|
|
|
return FALSE;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
is_gravity_facing_west (GdkGravity gravity)
|
|
|
|
|
{
|
|
|
|
|
switch (gravity)
|
|
|
|
|
{
|
|
|
|
|
case GDK_GRAVITY_NORTH_WEST:
|
|
|
|
|
case GDK_GRAVITY_STATIC:
|
|
|
|
|
case GDK_GRAVITY_SOUTH_WEST:
|
|
|
|
|
case GDK_GRAVITY_WEST:
|
|
|
|
|
return TRUE;
|
|
|
|
|
case GDK_GRAVITY_NORTH_EAST:
|
|
|
|
|
case GDK_GRAVITY_SOUTH_EAST:
|
|
|
|
|
case GDK_GRAVITY_EAST:
|
|
|
|
|
case GDK_GRAVITY_NORTH:
|
|
|
|
|
case GDK_GRAVITY_CENTER:
|
|
|
|
|
case GDK_GRAVITY_SOUTH:
|
|
|
|
|
return FALSE;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
is_gravity_facing_east (GdkGravity gravity)
|
|
|
|
|
{
|
|
|
|
|
switch (gravity)
|
|
|
|
|
{
|
|
|
|
|
case GDK_GRAVITY_NORTH_EAST:
|
|
|
|
|
case GDK_GRAVITY_SOUTH_EAST:
|
|
|
|
|
case GDK_GRAVITY_EAST:
|
|
|
|
|
return TRUE;
|
|
|
|
|
case GDK_GRAVITY_NORTH_WEST:
|
|
|
|
|
case GDK_GRAVITY_STATIC:
|
|
|
|
|
case GDK_GRAVITY_SOUTH_WEST:
|
|
|
|
|
case GDK_GRAVITY_WEST:
|
|
|
|
|
case GDK_GRAVITY_NORTH:
|
|
|
|
|
case GDK_GRAVITY_CENTER:
|
|
|
|
|
case GDK_GRAVITY_SOUTH:
|
|
|
|
|
return FALSE;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
did_flip_horizontally (GdkGravity original_gravity,
|
|
|
|
|
GdkGravity final_gravity)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (original_gravity, FALSE);
|
|
|
|
|
g_return_val_if_fail (final_gravity, FALSE);
|
|
|
|
|
|
|
|
|
|
if (is_gravity_facing_east (original_gravity) &&
|
|
|
|
|
is_gravity_facing_west (final_gravity))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
if (is_gravity_facing_west (original_gravity) &&
|
|
|
|
|
is_gravity_facing_east (final_gravity))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
did_flip_vertically (GdkGravity original_gravity,
|
|
|
|
|
GdkGravity final_gravity)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (original_gravity, FALSE);
|
|
|
|
|
g_return_val_if_fail (final_gravity, FALSE);
|
|
|
|
|
|
|
|
|
|
if (is_gravity_facing_north (original_gravity) &&
|
|
|
|
|
is_gravity_facing_south (final_gravity))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
if (is_gravity_facing_south (original_gravity) &&
|
|
|
|
|
is_gravity_facing_north (final_gravity))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-08 10:04:44 +00:00
|
|
|
|
static void
|
2020-02-16 11:59:24 +00:00
|
|
|
|
update_popover_layout (GtkPopover *popover,
|
2020-12-22 03:46:52 +00:00
|
|
|
|
GdkPopupLayout *layout,
|
|
|
|
|
int width,
|
|
|
|
|
int height)
|
2020-02-16 11:59:24 +00:00
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
GdkRectangle final_rect;
|
|
|
|
|
gboolean flipped_x;
|
|
|
|
|
gboolean flipped_y;
|
2020-02-29 14:44:05 +00:00
|
|
|
|
GdkPopup *popup = GDK_POPUP (priv->surface);
|
2020-04-29 03:26:19 +00:00
|
|
|
|
GtkPositionType position;
|
2020-02-16 11:59:24 +00:00
|
|
|
|
|
|
|
|
|
g_clear_pointer (&priv->layout, gdk_popup_layout_unref);
|
|
|
|
|
priv->layout = layout;
|
|
|
|
|
|
|
|
|
|
final_rect = (GdkRectangle) {
|
2020-02-29 14:44:05 +00:00
|
|
|
|
.x = gdk_popup_get_position_x (GDK_POPUP (priv->surface)),
|
|
|
|
|
.y = gdk_popup_get_position_y (GDK_POPUP (priv->surface)),
|
2020-02-16 11:59:24 +00:00
|
|
|
|
.width = gdk_surface_get_width (priv->surface),
|
|
|
|
|
.height = gdk_surface_get_height (priv->surface),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
flipped_x =
|
|
|
|
|
did_flip_horizontally (gdk_popup_layout_get_rect_anchor (layout),
|
2020-02-29 14:44:05 +00:00
|
|
|
|
gdk_popup_get_rect_anchor (popup)) &&
|
2020-02-16 11:59:24 +00:00
|
|
|
|
did_flip_horizontally (gdk_popup_layout_get_surface_anchor (layout),
|
2020-02-29 14:44:05 +00:00
|
|
|
|
gdk_popup_get_surface_anchor (popup));
|
2020-02-16 11:59:24 +00:00
|
|
|
|
flipped_y =
|
|
|
|
|
did_flip_vertically (gdk_popup_layout_get_rect_anchor (layout),
|
2020-02-29 14:44:05 +00:00
|
|
|
|
gdk_popup_get_rect_anchor (popup)) &&
|
2020-02-16 11:59:24 +00:00
|
|
|
|
did_flip_vertically (gdk_popup_layout_get_surface_anchor (layout),
|
2020-02-29 14:44:05 +00:00
|
|
|
|
gdk_popup_get_surface_anchor (popup));
|
2020-02-16 11:59:24 +00:00
|
|
|
|
|
|
|
|
|
priv->final_rect = final_rect;
|
|
|
|
|
|
2020-04-29 03:26:19 +00:00
|
|
|
|
position = priv->final_position;
|
|
|
|
|
|
2020-02-16 11:59:24 +00:00
|
|
|
|
switch (priv->position)
|
|
|
|
|
{
|
|
|
|
|
case GTK_POS_LEFT:
|
|
|
|
|
priv->final_position = flipped_x ? GTK_POS_RIGHT : GTK_POS_LEFT;
|
|
|
|
|
break;
|
|
|
|
|
case GTK_POS_RIGHT:
|
|
|
|
|
priv->final_position = flipped_x ? GTK_POS_LEFT : GTK_POS_RIGHT;
|
|
|
|
|
break;
|
|
|
|
|
case GTK_POS_TOP:
|
|
|
|
|
priv->final_position = flipped_y ? GTK_POS_BOTTOM : GTK_POS_TOP;
|
|
|
|
|
break;
|
|
|
|
|
case GTK_POS_BOTTOM:
|
|
|
|
|
priv->final_position = flipped_y ? GTK_POS_TOP : GTK_POS_BOTTOM;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-22 03:46:52 +00:00
|
|
|
|
if (priv->final_position != position ||
|
|
|
|
|
priv->final_rect.width != width ||
|
|
|
|
|
priv->final_rect.height != height)
|
2020-09-10 04:02:34 +00:00
|
|
|
|
{
|
|
|
|
|
gtk_widget_queue_allocate (GTK_WIDGET (popover));
|
|
|
|
|
g_clear_pointer (&priv->arrow_render_node, gsk_render_node_unref);
|
|
|
|
|
}
|
2020-04-29 03:26:19 +00:00
|
|
|
|
|
2020-02-16 11:59:24 +00:00
|
|
|
|
gtk_widget_queue_draw (GTK_WIDGET (popover));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GdkPopupLayout *
|
|
|
|
|
create_popup_layout (GtkPopover *popover)
|
2017-07-08 10:04:44 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
GdkRectangle rect;
|
|
|
|
|
GdkGravity parent_anchor;
|
|
|
|
|
GdkGravity surface_anchor;
|
|
|
|
|
GdkAnchorHints anchor_hints;
|
2020-02-16 11:59:24 +00:00
|
|
|
|
GdkPopupLayout *layout;
|
2020-02-24 12:21:46 +00:00
|
|
|
|
GtkWidget *parent;
|
2021-02-01 00:26:33 +00:00
|
|
|
|
GtkCssStyle *style;
|
|
|
|
|
GtkBorder shadow_width;
|
2017-07-08 10:04:44 +00:00
|
|
|
|
|
2020-02-24 12:21:46 +00:00
|
|
|
|
parent = gtk_widget_get_parent (GTK_WIDGET (popover));
|
|
|
|
|
gtk_widget_get_surface_allocation (parent, &rect);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
if (priv->has_pointing_to)
|
|
|
|
|
{
|
|
|
|
|
rect.x += priv->pointing_to.x;
|
|
|
|
|
rect.y += priv->pointing_to.y;
|
|
|
|
|
rect.width = priv->pointing_to.width;
|
|
|
|
|
rect.height = priv->pointing_to.height;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-01 00:26:33 +00:00
|
|
|
|
style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget)));
|
|
|
|
|
gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
switch (priv->position)
|
|
|
|
|
{
|
|
|
|
|
case GTK_POS_LEFT:
|
2019-09-05 19:29:19 +00:00
|
|
|
|
switch (gtk_widget_get_valign (GTK_WIDGET (popover)))
|
|
|
|
|
{
|
|
|
|
|
case GTK_ALIGN_START:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_NORTH_WEST;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_NORTH_EAST;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_ALIGN_END:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_SOUTH_WEST;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_SOUTH_EAST;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_ALIGN_FILL:
|
|
|
|
|
case GTK_ALIGN_CENTER:
|
|
|
|
|
case GTK_ALIGN_BASELINE:
|
|
|
|
|
default:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_WEST;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_EAST;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-29 03:25:37 +00:00
|
|
|
|
anchor_hints = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_SLIDE_Y;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_POS_RIGHT:
|
2019-09-05 19:29:19 +00:00
|
|
|
|
switch (gtk_widget_get_valign (GTK_WIDGET (popover)))
|
|
|
|
|
{
|
|
|
|
|
case GTK_ALIGN_START:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_NORTH_EAST;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_NORTH_WEST;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_ALIGN_END:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_SOUTH_EAST;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_SOUTH_WEST;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_ALIGN_FILL:
|
|
|
|
|
case GTK_ALIGN_CENTER:
|
|
|
|
|
case GTK_ALIGN_BASELINE:
|
|
|
|
|
default:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_EAST;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_WEST;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-29 03:25:37 +00:00
|
|
|
|
anchor_hints = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_SLIDE_Y;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_POS_TOP:
|
2019-06-08 03:14:02 +00:00
|
|
|
|
switch (gtk_widget_get_halign (GTK_WIDGET (popover)))
|
|
|
|
|
{
|
|
|
|
|
case GTK_ALIGN_START:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_NORTH_WEST;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_SOUTH_WEST;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_ALIGN_END:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_NORTH_EAST;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_SOUTH_EAST;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_ALIGN_FILL:
|
|
|
|
|
case GTK_ALIGN_CENTER:
|
|
|
|
|
case GTK_ALIGN_BASELINE:
|
|
|
|
|
default:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_NORTH;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_SOUTH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-29 03:25:37 +00:00
|
|
|
|
anchor_hints = GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE_X;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_POS_BOTTOM:
|
2019-06-08 03:14:02 +00:00
|
|
|
|
switch (gtk_widget_get_halign (GTK_WIDGET (popover)))
|
|
|
|
|
{
|
|
|
|
|
case GTK_ALIGN_START:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_SOUTH_WEST;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_NORTH_WEST;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_ALIGN_END:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_SOUTH_EAST;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_NORTH_EAST;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GTK_ALIGN_FILL:
|
|
|
|
|
case GTK_ALIGN_CENTER:
|
|
|
|
|
case GTK_ALIGN_BASELINE:
|
|
|
|
|
default:
|
|
|
|
|
parent_anchor = GDK_GRAVITY_SOUTH;
|
|
|
|
|
surface_anchor = GDK_GRAVITY_NORTH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-29 03:25:37 +00:00
|
|
|
|
anchor_hints = GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE_X;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-22 03:46:52 +00:00
|
|
|
|
anchor_hints |= GDK_ANCHOR_RESIZE;
|
|
|
|
|
|
|
|
|
|
layout = gdk_popup_layout_new (&rect, parent_anchor, surface_anchor);
|
2020-02-16 11:59:24 +00:00
|
|
|
|
gdk_popup_layout_set_anchor_hints (layout, anchor_hints);
|
2021-02-01 00:26:33 +00:00
|
|
|
|
gdk_popup_layout_set_shadow_width (layout,
|
|
|
|
|
shadow_width.left,
|
|
|
|
|
shadow_width.right,
|
|
|
|
|
shadow_width.top,
|
|
|
|
|
shadow_width.bottom);
|
2020-02-16 11:59:24 +00:00
|
|
|
|
|
2020-08-08 00:06:08 +00:00
|
|
|
|
if (priv->x_offset || priv->y_offset)
|
|
|
|
|
gdk_popup_layout_set_offset (layout, priv->x_offset, priv->y_offset);
|
|
|
|
|
|
2020-02-16 11:59:24 +00:00
|
|
|
|
return layout;
|
2017-07-08 10:04:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-24 21:06:52 +00:00
|
|
|
|
static gboolean
|
2020-02-16 11:59:24 +00:00
|
|
|
|
present_popup (GtkPopover *popover)
|
2017-07-08 10:04:44 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2020-12-22 03:46:52 +00:00
|
|
|
|
GtkRequisition nat;
|
2020-02-16 11:59:24 +00:00
|
|
|
|
GdkPopupLayout *layout;
|
|
|
|
|
|
|
|
|
|
layout = create_popup_layout (popover);
|
2020-12-22 03:46:52 +00:00
|
|
|
|
gtk_widget_get_preferred_size (GTK_WIDGET (popover), NULL, &nat);
|
|
|
|
|
|
2021-02-01 00:26:33 +00:00
|
|
|
|
if (gdk_popup_present (GDK_POPUP (priv->surface), nat.width, nat.height, layout))
|
2020-04-24 21:06:52 +00:00
|
|
|
|
{
|
2020-12-22 03:46:52 +00:00
|
|
|
|
update_popover_layout (popover, layout, nat.width, nat.height);
|
2020-04-24 21:06:52 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
2017-07-08 10:04:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-16 15:32:32 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_present:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
*
|
|
|
|
|
* Presents the popover to the user.
|
|
|
|
|
*/
|
2020-12-04 08:20:50 +00:00
|
|
|
|
void
|
|
|
|
|
gtk_popover_present (GtkPopover *popover)
|
2018-06-07 11:32:31 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkWidget *widget = GTK_WIDGET (popover);
|
2018-06-07 11:32:31 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
if (!_gtk_widget_get_alloc_needed (widget))
|
|
|
|
|
gtk_widget_ensure_allocate (widget);
|
|
|
|
|
else if (gtk_widget_get_visible (widget))
|
2020-02-16 11:59:24 +00:00
|
|
|
|
present_popup (popover);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
}
|
2018-06-07 11:32:31 +00:00
|
|
|
|
|
2020-12-04 08:12:22 +00:00
|
|
|
|
static void
|
|
|
|
|
maybe_request_motion_event (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *widget = GTK_WIDGET (popover);
|
|
|
|
|
GtkRoot *root = gtk_widget_get_root (widget);
|
|
|
|
|
GdkSeat *seat;
|
|
|
|
|
GdkDevice *device;
|
|
|
|
|
GtkWidget *focus;
|
|
|
|
|
GdkSurface *focus_surface;
|
|
|
|
|
|
|
|
|
|
seat = gdk_display_get_default_seat (gtk_widget_get_display (widget));
|
|
|
|
|
if (!seat)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
device = gdk_seat_get_pointer (seat);
|
|
|
|
|
focus = gtk_window_lookup_pointer_focus_widget (GTK_WINDOW (root),
|
|
|
|
|
device, NULL);
|
|
|
|
|
if (!focus)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!gtk_widget_is_ancestor (focus, GTK_WIDGET (popover)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
focus_surface = gtk_native_get_surface (gtk_widget_get_native (focus));
|
|
|
|
|
gdk_surface_request_motion (focus_surface);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-02 10:59:23 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_popover_native_layout (GtkNative *native,
|
|
|
|
|
int width,
|
|
|
|
|
int height)
|
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = GTK_POPOVER (native);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
GtkWidget *widget = GTK_WIDGET (popover);
|
|
|
|
|
|
2020-12-22 03:46:52 +00:00
|
|
|
|
update_popover_layout (popover, gdk_popup_layout_ref (priv->layout), width, height);
|
2020-12-02 10:59:23 +00:00
|
|
|
|
|
|
|
|
|
if (gtk_widget_needs_allocate (widget))
|
2020-12-04 08:12:22 +00:00
|
|
|
|
{
|
|
|
|
|
gtk_widget_allocate (widget, width, height, -1, NULL);
|
|
|
|
|
|
|
|
|
|
/* This fake motion event is needed for getting up to date pointer focus
|
2021-02-14 00:22:06 +00:00
|
|
|
|
* and coordinates when the pointer didn't move but the layout changed
|
2020-12-04 08:12:22 +00:00
|
|
|
|
* within the popover.
|
|
|
|
|
*/
|
|
|
|
|
maybe_request_motion_event (popover);
|
|
|
|
|
}
|
2020-12-02 10:59:23 +00:00
|
|
|
|
else
|
2020-12-04 08:12:22 +00:00
|
|
|
|
{
|
|
|
|
|
gtk_widget_ensure_allocate (widget);
|
|
|
|
|
}
|
2020-12-02 10:59:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 16:45:43 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
gtk_popover_has_mnemonic_modifier_pressed (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
GList *seats, *s;
|
|
|
|
|
gboolean retval = FALSE;
|
|
|
|
|
|
|
|
|
|
seats = gdk_display_list_seats (gtk_widget_get_display (GTK_WIDGET (popover)));
|
|
|
|
|
|
|
|
|
|
for (s = seats; s; s = s->next)
|
|
|
|
|
{
|
2020-07-28 13:44:09 +00:00
|
|
|
|
GdkDevice *dev = gdk_seat_get_keyboard (s->data);
|
2020-03-24 16:45:43 +00:00
|
|
|
|
GdkModifierType mask;
|
|
|
|
|
|
2020-07-28 13:44:09 +00:00
|
|
|
|
mask = gdk_device_get_modifier_state (dev);
|
2020-04-05 13:39:03 +00:00
|
|
|
|
if ((mask & gtk_accelerator_get_default_mod_mask ()) == GDK_ALT_MASK)
|
2020-03-24 16:45:43 +00:00
|
|
|
|
{
|
|
|
|
|
retval = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_list_free (seats);
|
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
schedule_mnemonics_visible_cb (gpointer data)
|
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = data;
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
priv->mnemonics_display_timeout_id = 0;
|
|
|
|
|
|
|
|
|
|
gtk_popover_set_mnemonics_visible (popover, TRUE);
|
|
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_popover_schedule_mnemonics_visible (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
if (priv->mnemonics_display_timeout_id)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
priv->mnemonics_display_timeout_id =
|
|
|
|
|
g_timeout_add (MNEMONICS_DELAY, schedule_mnemonics_visible_cb, popover);
|
|
|
|
|
g_source_set_name_by_id (priv->mnemonics_display_timeout_id, "[gtk] popover_schedule_mnemonics_visible_cb");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_popover_focus_in (GtkWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
if (priv->disable_auto_mnemonics)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (gtk_widget_get_visible (widget))
|
|
|
|
|
{
|
|
|
|
|
if (gtk_popover_has_mnemonic_modifier_pressed (popover))
|
|
|
|
|
gtk_popover_schedule_mnemonics_visible (popover);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_popover_focus_out (GtkWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
if (priv->disable_auto_mnemonics)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
gtk_popover_set_mnemonics_visible (popover, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
update_mnemonics_visible (GtkPopover *popover,
|
|
|
|
|
guint keyval,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
gboolean visible)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
if (priv->disable_auto_mnemonics)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ((keyval == GDK_KEY_Alt_L || keyval == GDK_KEY_Alt_R) &&
|
2020-04-05 13:39:03 +00:00
|
|
|
|
((state & (gtk_accelerator_get_default_mod_mask ()) & ~(GDK_ALT_MASK)) == 0))
|
2020-03-24 16:45:43 +00:00
|
|
|
|
{
|
|
|
|
|
if (visible)
|
|
|
|
|
gtk_popover_schedule_mnemonics_visible (popover);
|
|
|
|
|
else
|
|
|
|
|
gtk_popover_set_mnemonics_visible (popover, FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
gtk_popover_key_pressed (GtkWidget *widget,
|
|
|
|
|
guint keyval,
|
|
|
|
|
guint keycode,
|
|
|
|
|
GdkModifierType state)
|
|
|
|
|
{
|
2020-03-24 16:45:43 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
if (keyval == GDK_KEY_Escape)
|
|
|
|
|
{
|
2020-10-13 12:58:13 +00:00
|
|
|
|
gtk_popover_popdown (popover);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
return TRUE;
|
2018-06-07 11:32:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 16:45:43 +00:00
|
|
|
|
update_mnemonics_visible (popover, keyval, state, TRUE);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gtk_popover_key_released (GtkWidget *widget,
|
|
|
|
|
guint keyval,
|
|
|
|
|
guint keycode,
|
|
|
|
|
GdkModifierType state)
|
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
|
|
|
|
|
update_mnemonics_visible (popover, keyval, state, FALSE);
|
|
|
|
|
|
2018-06-07 11:32:31 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2020-03-01 01:32:15 +00:00
|
|
|
|
surface_mapped_changed (GtkWidget *widget)
|
2018-06-07 11:32:31 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
2018-06-07 11:32:31 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
2020-03-01 01:32:15 +00:00
|
|
|
|
gtk_widget_set_visible (widget, gdk_surface_get_mapped (priv->surface));
|
2018-06-07 11:32:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-19 20:14:44 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
surface_render (GdkSurface *surface,
|
|
|
|
|
cairo_region_t *region,
|
|
|
|
|
GtkWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
gtk_widget_render (widget, surface, region);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
surface_event (GdkSurface *surface,
|
|
|
|
|
GdkEvent *event,
|
|
|
|
|
GtkWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_do_event (event);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-28 17:07:05 +00:00
|
|
|
|
static void
|
2019-06-12 16:54:57 +00:00
|
|
|
|
gtk_popover_activate_default (GtkPopover *popover)
|
2019-04-28 17:07:05 +00:00
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
GtkWidget *focus_widget;
|
|
|
|
|
|
2020-02-24 12:21:46 +00:00
|
|
|
|
focus_widget = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (popover))));
|
2019-04-29 03:25:37 +00:00
|
|
|
|
if (!gtk_widget_is_ancestor (focus_widget, GTK_WIDGET (popover)))
|
|
|
|
|
focus_widget = NULL;
|
|
|
|
|
|
2019-04-28 17:07:05 +00:00
|
|
|
|
if (priv->default_widget && gtk_widget_is_sensitive (priv->default_widget) &&
|
2019-04-29 03:25:37 +00:00
|
|
|
|
(!focus_widget || !gtk_widget_get_receives_default (focus_widget)
|
|
|
|
|
))
|
2019-04-28 17:07:05 +00:00
|
|
|
|
gtk_widget_activate (priv->default_widget);
|
|
|
|
|
else if (focus_widget && gtk_widget_is_sensitive (focus_widget))
|
|
|
|
|
gtk_widget_activate (focus_widget);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-12 16:54:57 +00:00
|
|
|
|
static void
|
|
|
|
|
activate_default_cb (GSimpleAction *action,
|
|
|
|
|
GVariant *parameter,
|
|
|
|
|
gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_popover_activate_default (GTK_POPOVER (data));
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-28 17:07:05 +00:00
|
|
|
|
static void
|
|
|
|
|
add_actions (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
GActionEntry entries[] = {
|
|
|
|
|
{ "activate", activate_default_cb, NULL, NULL, NULL },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
GActionGroup *actions;
|
|
|
|
|
|
|
|
|
|
actions = G_ACTION_GROUP (g_simple_action_group_new ());
|
|
|
|
|
g_action_map_add_action_entries (G_ACTION_MAP (actions),
|
|
|
|
|
entries, G_N_ELEMENTS (entries),
|
|
|
|
|
popover);
|
|
|
|
|
gtk_widget_insert_action_group (GTK_WIDGET (popover), "default", actions);
|
|
|
|
|
g_object_unref (actions);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-05 23:53:02 +00:00
|
|
|
|
static void
|
|
|
|
|
node_style_changed_cb (GtkCssNode *node,
|
|
|
|
|
GtkCssStyleChange *change,
|
|
|
|
|
GtkWidget *widget)
|
|
|
|
|
{
|
2019-05-25 23:11:30 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
|
|
|
|
|
g_clear_pointer (&priv->arrow_render_node, gsk_render_node_unref);
|
|
|
|
|
|
2019-05-05 23:53:02 +00:00
|
|
|
|
if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_SIZE))
|
|
|
|
|
gtk_widget_queue_resize (widget);
|
|
|
|
|
else
|
|
|
|
|
gtk_widget_queue_draw (widget);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-11 16:32:08 +00:00
|
|
|
|
static void
|
2013-11-12 15:55:23 +00:00
|
|
|
|
gtk_popover_init (GtkPopover *popover)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2018-03-29 18:15:39 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
GtkWidget *widget = GTK_WIDGET (popover);
|
2018-06-07 11:32:31 +00:00
|
|
|
|
GtkEventController *controller;
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-08-01 14:03:57 +00:00
|
|
|
|
priv->position = GTK_POS_BOTTOM;
|
|
|
|
|
priv->final_position = GTK_POS_BOTTOM;
|
2019-05-19 23:46:56 +00:00
|
|
|
|
priv->autohide = TRUE;
|
2019-05-22 00:42:07 +00:00
|
|
|
|
priv->has_arrow = TRUE;
|
2020-11-03 15:23:34 +00:00
|
|
|
|
priv->cascade_popdown = FALSE;
|
2018-06-07 11:32:31 +00:00
|
|
|
|
|
|
|
|
|
controller = gtk_event_controller_key_new ();
|
2019-04-29 03:25:37 +00:00
|
|
|
|
g_signal_connect_swapped (controller, "key-pressed", G_CALLBACK (gtk_popover_key_pressed), popover);
|
2020-03-24 16:45:43 +00:00
|
|
|
|
g_signal_connect_swapped (controller, "key-released", G_CALLBACK (gtk_popover_key_released), popover);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_widget_add_controller (GTK_WIDGET (popover), controller);
|
|
|
|
|
|
2020-03-24 16:45:43 +00:00
|
|
|
|
controller = gtk_event_controller_focus_new ();
|
|
|
|
|
g_signal_connect_swapped (controller, "enter", G_CALLBACK (gtk_popover_focus_in), popover);
|
|
|
|
|
g_signal_connect_swapped (controller, "leave", G_CALLBACK (gtk_popover_focus_out), popover);
|
|
|
|
|
gtk_widget_add_controller (widget, controller);
|
|
|
|
|
|
2019-05-05 23:53:02 +00:00
|
|
|
|
priv->arrow_node = gtk_css_node_new ();
|
2020-01-23 23:43:26 +00:00
|
|
|
|
gtk_css_node_set_name (priv->arrow_node, g_quark_from_static_string ("arrow"));
|
2019-05-05 23:53:02 +00:00
|
|
|
|
gtk_css_node_set_parent (priv->arrow_node, gtk_widget_get_css_node (widget));
|
|
|
|
|
gtk_css_node_set_state (priv->arrow_node,
|
|
|
|
|
gtk_css_node_get_state (gtk_widget_get_css_node (widget)));
|
|
|
|
|
g_signal_connect_object (priv->arrow_node, "style-changed",
|
|
|
|
|
G_CALLBACK (node_style_changed_cb), popover, 0);
|
|
|
|
|
g_object_unref (priv->arrow_node);
|
|
|
|
|
|
2021-02-17 04:47:20 +00:00
|
|
|
|
priv->contents_widget = gtk_popover_content_new ();
|
|
|
|
|
|
2019-10-25 08:36:29 +00:00
|
|
|
|
gtk_widget_set_layout_manager (priv->contents_widget, gtk_bin_layout_new ());
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_widget_set_parent (priv->contents_widget, GTK_WIDGET (popover));
|
2020-08-04 15:09:45 +00:00
|
|
|
|
gtk_widget_set_overflow (priv->contents_widget, GTK_OVERFLOW_HIDDEN);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
|
2020-08-01 08:31:38 +00:00
|
|
|
|
gtk_widget_add_css_class (widget, "background");
|
2019-04-28 17:07:05 +00:00
|
|
|
|
|
|
|
|
|
add_actions (popover);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_realize (GtkWidget *widget)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2020-02-24 12:21:46 +00:00
|
|
|
|
GdkSurface *parent_surface;
|
|
|
|
|
GtkWidget *parent;
|
2019-04-29 03:25:37 +00:00
|
|
|
|
|
2020-02-24 12:21:46 +00:00
|
|
|
|
parent = gtk_widget_get_parent (widget);
|
|
|
|
|
parent_surface = gtk_native_get_surface (gtk_widget_get_native (parent));
|
|
|
|
|
priv->surface = gdk_surface_new_popup (parent_surface, priv->autohide);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
|
2019-04-19 20:14:44 +00:00
|
|
|
|
gdk_surface_set_widget (priv->surface, widget);
|
|
|
|
|
|
2020-03-01 01:32:15 +00:00
|
|
|
|
g_signal_connect_swapped (priv->surface, "notify::mapped", G_CALLBACK (surface_mapped_changed), widget);
|
2019-04-19 20:14:44 +00:00
|
|
|
|
g_signal_connect (priv->surface, "render", G_CALLBACK (surface_render), widget);
|
|
|
|
|
g_signal_connect (priv->surface, "event", G_CALLBACK (surface_event), widget);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
|
|
|
|
|
GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget);
|
|
|
|
|
|
|
|
|
|
priv->renderer = gsk_renderer_new_for_surface (priv->surface);
|
2020-12-02 10:59:23 +00:00
|
|
|
|
|
|
|
|
|
gtk_native_realize (GTK_NATIVE (popover));
|
2013-01-11 16:32:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_unrealize (GtkWidget *widget)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2020-12-02 10:59:23 +00:00
|
|
|
|
gtk_native_unrealize (GTK_NATIVE (popover));
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GTK_WIDGET_CLASS (gtk_popover_parent_class)->unrealize (widget);
|
|
|
|
|
|
|
|
|
|
gsk_renderer_unrealize (priv->renderer);
|
|
|
|
|
g_clear_object (&priv->renderer);
|
|
|
|
|
|
2020-03-01 01:32:15 +00:00
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->surface, surface_mapped_changed, widget);
|
2019-04-19 20:14:44 +00:00
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->surface, surface_render, widget);
|
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->surface, surface_event, widget);
|
|
|
|
|
gdk_surface_set_widget (priv->surface, NULL);
|
2019-05-17 21:25:36 +00:00
|
|
|
|
gdk_surface_destroy (priv->surface);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
g_clear_object (&priv->surface);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-10 16:28:14 +00:00
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_show (GtkWidget *widget)
|
2016-08-10 16:28:14 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
2016-08-10 16:28:14 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
_gtk_widget_set_visible_flag (widget, TRUE);
|
|
|
|
|
gtk_widget_realize (widget);
|
2020-04-24 21:06:52 +00:00
|
|
|
|
if (!present_popup (popover))
|
|
|
|
|
return;
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_widget_map (widget);
|
2016-08-10 16:28:14 +00:00
|
|
|
|
|
2019-05-19 23:46:56 +00:00
|
|
|
|
if (priv->autohide)
|
2016-08-10 16:28:14 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
if (!gtk_widget_get_focus_child (widget))
|
|
|
|
|
gtk_widget_child_focus (widget, GTK_DIR_TAB_FORWARD);
|
2020-04-20 17:48:10 +00:00
|
|
|
|
|
|
|
|
|
gtk_grab_add (widget);
|
2016-08-10 16:28:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-11 16:32:08 +00:00
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_hide (GtkWidget *widget)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2020-04-20 17:48:10 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
if (priv->autohide)
|
|
|
|
|
gtk_grab_remove (widget);
|
|
|
|
|
|
2020-03-24 16:45:43 +00:00
|
|
|
|
gtk_popover_set_mnemonics_visible (GTK_POPOVER (widget), FALSE);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
_gtk_widget_set_visible_flag (widget, FALSE);
|
|
|
|
|
gtk_widget_unmap (widget);
|
|
|
|
|
g_signal_emit (widget, signals[CLOSED], 0);
|
|
|
|
|
}
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2014-12-02 14:44:04 +00:00
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
unset_surface_transform_changed_cb (gpointer data)
|
2014-12-02 14:44:04 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopover *popover = data;
|
2018-03-29 18:15:39 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2014-12-02 14:44:04 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
priv->surface_transform_changed_cb = 0;
|
|
|
|
|
}
|
2014-12-02 14:44:04 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
surface_transform_changed_cb (GtkWidget *widget,
|
|
|
|
|
const graphene_matrix_t *transform,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
2019-07-13 15:06:22 +00:00
|
|
|
|
GtkPopover *popover = user_data;
|
2019-05-25 23:11:30 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
2020-02-25 00:02:34 +00:00
|
|
|
|
if (priv->surface && gdk_surface_get_mapped (priv->surface))
|
2020-02-16 11:59:24 +00:00
|
|
|
|
present_popup (popover);
|
2014-12-02 14:44:04 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
return G_SOURCE_CONTINUE;
|
2014-12-02 14:44:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-11 09:36:51 +00:00
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_map (GtkWidget *widget)
|
2013-11-11 09:36:51 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
2018-03-29 18:15:39 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2020-02-24 12:21:46 +00:00
|
|
|
|
GtkWidget *parent;
|
2013-11-11 09:36:51 +00:00
|
|
|
|
|
2020-02-16 11:59:24 +00:00
|
|
|
|
present_popup (popover);
|
2017-07-08 10:04:44 +00:00
|
|
|
|
|
2020-02-24 12:21:46 +00:00
|
|
|
|
parent = gtk_widget_get_parent (widget);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
priv->surface_transform_changed_cb =
|
2020-02-24 12:21:46 +00:00
|
|
|
|
gtk_widget_add_surface_transform_changed_callback (parent,
|
2019-04-29 03:25:37 +00:00
|
|
|
|
surface_transform_changed_cb,
|
|
|
|
|
popover,
|
|
|
|
|
unset_surface_transform_changed_cb);
|
2017-07-08 10:04:44 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GTK_WIDGET_CLASS (gtk_popover_parent_class)->map (widget);
|
2013-11-11 09:36:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_unmap (GtkWidget *widget)
|
2015-01-09 15:10:29 +00:00
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2020-02-24 12:21:46 +00:00
|
|
|
|
GtkWidget *parent;
|
2014-01-10 14:23:12 +00:00
|
|
|
|
|
2020-02-24 12:21:46 +00:00
|
|
|
|
parent = gtk_widget_get_parent (widget);
|
|
|
|
|
gtk_widget_remove_surface_transform_changed_callback (parent,
|
2019-04-29 03:25:37 +00:00
|
|
|
|
priv->surface_transform_changed_cb);
|
|
|
|
|
priv->surface_transform_changed_cb = 0;
|
2014-01-10 14:23:12 +00:00
|
|
|
|
|
2013-11-12 15:55:23 +00:00
|
|
|
|
GTK_WIDGET_CLASS (gtk_popover_parent_class)->unmap (widget);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gdk_surface_hide (priv->surface);
|
2017-07-08 10:04:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-15 16:28:34 +00:00
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_dispose (GObject *object)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (object);
|
2017-07-08 10:04:44 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2013-03-05 16:13:54 +00:00
|
|
|
|
|
2020-05-09 19:20:15 +00:00
|
|
|
|
g_clear_object (&priv->default_widget);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
g_clear_pointer (&priv->contents_widget, gtk_widget_unparent);
|
2019-05-25 23:11:30 +00:00
|
|
|
|
g_clear_pointer (&priv->arrow_render_node, gsk_render_node_unref);
|
2013-01-15 16:32:42 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
G_OBJECT_CLASS (gtk_popover_parent_class)->dispose (object);
|
2013-03-05 15:55:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_popover_finalize (GObject *object)
|
2014-01-28 15:02:47 +00:00
|
|
|
|
{
|
2020-02-16 11:59:24 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (object);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
g_clear_pointer (&priv->layout, gdk_popup_layout_unref);
|
|
|
|
|
|
2020-03-24 16:45:43 +00:00
|
|
|
|
if (priv->mnemonics_display_timeout_id)
|
|
|
|
|
{
|
|
|
|
|
g_source_remove (priv->mnemonics_display_timeout_id);
|
|
|
|
|
priv->mnemonics_display_timeout_id = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
G_OBJECT_CLASS (gtk_popover_parent_class)->finalize (object);
|
2014-01-28 15:02:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-05 23:53:02 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_popover_get_gap_coords (GtkPopover *popover,
|
2020-07-24 13:54:49 +00:00
|
|
|
|
int *initial_x_out,
|
|
|
|
|
int *initial_y_out,
|
|
|
|
|
int *tip_x_out,
|
|
|
|
|
int *tip_y_out,
|
|
|
|
|
int *final_x_out,
|
|
|
|
|
int *final_y_out)
|
2019-05-05 23:53:02 +00:00
|
|
|
|
{
|
|
|
|
|
GtkWidget *widget = GTK_WIDGET (popover);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
GdkRectangle rect = { 0 };
|
2020-07-24 13:54:49 +00:00
|
|
|
|
int base, tip, tip_pos;
|
|
|
|
|
int initial_x, initial_y;
|
|
|
|
|
int tip_x, tip_y;
|
|
|
|
|
int final_x, final_y;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
GtkPositionType pos;
|
2020-01-18 16:48:30 +00:00
|
|
|
|
int border_top, border_right, border_bottom;
|
|
|
|
|
int border_radius;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
int popover_width, popover_height;
|
2020-01-18 16:48:30 +00:00
|
|
|
|
GtkCssStyle *style;
|
2020-02-24 12:21:46 +00:00
|
|
|
|
GtkWidget *parent;
|
2021-02-01 00:26:33 +00:00
|
|
|
|
GtkBorder shadow_width;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
|
|
|
|
popover_width = gtk_widget_get_allocated_width (widget);
|
|
|
|
|
popover_height = gtk_widget_get_allocated_height (widget);
|
2020-02-24 12:21:46 +00:00
|
|
|
|
parent = gtk_widget_get_parent (widget);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2020-02-24 12:21:46 +00:00
|
|
|
|
gtk_widget_get_surface_allocation (parent, &rect);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
if (priv->has_pointing_to)
|
|
|
|
|
{
|
|
|
|
|
rect.x += priv->pointing_to.x;
|
|
|
|
|
rect.y += priv->pointing_to.y;
|
|
|
|
|
rect.width = priv->pointing_to.width;
|
|
|
|
|
rect.height = priv->pointing_to.height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rect.x -= priv->final_rect.x;
|
|
|
|
|
rect.y -= priv->final_rect.y;
|
|
|
|
|
|
|
|
|
|
pos = priv->final_position;
|
|
|
|
|
|
2020-01-27 12:01:37 +00:00
|
|
|
|
style = gtk_css_node_get_style (gtk_widget_get_css_node (priv->contents_widget));
|
2020-01-28 07:38:25 +00:00
|
|
|
|
border_radius = _gtk_css_number_value_get (style->border->border_top_left_radius, 100);
|
|
|
|
|
border_top = _gtk_css_number_value_get (style->border->border_top_width, 100);
|
|
|
|
|
border_right = _gtk_css_number_value_get (style->border->border_right_width, 100);
|
|
|
|
|
border_bottom = _gtk_css_number_value_get (style->border->border_bottom_width, 100);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2021-02-01 00:26:33 +00:00
|
|
|
|
gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
|
|
|
|
|
|
|
|
|
|
if (pos == GTK_POS_BOTTOM)
|
2019-05-05 23:53:02 +00:00
|
|
|
|
{
|
2021-02-01 00:26:33 +00:00
|
|
|
|
tip = shadow_width.top;
|
|
|
|
|
base = tip + TAIL_HEIGHT + border_top;
|
|
|
|
|
}
|
|
|
|
|
else if (pos == GTK_POS_RIGHT)
|
|
|
|
|
{
|
|
|
|
|
tip = shadow_width.left;
|
|
|
|
|
base = tip + TAIL_HEIGHT + border_top;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
}
|
|
|
|
|
else if (pos == GTK_POS_TOP)
|
|
|
|
|
{
|
2021-02-01 00:26:33 +00:00
|
|
|
|
tip = popover_height - shadow_width.bottom;
|
|
|
|
|
base = tip - border_bottom - TAIL_HEIGHT;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
}
|
|
|
|
|
else if (pos == GTK_POS_LEFT)
|
|
|
|
|
{
|
2021-02-01 00:26:33 +00:00
|
|
|
|
tip = popover_width - shadow_width.right;
|
|
|
|
|
base = tip - border_right - TAIL_HEIGHT;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
|
|
|
|
|
if (POS_IS_VERTICAL (pos))
|
|
|
|
|
{
|
|
|
|
|
tip_pos = rect.x + (rect.width / 2);
|
|
|
|
|
initial_x = CLAMP (tip_pos - TAIL_GAP_WIDTH / 2,
|
|
|
|
|
border_radius,
|
|
|
|
|
popover_width - TAIL_GAP_WIDTH - border_radius);
|
|
|
|
|
initial_y = base;
|
|
|
|
|
|
|
|
|
|
tip_x = CLAMP (tip_pos, 0, popover_width);
|
|
|
|
|
tip_y = tip;
|
|
|
|
|
|
|
|
|
|
final_x = CLAMP (tip_pos + TAIL_GAP_WIDTH / 2,
|
|
|
|
|
border_radius + TAIL_GAP_WIDTH,
|
|
|
|
|
popover_width - border_radius);
|
|
|
|
|
final_y = base;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tip_pos = rect.y + (rect.height / 2);
|
|
|
|
|
|
|
|
|
|
initial_x = base;
|
|
|
|
|
initial_y = CLAMP (tip_pos - TAIL_GAP_WIDTH / 2,
|
|
|
|
|
border_radius,
|
|
|
|
|
popover_height - TAIL_GAP_WIDTH - border_radius);
|
|
|
|
|
|
|
|
|
|
tip_x = tip;
|
|
|
|
|
tip_y = CLAMP (tip_pos, 0, popover_height);
|
|
|
|
|
|
|
|
|
|
final_x = base;
|
|
|
|
|
final_y = CLAMP (tip_pos + TAIL_GAP_WIDTH / 2,
|
|
|
|
|
border_radius + TAIL_GAP_WIDTH,
|
|
|
|
|
popover_height - border_radius);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*initial_x_out = initial_x;
|
|
|
|
|
*initial_y_out = initial_y;
|
|
|
|
|
|
|
|
|
|
*tip_x_out = tip_x;
|
|
|
|
|
*tip_y_out = tip_y;
|
|
|
|
|
|
|
|
|
|
*final_x_out = final_x;
|
|
|
|
|
*final_y_out = final_y;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-18 16:48:30 +00:00
|
|
|
|
static void
|
|
|
|
|
get_border (GtkCssNode *node,
|
|
|
|
|
GtkBorder *border)
|
|
|
|
|
{
|
|
|
|
|
GtkCssStyle *style;
|
|
|
|
|
|
|
|
|
|
style = gtk_css_node_get_style (node);
|
|
|
|
|
|
2020-01-28 07:38:25 +00:00
|
|
|
|
border->top = _gtk_css_number_value_get (style->border->border_top_width, 100);
|
|
|
|
|
border->right = _gtk_css_number_value_get (style->border->border_right_width, 100);
|
|
|
|
|
border->bottom = _gtk_css_number_value_get (style->border->border_bottom_width, 100);
|
|
|
|
|
border->left = _gtk_css_number_value_get (style->border->border_left_width, 100);
|
2020-01-18 16:48:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-05 23:53:02 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_popover_apply_tail_path (GtkPopover *popover,
|
|
|
|
|
cairo_t *cr)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2020-07-24 13:54:49 +00:00
|
|
|
|
int initial_x, initial_y;
|
|
|
|
|
int tip_x, tip_y;
|
|
|
|
|
int final_x, final_y;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
GtkBorder border;
|
2020-02-24 12:21:46 +00:00
|
|
|
|
GtkWidget *parent;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2020-02-24 12:21:46 +00:00
|
|
|
|
parent = gtk_widget_get_parent (GTK_WIDGET (popover));
|
|
|
|
|
|
|
|
|
|
if (!parent)
|
2019-05-05 23:53:02 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2020-01-18 16:48:30 +00:00
|
|
|
|
get_border (priv->arrow_node, &border);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
|
|
|
|
cairo_set_line_width (cr, 1);
|
|
|
|
|
gtk_popover_get_gap_coords (popover,
|
|
|
|
|
&initial_x, &initial_y,
|
|
|
|
|
&tip_x, &tip_y,
|
|
|
|
|
&final_x, &final_y);
|
|
|
|
|
|
|
|
|
|
cairo_move_to (cr, initial_x, initial_y);
|
|
|
|
|
cairo_line_to (cr, tip_x, tip_y);
|
|
|
|
|
cairo_line_to (cr, final_x, final_y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_popover_update_shape (GtkPopover *popover)
|
|
|
|
|
{
|
2019-05-20 00:38:08 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-22 00:42:07 +00:00
|
|
|
|
if (priv->has_arrow)
|
|
|
|
|
{
|
2020-05-16 20:34:38 +00:00
|
|
|
|
GtkCssBoxes content_css_boxes;
|
|
|
|
|
const GskRoundedRect *box;
|
2019-05-22 00:42:07 +00:00
|
|
|
|
cairo_surface_t *cairo_surface;
|
|
|
|
|
cairo_region_t *region;
|
|
|
|
|
cairo_t *cr;
|
2020-05-17 21:08:01 +00:00
|
|
|
|
double x, y;
|
|
|
|
|
double native_x, native_y;
|
2020-05-16 20:34:38 +00:00
|
|
|
|
|
|
|
|
|
gtk_native_get_surface_transform (GTK_NATIVE (popover), &native_x, &native_y);
|
|
|
|
|
gtk_css_boxes_init (&content_css_boxes, priv->contents_widget);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-22 00:42:07 +00:00
|
|
|
|
cairo_surface =
|
|
|
|
|
gdk_surface_create_similar_surface (priv->surface,
|
|
|
|
|
CAIRO_CONTENT_COLOR_ALPHA,
|
|
|
|
|
gdk_surface_get_width (priv->surface),
|
|
|
|
|
gdk_surface_get_height (priv->surface));
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-22 00:42:07 +00:00
|
|
|
|
cr = cairo_create (cairo_surface);
|
2020-05-16 20:34:38 +00:00
|
|
|
|
|
|
|
|
|
cairo_translate (cr, native_x, native_y);
|
|
|
|
|
|
|
|
|
|
cairo_set_source_rgba (cr, 0, 0, 0, 1);
|
|
|
|
|
gtk_popover_apply_tail_path (popover, cr);
|
|
|
|
|
cairo_close_path (cr);
|
|
|
|
|
cairo_fill (cr);
|
|
|
|
|
|
|
|
|
|
box = gtk_css_boxes_get_border_box (&content_css_boxes);
|
|
|
|
|
gtk_widget_translate_coordinates (priv->contents_widget, GTK_WIDGET (popover),
|
|
|
|
|
0, 0,
|
|
|
|
|
&x, &y);
|
|
|
|
|
cairo_translate (cr, x, y);
|
|
|
|
|
gsk_rounded_rect_path (box, cr);
|
|
|
|
|
cairo_fill (cr);
|
2019-05-22 00:42:07 +00:00
|
|
|
|
cairo_destroy (cr);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-22 00:42:07 +00:00
|
|
|
|
region = gdk_cairo_region_create_from_surface (cairo_surface);
|
|
|
|
|
cairo_surface_destroy (cairo_surface);
|
|
|
|
|
|
2020-03-01 19:29:06 +00:00
|
|
|
|
gdk_surface_set_input_region (priv->surface, region);
|
2019-05-22 00:42:07 +00:00
|
|
|
|
cairo_region_destroy (region);
|
|
|
|
|
}
|
|
|
|
|
else
|
2021-02-01 00:26:33 +00:00
|
|
|
|
{
|
|
|
|
|
GtkCssNode *content_css_node;
|
|
|
|
|
GtkCssStyle *style;
|
|
|
|
|
GtkBorder shadow_width;
|
|
|
|
|
cairo_rectangle_int_t input_rect;
|
|
|
|
|
cairo_region_t *region;
|
|
|
|
|
|
|
|
|
|
content_css_node =
|
|
|
|
|
gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget));
|
|
|
|
|
style = gtk_css_node_get_style (content_css_node);
|
|
|
|
|
gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
|
|
|
|
|
|
|
|
|
|
input_rect.x = shadow_width.left;
|
|
|
|
|
input_rect.y = shadow_width.top;
|
|
|
|
|
input_rect.width =
|
|
|
|
|
gdk_surface_get_width (priv->surface) -
|
|
|
|
|
(shadow_width.left + shadow_width.right);
|
|
|
|
|
input_rect.height =
|
|
|
|
|
gdk_surface_get_height (priv->surface) -
|
|
|
|
|
(shadow_width.top + shadow_width.bottom);
|
|
|
|
|
|
|
|
|
|
region = cairo_region_create_rectangle (&input_rect);
|
|
|
|
|
gdk_surface_set_input_region (priv->surface, region);
|
|
|
|
|
cairo_region_destroy (region);
|
|
|
|
|
}
|
2019-05-05 23:53:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-24 13:54:49 +00:00
|
|
|
|
static int
|
2019-05-05 23:53:02 +00:00
|
|
|
|
get_border_radius (GtkWidget *widget)
|
|
|
|
|
{
|
2020-01-18 16:48:30 +00:00
|
|
|
|
GtkCssStyle *style;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2020-01-18 16:48:30 +00:00
|
|
|
|
style = gtk_css_node_get_style (gtk_widget_get_css_node (widget));
|
2020-01-28 07:38:25 +00:00
|
|
|
|
return round (_gtk_css_number_value_get (style->border->border_top_left_radius, 100));
|
2019-05-05 23:53:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-24 13:54:49 +00:00
|
|
|
|
static int
|
2019-05-05 23:53:02 +00:00
|
|
|
|
get_minimal_size (GtkPopover *popover,
|
|
|
|
|
GtkOrientation orientation)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
GtkPositionType pos;
|
2020-07-24 13:54:49 +00:00
|
|
|
|
int minimal_size;
|
2019-05-22 00:42:07 +00:00
|
|
|
|
int tail_gap_width = priv->has_arrow ? TAIL_GAP_WIDTH : 0;
|
2021-02-01 00:26:33 +00:00
|
|
|
|
int min_width, min_height;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2021-02-01 00:26:33 +00:00
|
|
|
|
minimal_size = 2 * get_border_radius (GTK_WIDGET (priv->contents_widget));
|
2019-05-05 23:53:02 +00:00
|
|
|
|
pos = priv->position;
|
|
|
|
|
|
|
|
|
|
if ((orientation == GTK_ORIENTATION_HORIZONTAL && POS_IS_VERTICAL (pos)) ||
|
|
|
|
|
(orientation == GTK_ORIENTATION_VERTICAL && !POS_IS_VERTICAL (pos)))
|
2019-05-22 00:42:07 +00:00
|
|
|
|
minimal_size += tail_gap_width;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2021-02-01 00:26:33 +00:00
|
|
|
|
gtk_widget_get_size_request (GTK_WIDGET (popover), &min_width, &min_height);
|
|
|
|
|
|
|
|
|
|
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
|
|
|
|
minimal_size = MAX (minimal_size, min_width);
|
|
|
|
|
else
|
|
|
|
|
minimal_size = MAX (minimal_size, min_height);
|
|
|
|
|
|
2019-05-05 23:53:02 +00:00
|
|
|
|
return minimal_size;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-11 16:32:08 +00:00
|
|
|
|
static void
|
2016-10-22 14:06:14 +00:00
|
|
|
|
gtk_popover_measure (GtkWidget *widget,
|
|
|
|
|
GtkOrientation orientation,
|
|
|
|
|
int for_size,
|
|
|
|
|
int *minimum,
|
|
|
|
|
int *natural,
|
|
|
|
|
int *minimum_baseline,
|
|
|
|
|
int *natural_baseline)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2014-02-09 06:22:07 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
2017-07-08 10:04:44 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
int minimal_size;
|
2019-05-22 00:42:07 +00:00
|
|
|
|
int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0;
|
2021-02-01 00:26:33 +00:00
|
|
|
|
GtkCssStyle *style;
|
|
|
|
|
GtkBorder shadow_width;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
|
|
|
|
if (for_size >= 0)
|
2019-05-22 00:42:07 +00:00
|
|
|
|
for_size -= tail_height;
|
2014-01-10 22:43:42 +00:00
|
|
|
|
|
2021-02-01 00:26:33 +00:00
|
|
|
|
style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget)));
|
|
|
|
|
gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_widget_measure (priv->contents_widget,
|
|
|
|
|
orientation, for_size,
|
|
|
|
|
minimum, natural,
|
|
|
|
|
minimum_baseline, natural_baseline);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
|
|
|
|
minimal_size = get_minimal_size (popover, orientation);
|
|
|
|
|
*minimum = MAX (*minimum, minimal_size);
|
|
|
|
|
*natural = MAX (*natural, minimal_size);
|
|
|
|
|
|
2021-02-01 00:26:33 +00:00
|
|
|
|
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
|
|
|
|
{
|
|
|
|
|
*minimum += shadow_width.left + shadow_width.right;
|
|
|
|
|
*natural += shadow_width.left + shadow_width.right;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*minimum += shadow_width.top + shadow_width.bottom;
|
|
|
|
|
*natural += shadow_width.top + shadow_width.bottom;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (POS_IS_VERTICAL (priv->position) == (orientation == GTK_ORIENTATION_VERTICAL))
|
|
|
|
|
{
|
|
|
|
|
*minimum += tail_height;
|
|
|
|
|
*natural += tail_height;
|
|
|
|
|
}
|
2015-10-12 22:21:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-11 16:32:08 +00:00
|
|
|
|
static void
|
2018-08-16 04:53:03 +00:00
|
|
|
|
gtk_popover_size_allocate (GtkWidget *widget,
|
|
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
int baseline)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2014-02-09 06:22:07 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
2017-07-08 10:04:44 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
GtkAllocation child_alloc;
|
2019-05-22 00:42:07 +00:00
|
|
|
|
int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0;
|
2021-02-01 00:26:33 +00:00
|
|
|
|
GtkCssStyle *style;
|
|
|
|
|
GtkBorder shadow_width;
|
|
|
|
|
|
|
|
|
|
style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget)));
|
|
|
|
|
gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-05-05 23:53:02 +00:00
|
|
|
|
switch (priv->final_position)
|
|
|
|
|
{
|
|
|
|
|
case GTK_POS_TOP:
|
2021-02-01 00:26:33 +00:00
|
|
|
|
child_alloc.x = shadow_width.left;
|
|
|
|
|
child_alloc.y = shadow_width.top;
|
|
|
|
|
child_alloc.width = width - (shadow_width.left + shadow_width.right);
|
|
|
|
|
child_alloc.height = height - (shadow_width.top + shadow_width.bottom + tail_height);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
break;
|
|
|
|
|
case GTK_POS_BOTTOM:
|
2021-02-01 00:26:33 +00:00
|
|
|
|
child_alloc.x = shadow_width.left;
|
|
|
|
|
child_alloc.y = shadow_width.top + tail_height;
|
|
|
|
|
child_alloc.width = width - (shadow_width.left + shadow_width.right);
|
|
|
|
|
child_alloc.height = height - (shadow_width.top + shadow_width.bottom + tail_height);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
break;
|
|
|
|
|
case GTK_POS_LEFT:
|
2021-02-01 00:26:33 +00:00
|
|
|
|
child_alloc.x = shadow_width.left;
|
|
|
|
|
child_alloc.y = shadow_width.top;
|
|
|
|
|
child_alloc.width = width - (shadow_width.left + shadow_width.right + tail_height);
|
|
|
|
|
child_alloc.height = height - (shadow_width.top + shadow_width.bottom);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
break;
|
|
|
|
|
case GTK_POS_RIGHT:
|
2021-02-01 00:26:33 +00:00
|
|
|
|
child_alloc.x = shadow_width.left + tail_height;
|
|
|
|
|
child_alloc.y = shadow_width.top;
|
|
|
|
|
child_alloc.width = width - (shadow_width.left + shadow_width.right + tail_height);
|
|
|
|
|
child_alloc.height = height - (shadow_width.top + shadow_width.bottom);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gtk_widget_size_allocate (priv->contents_widget, &child_alloc, baseline);
|
|
|
|
|
|
|
|
|
|
if (priv->surface)
|
2019-05-25 23:11:30 +00:00
|
|
|
|
{
|
|
|
|
|
gtk_popover_update_shape (popover);
|
|
|
|
|
g_clear_pointer (&priv->arrow_render_node, gsk_render_node_unref);
|
|
|
|
|
}
|
2020-05-06 17:56:27 +00:00
|
|
|
|
|
|
|
|
|
gtk_tooltip_maybe_allocate (GTK_NATIVE (popover));
|
2016-10-29 17:43:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-09 11:53:29 +00:00
|
|
|
|
static void
|
2019-05-25 23:11:30 +00:00
|
|
|
|
create_arrow_render_node (GtkPopover *popover)
|
2014-01-09 11:53:29 +00:00
|
|
|
|
{
|
2018-03-29 18:15:39 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2019-05-25 23:11:30 +00:00
|
|
|
|
GtkWidget *widget = GTK_WIDGET (popover);
|
|
|
|
|
GtkStyleContext *context;
|
|
|
|
|
GtkBorder border;
|
|
|
|
|
cairo_t *cr;
|
|
|
|
|
GtkSnapshot *snapshot;
|
2015-01-09 15:10:29 +00:00
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
snapshot = gtk_snapshot_new ();
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
cr = gtk_snapshot_append_cairo (snapshot,
|
|
|
|
|
&GRAPHENE_RECT_INIT (
|
|
|
|
|
0, 0,
|
|
|
|
|
gtk_widget_get_width (widget),
|
|
|
|
|
gtk_widget_get_height (widget)
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
/* Clip to the arrow shape */
|
|
|
|
|
cairo_save (cr);
|
|
|
|
|
gtk_popover_apply_tail_path (popover, cr);
|
|
|
|
|
cairo_clip (cr);
|
|
|
|
|
|
2020-01-18 16:48:30 +00:00
|
|
|
|
get_border (priv->arrow_node, &border);
|
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
context = gtk_widget_get_style_context (widget);
|
|
|
|
|
gtk_style_context_save_to_node (context, priv->arrow_node);
|
2019-05-22 00:42:07 +00:00
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
/* Render the arrow background */
|
|
|
|
|
gtk_render_background (context, cr,
|
|
|
|
|
0, 0,
|
|
|
|
|
gtk_widget_get_width (widget),
|
|
|
|
|
gtk_widget_get_height (widget));
|
2019-05-22 00:42:07 +00:00
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
/* Render the border of the arrow tip */
|
|
|
|
|
if (border.bottom > 0)
|
|
|
|
|
{
|
2020-01-28 07:38:25 +00:00
|
|
|
|
GtkCssStyle *style;
|
2020-01-18 16:48:30 +00:00
|
|
|
|
const GdkRGBA *border_color;
|
|
|
|
|
|
2020-01-28 07:38:25 +00:00
|
|
|
|
style = gtk_css_node_get_style (priv->arrow_node);
|
|
|
|
|
border_color = gtk_css_color_value_get_rgba (style->border->border_left_color ? style->border->border_left_color : style->core->color);
|
2019-05-25 23:11:30 +00:00
|
|
|
|
|
2019-05-22 00:42:07 +00:00
|
|
|
|
gtk_popover_apply_tail_path (popover, cr);
|
2019-05-25 23:11:30 +00:00
|
|
|
|
gdk_cairo_set_source_rgba (cr, border_color);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
cairo_set_line_width (cr, border.bottom + 1);
|
|
|
|
|
cairo_stroke (cr);
|
|
|
|
|
}
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
cairo_restore (cr);
|
|
|
|
|
cairo_destroy (cr);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
gtk_style_context_restore (context);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
priv->arrow_render_node = gtk_snapshot_free_to_node (snapshot);
|
|
|
|
|
}
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_popover_snapshot (GtkWidget *widget,
|
|
|
|
|
GtkSnapshot *snapshot)
|
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2019-05-25 23:11:30 +00:00
|
|
|
|
gtk_widget_snapshot_child (widget, priv->contents_widget, snapshot);
|
|
|
|
|
|
|
|
|
|
if (priv->has_arrow)
|
|
|
|
|
{
|
|
|
|
|
if (!priv->arrow_render_node)
|
|
|
|
|
create_arrow_render_node (popover);
|
|
|
|
|
|
|
|
|
|
gtk_snapshot_append_node (snapshot, priv->arrow_render_node);
|
2019-05-05 23:53:02 +00:00
|
|
|
|
}
|
2014-01-09 11:53:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-09 15:10:29 +00:00
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_set_property (GObject *object,
|
|
|
|
|
guint prop_id,
|
|
|
|
|
const GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
2015-01-09 15:10:29 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (object);
|
2015-01-09 15:10:29 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
switch (prop_id)
|
|
|
|
|
{
|
|
|
|
|
case PROP_POINTING_TO:
|
|
|
|
|
gtk_popover_set_pointing_to (popover, g_value_get_boxed (value));
|
|
|
|
|
break;
|
2015-01-09 15:10:29 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
case PROP_POSITION:
|
|
|
|
|
gtk_popover_set_position (popover, g_value_get_enum (value));
|
|
|
|
|
break;
|
2015-01-09 15:10:29 +00:00
|
|
|
|
|
2019-05-19 23:46:56 +00:00
|
|
|
|
case PROP_AUTOHIDE:
|
|
|
|
|
gtk_popover_set_autohide (popover, g_value_get_boolean (value));
|
2019-04-29 03:25:37 +00:00
|
|
|
|
break;
|
2015-01-09 15:10:29 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
case PROP_DEFAULT_WIDGET:
|
|
|
|
|
gtk_popover_set_default_widget (popover, g_value_get_object (value));
|
|
|
|
|
break;
|
2015-01-09 15:10:29 +00:00
|
|
|
|
|
2019-05-22 00:42:07 +00:00
|
|
|
|
case PROP_HAS_ARROW:
|
|
|
|
|
gtk_popover_set_has_arrow (popover, g_value_get_boolean (value));
|
|
|
|
|
break;
|
|
|
|
|
|
2020-03-24 16:29:26 +00:00
|
|
|
|
case PROP_MNEMONICS_VISIBLE:
|
|
|
|
|
gtk_popover_set_mnemonics_visible (popover, g_value_get_boolean (value));
|
|
|
|
|
break;
|
|
|
|
|
|
2020-05-01 22:24:15 +00:00
|
|
|
|
case PROP_CHILD:
|
|
|
|
|
gtk_popover_set_child (popover, g_value_get_object (value));
|
|
|
|
|
break;
|
|
|
|
|
|
2020-10-13 12:26:41 +00:00
|
|
|
|
case PROP_CASCADE_POPDOWN:
|
|
|
|
|
gtk_popover_set_cascade_popdown (popover, g_value_get_boolean (value));
|
|
|
|
|
break;
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-01-09 15:10:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_get_property (GObject *object,
|
|
|
|
|
guint prop_id,
|
|
|
|
|
GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
2015-01-09 15:10:29 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopover *popover = GTK_POPOVER (object);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
|
{
|
|
|
|
|
case PROP_POINTING_TO:
|
|
|
|
|
g_value_set_boxed (value, &priv->pointing_to);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PROP_POSITION:
|
|
|
|
|
g_value_set_enum (value, priv->position);
|
|
|
|
|
break;
|
2015-01-09 15:10:29 +00:00
|
|
|
|
|
2019-05-19 23:46:56 +00:00
|
|
|
|
case PROP_AUTOHIDE:
|
|
|
|
|
g_value_set_boolean (value, priv->autohide);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
break;
|
2015-01-09 15:10:29 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
case PROP_DEFAULT_WIDGET:
|
|
|
|
|
g_value_set_object (value, priv->default_widget);
|
|
|
|
|
break;
|
2015-01-09 15:10:29 +00:00
|
|
|
|
|
2019-05-22 00:42:07 +00:00
|
|
|
|
case PROP_HAS_ARROW:
|
|
|
|
|
g_value_set_boolean (value, priv->has_arrow);
|
|
|
|
|
break;
|
|
|
|
|
|
2020-03-24 16:29:26 +00:00
|
|
|
|
case PROP_MNEMONICS_VISIBLE:
|
|
|
|
|
g_value_set_boolean (value, priv->mnemonics_visible);
|
|
|
|
|
break;
|
|
|
|
|
|
2020-05-01 22:24:15 +00:00
|
|
|
|
case PROP_CHILD:
|
|
|
|
|
g_value_set_object (value, gtk_popover_get_child (popover));
|
|
|
|
|
break;
|
|
|
|
|
|
2020-10-13 12:26:41 +00:00
|
|
|
|
case PROP_CASCADE_POPDOWN:
|
|
|
|
|
g_value_set_boolean (value, priv->cascade_popdown);
|
|
|
|
|
break;
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-01-09 15:10:29 +00:00
|
|
|
|
}
|
2014-01-09 11:53:29 +00:00
|
|
|
|
|
2020-03-17 21:24:09 +00:00
|
|
|
|
static void
|
2020-03-17 21:24:09 +00:00
|
|
|
|
add_tab_bindings (GtkWidgetClass *widget_class,
|
2020-03-17 21:24:09 +00:00
|
|
|
|
GdkModifierType modifiers,
|
|
|
|
|
GtkDirectionType direction)
|
|
|
|
|
{
|
2020-03-17 21:24:09 +00:00
|
|
|
|
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Tab, modifiers,
|
|
|
|
|
"move-focus",
|
|
|
|
|
"(i)", direction);
|
|
|
|
|
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Tab, modifiers,
|
|
|
|
|
"move-focus",
|
|
|
|
|
"(i)", direction);
|
2020-03-17 21:24:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2020-03-17 21:24:09 +00:00
|
|
|
|
add_arrow_bindings (GtkWidgetClass *widget_class,
|
2020-03-17 21:24:09 +00:00
|
|
|
|
guint keysym,
|
|
|
|
|
GtkDirectionType direction)
|
|
|
|
|
{
|
|
|
|
|
guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
|
|
|
|
|
|
2020-03-17 21:24:09 +00:00
|
|
|
|
gtk_widget_class_add_binding_signal (widget_class, keysym, 0,
|
|
|
|
|
"move-focus",
|
|
|
|
|
"(i)",
|
|
|
|
|
direction);
|
|
|
|
|
gtk_widget_class_add_binding_signal (widget_class, keysym, GDK_CONTROL_MASK,
|
|
|
|
|
"move-focus",
|
|
|
|
|
"(i)",
|
|
|
|
|
direction);
|
|
|
|
|
gtk_widget_class_add_binding_signal (widget_class, keypad_keysym, 0,
|
|
|
|
|
"move-focus",
|
|
|
|
|
"(i)",
|
|
|
|
|
direction);
|
|
|
|
|
gtk_widget_class_add_binding_signal (widget_class, keypad_keysym, GDK_CONTROL_MASK,
|
|
|
|
|
"move-focus",
|
|
|
|
|
"(i)",
|
|
|
|
|
direction);
|
2020-03-17 21:24:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-02 02:35:31 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_popover_compute_expand (GtkWidget *widget,
|
|
|
|
|
gboolean *hexpand,
|
|
|
|
|
gboolean *vexpand)
|
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
if (priv->child)
|
|
|
|
|
{
|
|
|
|
|
*hexpand = gtk_widget_compute_expand (priv->child, GTK_ORIENTATION_HORIZONTAL);
|
|
|
|
|
*vexpand = gtk_widget_compute_expand (priv->child, GTK_ORIENTATION_VERTICAL);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*hexpand = FALSE;
|
|
|
|
|
*vexpand = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GtkSizeRequestMode
|
|
|
|
|
gtk_popover_get_request_mode (GtkWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
GtkPopover *popover = GTK_POPOVER (widget);
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
if (priv->child)
|
|
|
|
|
return gtk_widget_get_request_mode (priv->child);
|
|
|
|
|
else
|
|
|
|
|
return GTK_SIZE_REQUEST_CONSTANT_SIZE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-11 16:32:08 +00:00
|
|
|
|
static void
|
2013-11-12 15:55:23 +00:00
|
|
|
|
gtk_popover_class_init (GtkPopoverClass *klass)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2017-07-08 10:04:44 +00:00
|
|
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
object_class->dispose = gtk_popover_dispose;
|
|
|
|
|
object_class->finalize = gtk_popover_finalize;
|
2013-11-12 15:55:23 +00:00
|
|
|
|
object_class->set_property = gtk_popover_set_property;
|
|
|
|
|
object_class->get_property = gtk_popover_get_property;
|
|
|
|
|
|
|
|
|
|
widget_class->realize = gtk_popover_realize;
|
2019-04-29 03:25:37 +00:00
|
|
|
|
widget_class->unrealize = gtk_popover_unrealize;
|
2013-11-12 15:55:23 +00:00
|
|
|
|
widget_class->map = gtk_popover_map;
|
|
|
|
|
widget_class->unmap = gtk_popover_unmap;
|
2019-04-29 03:25:37 +00:00
|
|
|
|
widget_class->show = gtk_popover_show;
|
|
|
|
|
widget_class->hide = gtk_popover_hide;
|
2016-10-22 14:06:14 +00:00
|
|
|
|
widget_class->measure = gtk_popover_measure;
|
2013-11-12 15:55:23 +00:00
|
|
|
|
widget_class->size_allocate = gtk_popover_size_allocate;
|
2016-11-15 16:28:34 +00:00
|
|
|
|
widget_class->snapshot = gtk_popover_snapshot;
|
2020-05-02 02:35:31 +00:00
|
|
|
|
widget_class->compute_expand = gtk_popover_compute_expand;
|
|
|
|
|
widget_class->get_request_mode = gtk_popover_get_request_mode;
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-06-12 16:54:57 +00:00
|
|
|
|
klass->activate_default = gtk_popover_activate_default;
|
|
|
|
|
|
2015-12-02 06:03:35 +00:00
|
|
|
|
properties[PROP_POINTING_TO] =
|
|
|
|
|
g_param_spec_boxed ("pointing-to",
|
|
|
|
|
P_("Pointing to"),
|
|
|
|
|
P_("Rectangle the bubble window points to"),
|
|
|
|
|
GDK_TYPE_RECTANGLE,
|
|
|
|
|
GTK_PARAM_READWRITE);
|
|
|
|
|
|
|
|
|
|
properties[PROP_POSITION] =
|
|
|
|
|
g_param_spec_enum ("position",
|
2019-04-29 03:25:37 +00:00
|
|
|
|
P_("Position"),
|
|
|
|
|
P_("Position to place the bubble window"),
|
2019-08-01 14:03:57 +00:00
|
|
|
|
GTK_TYPE_POSITION_TYPE, GTK_POS_BOTTOM,
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
2015-02-05 13:17:51 +00:00
|
|
|
|
|
2019-05-19 23:46:56 +00:00
|
|
|
|
properties[PROP_AUTOHIDE] =
|
|
|
|
|
g_param_spec_boolean ("autohide",
|
|
|
|
|
P_("Autohide"),
|
2019-08-29 12:50:20 +00:00
|
|
|
|
P_("Whether to dismiss the popover on outside clicks"),
|
2019-04-29 03:25:37 +00:00
|
|
|
|
TRUE,
|
|
|
|
|
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
2014-01-22 15:43:37 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
properties[PROP_DEFAULT_WIDGET] =
|
|
|
|
|
g_param_spec_object ("default-widget",
|
|
|
|
|
P_("Default widget"),
|
|
|
|
|
P_("The default widget"),
|
|
|
|
|
GTK_TYPE_WIDGET,
|
|
|
|
|
GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
|
2014-01-22 15:43:37 +00:00
|
|
|
|
|
2019-05-22 00:42:07 +00:00
|
|
|
|
properties[PROP_HAS_ARROW] =
|
|
|
|
|
g_param_spec_boolean ("has-arrow",
|
|
|
|
|
P_("Has Arrow"),
|
|
|
|
|
P_("Whether to draw an arrow"),
|
|
|
|
|
TRUE,
|
|
|
|
|
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
|
|
|
|
|
2020-03-24 16:29:26 +00:00
|
|
|
|
properties[PROP_MNEMONICS_VISIBLE] =
|
|
|
|
|
g_param_spec_boolean ("mnemonics-visible",
|
|
|
|
|
P_("Mnemonics visible"),
|
|
|
|
|
P_("Whether mnemonics are currently visible in this popover"),
|
|
|
|
|
FALSE,
|
|
|
|
|
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
|
|
|
|
|
2020-05-01 22:24:15 +00:00
|
|
|
|
properties[PROP_CHILD] =
|
|
|
|
|
g_param_spec_object ("child",
|
|
|
|
|
P_("Child"),
|
|
|
|
|
P_("The child widget"),
|
|
|
|
|
GTK_TYPE_WIDGET,
|
|
|
|
|
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
|
|
|
|
|
2020-10-13 12:26:41 +00:00
|
|
|
|
properties[PROP_CASCADE_POPDOWN] =
|
|
|
|
|
g_param_spec_boolean ("cascade-popdown",
|
|
|
|
|
P_("Cascade popdown"),
|
2020-11-25 18:59:16 +00:00
|
|
|
|
P_("Whether the popover pops down after a child popover"),
|
2020-11-03 15:23:34 +00:00
|
|
|
|
FALSE,
|
2020-10-13 12:26:41 +00:00
|
|
|
|
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
|
2014-01-22 15:43:37 +00:00
|
|
|
|
|
2020-11-17 03:46:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* GtkPopover::closed:
|
|
|
|
|
* @self: the #GtkPopover which received the signal
|
|
|
|
|
*
|
|
|
|
|
* The ::closed signal is emitted when the popover is closed.
|
|
|
|
|
*/
|
2019-04-29 03:25:37 +00:00
|
|
|
|
signals[CLOSED] =
|
|
|
|
|
g_signal_new (I_("closed"),
|
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
|
G_STRUCT_OFFSET (GtkPopoverClass, closed),
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
G_TYPE_NONE,
|
|
|
|
|
0);
|
2019-06-12 16:54:57 +00:00
|
|
|
|
|
2020-11-17 03:46:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* GtkPopover::activate-default:
|
|
|
|
|
* @self: the #GtkPopover which received the signal
|
|
|
|
|
*
|
|
|
|
|
* The ::activate-default signal is a
|
2020-11-17 03:58:53 +00:00
|
|
|
|
* [keybinding signal][GtkSignalAction]
|
2020-11-17 03:46:17 +00:00
|
|
|
|
* which gets emitted when the user activates the default widget
|
|
|
|
|
* of @self.
|
|
|
|
|
*/
|
2019-06-12 16:54:57 +00:00
|
|
|
|
signals[ACTIVATE_DEFAULT] =
|
|
|
|
|
g_signal_new (I_("activate-default"),
|
|
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
|
|
|
|
G_STRUCT_OFFSET (GtkPopoverClass, activate_default),
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
G_TYPE_NONE,
|
|
|
|
|
0);
|
2014-01-22 15:43:37 +00:00
|
|
|
|
|
2020-03-17 21:24:09 +00:00
|
|
|
|
add_arrow_bindings (widget_class, GDK_KEY_Up, GTK_DIR_UP);
|
|
|
|
|
add_arrow_bindings (widget_class, GDK_KEY_Down, GTK_DIR_DOWN);
|
|
|
|
|
add_arrow_bindings (widget_class, GDK_KEY_Left, GTK_DIR_LEFT);
|
|
|
|
|
add_arrow_bindings (widget_class, GDK_KEY_Right, GTK_DIR_RIGHT);
|
|
|
|
|
|
|
|
|
|
add_tab_bindings (widget_class, 0, GTK_DIR_TAB_FORWARD);
|
|
|
|
|
add_tab_bindings (widget_class, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
|
|
|
|
|
add_tab_bindings (widget_class, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
|
|
|
|
|
add_tab_bindings (widget_class, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
|
|
|
|
|
|
|
|
|
|
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, 0,
|
|
|
|
|
"activate-default", NULL);
|
|
|
|
|
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_ISO_Enter, 0,
|
|
|
|
|
"activate-default", NULL);
|
|
|
|
|
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Enter, 0,
|
|
|
|
|
"activate-default", NULL);
|
2020-03-17 21:24:09 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_widget_class_set_css_name (widget_class, "popover");
|
2014-01-22 15:43:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-20 02:50:35 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_new:
|
|
|
|
|
*
|
|
|
|
|
* Creates a new popover.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the new popover
|
|
|
|
|
*/
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkWidget *
|
2020-02-24 12:21:46 +00:00
|
|
|
|
gtk_popover_new (void)
|
2014-01-22 15:43:37 +00:00
|
|
|
|
{
|
2020-02-24 12:21:46 +00:00
|
|
|
|
return g_object_new (GTK_TYPE_POPOVER, NULL);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
}
|
2016-09-28 17:53:10 +00:00
|
|
|
|
|
2020-05-01 22:24:15 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_set_child:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
* @child: (allow-none): the child widget
|
|
|
|
|
*
|
|
|
|
|
* Sets the child widget of @popover.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gtk_popover_set_child (GtkPopover *popover,
|
|
|
|
|
GtkWidget *child)
|
|
|
|
|
{
|
2020-05-02 02:35:31 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
2020-05-01 22:24:15 +00:00
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
|
|
|
|
g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
|
|
|
|
|
|
2020-05-02 02:35:31 +00:00
|
|
|
|
if (priv->child == child)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
g_clear_pointer (&priv->child, gtk_widget_unparent);
|
|
|
|
|
|
|
|
|
|
if (child)
|
|
|
|
|
{
|
|
|
|
|
priv->child = child;
|
|
|
|
|
gtk_widget_set_parent (child, priv->contents_widget);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-01 22:24:15 +00:00
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_CHILD]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_get_child:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
*
|
|
|
|
|
* Gets the child widget of @popover.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (nullable) (transfer none): the child widget of @popover
|
|
|
|
|
*/
|
|
|
|
|
GtkWidget *
|
|
|
|
|
gtk_popover_get_child (GtkPopover *popover)
|
|
|
|
|
{
|
2020-05-02 02:35:31 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
2020-05-01 22:24:15 +00:00
|
|
|
|
g_return_val_if_fail (GTK_IS_POPOVER (popover), NULL);
|
|
|
|
|
|
2020-05-02 02:35:31 +00:00
|
|
|
|
return priv->child;
|
2020-05-01 22:24:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-04-20 02:50:35 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_set_default_widget:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
* @widget: (allow-none): a child widget of @popover to set as
|
|
|
|
|
* the default, or %NULL to unset the default widget for the popover
|
|
|
|
|
*
|
|
|
|
|
* The default widget is the widget that’s activated when the user
|
|
|
|
|
* presses Enter in a dialog (for example). This function sets or
|
|
|
|
|
* unsets the default widget for a #GtkPopover.
|
|
|
|
|
*/
|
2019-04-29 03:25:37 +00:00
|
|
|
|
void
|
|
|
|
|
gtk_popover_set_default_widget (GtkPopover *popover,
|
|
|
|
|
GtkWidget *widget)
|
2013-11-12 15:55:23 +00:00
|
|
|
|
{
|
2018-03-29 18:15:39 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
2014-01-22 15:43:37 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
if (priv->default_widget == widget)
|
|
|
|
|
return;
|
2013-11-11 09:36:51 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
if (priv->default_widget)
|
2013-11-13 09:47:13 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
_gtk_widget_set_has_default (priv->default_widget, FALSE);
|
|
|
|
|
gtk_widget_queue_draw (priv->default_widget);
|
|
|
|
|
g_object_notify (G_OBJECT (priv->default_widget), "has-default");
|
2013-11-13 09:47:13 +00:00
|
|
|
|
}
|
2013-11-11 09:36:51 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
g_set_object (&priv->default_widget, widget);
|
2013-11-12 11:56:40 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
if (priv->default_widget)
|
2013-11-12 11:56:40 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
_gtk_widget_set_has_default (priv->default_widget, TRUE);
|
|
|
|
|
gtk_widget_queue_draw (priv->default_widget);
|
|
|
|
|
g_object_notify (G_OBJECT (priv->default_widget), "has-default");
|
2013-11-12 11:56:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_DEFAULT_WIDGET]);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 03:04:06 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_popover_shortcut_manager_interface_init (GtkShortcutManagerInterface *iface)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-11 16:32:08 +00:00
|
|
|
|
static void
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_native_interface_init (GtkNativeInterface *iface)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
iface->get_surface = gtk_popover_native_get_surface;
|
|
|
|
|
iface->get_renderer = gtk_popover_native_get_renderer;
|
|
|
|
|
iface->get_surface_transform = gtk_popover_native_get_surface_transform;
|
2020-12-02 10:59:23 +00:00
|
|
|
|
iface->layout = gtk_popover_native_layout;
|
2013-01-11 16:32:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-02 02:35:31 +00:00
|
|
|
|
static GtkBuildableIface *parent_buildable_iface;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_popover_buildable_add_child (GtkBuildable *buildable,
|
|
|
|
|
GtkBuilder *builder,
|
|
|
|
|
GObject *child,
|
2020-07-24 18:40:36 +00:00
|
|
|
|
const char *type)
|
2020-05-02 02:35:31 +00:00
|
|
|
|
{
|
|
|
|
|
if (GTK_IS_WIDGET (child))
|
2020-05-13 12:11:41 +00:00
|
|
|
|
gtk_popover_set_child (GTK_POPOVER (buildable), GTK_WIDGET (child));
|
2020-05-02 02:35:31 +00:00
|
|
|
|
else
|
|
|
|
|
parent_buildable_iface->add_child (buildable, builder, child, type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_popover_buildable_init (GtkBuildableIface *iface)
|
|
|
|
|
{
|
|
|
|
|
parent_buildable_iface = g_type_interface_peek_parent (iface);
|
|
|
|
|
|
|
|
|
|
iface->add_child = gtk_popover_buildable_add_child;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-13 14:11:21 +00:00
|
|
|
|
/**
|
2013-11-12 15:55:23 +00:00
|
|
|
|
* gtk_popover_set_pointing_to:
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* @popover: a #GtkPopover
|
2013-01-11 16:32:08 +00:00
|
|
|
|
* @rect: rectangle to point to
|
|
|
|
|
*
|
2014-02-18 03:37:55 +00:00
|
|
|
|
* Sets the rectangle that @popover will point to, in the
|
2020-02-24 12:21:46 +00:00
|
|
|
|
* coordinate space of the @popover parent.
|
2013-11-13 14:11:21 +00:00
|
|
|
|
**/
|
2013-01-11 16:32:08 +00:00
|
|
|
|
void
|
2014-02-09 03:18:15 +00:00
|
|
|
|
gtk_popover_set_pointing_to (GtkPopover *popover,
|
2014-02-04 21:33:25 +00:00
|
|
|
|
const GdkRectangle *rect)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
2013-11-12 15:55:23 +00:00
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
if (rect)
|
|
|
|
|
{
|
|
|
|
|
priv->pointing_to = *rect;
|
|
|
|
|
priv->has_pointing_to = TRUE;
|
2020-02-27 17:07:38 +00:00
|
|
|
|
priv->pointing_to.width = MAX (priv->pointing_to.width, 1);
|
|
|
|
|
priv->pointing_to.height = MAX (priv->pointing_to.height, 1);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
priv->has_pointing_to = FALSE;
|
|
|
|
|
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POINTING_TO]);
|
2020-02-27 17:08:46 +00:00
|
|
|
|
|
|
|
|
|
if (gtk_widget_is_visible (GTK_WIDGET (popover)))
|
|
|
|
|
present_popup (popover);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-13 14:11:21 +00:00
|
|
|
|
/**
|
2013-11-12 15:55:23 +00:00
|
|
|
|
* gtk_popover_get_pointing_to:
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* @popover: a #GtkPopover
|
2013-01-11 16:32:08 +00:00
|
|
|
|
* @rect: (out): location to store the rectangle
|
|
|
|
|
*
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* If a rectangle to point to has been set, this function will
|
|
|
|
|
* return %TRUE and fill in @rect with such rectangle, otherwise
|
|
|
|
|
* it will return %FALSE and fill in @rect with the attached
|
|
|
|
|
* widget coordinates.
|
2013-01-11 16:32:08 +00:00
|
|
|
|
*
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* Returns: %TRUE if a rectangle to point to was set.
|
|
|
|
|
**/
|
2013-01-11 16:32:08 +00:00
|
|
|
|
gboolean
|
2014-02-04 21:33:25 +00:00
|
|
|
|
gtk_popover_get_pointing_to (GtkPopover *popover,
|
|
|
|
|
GdkRectangle *rect)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2016-08-09 17:29:41 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2013-11-12 15:55:23 +00:00
|
|
|
|
g_return_val_if_fail (GTK_IS_POPOVER (popover), FALSE);
|
2017-06-03 12:38:56 +00:00
|
|
|
|
g_return_val_if_fail (rect != NULL, FALSE);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2017-06-03 12:38:56 +00:00
|
|
|
|
if (priv->has_pointing_to)
|
|
|
|
|
*rect = priv->pointing_to;
|
2020-02-24 12:21:46 +00:00
|
|
|
|
else
|
2019-05-05 23:53:02 +00:00
|
|
|
|
{
|
|
|
|
|
graphene_rect_t r;
|
2020-02-24 12:21:46 +00:00
|
|
|
|
GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (popover));
|
2019-05-05 23:53:02 +00:00
|
|
|
|
|
2020-02-24 12:21:46 +00:00
|
|
|
|
if (!gtk_widget_compute_bounds (parent, parent, &r))
|
2019-05-05 23:53:02 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
rect->x = floorf (r.origin.x);
|
|
|
|
|
rect->y = floorf (r.origin.y);
|
|
|
|
|
rect->width = ceilf (r.size.width);
|
|
|
|
|
rect->height = ceilf (r.size.height);
|
|
|
|
|
}
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
|
|
|
|
return priv->has_pointing_to;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-13 14:11:21 +00:00
|
|
|
|
/**
|
2013-11-12 15:55:23 +00:00
|
|
|
|
* gtk_popover_set_position:
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
* @position: preferred popover position
|
2013-01-11 16:32:08 +00:00
|
|
|
|
*
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* Sets the preferred position for @popover to appear. If the @popover
|
|
|
|
|
* is currently visible, it will be immediately updated.
|
2013-01-11 16:32:08 +00:00
|
|
|
|
*
|
2014-02-02 06:22:14 +00:00
|
|
|
|
* This preference will be respected where possible, although
|
|
|
|
|
* on lack of space (eg. if close to the window edges), the
|
|
|
|
|
* #GtkPopover may choose to appear on the opposite side
|
2013-11-13 14:11:21 +00:00
|
|
|
|
**/
|
2013-01-11 16:32:08 +00:00
|
|
|
|
void
|
2013-11-12 15:55:23 +00:00
|
|
|
|
gtk_popover_set_position (GtkPopover *popover,
|
|
|
|
|
GtkPositionType position)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2019-04-29 03:25:37 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
2013-11-12 15:55:23 +00:00
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
if (priv->position == position)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
priv->position = position;
|
2019-05-05 23:53:02 +00:00
|
|
|
|
priv->final_position = position;
|
2019-04-29 03:25:37 +00:00
|
|
|
|
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POSITION]);
|
2020-02-27 17:08:46 +00:00
|
|
|
|
|
2021-02-14 01:25:24 +00:00
|
|
|
|
gtk_widget_queue_resize (GTK_WIDGET (popover));
|
|
|
|
|
|
2020-02-27 17:08:46 +00:00
|
|
|
|
if (gtk_widget_is_visible (GTK_WIDGET (popover)))
|
|
|
|
|
present_popup (popover);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-13 14:11:21 +00:00
|
|
|
|
/**
|
2013-11-12 15:55:23 +00:00
|
|
|
|
* gtk_popover_get_position:
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* @popover: a #GtkPopover
|
2013-01-11 16:32:08 +00:00
|
|
|
|
*
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* Returns the preferred position of @popover.
|
2013-01-11 16:32:08 +00:00
|
|
|
|
*
|
2013-11-13 14:11:21 +00:00
|
|
|
|
* Returns: The preferred position.
|
|
|
|
|
**/
|
2013-01-11 16:32:08 +00:00
|
|
|
|
GtkPositionType
|
2013-11-12 15:55:23 +00:00
|
|
|
|
gtk_popover_get_position (GtkPopover *popover)
|
2013-01-11 16:32:08 +00:00
|
|
|
|
{
|
2018-03-29 18:15:39 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
2013-11-12 15:55:23 +00:00
|
|
|
|
g_return_val_if_fail (GTK_IS_POPOVER (popover), GTK_POS_TOP);
|
2013-01-11 16:32:08 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
return priv->position;
|
2013-01-11 16:32:08 +00:00
|
|
|
|
}
|
2014-01-10 11:04:17 +00:00
|
|
|
|
|
|
|
|
|
/**
|
2019-05-19 23:46:56 +00:00
|
|
|
|
* gtk_popover_set_autohide:
|
2014-01-10 11:04:17 +00:00
|
|
|
|
* @popover: a #GtkPopover
|
2019-05-19 23:46:56 +00:00
|
|
|
|
* @autohide: #TRUE to dismiss the popover on outside clicks
|
2014-01-10 11:04:17 +00:00
|
|
|
|
*
|
2019-05-19 23:46:56 +00:00
|
|
|
|
* Sets whether @popover is modal.
|
|
|
|
|
*
|
|
|
|
|
* A modal popover will grab the keyboard focus on it when being
|
2014-01-10 11:04:17 +00:00
|
|
|
|
* displayed. Clicking outside the popover area or pressing Esc will
|
2019-05-19 23:46:56 +00:00
|
|
|
|
* dismiss the popover.
|
2019-07-24 13:45:34 +00:00
|
|
|
|
*
|
|
|
|
|
* Called this function on an already showing popup with a new autohide value
|
|
|
|
|
* different from the current one, will cause the popup to be hidden.
|
2014-01-10 11:04:17 +00:00
|
|
|
|
**/
|
|
|
|
|
void
|
2019-05-19 23:46:56 +00:00
|
|
|
|
gtk_popover_set_autohide (GtkPopover *popover,
|
|
|
|
|
gboolean autohide)
|
2014-01-10 11:04:17 +00:00
|
|
|
|
{
|
2016-08-09 17:29:41 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
2014-01-10 11:04:17 +00:00
|
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
|
|
|
|
|
2019-05-19 23:46:56 +00:00
|
|
|
|
autohide = autohide != FALSE;
|
2014-02-09 05:48:38 +00:00
|
|
|
|
|
2019-05-19 23:46:56 +00:00
|
|
|
|
if (priv->autohide == autohide)
|
2014-01-10 11:04:17 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2019-05-19 23:46:56 +00:00
|
|
|
|
priv->autohide = autohide;
|
2014-01-10 11:04:17 +00:00
|
|
|
|
|
2019-07-24 13:45:34 +00:00
|
|
|
|
gtk_widget_unrealize (GTK_WIDGET (popover));
|
|
|
|
|
|
2019-05-19 23:46:56 +00:00
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_AUTOHIDE]);
|
2014-01-10 11:04:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2019-05-19 23:46:56 +00:00
|
|
|
|
* gtk_popover_get_autohide:
|
2014-01-10 11:04:17 +00:00
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
*
|
2019-05-19 23:46:56 +00:00
|
|
|
|
* Returns whether the popover is modal.
|
|
|
|
|
*
|
|
|
|
|
* See gtk_popover_set_autohide() for the
|
|
|
|
|
* implications of this.
|
2014-01-10 11:04:17 +00:00
|
|
|
|
*
|
|
|
|
|
* Returns: #TRUE if @popover is modal
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
2019-05-19 23:46:56 +00:00
|
|
|
|
gtk_popover_get_autohide (GtkPopover *popover)
|
2014-01-10 11:04:17 +00:00
|
|
|
|
{
|
2018-03-29 18:15:39 +00:00
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
2014-01-10 11:04:17 +00:00
|
|
|
|
g_return_val_if_fail (GTK_IS_POPOVER (popover), FALSE);
|
|
|
|
|
|
2019-05-19 23:46:56 +00:00
|
|
|
|
return priv->autohide;
|
2014-01-10 11:04:17 +00:00
|
|
|
|
}
|
2014-02-04 19:45:53 +00:00
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_popup:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
*
|
|
|
|
|
* Pops @popover up. This is different than a gtk_widget_show() call
|
|
|
|
|
* in that it shows the popover with a transition. If you want to show
|
|
|
|
|
* the popover without a transition, use gtk_widget_show().
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gtk_popover_popup (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (GTK_WIDGET (popover));
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-13 12:26:41 +00:00
|
|
|
|
static void
|
|
|
|
|
cascade_popdown (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *parent;
|
|
|
|
|
|
|
|
|
|
/* Do not trigger cascade close from non-modal popovers */
|
|
|
|
|
if (!gtk_popover_get_autohide (popover))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
parent = gtk_widget_get_parent (GTK_WIDGET (popover));
|
|
|
|
|
|
|
|
|
|
while (parent)
|
|
|
|
|
{
|
|
|
|
|
if (GTK_IS_POPOVER (parent))
|
|
|
|
|
{
|
|
|
|
|
if (gtk_popover_get_cascade_popdown (GTK_POPOVER (parent)))
|
|
|
|
|
gtk_widget_hide (parent);
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parent = gtk_widget_get_parent (parent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_popdown:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
*
|
|
|
|
|
* Pops @popover down.This is different than a gtk_widget_hide() call
|
|
|
|
|
* in that it shows the popover with a transition. If you want to hide
|
|
|
|
|
* the popover without a transition, use gtk_widget_hide().
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gtk_popover_popdown (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
|
|
|
|
|
|
|
|
|
gtk_widget_hide (GTK_WIDGET (popover));
|
2020-10-13 12:26:41 +00:00
|
|
|
|
|
|
|
|
|
cascade_popdown (popover);
|
2019-04-29 03:25:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-04-17 04:10:06 +00:00
|
|
|
|
GtkWidget *
|
2019-04-29 03:25:37 +00:00
|
|
|
|
gtk_popover_get_contents_widget (GtkPopover *popover)
|
2016-08-10 16:28:14 +00:00
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
2019-04-29 03:25:37 +00:00
|
|
|
|
return priv->contents_widget;
|
2016-08-10 16:28:14 +00:00
|
|
|
|
}
|
2019-05-22 00:42:07 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_set_has_arrow:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
* @has_arrow: %TRUE to draw an arrow
|
|
|
|
|
*
|
|
|
|
|
* Sets whether this popover should draw an arrow
|
|
|
|
|
* pointing at the widget it is relative to.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gtk_popover_set_has_arrow (GtkPopover *popover,
|
|
|
|
|
gboolean has_arrow)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
|
|
|
|
|
|
|
|
|
if (priv->has_arrow == has_arrow)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
priv->has_arrow = has_arrow;
|
|
|
|
|
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_HAS_ARROW]);
|
|
|
|
|
gtk_widget_queue_resize (GTK_WIDGET (popover));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_get_has_arrow:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
*
|
|
|
|
|
* Gets whether this popover is showing an arrow
|
|
|
|
|
* pointing at the widget that it is relative to.
|
|
|
|
|
*
|
|
|
|
|
* Returns: whether the popover has an arrow
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
gtk_popover_get_has_arrow (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GTK_IS_POPOVER (popover), TRUE);
|
|
|
|
|
|
|
|
|
|
return priv->has_arrow;
|
|
|
|
|
}
|
2020-03-24 16:29:26 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_set_mnemonics_visible:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
* @mnemonics_visible: the new value
|
|
|
|
|
*
|
|
|
|
|
* Sets the #GtkPopover:mnemonics-visible property.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gtk_popover_set_mnemonics_visible (GtkPopover *popover,
|
|
|
|
|
gboolean mnemonics_visible)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
|
|
|
|
|
|
|
|
|
if (priv->mnemonics_visible == mnemonics_visible)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
priv->mnemonics_visible = mnemonics_visible;
|
|
|
|
|
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_MNEMONICS_VISIBLE]);
|
|
|
|
|
gtk_widget_queue_resize (GTK_WIDGET (popover));
|
2020-03-24 16:45:43 +00:00
|
|
|
|
|
|
|
|
|
if (priv->mnemonics_display_timeout_id)
|
|
|
|
|
{
|
|
|
|
|
g_source_remove (priv->mnemonics_display_timeout_id);
|
|
|
|
|
priv->mnemonics_display_timeout_id = 0;
|
|
|
|
|
}
|
2020-03-24 16:29:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_get_mnemonics_visible:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
*
|
|
|
|
|
* Gets the value of the #GtkPopover:mnemonics-visible property.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if mnemonics are supposed to be visible in this popover
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
gtk_popover_get_mnemonics_visible (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GTK_IS_POPOVER (popover), FALSE);
|
|
|
|
|
|
|
|
|
|
return priv->mnemonics_visible;
|
|
|
|
|
}
|
2020-03-24 16:45:43 +00:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gtk_popover_disable_auto_mnemonics (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
priv->disable_auto_mnemonics = TRUE;
|
|
|
|
|
}
|
2020-08-08 00:06:08 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_set_offset:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
* @x_offset: the x offset to adjust the position by
|
|
|
|
|
* @y_offset: the y offset to adjust the position by
|
|
|
|
|
*
|
|
|
|
|
* Sets the offset to use when calculating the position of the popover.
|
|
|
|
|
*
|
|
|
|
|
* These values are used when preparing the #GtkPopupLayout for positioning
|
|
|
|
|
* the popover.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gtk_popover_set_offset (GtkPopover *popover,
|
|
|
|
|
int x_offset,
|
|
|
|
|
int y_offset)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
|
|
|
|
|
|
|
|
|
if (priv->x_offset != x_offset || priv->y_offset != y_offset)
|
|
|
|
|
{
|
|
|
|
|
priv->x_offset = x_offset;
|
|
|
|
|
priv->y_offset = y_offset;
|
|
|
|
|
|
|
|
|
|
gtk_widget_queue_resize (GTK_WIDGET (popover));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_get_offset:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
* @x_offset: (out) (nullable): a location for the x_offset
|
|
|
|
|
* @y_offset: (out) (nullable): a location for the y_offset
|
|
|
|
|
*
|
|
|
|
|
* Gets the offset previous set with gtk_popover_set_offset().
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gtk_popover_get_offset (GtkPopover *popover,
|
|
|
|
|
int *x_offset,
|
|
|
|
|
int *y_offset)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_POPOVER (popover));
|
|
|
|
|
|
|
|
|
|
if (x_offset)
|
|
|
|
|
*x_offset = priv->x_offset;
|
|
|
|
|
|
|
|
|
|
if (y_offset)
|
|
|
|
|
*y_offset = priv->y_offset;
|
|
|
|
|
}
|
2020-10-13 12:26:41 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_set_cascade_popdown:
|
|
|
|
|
* @popover: A #GtkPopover
|
|
|
|
|
* @cascade_popdown: #TRUE if the popover should follow a child closing
|
|
|
|
|
*
|
|
|
|
|
* If @cascade_popdown is #TRUE, the popover will be closed when a child
|
|
|
|
|
* modal popover is closed. If #FALSE, @popover will stay visible.
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
gtk_popover_set_cascade_popdown (GtkPopover *popover,
|
|
|
|
|
gboolean cascade_popdown)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
if (priv->cascade_popdown != !!cascade_popdown)
|
|
|
|
|
{
|
|
|
|
|
priv->cascade_popdown = !!cascade_popdown;
|
|
|
|
|
g_object_notify (G_OBJECT (popover), "cascade-popdown");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_popover_get_cascade_popdown:
|
|
|
|
|
* @popover: a #GtkPopover
|
|
|
|
|
*
|
|
|
|
|
* Returns whether the popover will close after a modal child is closed.
|
|
|
|
|
*
|
|
|
|
|
* Returns: #TRUE if @popover will close after a modal child.
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
gtk_popover_get_cascade_popdown (GtkPopover *popover)
|
|
|
|
|
{
|
|
|
|
|
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
|
|
|
|
|
|
|
|
|
return priv->cascade_popdown;
|
|
|
|
|
}
|