Merge branch 'popup-shadow-width' into 'master'
Support shadows on popovers See merge request GNOME/gtk!3089
This commit is contained in:
@@ -75,6 +75,10 @@
|
||||
<title>Index of all symbols</title>
|
||||
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-4-2" role="4.2">
|
||||
<title>Index of new symbols in 4.2</title>
|
||||
<xi:include href="xml/api-index-4.2.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="api-index-deprecated" role="deprecated">
|
||||
<title>Index of deprecated symbols</title>
|
||||
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
|
||||
|
||||
@@ -627,6 +627,8 @@ gdk_popup_layout_set_anchor_hints
|
||||
gdk_popup_layout_get_anchor_hints
|
||||
gdk_popup_layout_set_offset
|
||||
gdk_popup_layout_get_offset
|
||||
gdk_popup_layout_set_shadow_width
|
||||
gdk_popup_layout_get_shadow_width
|
||||
<SUBSECTION Standard>
|
||||
GDK_TYPE_POPUP_LAYOUT
|
||||
gdk_popup_layout_get_type
|
||||
|
||||
@@ -74,6 +74,10 @@ struct _GdkPopupLayout
|
||||
GdkAnchorHints anchor_hints;
|
||||
int dx;
|
||||
int dy;
|
||||
int shadow_left;
|
||||
int shadow_right;
|
||||
int shadow_top;
|
||||
int shadow_bottom;
|
||||
};
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GdkPopupLayout, gdk_popup_layout,
|
||||
@@ -165,6 +169,10 @@ gdk_popup_layout_copy (GdkPopupLayout *layout)
|
||||
new_layout->anchor_hints = layout->anchor_hints;
|
||||
new_layout->dx = layout->dx;
|
||||
new_layout->dy = layout->dy;
|
||||
new_layout->shadow_left = layout->shadow_left;
|
||||
new_layout->shadow_right = layout->shadow_right;
|
||||
new_layout->shadow_top = layout->shadow_top;
|
||||
new_layout->shadow_bottom = layout->shadow_bottom;
|
||||
|
||||
return new_layout;
|
||||
}
|
||||
@@ -191,7 +199,11 @@ gdk_popup_layout_equal (GdkPopupLayout *layout,
|
||||
layout->surface_anchor == other->surface_anchor &&
|
||||
layout->anchor_hints == other->anchor_hints &&
|
||||
layout->dx == other->dx &&
|
||||
layout->dy == other->dy);
|
||||
layout->dy == other->dy &&
|
||||
layout->shadow_left == other->shadow_left &&
|
||||
layout->shadow_right == other->shadow_right &&
|
||||
layout->shadow_top == other->shadow_top &&
|
||||
layout->shadow_bottom == other->shadow_bottom);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,3 +358,59 @@ gdk_popup_layout_get_offset (GdkPopupLayout *layout,
|
||||
if (dy)
|
||||
*dy = layout->dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_set_shadow_width:
|
||||
* @layout: a #GdkPopupLayout
|
||||
* @left: width of the left part of the shadow
|
||||
* @right: width of the right part of the shadow
|
||||
* @top: height of the top part of the shadow
|
||||
* @bottom: height of the bottom part of the shadow
|
||||
*
|
||||
* The shadow width corresponds to the part of the computed surface size
|
||||
* that would consist of the shadow margin surrounding the window, would
|
||||
* there be any.
|
||||
*
|
||||
* Since: 4.2
|
||||
*/
|
||||
void
|
||||
gdk_popup_layout_set_shadow_width (GdkPopupLayout *layout,
|
||||
int left,
|
||||
int right,
|
||||
int top,
|
||||
int bottom)
|
||||
{
|
||||
layout->shadow_left = left;
|
||||
layout->shadow_right = right;
|
||||
layout->shadow_top = top;
|
||||
layout->shadow_bottom = bottom;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_get_shadow_width:
|
||||
* @layout: a #GdkPopupLayout
|
||||
* @left: (out): return location for the left shadow width
|
||||
* @right: (out): return location for the right shadow width
|
||||
* @top: (out): return location for the top shadow width
|
||||
* @bottom: (out): return location for the bottom shadow width
|
||||
*
|
||||
* Obtains the shadow widths of this layout.
|
||||
*
|
||||
* Since: 4.2
|
||||
*/
|
||||
void
|
||||
gdk_popup_layout_get_shadow_width (GdkPopupLayout *layout,
|
||||
int *left,
|
||||
int *right,
|
||||
int *top,
|
||||
int *bottom)
|
||||
{
|
||||
if (left)
|
||||
*left = layout->shadow_left;
|
||||
if (right)
|
||||
*right = layout->shadow_right;
|
||||
if (top)
|
||||
*top = layout->shadow_top;
|
||||
if (bottom)
|
||||
*bottom = layout->shadow_bottom;
|
||||
}
|
||||
|
||||
@@ -137,6 +137,20 @@ void gdk_popup_layout_get_offset (GdkPopupLayout
|
||||
int *dx,
|
||||
int *dy);
|
||||
|
||||
GDK_AVAILABLE_IN_4_2
|
||||
void gdk_popup_layout_set_shadow_width (GdkPopupLayout *layout,
|
||||
int left,
|
||||
int right,
|
||||
int top,
|
||||
int bottom);
|
||||
GDK_AVAILABLE_IN_4_2
|
||||
void gdk_popup_layout_get_shadow_width (GdkPopupLayout *layout,
|
||||
int *left,
|
||||
int *right,
|
||||
int *top,
|
||||
int *bottom);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_POPUP_LAYOUT_H__ */
|
||||
|
||||
@@ -66,6 +66,12 @@ gdk_macos_popup_surface_layout (GdkMacosPopupSurface *self,
|
||||
monitor = _gdk_macos_surface_get_best_monitor (GDK_MACOS_SURFACE (self));
|
||||
gdk_macos_monitor_get_workarea (monitor, &bounds);
|
||||
|
||||
gdk_popup_layout_get_shadow_width (layout,
|
||||
&self->parent_instance.shadow_left,
|
||||
&self->parent_instance.shadow_right,
|
||||
&self->parent_instance.shadow_top,
|
||||
&self->parent_instance.shadow_bottom);
|
||||
|
||||
gdk_surface_layout_popup_helper (GDK_SURFACE (self),
|
||||
width,
|
||||
height,
|
||||
|
||||
@@ -630,12 +630,19 @@ static void
|
||||
configure_popup_geometry (GdkSurface *surface)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
int x, y;
|
||||
int width, height;
|
||||
|
||||
gdk_wayland_surface_move_resize (surface,
|
||||
impl->next_layout.popup.x,
|
||||
impl->next_layout.popup.y,
|
||||
impl->next_layout.configured_width,
|
||||
impl->next_layout.configured_height);
|
||||
x = impl->next_layout.popup.x - impl->shadow_left;
|
||||
y = impl->next_layout.popup.y - impl->shadow_top;
|
||||
width =
|
||||
impl->next_layout.configured_width +
|
||||
(impl->shadow_left + impl->shadow_right);
|
||||
height =
|
||||
impl->next_layout.configured_height +
|
||||
(impl->shadow_top + impl->shadow_bottom);
|
||||
|
||||
gdk_wayland_surface_move_resize (surface, x, y, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2289,12 +2296,17 @@ calculate_popup_rect (GdkSurface *surface,
|
||||
int width, height;
|
||||
GdkRectangle anchor_rect;
|
||||
int dx, dy;
|
||||
int shadow_left, shadow_right, shadow_top, shadow_bottom;
|
||||
int x = 0, y = 0;
|
||||
|
||||
width = (impl->popup.unconstrained_width -
|
||||
(impl->shadow_left + impl->shadow_right));
|
||||
height = (impl->popup.unconstrained_height -
|
||||
(impl->shadow_top + impl->shadow_bottom));
|
||||
gdk_popup_layout_get_shadow_width (layout,
|
||||
&shadow_left,
|
||||
&shadow_right,
|
||||
&shadow_top,
|
||||
&shadow_bottom);
|
||||
|
||||
width = (impl->popup.unconstrained_width - (shadow_left + shadow_right));
|
||||
height = (impl->popup.unconstrained_height - (shadow_top + shadow_bottom));
|
||||
|
||||
anchor_rect = *gdk_popup_layout_get_anchor_rect (layout);
|
||||
gdk_popup_layout_get_offset (layout, &dx, &dy);
|
||||
@@ -2478,7 +2490,6 @@ create_dynamic_positioner (GdkSurface *surface,
|
||||
GdkPopupLayout *layout,
|
||||
gboolean ack_parent_configure)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
GdkSurface *parent = surface->parent;
|
||||
GdkWaylandSurface *parent_impl = GDK_WAYLAND_SURFACE (parent);
|
||||
GdkWaylandDisplay *display =
|
||||
@@ -2493,12 +2504,21 @@ create_dynamic_positioner (GdkSurface *surface,
|
||||
GdkGravity rect_anchor;
|
||||
GdkGravity surface_anchor;
|
||||
GdkAnchorHints anchor_hints;
|
||||
int shadow_left;
|
||||
int shadow_right;
|
||||
int shadow_top;
|
||||
int shadow_bottom;
|
||||
|
||||
gdk_popup_layout_get_shadow_width (layout,
|
||||
&shadow_left,
|
||||
&shadow_right,
|
||||
&shadow_top,
|
||||
&shadow_bottom);
|
||||
geometry = (GdkRectangle) {
|
||||
.x = impl->shadow_left,
|
||||
.y = impl->shadow_top,
|
||||
.width = width - (impl->shadow_left + impl->shadow_right),
|
||||
.height = height - (impl->shadow_top + impl->shadow_bottom),
|
||||
.x = shadow_left,
|
||||
.y = shadow_top,
|
||||
.width = width - (shadow_left + shadow_right),
|
||||
.height = height - (shadow_top + shadow_bottom),
|
||||
};
|
||||
|
||||
anchor_rect = gdk_popup_layout_get_anchor_rect (layout);
|
||||
@@ -2724,6 +2744,12 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface,
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
gdk_popup_layout_get_shadow_width (layout,
|
||||
&impl->shadow_left,
|
||||
&impl->shadow_right,
|
||||
&impl->shadow_top,
|
||||
&impl->shadow_bottom);
|
||||
|
||||
if (grab_input_seat)
|
||||
{
|
||||
struct wl_seat *seat;
|
||||
|
||||
@@ -1201,6 +1201,12 @@ gdk_win32_surface_move (GdkSurface *surface,
|
||||
gdk_win32_surface_move_resize_internal (surface, TRUE, x, y, -1, -1);
|
||||
}
|
||||
|
||||
static void gdk_win32_surface_set_shadow_width (GdkSurface *window,
|
||||
int left,
|
||||
int right,
|
||||
int top,
|
||||
int bottom);
|
||||
|
||||
static void
|
||||
gdk_win32_surface_layout_popup (GdkSurface *surface,
|
||||
int width,
|
||||
@@ -1212,11 +1218,23 @@ gdk_win32_surface_layout_popup (GdkSurface *surface,
|
||||
GdkRectangle bounds;
|
||||
GdkRectangle final_rect;
|
||||
int x, y;
|
||||
int shadow_left, shadow_right, shadow_top, shadow_bottom;
|
||||
|
||||
monitor = gdk_surface_get_layout_monitor (surface, layout,
|
||||
gdk_win32_monitor_get_workarea);
|
||||
gdk_win32_monitor_get_workarea (monitor, &bounds);
|
||||
|
||||
gdk_popup_layout_get_shadow_width (layout,
|
||||
&shadow_left,
|
||||
&shadow_right,
|
||||
&shadow_top,
|
||||
&shadow_bottom);
|
||||
gdk_win32_surface_set_shadow_width (surface,
|
||||
shadow_left,
|
||||
shadow_right,
|
||||
shadow_top,
|
||||
shadow_bottom);
|
||||
|
||||
gdk_surface_layout_popup_helper (surface,
|
||||
width,
|
||||
height,
|
||||
|
||||
@@ -1814,6 +1814,12 @@ gdk_x11_surface_layout_popup (GdkSurface *surface,
|
||||
gdk_x11_monitor_get_workarea);
|
||||
gdk_x11_monitor_get_workarea (monitor, &bounds);
|
||||
|
||||
gdk_popup_layout_get_shadow_width (layout,
|
||||
&impl->shadow_left,
|
||||
&impl->shadow_right,
|
||||
&impl->shadow_top,
|
||||
&impl->shadow_bottom);
|
||||
|
||||
gdk_surface_layout_popup_helper (surface,
|
||||
width,
|
||||
height,
|
||||
|
||||
@@ -82,6 +82,16 @@ gtk_gizmo_grab_focus (GtkWidget *widget)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gizmo_css_changed (GtkWidget *widget,
|
||||
GtkCssStyleChange *change)
|
||||
{
|
||||
GtkGizmo *self = GTK_GIZMO (widget);
|
||||
|
||||
if (self->css_changed_func)
|
||||
self->css_changed_func (self, change);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gizmo_finalize (GObject *object)
|
||||
{
|
||||
@@ -115,6 +125,7 @@ gtk_gizmo_class_init (GtkGizmoClass *klass)
|
||||
widget_class->contains = gtk_gizmo_contains;
|
||||
widget_class->grab_focus = gtk_gizmo_grab_focus;
|
||||
widget_class->focus = gtk_gizmo_focus;
|
||||
widget_class->css_changed = gtk_gizmo_css_changed;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -165,3 +176,12 @@ gtk_gizmo_new_with_role (const char *css_name,
|
||||
|
||||
return GTK_WIDGET (gizmo);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_gizmo_set_css_changed_func (GtkGizmo *gizmo,
|
||||
GtkGizmoCssChangedFunc css_changed_func)
|
||||
{
|
||||
g_return_if_fail (!gtk_widget_get_realized (GTK_WIDGET (gizmo)));
|
||||
|
||||
gizmo->css_changed_func = css_changed_func;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ typedef gboolean (* GtkGizmoContainsFunc) (GtkGizmo *gizmo,
|
||||
double y);
|
||||
typedef gboolean (* GtkGizmoFocusFunc) (GtkGizmo *gizmo,
|
||||
GtkDirectionType direction);
|
||||
typedef gboolean (* GtkGizmoGrabFocusFunc)(GtkGizmo *gizmo);
|
||||
typedef gboolean (* GtkGizmoGrabFocusFunc) (GtkGizmo *gizmo);
|
||||
typedef void (* GtkGizmoCssChangedFunc) (GtkGizmo *gizmo,
|
||||
GtkCssStyleChange *change);
|
||||
|
||||
struct _GtkGizmo
|
||||
{
|
||||
@@ -45,6 +47,7 @@ struct _GtkGizmo
|
||||
GtkGizmoContainsFunc contains_func;
|
||||
GtkGizmoFocusFunc focus_func;
|
||||
GtkGizmoGrabFocusFunc grab_focus_func;
|
||||
GtkGizmoCssChangedFunc css_changed_func;
|
||||
};
|
||||
|
||||
struct _GtkGizmoClass
|
||||
@@ -71,5 +74,7 @@ GtkWidget *gtk_gizmo_new_with_role (const char *css_name,
|
||||
GtkGizmoFocusFunc focus_func,
|
||||
GtkGizmoGrabFocusFunc grab_focus_func);
|
||||
|
||||
void gtk_gizmo_set_css_changed_func (GtkGizmo *gizmo,
|
||||
GtkGizmoCssChangedFunc css_changed_func);
|
||||
|
||||
#endif
|
||||
|
||||
145
gtk/gtkpopover.c
145
gtk/gtkpopover.c
@@ -83,14 +83,15 @@
|
||||
* to differentiate from plain popovers.
|
||||
*
|
||||
* When styling a popover directly, the popover node should usually
|
||||
* not have any background.
|
||||
* 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.
|
||||
*
|
||||
* Note that, in order to accomplish appropriate arrow visuals, #GtkPopover uses
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* not support any border shape other than solid, no border-radius, only one
|
||||
* border width (border-bottom-width is used) and no box-shadow.
|
||||
*/
|
||||
@@ -126,6 +127,7 @@
|
||||
#include "gtkstylecontextprivate.h"
|
||||
#include "gtkroundedboxprivate.h"
|
||||
#include "gsk/gskroundedrectprivate.h"
|
||||
#include "gtkcssshadowvalueprivate.h"
|
||||
|
||||
#define MNEMONICS_DELAY 300 /* ms */
|
||||
|
||||
@@ -436,6 +438,8 @@ create_popup_layout (GtkPopover *popover)
|
||||
GdkAnchorHints anchor_hints;
|
||||
GdkPopupLayout *layout;
|
||||
GtkWidget *parent;
|
||||
GtkCssStyle *style;
|
||||
GtkBorder shadow_width;
|
||||
|
||||
parent = gtk_widget_get_parent (GTK_WIDGET (popover));
|
||||
gtk_widget_get_surface_allocation (parent, &rect);
|
||||
@@ -447,6 +451,9 @@ create_popup_layout (GtkPopover *popover)
|
||||
rect.height = priv->pointing_to.height;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
switch (priv->position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
@@ -553,6 +560,11 @@ create_popup_layout (GtkPopover *popover)
|
||||
|
||||
layout = gdk_popup_layout_new (&rect, parent_anchor, surface_anchor);
|
||||
gdk_popup_layout_set_anchor_hints (layout, anchor_hints);
|
||||
gdk_popup_layout_set_shadow_width (layout,
|
||||
shadow_width.left,
|
||||
shadow_width.right,
|
||||
shadow_width.top,
|
||||
shadow_width.bottom);
|
||||
|
||||
if (priv->x_offset || priv->y_offset)
|
||||
gdk_popup_layout_set_offset (layout, priv->x_offset, priv->y_offset);
|
||||
@@ -570,9 +582,7 @@ present_popup (GtkPopover *popover)
|
||||
layout = create_popup_layout (popover);
|
||||
gtk_widget_get_preferred_size (GTK_WIDGET (popover), NULL, &nat);
|
||||
|
||||
if (gdk_popup_present (GDK_POPUP (priv->surface),
|
||||
nat.width, nat.height,
|
||||
layout))
|
||||
if (gdk_popup_present (GDK_POPUP (priv->surface), nat.width, nat.height, layout))
|
||||
{
|
||||
update_popover_layout (popover, layout, nat.width, nat.height);
|
||||
return TRUE;
|
||||
@@ -870,6 +880,15 @@ node_style_changed_cb (GtkCssNode *node,
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
contents_css_changed (GtkGizmo *contents,
|
||||
GtkCssStyleChange *change)
|
||||
{
|
||||
if (change == NULL ||
|
||||
gtk_css_style_change_changes_property (change, GTK_CSS_PROPERTY_BOX_SHADOW))
|
||||
gtk_widget_queue_resize (gtk_widget_get_parent (GTK_WIDGET (contents)));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_init (GtkPopover *popover)
|
||||
{
|
||||
@@ -905,6 +924,7 @@ gtk_popover_init (GtkPopover *popover)
|
||||
priv->contents_widget = gtk_gizmo_new ("contents", NULL, NULL, NULL, NULL,
|
||||
(GtkGizmoFocusFunc)gtk_widget_focus_child,
|
||||
(GtkGizmoGrabFocusFunc)gtk_widget_grab_focus_child);
|
||||
gtk_gizmo_set_css_changed_func (GTK_GIZMO (priv->contents_widget), contents_css_changed);
|
||||
gtk_widget_set_layout_manager (priv->contents_widget, gtk_bin_layout_new ());
|
||||
gtk_widget_set_parent (priv->contents_widget, GTK_WIDGET (popover));
|
||||
gtk_widget_set_overflow (priv->contents_widget, GTK_OVERFLOW_HIDDEN);
|
||||
@@ -1107,6 +1127,7 @@ gtk_popover_get_gap_coords (GtkPopover *popover,
|
||||
int popover_width, popover_height;
|
||||
GtkCssStyle *style;
|
||||
GtkWidget *parent;
|
||||
GtkBorder shadow_width;
|
||||
|
||||
popover_width = gtk_widget_get_allocated_width (widget);
|
||||
popover_height = gtk_widget_get_allocated_height (widget);
|
||||
@@ -1132,20 +1153,27 @@ gtk_popover_get_gap_coords (GtkPopover *popover,
|
||||
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);
|
||||
|
||||
if (pos == GTK_POS_BOTTOM || pos == GTK_POS_RIGHT)
|
||||
gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
|
||||
|
||||
if (pos == GTK_POS_BOTTOM)
|
||||
{
|
||||
tip = 0;
|
||||
base = TAIL_HEIGHT + border_top;
|
||||
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;
|
||||
}
|
||||
else if (pos == GTK_POS_TOP)
|
||||
{
|
||||
base = popover_height - border_bottom - TAIL_HEIGHT;
|
||||
tip = popover_height;
|
||||
tip = popover_height - shadow_width.bottom;
|
||||
base = tip - border_bottom - TAIL_HEIGHT;
|
||||
}
|
||||
else if (pos == GTK_POS_LEFT)
|
||||
{
|
||||
base = popover_width - border_right - TAIL_HEIGHT;
|
||||
tip = popover_width;
|
||||
tip = popover_width - shadow_width.right;
|
||||
base = tip - border_right - TAIL_HEIGHT;
|
||||
}
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
@@ -1286,7 +1314,31 @@ gtk_popover_update_shape (GtkPopover *popover)
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
else
|
||||
gdk_surface_set_input_region (priv->surface, NULL);
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1306,14 +1358,22 @@ get_minimal_size (GtkPopover *popover,
|
||||
GtkPositionType pos;
|
||||
int minimal_size;
|
||||
int tail_gap_width = priv->has_arrow ? TAIL_GAP_WIDTH : 0;
|
||||
int min_width, min_height;
|
||||
|
||||
minimal_size = 2 * get_border_radius (GTK_WIDGET (popover));
|
||||
minimal_size = 2 * get_border_radius (GTK_WIDGET (priv->contents_widget));
|
||||
pos = priv->position;
|
||||
|
||||
if ((orientation == GTK_ORIENTATION_HORIZONTAL && POS_IS_VERTICAL (pos)) ||
|
||||
(orientation == GTK_ORIENTATION_VERTICAL && !POS_IS_VERTICAL (pos)))
|
||||
minimal_size += tail_gap_width;
|
||||
|
||||
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);
|
||||
|
||||
return minimal_size;
|
||||
}
|
||||
|
||||
@@ -1330,10 +1390,15 @@ gtk_popover_measure (GtkWidget *widget,
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
int minimal_size;
|
||||
int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0;
|
||||
GtkCssStyle *style;
|
||||
GtkBorder shadow_width;
|
||||
|
||||
if (for_size >= 0)
|
||||
for_size -= tail_height;
|
||||
|
||||
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);
|
||||
|
||||
gtk_widget_measure (priv->contents_widget,
|
||||
orientation, for_size,
|
||||
minimum, natural,
|
||||
@@ -1343,8 +1408,22 @@ gtk_popover_measure (GtkWidget *widget,
|
||||
*minimum = MAX (*minimum, minimal_size);
|
||||
*natural = MAX (*natural, minimal_size);
|
||||
|
||||
*minimum += tail_height;
|
||||
*natural += tail_height;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1357,32 +1436,42 @@ gtk_popover_size_allocate (GtkWidget *widget,
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GtkAllocation child_alloc;
|
||||
int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0;
|
||||
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);
|
||||
|
||||
switch (priv->final_position)
|
||||
{
|
||||
case GTK_POS_TOP:
|
||||
child_alloc.x = tail_height / 2;
|
||||
child_alloc.y = 0;
|
||||
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);
|
||||
break;
|
||||
case GTK_POS_BOTTOM:
|
||||
child_alloc.x = tail_height / 2;
|
||||
child_alloc.y = tail_height;
|
||||
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);
|
||||
break;
|
||||
case GTK_POS_LEFT:
|
||||
child_alloc.x = 0;
|
||||
child_alloc.y = tail_height / 2;
|
||||
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);
|
||||
break;
|
||||
case GTK_POS_RIGHT:
|
||||
child_alloc.x = tail_height;
|
||||
child_alloc.y = tail_height / 2;
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
child_alloc.width = width - tail_height;
|
||||
child_alloc.height = height - tail_height;
|
||||
|
||||
gtk_widget_size_allocate (priv->contents_widget, &child_alloc, baseline);
|
||||
|
||||
if (priv->surface)
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
* # CSS nodes
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* window.background
|
||||
* window.background [.csd / .solid-csd / .ssd] [.maximized / .fullscreen / .tiled]
|
||||
* ├── <child>
|
||||
* ╰── <titlebar child>.titlebar [.default-decoration]
|
||||
* ]|
|
||||
@@ -125,9 +125,11 @@
|
||||
* client-side decorations are in use), .solid-csd (for client-side decorations
|
||||
* without invisible borders), .ssd (used by mutter when rendering server-side
|
||||
* decorations). GtkWindow also represents window states with the following
|
||||
* style classes on the main node: .tiled, .maximized, .fullscreen. Specialized
|
||||
* types of window often add their own discriminating style classes, such as
|
||||
* .popup or .tooltip.
|
||||
* style classes on the main node: .maximized, .fullscreen, .tiled (when supported,
|
||||
* also .tiled-top, .tiled-left, .tiled-right, .tiled-bottom).
|
||||
*
|
||||
* GtkWindow subclasses often add their own discriminating style classes,
|
||||
* such as .dialog, .popup or .tooltip.
|
||||
*
|
||||
* Generally, some CSS properties don't make sense on the toplevel window node,
|
||||
* such as margins or padding. When client-side decorations without invisible
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
gtk_tests = [
|
||||
# testname, optional extra sources
|
||||
['testpopup'],
|
||||
['testupload'],
|
||||
['testtransform'],
|
||||
['testdropdown'],
|
||||
|
||||
131
tests/testpopup.c
Normal file
131
tests/testpopup.c
Normal file
@@ -0,0 +1,131 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static void
|
||||
update_offset (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (object)))
|
||||
gtk_popover_set_offset (GTK_POPOVER (widget), 12, 12);
|
||||
else
|
||||
gtk_popover_set_offset (GTK_POPOVER (widget), 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
update_shadow (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
const char *classes[] = {
|
||||
"no-shadow",
|
||||
"shadow1",
|
||||
"shadow2",
|
||||
"shadow3",
|
||||
"shadow4",
|
||||
};
|
||||
guint selected;
|
||||
|
||||
selected = gtk_drop_down_get_selected (GTK_DROP_DOWN (object));
|
||||
g_assert (selected < G_N_ELEMENTS (classes));
|
||||
|
||||
for (int i = 0; i < G_N_ELEMENTS (classes); i++)
|
||||
gtk_widget_remove_css_class (widget, classes[i]);
|
||||
|
||||
gtk_widget_add_css_class (widget, classes[selected]);
|
||||
}
|
||||
|
||||
static const char css[] =
|
||||
"popover.no-shadow > contents { box-shadow: none; }\n"
|
||||
"popover.shadow1 > contents { box-shadow: 6px 6px rgba(128,0,255,0.5); }\n"
|
||||
"popover.shadow2 > contents { box-shadow: -6px -6px rgba(255,0,0,0.5), 6px 6px rgba(128,0,255,0.5); }\n"
|
||||
"popover.shadow3 > contents { box-shadow: -6px -6px rgba(255,0,0,0.5), 18px 18px rgba(128,0,255,0.5); }\n"
|
||||
"popover.shadow4 > contents { box-shadow: -18px -18px rgba(255,0,0,0.5), 18px 18px rgba(128,0,255,0.5); }\n";
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *box;
|
||||
GtkWidget *button;
|
||||
GtkWidget *popover;
|
||||
GtkWidget *box2;
|
||||
GtkWidget *box3;
|
||||
GtkWidget *checkbox;
|
||||
GtkWidget *checkbox2;
|
||||
GtkWidget *dropdown;
|
||||
GtkWidget *dropdown2;
|
||||
GtkCssProvider *provider;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, css, -1);
|
||||
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
800);
|
||||
|
||||
window = gtk_window_new ();
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
g_object_set (box,
|
||||
"margin-top", 20,
|
||||
"margin-bottom", 20,
|
||||
"margin-start", 20,
|
||||
"margin-end", 20,
|
||||
NULL);
|
||||
|
||||
button = gtk_menu_button_new ();
|
||||
|
||||
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
|
||||
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
|
||||
popover = gtk_popover_new ();
|
||||
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
|
||||
gtk_popover_set_child (GTK_POPOVER (popover), box2);
|
||||
|
||||
gtk_box_append (GTK_BOX (box2), gtk_label_new ("First item"));
|
||||
gtk_box_append (GTK_BOX (box2), gtk_label_new ("Second item"));
|
||||
gtk_box_append (GTK_BOX (box2), gtk_label_new ("Third item"));
|
||||
|
||||
gtk_menu_button_set_popover (GTK_MENU_BUTTON (button), popover);
|
||||
|
||||
box3 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
|
||||
dropdown = gtk_drop_down_new_from_strings ((const char*[]){ "Left", "Right", "Top", "Bottom", NULL });
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (dropdown), 3);
|
||||
|
||||
checkbox = gtk_check_button_new_with_label ("Arrow");
|
||||
|
||||
checkbox2 = gtk_check_button_new_with_label ("Offset");
|
||||
|
||||
dropdown2 = gtk_drop_down_new_from_strings ((const char*[]){ "No Shadow", "Shadow 1", "Shadow 2", "Shadow 3", "Shadow 4", NULL });
|
||||
|
||||
gtk_box_append (GTK_BOX (box3), checkbox);
|
||||
gtk_box_append (GTK_BOX (box3), checkbox2);
|
||||
gtk_box_append (GTK_BOX (box3), dropdown);
|
||||
gtk_box_append (GTK_BOX (box3), dropdown2);
|
||||
|
||||
gtk_box_append (GTK_BOX (box), box3);
|
||||
|
||||
g_object_bind_property (checkbox, "active",
|
||||
popover, "has-arrow",
|
||||
G_BINDING_SYNC_CREATE);
|
||||
g_signal_connect (checkbox2, "notify::active",
|
||||
G_CALLBACK (update_offset), popover);
|
||||
g_object_bind_property (dropdown, "selected",
|
||||
popover, "position",
|
||||
G_BINDING_SYNC_CREATE);
|
||||
g_signal_connect (dropdown2, "notify::selected",
|
||||
G_CALLBACK (update_shadow), popover);
|
||||
update_shadow (G_OBJECT (dropdown2), NULL, popover);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user