Compare commits
15 Commits
gtk3.meson
...
wip/simple
Author | SHA1 | Date | |
---|---|---|---|
|
0d9b189a64 | ||
|
fe70c2db55 | ||
|
b40fc9d141 | ||
|
9da2f293e9 | ||
|
1270bcd5c3 | ||
|
b788fb784c | ||
|
472081c052 | ||
|
08159b89bd | ||
|
fc88ce08ee | ||
|
d0a10c847e | ||
|
20ed384efb | ||
|
73107e0a4e | ||
|
c95bcc2a9f | ||
|
36e71d80ad | ||
|
dacd820965 |
@@ -1470,56 +1470,6 @@ _gdk_broadway_window_queue_antiexpose (GdkWindow *window,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_region (cairo_surface_t *surface,
|
||||
cairo_region_t *area,
|
||||
gint dx,
|
||||
gint dy)
|
||||
{
|
||||
cairo_t *cr;
|
||||
|
||||
cr = cairo_create (surface);
|
||||
|
||||
gdk_cairo_region (cr, area);
|
||||
cairo_clip (cr);
|
||||
|
||||
/* NB: This is a self-copy and Cairo doesn't support that yet.
|
||||
* So we do a litle trick.
|
||||
*/
|
||||
cairo_push_group (cr);
|
||||
|
||||
cairo_set_source_surface (cr, surface, dx, dy);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_broadway_window_translate (GdkWindow *window,
|
||||
cairo_region_t *area,
|
||||
gint dx,
|
||||
gint dy)
|
||||
{
|
||||
GdkWindowImplBroadway *impl;
|
||||
GdkBroadwayDisplay *broadway_display;
|
||||
|
||||
impl = GDK_WINDOW_IMPL_BROADWAY (window->impl);
|
||||
|
||||
if (impl->surface)
|
||||
{
|
||||
copy_region (impl->surface, area, dx, dy);
|
||||
broadway_display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (window));
|
||||
|
||||
if (_gdk_broadway_server_window_translate (broadway_display->server,
|
||||
impl->id,
|
||||
area, dx, dy))
|
||||
queue_flush (window);
|
||||
}
|
||||
}
|
||||
|
||||
guint32
|
||||
gdk_broadway_get_last_seen_time (GdkWindow *window)
|
||||
{
|
||||
@@ -1558,7 +1508,6 @@ gdk_window_impl_broadway_class_init (GdkWindowImplBroadwayClass *klass)
|
||||
impl_class->input_shape_combine_region = gdk_window_broadway_input_shape_combine_region;
|
||||
impl_class->set_static_gravities = gdk_window_broadway_set_static_gravities;
|
||||
impl_class->queue_antiexpose = _gdk_broadway_window_queue_antiexpose;
|
||||
impl_class->translate = _gdk_broadway_window_translate;
|
||||
impl_class->destroy = _gdk_broadway_window_destroy;
|
||||
impl_class->destroy_foreign = gdk_broadway_window_destroy_foreign;
|
||||
impl_class->resize_cairo_surface = gdk_window_broadway_resize_cairo_surface;
|
||||
|
@@ -384,6 +384,7 @@ gdk_frame_clock_paint_idle (void *data)
|
||||
case GDK_FRAME_CLOCK_PHASE_LAYOUT:
|
||||
if (priv->freeze_count == 0)
|
||||
{
|
||||
int iter;
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
|
||||
{
|
||||
@@ -394,11 +395,20 @@ gdk_frame_clock_paint_idle (void *data)
|
||||
#endif /* G_ENABLE_DEBUG */
|
||||
|
||||
priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT;
|
||||
if (priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT)
|
||||
/* We loop in the layout phase, because we don't want to progress
|
||||
* into the paint phase with invalid size allocations. This may
|
||||
* happen in some situation like races between user window
|
||||
* resizes and natural size changes.
|
||||
*/
|
||||
iter = 0;
|
||||
while ((priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT) &&
|
||||
priv->freeze_count == 0 && iter++ < 4)
|
||||
{
|
||||
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT;
|
||||
g_signal_emit_by_name (G_OBJECT (clock), "layout");
|
||||
}
|
||||
if (iter == 4)
|
||||
g_warning ("gdk-frame-clock: layout continuously requested, giving up after 4 tries");
|
||||
}
|
||||
case GDK_FRAME_CLOCK_PHASE_PAINT:
|
||||
if (priv->freeze_count == 0)
|
||||
|
@@ -224,6 +224,7 @@ struct _GdkWindow
|
||||
guint native_visibility : 2; /* the native visibility of a impl windows */
|
||||
guint viewable : 1; /* mapped and all parents mapped */
|
||||
guint applied_shape : 1;
|
||||
guint in_update : 1;
|
||||
GdkFullscreenMode fullscreen_mode;
|
||||
|
||||
/* The GdkWindow that has the impl, ref:ed if another window.
|
||||
@@ -250,10 +251,6 @@ struct _GdkWindow
|
||||
GdkCursor *cursor;
|
||||
GHashTable *device_cursor;
|
||||
|
||||
GSList *implicit_paint;
|
||||
|
||||
GList *outstanding_moves;
|
||||
|
||||
cairo_region_t *shape;
|
||||
cairo_region_t *input_shape;
|
||||
|
||||
@@ -269,6 +266,7 @@ struct _GdkWindow
|
||||
guint num_offscreen_children;
|
||||
|
||||
GdkFrameClock *frame_clock; /* NULL to use from parent or default */
|
||||
GdkWindowInvalidateHandlerFunc invalidate_handler;
|
||||
};
|
||||
|
||||
#define GDK_WINDOW_TYPE(d) (((GDK_WINDOW (d)))->window_type)
|
||||
|
@@ -555,42 +555,6 @@ gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_offscreen_window_translate (GdkWindow *window,
|
||||
cairo_region_t *area,
|
||||
gint dx,
|
||||
gint dy)
|
||||
{
|
||||
GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
|
||||
|
||||
if (offscreen->surface)
|
||||
{
|
||||
cairo_t *cr;
|
||||
|
||||
cr = cairo_create (offscreen->surface);
|
||||
|
||||
area = cairo_region_copy (area);
|
||||
|
||||
gdk_cairo_region (cr, area);
|
||||
cairo_clip (cr);
|
||||
|
||||
/* NB: This is a self-copy and Cairo doesn't support that yet.
|
||||
* So we do a litle trick.
|
||||
*/
|
||||
cairo_push_group (cr);
|
||||
|
||||
cairo_set_source_surface (cr, offscreen->surface, dx, dy);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
_gdk_window_add_damage (window, area);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
gdk_offscreen_window_resize_cairo_surface (GdkWindow *window,
|
||||
cairo_surface_t *surface,
|
||||
@@ -752,7 +716,6 @@ gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
|
||||
impl_class->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
|
||||
impl_class->set_static_gravities = gdk_offscreen_window_set_static_gravities;
|
||||
impl_class->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
|
||||
impl_class->translate = gdk_offscreen_window_translate;
|
||||
impl_class->destroy = gdk_offscreen_window_destroy;
|
||||
impl_class->destroy_foreign = NULL;
|
||||
impl_class->resize_cairo_surface = gdk_offscreen_window_resize_cairo_surface;
|
||||
|
1673
gdk/gdkwindow.c
1673
gdk/gdkwindow.c
File diff suppressed because it is too large
Load Diff
@@ -634,6 +634,26 @@ gboolean gdk_window_set_static_gravities (GdkWindow *window,
|
||||
|
||||
/* GdkWindow */
|
||||
|
||||
/**
|
||||
* GdkWindowInvalidateHandlerFunc:
|
||||
* @window: a #GdkWindow
|
||||
* @region: a #cairo_region_t
|
||||
*
|
||||
* Whenever some area of the window is invalidated (directly in the
|
||||
* window or in a child window) this gets called with @region in
|
||||
* the coordinate space of @window. You can use @region to just
|
||||
* keep track of the dirty region, or you can actually change
|
||||
* @region in case you are doing display tricks like showing
|
||||
* a child in multiple places.
|
||||
*
|
||||
* Since: 3.10
|
||||
*/
|
||||
typedef void (*GdkWindowInvalidateHandlerFunc) (GdkWindow *window,
|
||||
cairo_region_t *region);
|
||||
GDK_AVAILABLE_IN_3_10
|
||||
void gdk_window_set_invalidate_handler (GdkWindow *window,
|
||||
GdkWindowInvalidateHandlerFunc handler);
|
||||
|
||||
gboolean gdk_window_has_native (GdkWindow *window);
|
||||
void gdk_window_set_type_hint (GdkWindow *window,
|
||||
GdkWindowTypeHint hint);
|
||||
|
@@ -125,16 +125,6 @@ struct _GdkWindowImplClass
|
||||
gboolean (* queue_antiexpose) (GdkWindow *window,
|
||||
cairo_region_t *update_area);
|
||||
|
||||
/* Called to move @area inside @window by @dx x @dy pixels. @area is
|
||||
* guaranteed to be inside @window. If part of @area is not invisible or
|
||||
* invalid, it is this function's job to queue expose events in those
|
||||
* areas.
|
||||
*/
|
||||
void (* translate) (GdkWindow *window,
|
||||
cairo_region_t *area,
|
||||
gint dx,
|
||||
gint dy);
|
||||
|
||||
/* Called to do the windowing system specific part of gdk_window_destroy(),
|
||||
*
|
||||
* window: The window being destroyed
|
||||
|
@@ -2237,49 +2237,6 @@ gdk_quartz_window_queue_antiexpose (GdkWindow *window,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_quartz_window_translate (GdkWindow *window,
|
||||
cairo_region_t *area,
|
||||
gint dx,
|
||||
gint dy)
|
||||
{
|
||||
cairo_region_t *invalidate, *scrolled;
|
||||
GdkWindowImplQuartz *impl = (GdkWindowImplQuartz *)window->impl;
|
||||
GdkRectangle extents;
|
||||
|
||||
cairo_region_get_extents (area, &extents);
|
||||
|
||||
[impl->view scrollRect:NSMakeRect (extents.x - dx, extents.y - dy,
|
||||
extents.width, extents.height)
|
||||
by:NSMakeSize (dx, dy)];
|
||||
|
||||
if (impl->needs_display_region)
|
||||
{
|
||||
cairo_region_t *intersection;
|
||||
|
||||
/* Invalidate already invalidated area that was moved at new
|
||||
* location.
|
||||
*/
|
||||
intersection = cairo_region_copy (impl->needs_display_region);
|
||||
cairo_region_intersect (intersection, area);
|
||||
cairo_region_translate (intersection, dx, dy);
|
||||
|
||||
gdk_quartz_window_set_needs_display_in_region (window, intersection);
|
||||
cairo_region_destroy (intersection);
|
||||
}
|
||||
|
||||
/* Calculate newly exposed area that needs invalidation */
|
||||
scrolled = cairo_region_copy (area);
|
||||
cairo_region_translate (scrolled, dx, dy);
|
||||
|
||||
invalidate = cairo_region_copy (area);
|
||||
cairo_region_subtract (invalidate, scrolled);
|
||||
cairo_region_destroy (scrolled);
|
||||
|
||||
gdk_quartz_window_set_needs_display_in_region (window, invalidate);
|
||||
cairo_region_destroy (invalidate);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_quartz_window_set_focus_on_map (GdkWindow *window,
|
||||
gboolean focus_on_map)
|
||||
@@ -3078,7 +3035,6 @@ gdk_window_impl_quartz_class_init (GdkWindowImplQuartzClass *klass)
|
||||
impl_class->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region;
|
||||
impl_class->set_static_gravities = gdk_window_quartz_set_static_gravities;
|
||||
impl_class->queue_antiexpose = gdk_quartz_window_queue_antiexpose;
|
||||
impl_class->translate = gdk_quartz_window_translate;
|
||||
impl_class->destroy = gdk_quartz_window_destroy;
|
||||
impl_class->destroy_foreign = gdk_quartz_window_destroy_foreign;
|
||||
impl_class->resize_cairo_surface = gdk_window_quartz_resize_cairo_surface;
|
||||
|
@@ -1009,15 +1009,6 @@ gdk_wayland_window_queue_antiexpose (GdkWindow *window,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_window_translate (GdkWindow *window,
|
||||
cairo_region_t *area,
|
||||
gint dx,
|
||||
gint dy)
|
||||
{
|
||||
_gdk_window_invalidate_for_expose (window, area);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_window_destroy (GdkWindow *window,
|
||||
gboolean recursing,
|
||||
@@ -1726,7 +1717,6 @@ _gdk_window_impl_wayland_class_init (GdkWindowImplWaylandClass *klass)
|
||||
impl_class->input_shape_combine_region = gdk_window_wayland_input_shape_combine_region;
|
||||
impl_class->set_static_gravities = gdk_window_wayland_set_static_gravities;
|
||||
impl_class->queue_antiexpose = gdk_wayland_window_queue_antiexpose;
|
||||
impl_class->translate = gdk_wayland_window_translate;
|
||||
impl_class->destroy = gdk_wayland_window_destroy;
|
||||
impl_class->destroy_foreign = gdk_window_wayland_destroy_foreign;
|
||||
impl_class->resize_cairo_surface = gdk_window_wayland_resize_cairo_surface;
|
||||
|
@@ -3319,77 +3319,6 @@ _gdk_win32_window_queue_antiexpose (GdkWindow *window,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Gets called from gdwindow.c(do_move_region_bits_on_impl)
|
||||
* and got tested with testgtk::big_window. Given the previous,
|
||||
* untested implementation this one looks much too simple ;)
|
||||
*/
|
||||
static void
|
||||
_gdk_win32_window_translate (GdkWindow *window,
|
||||
cairo_region_t *area, /* In impl window coords */
|
||||
gint dx,
|
||||
gint dy)
|
||||
{
|
||||
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
|
||||
HRGN hrgn, area_hrgn;
|
||||
cairo_region_t *update_region;
|
||||
HDC hdc;
|
||||
int ret;
|
||||
|
||||
/* Note: This is the destination area, not the source, and
|
||||
it has been moved by dx, dy from the source area */
|
||||
area_hrgn = cairo_region_to_hrgn (area, 0, 0);
|
||||
|
||||
/* First we copy any outstanding invalid areas in the
|
||||
source area to the new position in the destination area */
|
||||
hrgn = CreateRectRgn (0, 0, 0, 0);
|
||||
ret = GetUpdateRgn (GDK_WINDOW_HWND (window), hrgn, FALSE);
|
||||
if (ret == ERROR)
|
||||
WIN32_API_FAILED ("GetUpdateRgn");
|
||||
else if (ret != NULLREGION)
|
||||
{
|
||||
/* Convert the source invalid region as it would be copied */
|
||||
OffsetRgn (hrgn, dx, dy);
|
||||
/* Keep what intersects the copy destination area */
|
||||
ret = CombineRgn (hrgn, hrgn, area_hrgn, RGN_AND);
|
||||
/* And invalidate it */
|
||||
if (ret == ERROR)
|
||||
WIN32_API_FAILED ("CombineRgn");
|
||||
else if (ret != NULLREGION)
|
||||
API_CALL (InvalidateRgn, (GDK_WINDOW_HWND (window), hrgn, TRUE));
|
||||
}
|
||||
|
||||
/* Then we copy the bits, invalidating whatever is copied from
|
||||
otherwise invisible areas */
|
||||
|
||||
hdc = _gdk_win32_impl_acquire_dc (impl);
|
||||
|
||||
/* Clip hdc to target region */
|
||||
API_CALL (SelectClipRgn, (hdc, area_hrgn));
|
||||
|
||||
SetRectRgn (hrgn, 0, 0, 0, 0);
|
||||
|
||||
if (!ScrollDC (hdc, dx, dy, NULL, NULL, hrgn, NULL))
|
||||
WIN32_GDI_FAILED ("ScrollDC");
|
||||
else
|
||||
{
|
||||
update_region = _gdk_win32_hrgn_to_region (hrgn);
|
||||
if (!cairo_region_is_empty (update_region))
|
||||
_gdk_window_invalidate_for_expose (window, update_region);
|
||||
cairo_region_destroy (update_region);
|
||||
}
|
||||
|
||||
/* Unset hdc clip region */
|
||||
API_CALL (SelectClipRgn, (hdc, NULL));
|
||||
|
||||
_gdk_win32_impl_release_dc (impl);
|
||||
|
||||
if (!DeleteObject (hrgn))
|
||||
WIN32_GDI_FAILED ("DeleteObject");
|
||||
|
||||
if (!DeleteObject (area_hrgn))
|
||||
WIN32_GDI_FAILED ("DeleteObject");
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_win32_input_shape_combine_region (GdkWindow *window,
|
||||
const cairo_region_t *shape_region,
|
||||
@@ -3556,7 +3485,6 @@ gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
|
||||
impl_class->input_shape_combine_region = gdk_win32_input_shape_combine_region;
|
||||
impl_class->set_static_gravities = gdk_win32_window_set_static_gravities;
|
||||
impl_class->queue_antiexpose = _gdk_win32_window_queue_antiexpose;
|
||||
impl_class->translate = _gdk_win32_window_translate;
|
||||
impl_class->destroy = gdk_win32_window_destroy;
|
||||
impl_class->destroy_foreign = gdk_win32_window_destroy_foreign;
|
||||
impl_class->resize_cairo_surface = gdk_win32_window_resize_cairo_surface;
|
||||
|
@@ -28,26 +28,11 @@
|
||||
typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
|
||||
typedef struct _GdkWindowParentPos GdkWindowParentPos;
|
||||
|
||||
typedef enum {
|
||||
GDK_WINDOW_QUEUE_TRANSLATE,
|
||||
GDK_WINDOW_QUEUE_ANTIEXPOSE
|
||||
} GdkWindowQueueType;
|
||||
|
||||
struct _GdkWindowQueueItem
|
||||
{
|
||||
GdkWindow *window;
|
||||
gulong serial;
|
||||
GdkWindowQueueType type;
|
||||
union {
|
||||
struct {
|
||||
cairo_region_t *area;
|
||||
gint dx;
|
||||
gint dy;
|
||||
} translate;
|
||||
struct {
|
||||
cairo_region_t *area;
|
||||
} antiexpose;
|
||||
} u;
|
||||
cairo_region_t *antiexpose_area;
|
||||
};
|
||||
|
||||
void
|
||||
@@ -140,14 +125,7 @@ queue_item_free (GdkWindowQueueItem *item)
|
||||
(gpointer *)&(item->window));
|
||||
}
|
||||
|
||||
if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
|
||||
cairo_region_destroy (item->u.antiexpose.area);
|
||||
else
|
||||
{
|
||||
if (item->u.translate.area)
|
||||
cairo_region_destroy (item->u.translate.area);
|
||||
}
|
||||
|
||||
cairo_region_destroy (item->antiexpose_area);
|
||||
g_free (item);
|
||||
}
|
||||
|
||||
@@ -213,11 +191,8 @@ gdk_window_queue (GdkWindow *window,
|
||||
GdkWindowQueueItem *item = tmp_list->data;
|
||||
GList *next = tmp_list->next;
|
||||
|
||||
if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
|
||||
{
|
||||
queue_delete_link (display_x11->translate_queue, tmp_list);
|
||||
queue_item_free (item);
|
||||
}
|
||||
queue_delete_link (display_x11->translate_queue, tmp_list);
|
||||
queue_item_free (item);
|
||||
|
||||
tmp_list = next;
|
||||
}
|
||||
@@ -232,86 +207,12 @@ gdk_window_queue (GdkWindow *window,
|
||||
g_queue_push_tail (display_x11->translate_queue, item);
|
||||
}
|
||||
|
||||
static GC
|
||||
_get_scratch_gc (GdkWindow *window, cairo_region_t *clip_region)
|
||||
{
|
||||
GdkX11Screen *screen;
|
||||
XRectangle *rectangles;
|
||||
gint n_rects;
|
||||
gint depth;
|
||||
|
||||
screen = GDK_X11_SCREEN (gdk_window_get_screen (window));
|
||||
depth = gdk_visual_get_depth (gdk_window_get_visual (window)) - 1;
|
||||
|
||||
if (!screen->subwindow_gcs[depth])
|
||||
{
|
||||
XGCValues values;
|
||||
|
||||
values.graphics_exposures = True;
|
||||
values.subwindow_mode = IncludeInferiors;
|
||||
|
||||
screen->subwindow_gcs[depth] = XCreateGC (screen->xdisplay,
|
||||
GDK_WINDOW_XID (window),
|
||||
GCSubwindowMode | GCGraphicsExposures,
|
||||
&values);
|
||||
}
|
||||
|
||||
_gdk_x11_region_get_xrectangles (clip_region,
|
||||
0, 0,
|
||||
&rectangles,
|
||||
&n_rects);
|
||||
|
||||
XSetClipRectangles (screen->xdisplay,
|
||||
screen->subwindow_gcs[depth],
|
||||
0, 0,
|
||||
rectangles, n_rects,
|
||||
YXBanded);
|
||||
|
||||
g_free (rectangles);
|
||||
return screen->subwindow_gcs[depth];
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
_gdk_x11_window_translate (GdkWindow *window,
|
||||
cairo_region_t *area,
|
||||
gint dx,
|
||||
gint dy)
|
||||
{
|
||||
GdkWindowQueueItem *item;
|
||||
GC xgc;
|
||||
GdkRectangle extents;
|
||||
|
||||
cairo_region_get_extents (area, &extents);
|
||||
|
||||
xgc = _get_scratch_gc (window, area);
|
||||
|
||||
cairo_region_translate (area, -dx, -dy); /* Move to source region */
|
||||
|
||||
item = g_new (GdkWindowQueueItem, 1);
|
||||
item->type = GDK_WINDOW_QUEUE_TRANSLATE;
|
||||
item->u.translate.area = cairo_region_copy (area);
|
||||
item->u.translate.dx = dx;
|
||||
item->u.translate.dy = dy;
|
||||
gdk_window_queue (window, item);
|
||||
|
||||
XCopyArea (GDK_WINDOW_XDISPLAY (window),
|
||||
GDK_WINDOW_XID (window),
|
||||
GDK_WINDOW_XID (window),
|
||||
xgc,
|
||||
extents.x - dx, extents.y - dy,
|
||||
extents.width, extents.height,
|
||||
extents.x, extents.y);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_x11_window_queue_antiexpose (GdkWindow *window,
|
||||
cairo_region_t *area)
|
||||
{
|
||||
GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
|
||||
item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
|
||||
item->u.antiexpose.area = area;
|
||||
item->antiexpose_area = area;
|
||||
|
||||
gdk_window_queue (window, item);
|
||||
|
||||
@@ -339,28 +240,7 @@ _gdk_x11_window_process_expose (GdkWindow *window,
|
||||
if (serial - item->serial > (gulong) G_MAXLONG)
|
||||
{
|
||||
if (item->window == window)
|
||||
{
|
||||
if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
|
||||
{
|
||||
if (item->u.translate.area)
|
||||
{
|
||||
cairo_region_t *intersection;
|
||||
|
||||
intersection = cairo_region_copy (invalidate_region);
|
||||
cairo_region_intersect (intersection, item->u.translate.area);
|
||||
cairo_region_subtract (invalidate_region, intersection);
|
||||
cairo_region_translate (intersection, item->u.translate.dx, item->u.translate.dy);
|
||||
cairo_region_union (invalidate_region, intersection);
|
||||
cairo_region_destroy (intersection);
|
||||
}
|
||||
else
|
||||
cairo_region_translate (invalidate_region, item->u.translate.dx, item->u.translate.dy);
|
||||
}
|
||||
else /* anti-expose */
|
||||
{
|
||||
cairo_region_subtract (invalidate_region, item->u.antiexpose.area);
|
||||
}
|
||||
}
|
||||
cairo_region_subtract (invalidate_region, item->antiexpose_area);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -5334,7 +5334,6 @@ gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
|
||||
impl_class->input_shape_combine_region = gdk_window_x11_input_shape_combine_region;
|
||||
impl_class->set_static_gravities = gdk_window_x11_set_static_gravities;
|
||||
impl_class->queue_antiexpose = _gdk_x11_window_queue_antiexpose;
|
||||
impl_class->translate = _gdk_x11_window_translate;
|
||||
impl_class->destroy = gdk_x11_window_destroy;
|
||||
impl_class->destroy_foreign = gdk_x11_window_destroy_foreign;
|
||||
impl_class->resize_cairo_surface = gdk_window_x11_resize_cairo_surface;
|
||||
|
@@ -3315,7 +3315,7 @@ gtk_container_propagate_draw (GtkContainer *container,
|
||||
{
|
||||
GdkEventExpose *event;
|
||||
GtkAllocation allocation;
|
||||
GdkWindow *window, *w;
|
||||
GdkWindow *window, *w, *event_window, *child_in_window;
|
||||
int x, y;
|
||||
|
||||
g_return_if_fail (GTK_IS_CONTAINER (container));
|
||||
@@ -3324,13 +3324,26 @@ gtk_container_propagate_draw (GtkContainer *container,
|
||||
|
||||
g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (container));
|
||||
|
||||
if (!gtk_widget_is_drawable (child))
|
||||
return;
|
||||
|
||||
/* Only propagate to native child window if we're not handling
|
||||
an expose (i.e. in a pure gtk_widget_draw() call */
|
||||
event = _gtk_cairo_get_event (cr);
|
||||
if (event)
|
||||
{
|
||||
if (gtk_widget_get_has_window (child) ||
|
||||
gtk_widget_get_window (child) != event->window)
|
||||
return;
|
||||
}
|
||||
if (event &&
|
||||
(gtk_widget_get_has_window (child) &&
|
||||
gdk_window_has_native (gtk_widget_get_window (child))))
|
||||
return;
|
||||
|
||||
/* Never propagate to a child window when exposing a window
|
||||
that is not the one the child widget is in. */
|
||||
event_window = _gtk_cairo_get_event_window (cr);
|
||||
if (gtk_widget_get_has_window (child))
|
||||
child_in_window = gdk_window_get_parent (gtk_widget_get_window (child));
|
||||
else
|
||||
child_in_window = gtk_widget_get_window (child);
|
||||
if (child_in_window != event_window)
|
||||
return;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
@@ -3372,7 +3385,7 @@ gtk_container_propagate_draw (GtkContainer *container,
|
||||
|
||||
cairo_translate (cr, x, y);
|
||||
|
||||
_gtk_widget_draw_internal (child, cr, TRUE);
|
||||
gtk_widget_draw (child, cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
@@ -1614,9 +1614,17 @@ gtk_main_do_event (GdkEvent *event)
|
||||
case GDK_EXPOSE:
|
||||
if (event->any.window && gtk_widget_get_double_buffered (event_widget))
|
||||
{
|
||||
gdk_window_begin_paint_region (event->any.window, event->expose.region);
|
||||
gtk_widget_send_expose (event_widget, event);
|
||||
gdk_window_end_paint (event->any.window);
|
||||
/* We handle exposes only on native windows, relying on the
|
||||
* draw() handler to propagate down to non-native windows.
|
||||
* This is ok now that we child windows always are considered
|
||||
* (semi)transparent.
|
||||
*/
|
||||
if (gdk_window_has_native (event->expose.window))
|
||||
{
|
||||
gdk_window_begin_paint_region (event->any.window, event->expose.region);
|
||||
gtk_widget_send_expose (event_widget, event);
|
||||
gdk_window_end_paint (event->any.window);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -66,6 +66,13 @@ struct _GtkViewportPrivate
|
||||
GdkWindow *bin_window;
|
||||
GdkWindow *view_window;
|
||||
|
||||
int backing_surface_x;
|
||||
int backing_surface_y;
|
||||
int backing_surface_w;
|
||||
int backing_surface_h;
|
||||
cairo_surface_t *backing_surface;
|
||||
cairo_region_t *backing_surface_dirty;
|
||||
|
||||
/* GtkScrollablePolicy needs to be checked when
|
||||
* driving the scrollable adjustment values */
|
||||
guint hscroll_policy : 1;
|
||||
@@ -649,6 +656,37 @@ gtk_viewport_get_view_window (GtkViewport *viewport)
|
||||
return viewport->priv->view_window;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_viewport_bin_window_invalidate_handler (GdkWindow *window,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
gpointer widget;
|
||||
GtkViewport *viewport;
|
||||
GtkViewportPrivate *priv;
|
||||
cairo_rectangle_int_t r;
|
||||
|
||||
gdk_window_get_user_data (window, &widget);
|
||||
viewport = GTK_VIEWPORT (widget);
|
||||
priv = viewport->priv;
|
||||
|
||||
if (priv->backing_surface_dirty == NULL)
|
||||
priv->backing_surface_dirty = cairo_region_create ();
|
||||
|
||||
cairo_region_translate (region,
|
||||
-priv->backing_surface_x,
|
||||
-priv->backing_surface_y);
|
||||
cairo_region_union (priv->backing_surface_dirty, region);
|
||||
cairo_region_translate (region,
|
||||
priv->backing_surface_x,
|
||||
priv->backing_surface_y);
|
||||
|
||||
r.x = 0;
|
||||
r.y = 0;
|
||||
r.width = priv->backing_surface_w;
|
||||
r.height = priv->backing_surface_h;
|
||||
cairo_region_intersect_rectangle (priv->backing_surface_dirty, &r);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_viewport_realize (GtkWidget *widget)
|
||||
{
|
||||
@@ -713,6 +751,8 @@ gtk_viewport_realize (GtkWidget *widget)
|
||||
|
||||
priv->bin_window = gdk_window_new (priv->view_window, &attributes, attributes_mask);
|
||||
gtk_widget_register_window (widget, priv->bin_window);
|
||||
gdk_window_set_invalidate_handler (priv->bin_window,
|
||||
gtk_viewport_bin_window_invalidate_handler);
|
||||
|
||||
child = gtk_bin_get_child (bin);
|
||||
if (child)
|
||||
@@ -750,7 +790,10 @@ gtk_viewport_draw (GtkWidget *widget,
|
||||
GtkViewport *viewport = GTK_VIEWPORT (widget);
|
||||
GtkViewportPrivate *priv = viewport->priv;
|
||||
GtkStyleContext *context;
|
||||
int x, y;
|
||||
cairo_t *backing_cr;
|
||||
GtkWidget *child;
|
||||
int x, y, bin_x, bin_y, new_surf_x, new_surf_y;
|
||||
cairo_rectangle_int_t view_pos;
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
|
||||
@@ -766,30 +809,151 @@ gtk_viewport_draw (GtkWidget *widget,
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
}
|
||||
|
||||
if (gtk_cairo_should_draw_window (cr, priv->view_window))
|
||||
|
||||
if (priv->backing_surface &&
|
||||
/* Don't use backing surface if rendering elsewhere */
|
||||
cairo_surface_get_type (priv->backing_surface) == cairo_surface_get_type (cairo_get_target (cr)))
|
||||
{
|
||||
/* This is a cute hack to ensure the contents of bin_window are
|
||||
* restricted to where they are visible. We only need to do this
|
||||
* clipping when called via gtk_widget_draw() and not in expose
|
||||
* events. And when that happens every window (including this one)
|
||||
* should be drawn.
|
||||
*/
|
||||
gdk_window_get_position (priv->view_window, &x, &y);
|
||||
cairo_rectangle (cr, x, y,
|
||||
gdk_window_get_width (priv->view_window),
|
||||
gdk_window_get_height (priv->view_window));
|
||||
cairo_clip (cr);
|
||||
gdk_window_get_position (priv->bin_window, &bin_x, &bin_y);
|
||||
view_pos.x = -bin_x;
|
||||
view_pos.y = -bin_y;
|
||||
view_pos.width = gdk_window_get_width (priv->view_window);
|
||||
view_pos.height = gdk_window_get_height (priv->view_window);
|
||||
|
||||
/* Reposition so all is visible visible */
|
||||
if (priv->backing_surface)
|
||||
{
|
||||
cairo_rectangle_int_t r;
|
||||
cairo_region_t *copy_region;
|
||||
if (view_pos.x < priv->backing_surface_x ||
|
||||
view_pos.x + view_pos.width >
|
||||
priv->backing_surface_x + priv->backing_surface_w ||
|
||||
view_pos.y < priv->backing_surface_y ||
|
||||
view_pos.y + view_pos.height >
|
||||
priv->backing_surface_y + priv->backing_surface_h)
|
||||
{
|
||||
new_surf_x = priv->backing_surface_x;
|
||||
if (view_pos.x < priv->backing_surface_x)
|
||||
new_surf_x = view_pos.x - (priv->backing_surface_w - view_pos.width);
|
||||
else if (view_pos.x + view_pos.width >
|
||||
priv->backing_surface_x + priv->backing_surface_w)
|
||||
new_surf_x = view_pos.x;
|
||||
|
||||
new_surf_y = priv->backing_surface_y;
|
||||
if (view_pos.y < priv->backing_surface_y)
|
||||
new_surf_y = view_pos.y - (priv->backing_surface_h - view_pos.height);
|
||||
else if (view_pos.y + view_pos.height >
|
||||
priv->backing_surface_y + priv->backing_surface_h)
|
||||
new_surf_y = view_pos.y;
|
||||
|
||||
r.x = 0;
|
||||
r.y = 0;
|
||||
r.width = priv->backing_surface_w;
|
||||
r.height = priv->backing_surface_h;
|
||||
copy_region = cairo_region_create_rectangle (&r);
|
||||
|
||||
if (priv->backing_surface_dirty)
|
||||
{
|
||||
cairo_region_subtract (copy_region, priv->backing_surface_dirty);
|
||||
cairo_region_destroy (priv->backing_surface_dirty);
|
||||
priv->backing_surface_dirty = NULL;
|
||||
}
|
||||
|
||||
cairo_region_translate (copy_region,
|
||||
priv->backing_surface_x - new_surf_x,
|
||||
priv->backing_surface_y - new_surf_y);
|
||||
cairo_region_intersect_rectangle (copy_region, &r);
|
||||
|
||||
backing_cr = cairo_create (priv->backing_surface);
|
||||
gdk_cairo_region (backing_cr, copy_region);
|
||||
cairo_clip (backing_cr);
|
||||
cairo_push_group (backing_cr);
|
||||
cairo_set_source_surface (backing_cr, priv->backing_surface,
|
||||
priv->backing_surface_x - new_surf_x,
|
||||
priv->backing_surface_y - new_surf_y);
|
||||
cairo_paint (backing_cr);
|
||||
cairo_pop_group_to_source (backing_cr);
|
||||
cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_paint (backing_cr);
|
||||
cairo_destroy (backing_cr);
|
||||
|
||||
priv->backing_surface_x = new_surf_x;
|
||||
priv->backing_surface_y = new_surf_y;
|
||||
|
||||
cairo_region_xor_rectangle (copy_region, &r);
|
||||
priv->backing_surface_dirty = copy_region;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->backing_surface_dirty &&
|
||||
!cairo_region_is_empty (priv->backing_surface_dirty))
|
||||
{
|
||||
backing_cr = cairo_create (priv->backing_surface);
|
||||
gdk_cairo_region (backing_cr, priv->backing_surface_dirty);
|
||||
cairo_clip (backing_cr);
|
||||
cairo_translate (backing_cr,
|
||||
-priv->backing_surface_x,
|
||||
-priv->backing_surface_y);
|
||||
cairo_set_source_rgba (backing_cr,
|
||||
0, 0, 0, 0);
|
||||
cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_paint (backing_cr);
|
||||
cairo_set_operator (backing_cr, CAIRO_OPERATOR_OVER);
|
||||
gtk_render_background (context, backing_cr,
|
||||
0,0,
|
||||
gdk_window_get_width (priv->bin_window),
|
||||
gdk_window_get_height (priv->bin_window));
|
||||
child = gtk_bin_get_child (GTK_BIN (widget));
|
||||
if (child && gtk_widget_get_visible (child)) {
|
||||
if (!gtk_widget_get_has_window (child))
|
||||
{
|
||||
GtkAllocation child_allocation;
|
||||
gtk_widget_get_allocation (child, &child_allocation);
|
||||
cairo_translate (backing_cr,
|
||||
child_allocation.x,
|
||||
child_allocation.y);
|
||||
}
|
||||
|
||||
gtk_widget_draw (child, backing_cr);
|
||||
}
|
||||
|
||||
cairo_destroy (backing_cr);
|
||||
}
|
||||
|
||||
if (priv->backing_surface_dirty)
|
||||
{
|
||||
cairo_region_destroy (priv->backing_surface_dirty);
|
||||
priv->backing_surface_dirty = NULL;
|
||||
}
|
||||
|
||||
if (gtk_cairo_should_draw_window (cr, priv->bin_window))
|
||||
{
|
||||
gdk_window_get_position (priv->view_window, &x, &y);
|
||||
cairo_set_source_surface (cr, priv->backing_surface,
|
||||
priv->backing_surface_x + bin_x + x,
|
||||
priv->backing_surface_y + bin_y + y);
|
||||
cairo_rectangle (cr, x, y,
|
||||
gdk_window_get_width (priv->view_window),
|
||||
gdk_window_get_height (priv->view_window));
|
||||
cairo_fill (cr);
|
||||
}
|
||||
}
|
||||
|
||||
if (gtk_cairo_should_draw_window (cr, priv->bin_window))
|
||||
else
|
||||
{
|
||||
gdk_window_get_position (priv->bin_window, &x, &y);
|
||||
gtk_render_background (context, cr, x, y,
|
||||
gdk_window_get_width (priv->bin_window),
|
||||
gdk_window_get_height (priv->bin_window));
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_viewport_parent_class)->draw (widget, cr);
|
||||
/* Don't use backing_surface */
|
||||
if (gtk_cairo_should_draw_window (cr, priv->bin_window))
|
||||
{
|
||||
gdk_window_get_position (priv->view_window, &x, &y);
|
||||
cairo_rectangle (cr, x, y,
|
||||
gdk_window_get_width (priv->view_window),
|
||||
gdk_window_get_height (priv->view_window));
|
||||
cairo_clip (cr);
|
||||
gdk_window_get_position (priv->bin_window, &x, &y);
|
||||
gtk_render_background (context, cr, x, y,
|
||||
gdk_window_get_width (priv->bin_window),
|
||||
gdk_window_get_height (priv->bin_window));
|
||||
GTK_WIDGET_CLASS (gtk_viewport_parent_class)->draw (widget, cr);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
@@ -823,6 +987,7 @@ gtk_viewport_size_allocate (GtkWidget *widget,
|
||||
GtkAdjustment *vadjustment = priv->vadjustment;
|
||||
GtkAllocation child_allocation;
|
||||
GtkWidget *child;
|
||||
int surface_w, surface_h;
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
|
||||
|
||||
@@ -843,7 +1008,7 @@ gtk_viewport_size_allocate (GtkWidget *widget,
|
||||
|
||||
viewport_set_hadjustment_values (viewport);
|
||||
viewport_set_vadjustment_values (viewport);
|
||||
|
||||
|
||||
child_allocation.x = 0;
|
||||
child_allocation.y = 0;
|
||||
child_allocation.width = gtk_adjustment_get_upper (hadjustment);
|
||||
@@ -851,6 +1016,7 @@ gtk_viewport_size_allocate (GtkWidget *widget,
|
||||
if (gtk_widget_get_realized (widget))
|
||||
{
|
||||
GtkAllocation view_allocation;
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
gdk_window_move_resize (gtk_widget_get_window (widget),
|
||||
allocation->x + border_width,
|
||||
@@ -869,6 +1035,48 @@ gtk_viewport_size_allocate (GtkWidget *widget,
|
||||
- gtk_adjustment_get_value (vadjustment),
|
||||
child_allocation.width,
|
||||
child_allocation.height);
|
||||
|
||||
surface_w = view_allocation.width;
|
||||
if (child_allocation.width > view_allocation.width)
|
||||
surface_w = MIN (surface_w + 64, child_allocation.width);
|
||||
|
||||
surface_h = view_allocation.height;
|
||||
if (child_allocation.height > view_allocation.height)
|
||||
surface_h = MIN (surface_h + 64, child_allocation.height);
|
||||
|
||||
if (priv->backing_surface != NULL &&
|
||||
(priv->backing_surface_w < view_allocation.width ||
|
||||
priv->backing_surface_w > surface_w + 32 ||
|
||||
priv->backing_surface_h < view_allocation.height ||
|
||||
priv->backing_surface_h > surface_h + 32))
|
||||
{
|
||||
cairo_surface_destroy (priv->backing_surface);
|
||||
priv->backing_surface = NULL;
|
||||
if (priv->backing_surface_dirty)
|
||||
cairo_region_destroy (priv->backing_surface_dirty);
|
||||
priv->backing_surface_dirty = NULL;
|
||||
}
|
||||
|
||||
if (priv->backing_surface == NULL &&
|
||||
(view_allocation.width < child_allocation.width ||
|
||||
view_allocation.height < child_allocation.height))
|
||||
{
|
||||
priv->backing_surface_x = gtk_adjustment_get_value (hadjustment);
|
||||
priv->backing_surface_y = gtk_adjustment_get_value (vadjustment);
|
||||
priv->backing_surface_w = surface_w;
|
||||
priv->backing_surface_h = surface_h;
|
||||
priv->backing_surface_dirty = cairo_region_create ();
|
||||
priv->backing_surface =
|
||||
gdk_window_create_similar_surface (priv->bin_window,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
surface_w, surface_h);
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = surface_w;
|
||||
rect.height = surface_h;
|
||||
cairo_region_union_rectangle (priv->backing_surface_dirty,
|
||||
&rect);
|
||||
}
|
||||
}
|
||||
|
||||
child = gtk_bin_get_child (bin);
|
||||
|
361
gtk/gtkwidget.c
361
gtk/gtkwidget.c
@@ -827,9 +827,10 @@ static void gtk_widget_on_frame_clock_update (GdkFrameClock *frame_clock,
|
||||
GtkWidget *widget);
|
||||
|
||||
static gboolean event_window_is_still_viewable (GdkEvent *event);
|
||||
static void gtk_cairo_set_event_window (cairo_t *cr,
|
||||
GdkWindow *window);
|
||||
static void gtk_cairo_set_event (cairo_t *cr,
|
||||
GdkEventExpose *event);
|
||||
static void gtk_widget_propagate_alpha (GtkWidget *widget);
|
||||
|
||||
/* --- variables --- */
|
||||
static gpointer gtk_widget_parent_class = NULL;
|
||||
@@ -940,24 +941,9 @@ gtk_widget_draw_marshaller (GClosure *closure,
|
||||
gpointer invocation_hint,
|
||||
gpointer marshal_data)
|
||||
{
|
||||
GtkWidget *widget = g_value_get_object (¶m_values[0]);
|
||||
GdkEventExpose *tmp_event;
|
||||
gboolean push_group;
|
||||
cairo_t *cr = g_value_get_boxed (¶m_values[1]);
|
||||
|
||||
cairo_save (cr);
|
||||
tmp_event = _gtk_cairo_get_event (cr);
|
||||
|
||||
push_group =
|
||||
widget->priv->opacity_group ||
|
||||
(widget->priv->alpha != 255 &&
|
||||
(!gtk_widget_get_has_window (widget) || tmp_event == NULL));
|
||||
|
||||
if (push_group)
|
||||
{
|
||||
cairo_push_group (cr);
|
||||
gtk_cairo_set_event (cr, NULL);
|
||||
}
|
||||
|
||||
_gtk_marshal_BOOLEAN__BOXED (closure,
|
||||
return_value,
|
||||
@@ -967,14 +953,6 @@ gtk_widget_draw_marshaller (GClosure *closure,
|
||||
marshal_data);
|
||||
|
||||
|
||||
if (push_group)
|
||||
{
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0);
|
||||
}
|
||||
|
||||
gtk_cairo_set_event (cr, tmp_event);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
@@ -987,9 +965,6 @@ gtk_widget_draw_marshallerv (GClosure *closure,
|
||||
int n_params,
|
||||
GType *param_types)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (instance);
|
||||
GdkEventExpose *tmp_event;
|
||||
gboolean push_group;
|
||||
cairo_t *cr;
|
||||
va_list args_copy;
|
||||
|
||||
@@ -997,18 +972,6 @@ gtk_widget_draw_marshallerv (GClosure *closure,
|
||||
cr = va_arg (args_copy, gpointer);
|
||||
|
||||
cairo_save (cr);
|
||||
tmp_event = _gtk_cairo_get_event (cr);
|
||||
|
||||
push_group =
|
||||
widget->priv->opacity_group ||
|
||||
(widget->priv->alpha != 255 &&
|
||||
(!gtk_widget_get_has_window (widget) || tmp_event == NULL));
|
||||
|
||||
if (push_group)
|
||||
{
|
||||
cairo_push_group (cr);
|
||||
gtk_cairo_set_event (cr, NULL);
|
||||
}
|
||||
|
||||
_gtk_marshal_BOOLEAN__BOXEDv (closure,
|
||||
return_value,
|
||||
@@ -1019,14 +982,6 @@ gtk_widget_draw_marshallerv (GClosure *closure,
|
||||
param_types);
|
||||
|
||||
|
||||
if (push_group)
|
||||
{
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0);
|
||||
}
|
||||
|
||||
gtk_cairo_set_event (cr, tmp_event);
|
||||
cairo_restore (cr);
|
||||
|
||||
va_end (args_copy);
|
||||
@@ -4173,8 +4128,6 @@ gtk_widget_unparent (GtkWidget *widget)
|
||||
g_object_notify_queue_clear (G_OBJECT (widget), nqueue);
|
||||
g_object_notify_queue_thaw (G_OBJECT (widget), nqueue);
|
||||
|
||||
gtk_widget_propagate_alpha (widget);
|
||||
|
||||
gtk_widget_pop_verify_invariants (widget);
|
||||
g_object_unref (widget);
|
||||
}
|
||||
@@ -6187,6 +6140,23 @@ gtk_widget_real_mnemonic_activate (GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const cairo_user_data_key_t event_window_key;
|
||||
|
||||
GdkWindow *
|
||||
_gtk_cairo_get_event_window (cairo_t *cr)
|
||||
{
|
||||
g_return_val_if_fail (cr != NULL, NULL);
|
||||
|
||||
return cairo_get_user_data (cr, &event_window_key);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cairo_set_event_window (cairo_t *cr,
|
||||
GdkWindow *event_window)
|
||||
{
|
||||
cairo_set_user_data (cr, &event_window_key, event_window, NULL);
|
||||
}
|
||||
|
||||
static const cairo_user_data_key_t event_key;
|
||||
|
||||
GdkEventExpose *
|
||||
@@ -6199,7 +6169,7 @@ _gtk_cairo_get_event (cairo_t *cr)
|
||||
|
||||
static void
|
||||
gtk_cairo_set_event (cairo_t *cr,
|
||||
GdkEventExpose *event)
|
||||
GdkEventExpose *event)
|
||||
{
|
||||
cairo_set_user_data (cr, &event_key, event, NULL);
|
||||
}
|
||||
@@ -6228,15 +6198,15 @@ gboolean
|
||||
gtk_cairo_should_draw_window (cairo_t *cr,
|
||||
GdkWindow *window)
|
||||
{
|
||||
GdkEventExpose *event;
|
||||
GdkWindow *event_window;
|
||||
|
||||
g_return_val_if_fail (cr != NULL, FALSE);
|
||||
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
|
||||
|
||||
event = _gtk_cairo_get_event (cr);
|
||||
event_window = _gtk_cairo_get_event_window (cr);
|
||||
|
||||
return event == NULL ||
|
||||
event->window == window;
|
||||
return event_window == NULL ||
|
||||
event_window == window;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -6253,17 +6223,20 @@ gtk_widget_get_clip_draw (GtkWidget *widget)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* code shared by gtk_container_propagate_draw() and
|
||||
* gtk_widget_draw()
|
||||
*/
|
||||
void
|
||||
static void
|
||||
_gtk_widget_draw_internal (GtkWidget *widget,
|
||||
cairo_t *cr,
|
||||
gboolean clip_to_size)
|
||||
gboolean clip_to_size,
|
||||
GdkWindow *window)
|
||||
{
|
||||
GdkWindow *tmp_event_window;
|
||||
|
||||
if (!gtk_widget_is_drawable (widget))
|
||||
return;
|
||||
|
||||
tmp_event_window = _gtk_cairo_get_event_window (cr);
|
||||
gtk_cairo_set_event_window (cr, window);
|
||||
|
||||
clip_to_size &= gtk_widget_get_clip_draw (widget);
|
||||
|
||||
if (clip_to_size)
|
||||
@@ -6284,7 +6257,7 @@ _gtk_widget_draw_internal (GtkWidget *widget,
|
||||
&result);
|
||||
|
||||
if (cairo_status (cr) &&
|
||||
_gtk_cairo_get_event (cr))
|
||||
_gtk_cairo_get_event_window (cr))
|
||||
{
|
||||
/* We check the event so we only warn about internal GTK calls.
|
||||
* Errors might come from PDF streams having write failures and
|
||||
@@ -6296,6 +6269,77 @@ _gtk_widget_draw_internal (GtkWidget *widget,
|
||||
cairo_status_to_string (cairo_status (cr)));
|
||||
}
|
||||
}
|
||||
|
||||
gtk_cairo_set_event_window (cr, tmp_event_window);
|
||||
}
|
||||
|
||||
/* Emit draw() on the widget that owns window,
|
||||
and on any child windows that also belong
|
||||
to the widget. */
|
||||
static void
|
||||
_gtk_widget_draw_windows (GdkWindow *window,
|
||||
cairo_t *cr,
|
||||
int window_x,
|
||||
int window_y)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
gboolean do_clip;
|
||||
GtkWidget *widget = NULL;
|
||||
GList *l;
|
||||
int x, y;
|
||||
|
||||
if (!gdk_window_is_viewable (window))
|
||||
return;
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_translate (cr, window_x, window_y);
|
||||
cairo_rectangle (cr, 0, 0,
|
||||
gdk_window_get_width (window),
|
||||
gdk_window_get_height (window));
|
||||
cairo_clip (cr);
|
||||
|
||||
if (gdk_cairo_get_clip_rectangle (cr, NULL))
|
||||
{
|
||||
cairo_save (cr);
|
||||
pattern = gdk_window_get_background_pattern (window);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
|
||||
gdk_window_get_user_data (window, (gpointer *) &widget);
|
||||
do_clip = _gtk_widget_get_translation_to_window (widget, window,
|
||||
&x, &y);
|
||||
cairo_save (cr);
|
||||
cairo_translate (cr, -x, -y);
|
||||
_gtk_widget_draw_internal (widget, cr, do_clip, window);
|
||||
cairo_restore (cr);
|
||||
|
||||
for (l = g_list_last (gdk_window_peek_children (window));
|
||||
l != NULL;
|
||||
l = l->prev)
|
||||
{
|
||||
GdkWindow *child_window = l->data;
|
||||
gpointer child_data;
|
||||
GdkWindowType type;
|
||||
int wx, wy;
|
||||
|
||||
type = gdk_window_get_window_type (child_window);
|
||||
if (!gdk_window_is_visible (child_window) ||
|
||||
gdk_window_is_input_only (child_window) ||
|
||||
type == GDK_WINDOW_OFFSCREEN ||
|
||||
type == GDK_WINDOW_FOREIGN)
|
||||
continue;
|
||||
|
||||
gdk_window_get_user_data (child_window, &child_data);
|
||||
if (child_data == (gpointer)widget)
|
||||
{
|
||||
gdk_window_get_position (child_window, &wx, &wy);
|
||||
_gtk_widget_draw_windows (child_window, cr, wx,wy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6328,23 +6372,89 @@ void
|
||||
gtk_widget_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GdkEventExpose *tmp_event;
|
||||
GdkWindow *window, *child_window;
|
||||
gpointer child_data;
|
||||
GList *l;
|
||||
int wx, wy;
|
||||
gboolean push_group;
|
||||
GdkWindowType type;
|
||||
|
||||
/* We get expose events only on native windows, so the draw
|
||||
* implementation has to walk the entire widget hierarchy, except
|
||||
* that it stops at native subwindows while we're in an expose
|
||||
* event (_gtk_cairo_get_event () != NULL).
|
||||
*
|
||||
* However, we need to properly clip drawing into child windows
|
||||
* to avoid drawing outside if widgets use e.g. cairo_paint(), so
|
||||
* we traverse over GdkWindows as well as GtkWidgets.
|
||||
*
|
||||
* In order to be able to have opacity groups for entire widgets
|
||||
* that consists of multiple windows we collect all the windows
|
||||
* that belongs to a widget and draw them in one go. This means
|
||||
* we may somewhat reorder GdkWindows when we paint them, but
|
||||
* thats not generally a problem, as if you want a guaranteed
|
||||
* order you generally use a windowed widget where you control
|
||||
* the window hierarchy.
|
||||
*/
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (!widget->priv->alloc_needed);
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_save (cr);
|
||||
/* We have to reset the event here so that draw functions can call
|
||||
* gtk_widget_draw() on random other widgets and get the desired
|
||||
* effect: Drawing all contents, not just the current window.
|
||||
*/
|
||||
tmp_event = _gtk_cairo_get_event (cr);
|
||||
gtk_cairo_set_event (cr, NULL);
|
||||
|
||||
_gtk_widget_draw_internal (widget, cr, TRUE);
|
||||
push_group =
|
||||
widget->priv->opacity_group ||
|
||||
(widget->priv->alpha != 255 &&
|
||||
!gtk_widget_is_toplevel (widget));
|
||||
|
||||
if (push_group)
|
||||
cairo_push_group (cr);
|
||||
|
||||
window = gtk_widget_get_window (widget);
|
||||
if (gtk_widget_get_has_window (widget))
|
||||
{
|
||||
/* The widget will be completely contained in its window, so just
|
||||
* expose that (and any child window belonging to the widget) */
|
||||
_gtk_widget_draw_windows (window, cr, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The widget draws in its parent window, so we send a draw() for
|
||||
* that. */
|
||||
_gtk_widget_draw_internal (widget, cr, TRUE, window);
|
||||
|
||||
/* But, it may also have child windows in the parent which we should
|
||||
* draw (after having drawn on the parent) */
|
||||
for (l = g_list_last (gdk_window_peek_children (window));
|
||||
l != NULL;
|
||||
l = l->prev)
|
||||
{
|
||||
child_window = l->data;
|
||||
type = gdk_window_get_window_type (child_window);
|
||||
if (!gdk_window_is_visible (child_window) ||
|
||||
gdk_window_is_input_only (child_window) ||
|
||||
type == GDK_WINDOW_OFFSCREEN ||
|
||||
type == GDK_WINDOW_FOREIGN)
|
||||
continue;
|
||||
|
||||
gdk_window_get_user_data (child_window, &child_data);
|
||||
if (child_data == (gpointer)widget)
|
||||
{
|
||||
gdk_window_get_position (child_window, &wx, &wy);
|
||||
_gtk_widget_draw_windows (child_window, cr,
|
||||
wx - widget->priv->allocation.x,
|
||||
wy - widget->priv->allocation.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (push_group)
|
||||
{
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0);
|
||||
}
|
||||
|
||||
gtk_cairo_set_event (cr, tmp_event);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
@@ -6640,8 +6750,6 @@ gtk_widget_send_expose (GtkWidget *widget,
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
cairo_t *cr;
|
||||
int x, y;
|
||||
gboolean do_clip;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
|
||||
g_return_val_if_fail (gtk_widget_get_realized (widget), TRUE);
|
||||
@@ -6649,21 +6757,18 @@ gtk_widget_send_expose (GtkWidget *widget,
|
||||
g_return_val_if_fail (event->type == GDK_EXPOSE, TRUE);
|
||||
|
||||
cr = gdk_cairo_create (event->expose.window);
|
||||
gtk_cairo_set_event (cr, &event->expose);
|
||||
|
||||
gdk_cairo_region (cr, event->expose.region);
|
||||
cairo_clip (cr);
|
||||
|
||||
do_clip = _gtk_widget_get_translation_to_window (widget,
|
||||
event->expose.window,
|
||||
&x, &y);
|
||||
cairo_translate (cr, -x, -y);
|
||||
gtk_cairo_set_event (cr, &event->expose);
|
||||
|
||||
_gtk_widget_draw_internal (widget, cr, do_clip);
|
||||
if (event->expose.window == widget->priv->window)
|
||||
gtk_widget_draw (widget, cr);
|
||||
else
|
||||
_gtk_widget_draw_windows (event->expose.window, cr, 0, 0);
|
||||
|
||||
/* unset here, so if someone keeps a reference to cr we
|
||||
* don't leak the window. */
|
||||
gtk_cairo_set_event (cr, NULL);
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
return result;
|
||||
@@ -8345,6 +8450,9 @@ gtk_widget_get_app_paintable (GtkWidget *widget)
|
||||
* expose events, since even the clearing to the background color or
|
||||
* pixmap will not happen automatically (as it is done in
|
||||
* gdk_window_begin_paint_region()).
|
||||
*
|
||||
* Since 3.10 this function only works for widgets with native
|
||||
* windows.
|
||||
**/
|
||||
void
|
||||
gtk_widget_set_double_buffered (GtkWidget *widget,
|
||||
@@ -8603,8 +8711,6 @@ gtk_widget_set_parent (GtkWidget *widget,
|
||||
gtk_widget_queue_compute_expand (parent);
|
||||
}
|
||||
|
||||
gtk_widget_propagate_alpha (widget);
|
||||
|
||||
gtk_widget_pop_verify_invariants (widget);
|
||||
}
|
||||
|
||||
@@ -14371,10 +14477,6 @@ gtk_widget_set_window (GtkWidget *widget,
|
||||
{
|
||||
priv->window = window;
|
||||
|
||||
if (gtk_widget_get_has_window (widget) && window != NULL && !gdk_window_has_native (window))
|
||||
gdk_window_set_opacity (window,
|
||||
priv->norender ? 0 : priv->alpha / 255.0);
|
||||
|
||||
g_object_notify (G_OBJECT (widget), "window");
|
||||
}
|
||||
}
|
||||
@@ -14513,86 +14615,8 @@ gtk_widget_set_support_multidevice (GtkWidget *widget,
|
||||
* in gtk_widget_set_opacity, secondly we can get it from the css opacity. These two
|
||||
* are multiplied together to form the total alpha. Secondly, the user can specify
|
||||
* an opacity group for a widget, which means we must essentially handle it as having alpha.
|
||||
*
|
||||
* We handle opacity in two ways. For a windowed widget, with opacity set but no opacity
|
||||
* group we directly set the opacity of widget->window. This will cause gdk to properly
|
||||
* redirect drawing inside the window to a buffer and do OVER paint_with_alpha.
|
||||
*
|
||||
* However, if the widget is not windowed, or the user specified an opacity group for the
|
||||
* widget we do the opacity handling in the ::draw marshaller for the widget. A naive
|
||||
* implementation of this would break for windowed widgets or descendant widgets with
|
||||
* windows, as these would not be handled by the ::draw signal. To handle this we set
|
||||
* all such gdkwindows as fully transparent and then override gtk_cairo_should_draw_window()
|
||||
* to make the draw signal propagate to *all* child widgets/windows.
|
||||
*
|
||||
* Note: We don't make all child windows fully transparent, we stop at the first one
|
||||
* in each branch when propagating down the hierarchy.
|
||||
*/
|
||||
|
||||
|
||||
/* This is called when priv->alpha or priv->opacity_group group changes, and should
|
||||
* update priv->norender and GdkWindow opacity for this widget and any children that
|
||||
* needs changing. It is also called whenver the parent changes, the parents
|
||||
* norender_children state changes, or the has_window state of the widget changes.
|
||||
*/
|
||||
static void
|
||||
gtk_widget_propagate_alpha (GtkWidget *widget)
|
||||
{
|
||||
GtkWidgetPrivate *priv = widget->priv;
|
||||
GtkWidget *parent;
|
||||
gboolean norender, norender_children;
|
||||
GList *l;
|
||||
|
||||
parent = priv->parent;
|
||||
|
||||
/* Norender affects only windowed widget and means don't render widget->window in the
|
||||
normal fashion.
|
||||
We only set this if the parent has norender_children, because:
|
||||
a) For an opacity group (that does not have a norender_children parent) we still
|
||||
need to render the window or we will never get an expose event.
|
||||
b) For alpha we set the opacity of window->widget directly, so no other
|
||||
work is needed.
|
||||
*/
|
||||
norender = (parent != NULL && parent->priv->norender_children);
|
||||
|
||||
/* windows under this widget should not render if:
|
||||
a) This widget has an opacity group
|
||||
b) This widget has alpha and is no-windowed (otherwise we'd set alpha on widget->window)
|
||||
c) This widget has norender but is no-windowed (a windowed widget would "swallow" the norender)
|
||||
*/
|
||||
norender_children =
|
||||
priv->opacity_group ||
|
||||
(!gtk_widget_get_has_window (widget) &&
|
||||
( norender || priv->alpha != 255));
|
||||
|
||||
if (gtk_widget_get_has_window (widget))
|
||||
{
|
||||
if (priv->window != NULL &&
|
||||
(!gdk_window_has_native (priv->window) || gtk_widget_is_toplevel (widget)))
|
||||
gdk_window_set_opacity (priv->window,
|
||||
norender ? 0 : priv->alpha / 255.0);
|
||||
}
|
||||
|
||||
for (l = priv->registered_windows; l != NULL; l = l->next)
|
||||
{
|
||||
GdkWindow *w = l->data;
|
||||
if (w != priv->window && !gdk_window_has_native (w))
|
||||
gdk_window_set_opacity (w, norender_children ? 0.0 : 1.0);
|
||||
}
|
||||
|
||||
priv->norender = norender;
|
||||
if (priv->norender_children != norender_children)
|
||||
{
|
||||
priv->norender_children = norender_children;
|
||||
|
||||
if (GTK_IS_CONTAINER (widget))
|
||||
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback)gtk_widget_propagate_alpha, NULL);
|
||||
}
|
||||
|
||||
if (gtk_widget_get_realized (widget))
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_widget_update_alpha (GtkWidget *widget)
|
||||
{
|
||||
@@ -14619,8 +14643,12 @@ gtk_widget_update_alpha (GtkWidget *widget)
|
||||
|
||||
priv->alpha = alpha;
|
||||
|
||||
gtk_widget_propagate_alpha (widget);
|
||||
if (gtk_widget_is_toplevel (widget))
|
||||
gdk_window_set_opacity (priv->window,
|
||||
priv->alpha / 255.0);
|
||||
|
||||
if (gtk_widget_get_realized (widget))
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -14640,7 +14668,8 @@ gtk_widget_set_has_opacity_group (GtkWidget *widget,
|
||||
|
||||
priv->opacity_group = has_opacity_group;
|
||||
|
||||
gtk_widget_propagate_alpha (widget);
|
||||
if (gtk_widget_get_realized (widget))
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -81,11 +81,9 @@ const gchar* _gtk_widget_get_accel_path (GtkWidget *widget,
|
||||
|
||||
AtkObject * _gtk_widget_peek_accessible (GtkWidget *widget);
|
||||
|
||||
GdkWindow * _gtk_cairo_get_event_window (cairo_t *cr);
|
||||
GdkEventExpose * _gtk_cairo_get_event (cairo_t *cr);
|
||||
|
||||
void _gtk_widget_draw_internal (GtkWidget *widget,
|
||||
cairo_t *cr,
|
||||
gboolean clip_to_size);
|
||||
void _gtk_widget_set_has_default (GtkWidget *widget,
|
||||
gboolean has_default);
|
||||
void _gtk_widget_set_has_grab (GtkWidget *widget,
|
||||
|
Reference in New Issue
Block a user