Commit eabac453 authored by Alexander Larsson's avatar Alexander Larsson Committed by Alexander Larsson

Initial client-side-windows work

The history before this was kind of twisted as several different
approaches were tested, so that was all squashed into this initial
commit to hide the uninteresting changes and files that were later
removed.
parent e2a2ba9d
......@@ -120,6 +120,7 @@ gdk_c_sources = \
gdkintl.h \
gdkkeys.c \
gdkkeyuni.c \
gdkoffscreenwindow.c \
gdkpango.c \
gdkpixbuf-drawable.c \
gdkpixbuf-render.c \
......
......@@ -71,7 +71,6 @@ gdk_set_use_xshm
gdk_keyboard_grab
gdk_keyboard_grab_info_libgtk_only
gdk_pointer_grab
gdk_pointer_grab_info_libgtk_only
#endif
#endif
......@@ -85,6 +84,8 @@ gdk_pointer_is_grabbed
gdk_pointer_ungrab
gdk_event_send_client_message
gdk_event_send_clientmessage_toall
gdk_pointer_grab_info_libgtk_only
gdk_display_pointer_is_grabbed
#endif
#endif
......@@ -254,12 +255,6 @@ gdk_visual_type_get_type G_GNUC_CONST
#endif
#endif
#if IN_HEADER(__GDK_PIXMAP_H__)
#if IN_FILE(__GDK_PIXMAP_X11_C__)
gdk_bitmap_create_from_data
#endif
#endif
#if IN_HEADER(__GDK_FONT_H__)
#if IN_FILE(__GDK_FONT_C__)
#ifndef GDK_DISABLE_DEPRECATED
......@@ -466,7 +461,6 @@ gdk_display_get_default_screen
gdk_display_get_name
gdk_display_get_n_screens
gdk_display_get_screen
gdk_display_pointer_is_grabbed
gdk_display_pointer_ungrab
gdk_display_keyboard_ungrab
gdk_display_open
......@@ -719,6 +713,13 @@ gdk_window_set_composited
#endif
#endif
#if IN_HEADER(__GDK_WINDOW_H__)
#if IN_FILE(__GDK_OFFSCREEN_WINDOW_C__)
gdk_window_set_offscreen_hooks
gdk_window_get_offscreen_pixmap
#endif
#endif
#if IN_HEADER(__GDK_WINDOW_H__)
#if IN_FILE(__GDK_DND_X11_C__)
gdk_window_register_dnd
......@@ -925,23 +926,24 @@ gdk_pixbuf_render_to_drawable_alpha
#if IN_HEADER(__GDK_PIXMAP_H__)
#if IN_FILE(__GDK_PIXMAP_C__)
gdk_bitmap_create_from_data
gdk_pixmap_colormap_create_from_xpm
gdk_pixmap_create_from_data
gdk_pixmap_create_from_xpm
gdk_pixmap_colormap_create_from_xpm_d
gdk_pixmap_create_from_xpm_d
gdk_pixmap_get_type G_GNUC_CONST
gdk_pixmap_new
#endif
#endif
#if IN_HEADER(__GDK_PIXMAP_H__)
#if IN_FILE(__GDK_PIXMAP_X11_C__)
gdk_pixmap_create_from_data
gdk_pixmap_foreign_new
gdk_pixmap_foreign_new_for_display
gdk_pixmap_foreign_new_for_screen
gdk_pixmap_lookup
gdk_pixmap_lookup_for_display
gdk_pixmap_new
#endif
#endif
......
......@@ -50,6 +50,10 @@ gdk_cairo_create (GdkDrawable *drawable)
surface = _gdk_drawable_ref_cairo_surface (drawable);
cr = cairo_create (surface);
if (GDK_DRAWABLE_GET_CLASS (drawable)->set_cairo_clip)
GDK_DRAWABLE_GET_CLASS (drawable)->set_cairo_clip (drawable, cr);
cairo_surface_destroy (surface);
return cr;
......
......@@ -22,9 +22,11 @@
*/
#include "config.h"
#include <math.h>
#include <glib.h>
#include "gdk.h" /* gdk_event_send_client_message() */
#include "gdkdisplay.h"
#include "gdkwindowimpl.h"
#include "gdkinternals.h"
#include "gdkmarshalers.h"
#include "gdkscreen.h"
......@@ -60,6 +62,14 @@ static GdkWindow* singlehead_default_window_get_pointer (GdkWindow *window
static GdkWindow* singlehead_default_window_at_pointer (GdkScreen *screen,
gint *win_x,
gint *win_y);
static GdkWindow *gdk_window_real_window_get_pointer (GdkDisplay *display,
GdkWindow *window,
gint *x,
gint *y,
GdkModifierType *mask);
static GdkWindow *gdk_display_real_get_window_at_pointer (GdkDisplay *display,
gint *win_x,
gint *win_y);
static guint signals[LAST_SIGNAL] = { 0 };
......@@ -67,8 +77,8 @@ static char *gdk_sm_client_id;
static const GdkDisplayPointerHooks default_pointer_hooks = {
_gdk_windowing_get_pointer,
_gdk_windowing_window_get_pointer,
_gdk_windowing_window_at_pointer
gdk_window_real_window_get_pointer,
gdk_display_real_get_window_at_pointer
};
static const GdkDisplayPointerHooks singlehead_pointer_hooks = {
......@@ -473,6 +483,79 @@ gdk_display_get_pointer (GdkDisplay *display,
*mask = tmp_mask;
}
static GdkWindow *
gdk_display_real_get_window_at_pointer (GdkDisplay *display,
gint *win_x,
gint *win_y)
{
GdkWindow *window;
gint x, y;
window = _gdk_windowing_window_at_pointer (display, &x, &y);
/* This might need corrections, as the native window returned
may contain client side children */
if (window)
{
double xx, yy;
window = _gdk_window_find_descendant_at (window,
x, y,
&xx, &yy);
x = floor (xx + 0.5);
y = floor (yy + 0.5);
}
*win_x = x;
*win_y = y;
return window;
}
static GdkWindow *
gdk_window_real_window_get_pointer (GdkDisplay *display,
GdkWindow *window,
gint *x,
gint *y,
GdkModifierType *mask)
{
GdkWindowObject *private;
GdkWindow *pointer_window;
gint tmpx, tmpy;
private = (GdkWindowObject *) window;
pointer_window = _gdk_windowing_window_get_pointer (display,
window,
&tmpx, &tmpy,
mask);
/* We got the coords on the impl, conver to the window */
tmpx += private->abs_x;
tmpy += private->abs_y;
if (x)
*x = tmpx;
if (y)
*y = tmpy;
/* We need to recalculate the true child window with the pointer in it
due to possible client side child windows */
if (pointer_window != NULL)
{
/* First get the pointer coords relative to pointer_window */
_gdk_windowing_window_get_pointer (display,
pointer_window,
&tmpx, &tmpy,
NULL);
/* Then convert that to a client side window */
pointer_window = _gdk_window_find_descendant_at (pointer_window,
tmpx, tmpy,
NULL, NULL);
}
return pointer_window;
}
/**
* gdk_display_get_window_at_pointer:
* @display: a #GdkDisplay
......@@ -586,8 +669,8 @@ singlehead_default_window_get_pointer (GdkWindow *window,
gint *y,
GdkModifierType *mask)
{
return _gdk_windowing_window_get_pointer (gdk_drawable_get_display (window),
window, x, y, mask);
return gdk_window_real_window_get_pointer (gdk_drawable_get_display (window),
window, x, y, mask);
}
static GdkWindow*
......@@ -595,8 +678,8 @@ singlehead_default_window_at_pointer (GdkScreen *screen,
gint *win_x,
gint *win_y)
{
return _gdk_windowing_window_at_pointer (gdk_screen_get_display (screen),
win_x, win_y);
return gdk_display_real_get_window_at_pointer (gdk_screen_get_display (screen),
win_x, win_y);
}
/**
......@@ -632,5 +715,200 @@ gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks)
return (GdkPointerHooks *)result;
}
static void
generate_grab_broken_event (GdkWindow *window,
gboolean keyboard,
gboolean implicit,
GdkWindow *grab_window)
{
g_return_if_fail (window != NULL);
if (!GDK_WINDOW_DESTROYED (window))
{
GdkEvent event;
event.type = GDK_GRAB_BROKEN;
event.grab_broken.window = window;
event.grab_broken.send_event = 0;
event.grab_broken.keyboard = keyboard;
event.grab_broken.implicit = implicit;
event.grab_broken.grab_window = grab_window;
gdk_event_put (&event);
}
}
void
_gdk_display_set_has_pointer_grab (GdkDisplay *display,
GdkWindow *window,
GdkWindow *native_window,
gboolean owner_events,
GdkEventMask event_mask,
unsigned long serial,
guint32 time,
gboolean implicit)
{
int wx, wy;
/* Normal GRAB events are sent by listening for enter and leave
* events on the native event window, which is then proxied
* into the virtual windows when the events are seen.
* However, there are two cases where X will not send these events:
* * When there is already a grab on the native parent of the
* virtual grab window
* * When there is no grab, but the pointer is already in the
* native parent of the virtual grab window
* In the first case we send the right GRAB events from the grab, but
* in the second case we need to generate our own UNGRAB crossing events.
*/
if (display->pointer_grab.window != NULL &&
display->pointer_grab.window != window)
{
generate_grab_broken_event (GDK_WINDOW (display->pointer_grab.window),
FALSE, display->pointer_grab.implicit,
window);
/* Re-grabbing. Pretend we have no grab for now so that
the GRAB events get delivered */
display->pointer_grab.window = NULL;
_gdk_syntesize_crossing_events (display,
display->pointer_grab.window,
window,
GDK_CROSSING_GRAB,
/* These may be stale... */
display->pointer_info.toplevel_x,
display->pointer_info.toplevel_y,
display->pointer_info.state,
time, TRUE, TRUE);
}
else if (_gdk_windowing_window_at_pointer (display, &wx, &wy) == native_window)
{
_gdk_syntesize_crossing_events (display,
display->pointer_info.window_under_pointer,
window,
GDK_CROSSING_GRAB,
/* These may be stale... */
display->pointer_info.toplevel_x,
display->pointer_info.toplevel_y,
display->pointer_info.state,
time, TRUE, TRUE);
}
display->pointer_grab.window = window;
display->pointer_grab.native_window = native_window;
display->pointer_grab.serial = serial;
display->pointer_grab.owner_events = owner_events;
display->pointer_grab.event_mask = event_mask;
display->pointer_grab.time = time;
display->pointer_grab.implicit = implicit;
display->pointer_grab.converted_implicit = FALSE;
}
void
_gdk_display_unset_has_pointer_grab (GdkDisplay *display,
gboolean implicit,
gboolean do_grab_one_pointer_release_event,
guint32 time)
{
int wx, wy;
GdkWindow *old_grab_window;
GdkWindow *old_native_grab_window;
old_grab_window = display->pointer_grab.window;
old_native_grab_window = display->pointer_grab.native_window;
if (do_grab_one_pointer_release_event)
display->pointer_grab.grab_one_pointer_release_event = display->pointer_grab.window;
/* We need to set this to null befor syntesizing events to make sure they get
delivered to anything but the grab window */
display->pointer_grab.window = NULL;
/* Normal UNGRAB events are sent by listening for enter and leave
* events on the native event window, which is then proxied
* into the virtual windows when the events are seen.
* However, there are two cases where X will not send these events:
* * When this ungrab is due to a new grab on the native window that
* is a parent of the currently grabbed virtual window
* * When there is no new grab, and the pointer is already in the
* grabbed virtual windows parent native window
* In the first case we send the right GRAB events from the grab, but
* in the second case we need to generate our own UNGRAB crossing events.
*/
if (_gdk_windowing_window_at_pointer (display, &wx, &wy) == old_native_grab_window)
{
_gdk_syntesize_crossing_events (display,
old_grab_window,
display->pointer_info.window_under_pointer,
GDK_CROSSING_UNGRAB,
/* These may be stale... */
display->pointer_info.toplevel_x,
display->pointer_info.toplevel_y,
display->pointer_info.state,
time, TRUE, TRUE);
}
if (implicit)
generate_grab_broken_event (old_grab_window,
FALSE, implicit,
NULL);
}
/**
* gdk_pointer_grab_info_libgtk_only:
* @display: the #GdkDisplay for which to get the grab information
* @grab_window: location to store current grab window
* @owner_events: location to store boolean indicating whether
* the @owner_events flag to gdk_pointer_grab() was %TRUE.
*
* Determines information about the current pointer grab.
* This is not public API and must not be used by applications.
*
* Return value: %TRUE if this application currently has the
* pointer grabbed.
**/
gboolean
gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
GdkWindow **grab_window,
gboolean *owner_events)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
if (display->pointer_grab.window)
{
if (grab_window)
*grab_window = (GdkWindow *)display->pointer_grab.window;
if (owner_events)
*owner_events = display->pointer_grab.owner_events;
return TRUE;
}
else
return FALSE;
}
/**
* gdk_display_pointer_is_grabbed:
* @display: a #GdkDisplay
*
* Test if the pointer is grabbed.
*
* Returns: %TRUE if an active X pointer grab is in effect
*
* Since: 2.2
*/
gboolean
gdk_display_pointer_is_grabbed (GdkDisplay *display)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
return (display->pointer_grab.window != NULL &&
!display->pointer_grab.implicit);
}
#define __GDK_DISPLAY_C__
#include "gdkaliasdef.c"
......@@ -43,6 +43,32 @@ typedef struct _GdkDisplayPointerHooks GdkDisplayPointerHooks;
#define GDK_IS_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DISPLAY))
#define GDK_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DISPLAY, GdkDisplayClass))
/* Tracks information about the pointer grab on this display */
typedef struct
{
GdkWindow *window;
GdkWindow *native_window;
gulong serial;
gboolean owner_events;
guint event_mask;
gboolean implicit;
gboolean converted_implicit;
guint32 time;
GdkWindow *grab_one_pointer_release_event;
} GdkPointerGrabInfo;
/* Tracks information about which window the pointer is in and
* at what position the mouse is. This is useful when we need
* to synthesize events later.
*/
typedef struct
{
GdkWindow *window_under_pointer;
gdouble toplevel_x, toplevel_y;
guint32 state;
} GdkPointerWindowInfo;
struct _GdkDisplay
{
GObject parent_instance;
......@@ -68,6 +94,9 @@ struct _GdkDisplay
guint double_click_distance; /* Maximum distance between clicks in pixels */
gint button_x[2]; /* The last 2 button click positions. */
gint button_y[2];
GdkPointerGrabInfo pointer_grab;
GdkPointerWindowInfo pointer_info;
};
struct _GdkDisplayClass
......
......@@ -652,6 +652,8 @@ gdk_draw_drawable (GdkDrawable *drawable,
&composite_x_offset,
&composite_y_offset);
/* TODO: For non-native windows this may copy stuff from other overlapping
windows. We should clip that and clear that area in the destination instead. */
GDK_DRAWABLE_GET_CLASS (drawable)->draw_drawable (drawable, gc, composite,
xsrc - composite_x_offset,
......@@ -871,7 +873,7 @@ real_draw_glyphs (GdkDrawable *drawable,
cairo_t *cr;
cr = gdk_cairo_create (drawable);
_gdk_gc_update_context (gc, cr, NULL, NULL, TRUE);
_gdk_gc_update_context (gc, cr, NULL, NULL, TRUE, drawable);
if (matrix)
{
......@@ -995,7 +997,7 @@ gdk_draw_trapezoids (GdkDrawable *drawable,
g_return_if_fail (n_trapezoids == 0 || trapezoids != NULL);
cr = gdk_cairo_create (drawable);
_gdk_gc_update_context (gc, cr, NULL, NULL, TRUE);
_gdk_gc_update_context (gc, cr, NULL, NULL, TRUE, drawable);
for (i = 0; i < n_trapezoids; i++)
{
......@@ -1185,7 +1187,7 @@ gdk_drawable_real_get_image (GdkDrawable *drawable,
return gdk_drawable_copy_to_image (drawable, NULL, x, y, 0, 0, width, height);
}
static GdkDrawable*
static GdkDrawable *
gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
gint x,
gint y,
......@@ -1771,5 +1773,25 @@ _gdk_drawable_get_scratch_gc (GdkDrawable *drawable,
}
}
/**
* _gdk_drawable_get_source_drawable:
* @drawable: a #GdkDrawable
*
* Returns a drawable for the passed @drawable that is guaranteed to be
* usable to create a pixmap (e.g.: not an offscreen window).
*
* Since: 2.16
*/
GdkDrawable *
_gdk_drawable_get_source_drawable (GdkDrawable *drawable)
{
g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
if (GDK_DRAWABLE_GET_CLASS (drawable)->get_source_drawable)
return GDK_DRAWABLE_GET_CLASS (drawable)->get_source_drawable (drawable);
return drawable;
}
#define __GDK_DRAW_C__
#include "gdkaliasdef.c"
......@@ -200,9 +200,11 @@ struct _GdkDrawableClass
cairo_surface_t *(*ref_cairo_surface) (GdkDrawable *drawable);
GdkDrawable *(*get_source_drawable) (GdkDrawable *drawable);
void (*set_cairo_clip) (GdkDrawable *drawable,
cairo_t *cr);
/* Padding for future expansion */
void (*_gdk_reserved4) (void);
void (*_gdk_reserved5) (void);
void (*_gdk_reserved6) (void);
void (*_gdk_reserved7) (void);
void (*_gdk_reserved9) (void);
......
......@@ -120,6 +120,63 @@ _gdk_event_queue_append (GdkDisplay *display,
return display->queued_tail;
}
/**
* _gdk_event_queue_insert_after:
* @display: a #GdkDisplay
* @sibling: Append after this event.
* @event: Event to append.
*
* Appends an event after the specified event, or if it isn't in
* the queue, onto the tail of the event queue.
*
* Returns: the newly appended list node.
*
* Since: 2.16
*/
GList*
_gdk_event_queue_insert_after (GdkDisplay *display,
GdkEvent *sibling,
GdkEvent *event)
{
GList *prev = g_list_find (display->queued_events, sibling);
if (prev && prev->next)
{
display->queued_events = g_list_insert_before (display->queued_events, prev->next, event);
return prev->next;
}
else
return _gdk_event_queue_append (display, event);
}
/**
* _gdk_event_queue_insert_after:
* @display: a #GdkDisplay
* @sibling: Append after this event.
* @event: Event to append.
*
* Appends an event before the specified event, or if it isn't in
* the queue, onto the tail of the event queue.
*
* Returns: the newly appended list node.
*
* Since: 2.16
*/
GList*
_gdk_event_queue_insert_before (GdkDisplay *display,
GdkEvent *sibling,
GdkEvent *event)
{
GList *next = g_list_find (display->queued_events, sibling);
if (next)
{
display->queued_events = g_list_insert_before (display->queued_events, next, event);
return next->prev;
}
else
return _gdk_event_queue_append (display, event);
}
/**
* _gdk_event_queue_remove_link:
* @display: a #GdkDisplay
......@@ -1101,13 +1158,16 @@ gdk_synthesize_click (GdkDisplay *display,
gint nclicks)
{
GdkEvent temp_event;
GdkEvent *event_copy;
GList *link;
g_return_if_fail (event != NULL);
temp_event = *event;
temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
gdk_display_put_event (display, &temp_event);
event_copy = gdk_event_copy (&temp_event);
link = _gdk_event_queue_append (display, event_copy);
}
void
......
......@@ -151,7 +151,8 @@ typedef enum
GDK_SETTING = 33,
GDK_OWNER_CHANGE = 34,
GDK_GRAB_BROKEN = 35,
GDK_DAMAGE = 36
GDK_DAMAGE = 36,
GDK_EVENT_LAST /* helper variable for decls */
} GdkEventType;
/* Event masks. (Used to select what types of events a window
......
......@@ -43,6 +43,8 @@ struct _GdkGCPrivate
{
GdkRegion *clip_region;
GdkSubwindowMode subwindow_mode;
GdkFill fill;
GdkBitmap *stipple;
GdkPixmap *tile;
......@@ -172,6 +174,8 @@ _gdk_gc_init (GdkGC *gc,
priv->fg_pixel = values->foreground.pixel;
if (values_mask & GDK_GC_BACKGROUND)
priv->bg_pixel = values->background.pixel;
if (values_mask & GDK_GC_SUBWINDOW)
priv->subwindow_mode = values->subwindow_mode;
gc->colormap = gdk_drawable_get_colormap (drawable);
if (gc->colormap)
......@@ -183,7 +187,7 @@ gdk_gc_finalize (GObject *object)
{
GdkGC *gc = GDK_GC (object);
GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc);
if (priv->clip_region)
gdk_region_destroy (priv->clip_region);
if (gc->colormap)
......@@ -313,6 +317,8 @@ gdk_gc_set_values (GdkGC *gc,
priv->fg_pixel = values->foreground.pixel;
if (values_mask & GDK_GC_BACKGROUND)
priv->bg_pixel = values->background.pixel;
if (values_mask & GDK_GC_SUBWINDOW)
priv->subwindow_mode = values->subwindow_mode;
GDK_GC_GET_CLASS (gc)->set_values (gc, values, values_mask);
}
......@@ -542,9 +548,11 @@ gdk_gc_set_clip_mask (GdkGC *gc,
gdk_gc_set_values (gc, &values, GDK_GC_CLIP_MASK);
}
static void
/* Takes ownership of passed in region */
void
_gdk_gc_set_clip_region_internal (GdkGC *gc,
GdkRegion *region)
GdkRegion *region,
gboolean reset_origin)
{
GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc);
......@@ -553,7 +561,32 @@ _gdk_gc_set_clip_region_internal (GdkGC *gc,
priv->clip_region = region;
_gdk_windowing_gc_set_clip_region (gc, region);
_gdk_windowing_gc_set_clip_region (gc, region, reset_origin);
}
/* Takes ownership of passed in region, returns old clip region */
void
_gdk_gc_intersect_clip_region (GdkGC *gc,
GdkRegion *region,
GdkRegion **old_clip_region)
{
GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc);
GdkRegion *old_clip;
old_clip = priv->clip_region;
priv->clip_region = region;
if (old_clip)
gdk_region_intersect (region, old_clip);
if (old_clip_region)
*old_clip_region = old_clip;
else
gdk_region_destroy (old_clip);
_gdk_windowing_gc_set_clip_region (gc, priv->clip_region, FALSE);
return old_clip;
}
/**
......@@ -578,7 +611,7 @@ gdk_gc_set_clip_rectangle (GdkGC *gc,
else
region = NULL;
_gdk_gc_set_clip_region_internal (gc, region);
_gdk_gc_set_clip_region_internal (gc, region, TRUE);
}
/**
......@@ -603,7 +636,7 @@ gdk_gc_set_clip_region (GdkGC *gc,
else
copy = NULL;
_gdk_gc_set_clip_region_internal (gc, copy);
_gdk_gc_set_clip_region_internal (gc, copy, TRUE);
}
/**
......@@ -723,13 +756,27 @@ gdk_gc_set_subwindow (GdkGC *gc,
GdkSubwindowMode mode)
{
GdkGCValues values;
GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc);
g_return_if_fail (GDK_IS_GC (gc));
/* This could get called a lot to reset the subwindow mode in
the client side clipping, so bail out early */
if (priv->subwindow_mode == mode)