1/*
2 * Copyright © 2020 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Matthias Clasen <mclasen@redhat.com>
18 */
19
20#include "config.h"
21
22#include "gdk-private.h"
23#include "gdkintl.h"
24#include "gdkpopupprivate.h"
25
26/**
27 * GdkPopup:
28 *
29 * A `GdkPopup` is a surface that is attached to another surface.
30 *
31 * The `GdkPopup` is positioned relative to its parent surface.
32 *
33 * `GdkPopup`s are typically used to implement menus and similar popups.
34 * They can be modal, which is indicated by the [property@GdkPopup:autohide]
35 * property.
36 */
37
38G_DEFINE_INTERFACE (GdkPopup, gdk_popup, GDK_TYPE_SURFACE)
39
40static gboolean
41gdk_popup_default_present (GdkPopup *popup,
42 int width,
43 int height,
44 GdkPopupLayout *layout)
45{
46 return FALSE;
47}
48
49static GdkGravity
50gdk_popup_default_get_surface_anchor (GdkPopup *popup)
51{
52 return GDK_GRAVITY_STATIC;
53}
54
55static GdkGravity
56gdk_popup_default_get_rect_anchor (GdkPopup *popup)
57{
58 return GDK_GRAVITY_STATIC;
59}
60
61static int
62gdk_popup_default_get_position_x (GdkPopup *popup)
63{
64 return 0;
65}
66
67static int
68gdk_popup_default_get_position_y (GdkPopup *popup)
69{
70 return 0;
71}
72
73static void
74gdk_popup_default_init (GdkPopupInterface *iface)
75{
76 iface->present = gdk_popup_default_present;
77 iface->get_surface_anchor = gdk_popup_default_get_surface_anchor;
78 iface->get_rect_anchor = gdk_popup_default_get_rect_anchor;
79 iface->get_position_x = gdk_popup_default_get_position_x;
80 iface->get_position_y = gdk_popup_default_get_position_y;
81
82 /**
83 * GdkPopup:parent: (attributes org.gtk.Property.get=gdk_popup_get_parent)
84 *
85 * The parent surface.
86 */
87 g_object_interface_install_property (g_iface: iface,
88 pspec: g_param_spec_object (name: "parent",
89 P_("Parent"),
90 P_("The parent surface"),
91 GDK_TYPE_SURFACE,
92 flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
93
94 /**
95 * GdkPopup:autohide: (attributes org.gtk.Property.get=gdk_popup_get_autohide)
96 *
97 * Whether to hide on outside clicks.
98 */
99 g_object_interface_install_property (g_iface: iface,
100 pspec: g_param_spec_boolean (name: "autohide",
101 P_("Autohide"),
102 P_("Whether to hide on outside clicks"),
103 FALSE,
104 flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
105}
106
107/**
108 * gdk_popup_present:
109 * @popup: the `GdkPopup` to show
110 * @width: the unconstrained popup width to layout
111 * @height: the unconstrained popup height to layout
112 * @layout: the `GdkPopupLayout` object used to layout
113 *
114 * Present @popup after having processed the `GdkPopupLayout` rules.
115 *
116 * If the popup was previously now showing, it will be showed,
117 * otherwise it will change position according to @layout.
118 *
119 * After calling this function, the result should be handled in response
120 * to the [signal@GdkSurface::layout] signal being emitted. The resulting
121 * popup position can be queried using [method@Gdk.Popup.get_position_x],
122 * [method@Gdk.Popup.get_position_y], and the resulting size will be sent as
123 * parameters in the layout signal. Use [method@Gdk.Popup.get_rect_anchor]
124 * and [method@Gdk.Popup.get_surface_anchor] to get the resulting anchors.
125 *
126 * Presenting may fail, for example if the @popup is set to autohide
127 * and is immediately hidden upon being presented. If presenting failed,
128 * the [signal@Gdk.Surface::layout] signal will not me emitted.
129 *
130 * Returns: %FALSE if it failed to be presented, otherwise %TRUE.
131 */
132gboolean
133gdk_popup_present (GdkPopup *popup,
134 int width,
135 int height,
136 GdkPopupLayout *layout)
137{
138 g_return_val_if_fail (GDK_IS_POPUP (popup), FALSE);
139 g_return_val_if_fail (width > 0, FALSE);
140 g_return_val_if_fail (height > 0, FALSE);
141 g_return_val_if_fail (layout != NULL, FALSE);
142
143 return GDK_POPUP_GET_IFACE (ptr: popup)->present (popup, width, height, layout);
144}
145
146/**
147 * gdk_popup_get_surface_anchor:
148 * @popup: a `GdkPopup`
149 *
150 * Gets the current popup surface anchor.
151 *
152 * The value returned may change after calling [method@Gdk.Popup.present],
153 * or after the [signal@Gdk.Surface::layout] signal is emitted.
154 *
155 * Returns: the current surface anchor value of @popup
156 */
157GdkGravity
158gdk_popup_get_surface_anchor (GdkPopup *popup)
159{
160 g_return_val_if_fail (GDK_IS_POPUP (popup), GDK_GRAVITY_STATIC);
161
162 return GDK_POPUP_GET_IFACE (ptr: popup)->get_surface_anchor (popup);
163}
164
165/**
166 * gdk_popup_get_rect_anchor:
167 * @popup: a `GdkPopup`
168 *
169 * Gets the current popup rectangle anchor.
170 *
171 * The value returned may change after calling [method@Gdk.Popup.present],
172 * or after the [signal@Gdk.Surface::layout] signal is emitted.
173 *
174 * Returns: the current rectangle anchor value of @popup
175 */
176GdkGravity
177gdk_popup_get_rect_anchor (GdkPopup *popup)
178{
179 g_return_val_if_fail (GDK_IS_POPUP (popup), GDK_GRAVITY_STATIC);
180
181 return GDK_POPUP_GET_IFACE (ptr: popup)->get_rect_anchor (popup);
182}
183
184/**
185 * gdk_popup_get_parent: (attributes org.gtk.Method.get_property=parent)
186 * @popup: a `GdkPopup`
187 *
188 * Returns the parent surface of a popup.
189 *
190 * Returns: (transfer none) (nullable): the parent surface
191 */
192GdkSurface *
193gdk_popup_get_parent (GdkPopup *popup)
194{
195 GdkSurface *surface;
196
197 g_return_val_if_fail (GDK_IS_POPUP (popup), NULL);
198
199 g_object_get (object: popup, first_property_name: "parent", &surface, NULL);
200
201 if (surface)
202 g_object_unref (object: surface);
203
204 return surface;
205}
206
207/**
208 * gdk_popup_get_position_x:
209 * @popup: a `GdkPopup`
210 *
211 * Obtains the position of the popup relative to its parent.
212 *
213 * Returns: the X coordinate of @popup position
214 */
215int
216gdk_popup_get_position_x (GdkPopup *popup)
217{
218 g_return_val_if_fail (GDK_IS_POPUP (popup), 0);
219
220 return GDK_POPUP_GET_IFACE (ptr: popup)->get_position_x (popup);
221}
222
223/**
224 * gdk_popup_get_position_y:
225 * @popup: a `GdkPopup`
226 *
227 * Obtains the position of the popup relative to its parent.
228 *
229 * Returns: the Y coordinate of @popup position
230 */
231int
232gdk_popup_get_position_y (GdkPopup *popup)
233{
234 g_return_val_if_fail (GDK_IS_POPUP (popup), 0);
235
236 return GDK_POPUP_GET_IFACE (ptr: popup)->get_position_y (popup);
237}
238
239/**
240 * gdk_popup_get_autohide: (attributes org.gtk.Method.get_property=autohide)
241 * @popup: a `GdkPopup`
242 *
243 * Returns whether this popup is set to hide on outside clicks.
244 *
245 * Returns: %TRUE if @popup will autohide
246 */
247gboolean
248gdk_popup_get_autohide (GdkPopup *popup)
249{
250 gboolean autohide;
251
252 g_return_val_if_fail (GDK_IS_POPUP (popup), FALSE);
253
254 g_object_get (object: popup, first_property_name: "autohide", &autohide, NULL);
255
256 return autohide;
257}
258
259guint
260gdk_popup_install_properties (GObjectClass *object_class,
261 guint first_prop)
262{
263 /**
264 * GdkToplevel:parent:
265 *
266 * The parent surface of the toplevel.
267 */
268 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_POPUP_PROP_PARENT, name: "parent");
269
270 /**
271 * GdkToplevel:autohide:
272 *
273 * Whether the toplevel should be modal with respect to its parent.
274 */
275 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_POPUP_PROP_AUTOHIDE, name: "autohide");
276
277 return GDK_POPUP_NUM_PROPERTIES;
278}
279

source code of gtk/gdk/gdkpopup.c