зеркало из https://github.com/mozilla/gecko-dev.git
723 строки
24 KiB
C
723 строки
24 KiB
C
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org Code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Owen Taylor <otaylor@redhat.com> and Christopher Blizzard <blizzard@redhat.com>.
|
|
* Portions created by the Initial Developer are Copyright (C) 1999
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "gdksuperwin.h"
|
|
|
|
static void gdk_superwin_class_init(GdkSuperWinClass *klass);
|
|
static void gdk_superwin_init(GdkSuperWin *superwin);
|
|
static void gdk_superwin_expose_area (GdkSuperWin *superwin,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height);
|
|
static void gdk_superwin_flush(GdkSuperWin *superwin);
|
|
static void gdk_superwin_destroy(GtkObject *object);
|
|
|
|
static void gdk_superwin_add_translation(GdkSuperWin *superwin, unsigned long serial,
|
|
gint dx, gint dy);
|
|
static void gdk_superwin_add_antiexpose (GdkSuperWin *superwin, unsigned long serial,
|
|
gint x, gint y,
|
|
gint width, gint height);
|
|
|
|
static void gdk_superwin_handle_expose (GdkSuperWin *superwin, XEvent *xevent,
|
|
GdkRegion **region, gboolean dont_recurse);
|
|
|
|
static Bool gdk_superwin_expose_predicate(Display *display,
|
|
XEvent *xevent,
|
|
XPointer arg);
|
|
|
|
typedef struct _GdkSuperWinTranslate GdkSuperWinTranslate;
|
|
|
|
enum {
|
|
GDK_SUPERWIN_TRANSLATION = 1,
|
|
GDK_SUPERWIN_ANTIEXPOSE
|
|
};
|
|
|
|
|
|
struct _GdkSuperWinTranslate
|
|
{
|
|
int type;
|
|
unsigned long serial;
|
|
union {
|
|
struct {
|
|
gint dx;
|
|
gint dy;
|
|
} translation;
|
|
struct {
|
|
GdkRectangle rect;
|
|
} antiexpose;
|
|
} data;
|
|
};
|
|
|
|
GtkType
|
|
gdk_superwin_get_type(void)
|
|
{
|
|
static GtkType superwin_type = 0;
|
|
|
|
if (!superwin_type)
|
|
{
|
|
static const GtkTypeInfo superwin_info =
|
|
{
|
|
"GtkSuperWin",
|
|
sizeof(GdkSuperWin),
|
|
sizeof(GdkSuperWinClass),
|
|
(GtkClassInitFunc) gdk_superwin_class_init,
|
|
(GtkObjectInitFunc) gdk_superwin_init,
|
|
/* reserved_1 */ NULL,
|
|
/* reserved_2 */ NULL,
|
|
(GtkClassInitFunc) NULL
|
|
};
|
|
|
|
superwin_type = gtk_type_unique (gtk_object_get_type(), &superwin_info);
|
|
}
|
|
return superwin_type;
|
|
}
|
|
|
|
static void
|
|
gdk_superwin_class_init(GdkSuperWinClass *klass)
|
|
{
|
|
GtkObjectClass *object_class;
|
|
|
|
object_class = GTK_OBJECT_CLASS(klass);
|
|
object_class->destroy = gdk_superwin_destroy;
|
|
|
|
}
|
|
|
|
static void
|
|
gdk_superwin_init(GdkSuperWin *superwin)
|
|
{
|
|
|
|
}
|
|
|
|
static GdkFilterReturn gdk_superwin_bin_filter (GdkXEvent *gdk_xevent,
|
|
GdkEvent *event,
|
|
gpointer data);
|
|
static GdkFilterReturn gdk_superwin_shell_filter (GdkXEvent *gdk_xevent,
|
|
GdkEvent *event,
|
|
gpointer data);
|
|
|
|
static gboolean gravity_works;
|
|
|
|
GdkSuperWin *
|
|
gdk_superwin_new (GdkWindow *parent_window,
|
|
guint x,
|
|
guint y,
|
|
guint width,
|
|
guint height)
|
|
{
|
|
GdkWindowAttr attributes;
|
|
gint attributes_mask;
|
|
Window bin_xwindow;
|
|
Display *xdisplay;
|
|
XSetWindowAttributes xattr;
|
|
unsigned long xattr_mask;
|
|
|
|
GdkSuperWin *superwin = gtk_type_new(GDK_TYPE_SUPERWIN);
|
|
|
|
superwin->translate_queue = NULL;
|
|
|
|
superwin->shell_func = NULL;
|
|
superwin->paint_func = NULL;
|
|
superwin->flush_func = NULL;
|
|
superwin->func_data = NULL;
|
|
superwin->notify = NULL;
|
|
|
|
/* Create the shell (clipping) window */
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
attributes.x = x;
|
|
attributes.y = y;
|
|
attributes.width = width;
|
|
attributes.height = height;
|
|
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
attributes.colormap = gdk_rgb_get_cmap();
|
|
attributes.visual = gdk_rgb_get_visual();
|
|
attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
|
|
|
|
attributes_mask = GDK_WA_VISUAL | GDK_WA_X | GDK_WA_Y | GDK_WA_COLORMAP;
|
|
|
|
superwin->shell_window = gdk_window_new (parent_window,
|
|
&attributes, attributes_mask);
|
|
|
|
/* set the back pixmap to None so that you don't end up with the gtk
|
|
default which is BlackPixel */
|
|
gdk_window_set_back_pixmap (superwin->shell_window, NULL, FALSE);
|
|
|
|
/* if we failed to create a window, die a horrible death */
|
|
g_assert((superwin->shell_window));
|
|
|
|
/* Create the bin window for drawing */
|
|
|
|
attributes.x = 0;
|
|
attributes.y = 0;
|
|
attributes.event_mask = GDK_EXPOSURE_MASK;
|
|
|
|
superwin->bin_window = gdk_window_new (superwin->shell_window,
|
|
&attributes, attributes_mask);
|
|
|
|
/* set the back pixmap to None so that you don't end up with the gtk
|
|
default which is BlackPixel */
|
|
gdk_window_set_back_pixmap (superwin->bin_window, NULL, FALSE);
|
|
|
|
/* set the backing store for the bin window */
|
|
bin_xwindow = GDK_WINDOW_XWINDOW(superwin->bin_window);
|
|
xdisplay = GDK_WINDOW_XDISPLAY(superwin->bin_window);
|
|
/* XXX should we make this Always? */
|
|
xattr.backing_store = WhenMapped;
|
|
xattr_mask = CWBackingStore;
|
|
/* XChangeWindowAttributes(xdisplay, bin_xwindow, xattr_mask, &xattr); */
|
|
|
|
gdk_window_show (superwin->bin_window);
|
|
|
|
gdk_window_add_filter (superwin->shell_window, gdk_superwin_shell_filter, superwin);
|
|
gdk_window_add_filter (superwin->bin_window, gdk_superwin_bin_filter, superwin);
|
|
|
|
gravity_works = gdk_window_set_static_gravities (superwin->bin_window, TRUE);
|
|
|
|
return superwin;
|
|
}
|
|
|
|
/* XXX this should really be part of the object... */
|
|
/* XXX and it should chain up to the object's destructor */
|
|
|
|
void gdk_superwin_destroy(GtkObject *object)
|
|
{
|
|
|
|
GdkSuperWin *superwin = NULL;
|
|
|
|
g_return_if_fail(object != NULL);
|
|
g_return_if_fail(GTK_IS_OBJECT(object));
|
|
g_return_if_fail(GTK_OBJECT_CONSTRUCTED(object));
|
|
g_return_if_fail(GDK_IS_SUPERWIN(object));
|
|
|
|
superwin = GDK_SUPERWIN(object);
|
|
|
|
gdk_window_remove_filter(superwin->shell_window,
|
|
gdk_superwin_shell_filter,
|
|
superwin);
|
|
gdk_window_remove_filter(superwin->bin_window,
|
|
gdk_superwin_bin_filter,
|
|
superwin);
|
|
gdk_window_destroy(superwin->bin_window);
|
|
gdk_window_destroy(superwin->shell_window);
|
|
|
|
if (superwin->translate_queue) {
|
|
GSList *tmp_list = superwin->translate_queue;
|
|
while (tmp_list) {
|
|
g_free(tmp_list->data);
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
g_slist_free(superwin->translate_queue);
|
|
}
|
|
}
|
|
|
|
void
|
|
gdk_superwin_scroll (GdkSuperWin *superwin,
|
|
gint dx,
|
|
gint dy)
|
|
{
|
|
gint width, height;
|
|
|
|
gint first_resize_x = 0;
|
|
gint first_resize_y = 0;
|
|
gint first_resize_width = 0;
|
|
gint first_resize_height = 0;
|
|
|
|
unsigned long first_resize_serial = 0;
|
|
unsigned long move_serial = 0;
|
|
unsigned long last_resize_serial = 0;
|
|
gint move_x = 0;
|
|
gint move_y = 0;
|
|
|
|
/* get the current dimensions of the window */
|
|
gdk_window_get_size (superwin->shell_window, &width, &height);
|
|
|
|
/* calculate the first resize. */
|
|
|
|
/* for the first move resize, the width + height default to the
|
|
width and height of the window. */
|
|
first_resize_width = width;
|
|
first_resize_height = height;
|
|
|
|
/* if scrolling left ( dx < 0 ) need to extend window right by
|
|
ABS(dx) and left side of window won't move. */
|
|
if (dx < 0) {
|
|
/* left side of the window doesn't move. */
|
|
first_resize_x = 0;
|
|
/* right side of window will be the width + the offset of the
|
|
scroll */
|
|
first_resize_width = width + ABS(dx);
|
|
}
|
|
|
|
/* if scrolling right ( dx > 0 ) need to extend window left by
|
|
ABS(dx) and right side of the window doesn't move */
|
|
if (dx > 0) {
|
|
/* left side of the window will be offset to the left by ABS(dx) (
|
|
x will be < 0 ) */
|
|
first_resize_x = -dx;
|
|
/* right side of the window won't move. We have to add the offset
|
|
to the width so that it doesn't. */
|
|
first_resize_width = width + dx;
|
|
}
|
|
|
|
/* if scrolling down ( dy < 0 ) need to extend window down by
|
|
ABS(dy) and top of window won't move */
|
|
if (dy < 0) {
|
|
/* top of window not moving */
|
|
first_resize_y = 0;
|
|
/* bottom of window will be the height + the offset of the scroll */
|
|
first_resize_height = height + ABS(dy);
|
|
}
|
|
|
|
/* if scrolling up ( dy > 0 ) need to extend window up by ABS(dy)
|
|
and bottom of window won't move. */
|
|
if (dy > 0) {
|
|
/* top of the window will be moved up by ABS(dy) ( y will be < 0 ) */
|
|
first_resize_y = -dy;
|
|
/* this will cause the bottom of the window not to move since
|
|
we're moving y by the offset up. */
|
|
first_resize_height = height + dy;
|
|
}
|
|
|
|
/* calculate our move offsets */
|
|
|
|
/* if scrolling left ( dx < 0 ) we need to move the window left by
|
|
ABS(dx) */
|
|
if (dx < 0) {
|
|
/* dx will be negative - this will move it left */
|
|
move_x = dx;
|
|
}
|
|
|
|
/* if scrolling right ( dx > 0 ) we need to move the window right by
|
|
ABS(dx). Because we already resized the window to -dx by moving
|
|
it to zero we are actually moving the window to the right. */
|
|
if (dx > 0) {
|
|
move_x = 0;
|
|
}
|
|
|
|
/* If scrolling down ( dy < 0 ) we need to move the window up by
|
|
ABS(dy) */
|
|
if (dy < 0) {
|
|
/* dy will be negative - this will move it up */
|
|
move_y = dy;
|
|
}
|
|
|
|
/* If scrolling up ( dy > 0 ) we need to move the window down by
|
|
ABS(dy). In this case we already resized the top of the window
|
|
to -dy so by moving it to zero we are actually moving the window
|
|
down. */
|
|
if (dy > 0) {
|
|
move_y = 0;
|
|
}
|
|
|
|
/* save the serial of the first request */
|
|
first_resize_serial = NextRequest(GDK_DISPLAY());
|
|
|
|
/* move our window */
|
|
gdk_window_move_resize(superwin->bin_window,
|
|
first_resize_x, first_resize_y,
|
|
first_resize_width, first_resize_height);
|
|
|
|
/* window move - this move will cause all of the exposes to happen
|
|
and is where all the translation magic has to be applied. we
|
|
need to save the serial of this operation since any expose events
|
|
with serial request numbers lower than it will have to have their
|
|
coordinates translated into the new coordinate system. */
|
|
|
|
move_serial = NextRequest(GDK_DISPLAY());
|
|
|
|
gdk_window_move(superwin->bin_window,
|
|
move_x, move_y);
|
|
|
|
/* last resize. This will resize the window to its original
|
|
position. */
|
|
|
|
/* save the request of the last resize */
|
|
last_resize_serial = NextRequest(GDK_DISPLAY());
|
|
|
|
gdk_window_move_resize(superwin->bin_window,
|
|
0, 0, width, height);
|
|
|
|
/* now that we have moved everything, repaint the damaged areas */
|
|
|
|
/* if scrolling left ( dx < 0 ) moving window left so expose area at
|
|
the right of the window. Clip the width of the exposure to the
|
|
width of the window or the offset, whichever is smaller. Also
|
|
clip the start to the origin ( 0 ) if the width minus the
|
|
absolute value of the offset is < 0 to handle > 1 page
|
|
scrolls. */
|
|
if (dx < 0) {
|
|
gdk_superwin_expose_area(superwin, MAX(0, width - ABS(dx)), 0,
|
|
MIN(width, ABS(dx)), height);
|
|
/* If we've exposed this area add an antiexpose for it. When the
|
|
window was moved left the expose will be offset by ABS(dx).
|
|
For greated than one page scrolls, the expose will be offset by
|
|
the actual offset of the move, hence the MAX(height,
|
|
ABS(dy)). */
|
|
gdk_superwin_add_antiexpose(superwin, move_serial,
|
|
MAX(width, ABS(dx)),
|
|
0, MIN(width, ABS(dx)), height);
|
|
}
|
|
|
|
/* if scrolling right ( dx > 0 ) moving window right so expose area
|
|
at the left of the window. Clip the width of the exposure to the
|
|
width of the window or the offset, whichever is smaller. */
|
|
if (dx > 0) {
|
|
gdk_superwin_expose_area(superwin, 0, 0,
|
|
MIN(width, ABS(dx)), height);
|
|
/* If we've exposed this area add an antiexpose for it. */
|
|
gdk_superwin_add_antiexpose(superwin, move_serial,
|
|
0, 0, MIN(width, ABS(dx)), height);
|
|
}
|
|
|
|
/* if scrolling down ( dy < 0 ) moving window up so expose area at
|
|
the bottom of the window. Clip the exposed area to the height of
|
|
the window or the offset, whichever is smaller. Also clip the
|
|
start to the origin ( 0 ) if the the height minus the absolute
|
|
value of the offset is < 0 to handle > 1 page scrolls. */
|
|
|
|
if (dy < 0) {
|
|
gdk_superwin_expose_area(superwin, 0, MAX(0, height - ABS(dy)),
|
|
width, MIN(height, ABS(dy)));
|
|
/* If we've exposed this area add an antiexpose for it. When the
|
|
was moved up before the second move the expose will be offset
|
|
by ABS(dy). For greater than one page scrolls, the expose will
|
|
be offset by actual offset of the move, hence the MAX(height,
|
|
ABS(dy)). */
|
|
gdk_superwin_add_antiexpose(superwin, move_serial,
|
|
0,
|
|
MAX(height, ABS(dy)),
|
|
width, MIN(height, ABS(dy)));
|
|
}
|
|
|
|
/* if scrolling up ( dy > 0 ) moving window down so expose area at
|
|
the top of the window. Clip the exposed area to the height or
|
|
the offset, whichever is smaller. */
|
|
if (dy > 0) {
|
|
gdk_superwin_expose_area(superwin, 0, 0,
|
|
width, MIN(height, ABS(dy)));
|
|
/* if we've exposed this area add an antiexpose for it. */
|
|
gdk_superwin_add_antiexpose(superwin, move_serial,
|
|
0, 0, width, MIN(height, ABS(dy)));
|
|
}
|
|
|
|
/* if we are scrolling right or down ( dx > 0 or dy > 0 ) we need to
|
|
add our translation before the fist move_resize. Once we do this
|
|
all previous expose events will be translated into the new
|
|
coordinate space */
|
|
if (dx > 0 || dy > 0) {
|
|
gdk_superwin_add_translation(superwin, first_resize_serial,
|
|
MAX(0, dx), MAX(0, dy));
|
|
}
|
|
|
|
/* If we are scrolling left or down ( x < 0 or y < 0 ) we need to
|
|
add our translation before the last move_resize. Once we do this
|
|
all previous expose events will be translated in the new
|
|
coordinate space. */
|
|
if (dx < 0 || dy < 0) {
|
|
gdk_superwin_add_translation(superwin, last_resize_serial,
|
|
MIN(0, dx), MIN(0, dy));
|
|
}
|
|
|
|
/* sync so we get the windows moved now */
|
|
XSync(GDK_DISPLAY(), False);
|
|
}
|
|
|
|
void
|
|
gdk_superwin_set_event_funcs (GdkSuperWin *superwin,
|
|
GdkSuperWinFunc shell_func,
|
|
GdkSuperWinPaintFunc paint_func,
|
|
GdkSuperWinPaintFlushFunc flush_func,
|
|
GdkSuperWinKeyPressFunc keyprs_func,
|
|
GdkSuperWinKeyReleaseFunc keyrel_func,
|
|
gpointer func_data,
|
|
GDestroyNotify notify)
|
|
{
|
|
if (superwin->notify && superwin->func_data)
|
|
superwin->notify (superwin->func_data);
|
|
|
|
superwin->shell_func = shell_func;
|
|
superwin->paint_func = paint_func;
|
|
superwin->flush_func = flush_func;
|
|
superwin->keyprs_func = keyprs_func;
|
|
superwin->keyrel_func = keyrel_func;
|
|
superwin->func_data = func_data;
|
|
superwin->notify = notify;
|
|
|
|
}
|
|
|
|
void gdk_superwin_resize (GdkSuperWin *superwin,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
gdk_window_resize (superwin->bin_window, width, height);
|
|
gdk_window_resize (superwin->shell_window, width, height);
|
|
}
|
|
|
|
static void
|
|
gdk_superwin_expose_area (GdkSuperWin *superwin,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
if (superwin->paint_func)
|
|
superwin->paint_func(x, y, width, height, superwin->func_data);
|
|
}
|
|
|
|
static void
|
|
gdk_superwin_flush(GdkSuperWin *superwin)
|
|
{
|
|
if (superwin->flush_func)
|
|
superwin->flush_func(superwin->func_data);
|
|
}
|
|
|
|
static GdkFilterReturn
|
|
gdk_superwin_bin_filter (GdkXEvent *gdk_xevent,
|
|
GdkEvent *event,
|
|
gpointer data)
|
|
{
|
|
XEvent *xevent = (XEvent *)gdk_xevent;
|
|
GdkSuperWin *superwin = data;
|
|
GdkFilterReturn retval = GDK_FILTER_CONTINUE;
|
|
GdkRegion *region = NULL;
|
|
|
|
switch (xevent->xany.type) {
|
|
case Expose:
|
|
region = gdk_region_new();
|
|
retval = GDK_FILTER_REMOVE;
|
|
gdk_superwin_handle_expose(superwin, xevent, ®ion, FALSE);
|
|
gdk_region_destroy(region);
|
|
break;
|
|
case KeyPress:
|
|
if (superwin->keyprs_func)
|
|
superwin->keyprs_func(&xevent->xkey);
|
|
break;
|
|
case KeyRelease:
|
|
if (superwin->keyrel_func)
|
|
superwin->keyrel_func(&xevent->xkey);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
|
|
static GdkFilterReturn
|
|
gdk_superwin_shell_filter (GdkXEvent *gdk_xevent,
|
|
GdkEvent *event,
|
|
gpointer data)
|
|
{
|
|
XEvent *xevent = (XEvent *)gdk_xevent;
|
|
GdkSuperWin *superwin = data;
|
|
|
|
if (xevent->type == VisibilityNotify)
|
|
{
|
|
switch (xevent->xvisibility.state)
|
|
{
|
|
case VisibilityFullyObscured:
|
|
superwin->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
|
|
break;
|
|
|
|
case VisibilityPartiallyObscured:
|
|
superwin->visibility = GDK_VISIBILITY_PARTIAL;
|
|
break;
|
|
|
|
case VisibilityUnobscured:
|
|
superwin->visibility = GDK_VISIBILITY_UNOBSCURED;
|
|
break;
|
|
}
|
|
|
|
return GDK_FILTER_REMOVE;
|
|
}
|
|
|
|
if (superwin->shell_func) {
|
|
superwin->shell_func (superwin, xevent, superwin->func_data);
|
|
}
|
|
return GDK_FILTER_CONTINUE;
|
|
}
|
|
|
|
/* this function is used to check whether or not a particular event is
|
|
for a specific superwin and is a ConfigureNotify or Expose
|
|
event. */
|
|
|
|
Bool gdk_superwin_expose_predicate(Display *display,
|
|
XEvent *xevent,
|
|
XPointer arg) {
|
|
GdkSuperWin *superwin = (GdkSuperWin *)arg;
|
|
if (xevent->xany.window != GDK_WINDOW_XWINDOW(superwin->bin_window))
|
|
return False;
|
|
switch (xevent->xany.type) {
|
|
case Expose:
|
|
return True;
|
|
break;
|
|
default:
|
|
return False;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* static */
|
|
void gdk_superwin_add_translation(GdkSuperWin *superwin, unsigned long serial,
|
|
gint dx, gint dy)
|
|
{
|
|
GdkSuperWinTranslate *translate = g_new(GdkSuperWinTranslate, 1);
|
|
translate->type = GDK_SUPERWIN_TRANSLATION;
|
|
translate->serial = serial;
|
|
translate->data.translation.dx = dx;
|
|
translate->data.translation.dy = dy;
|
|
superwin->translate_queue = g_slist_append(superwin->translate_queue, translate);
|
|
}
|
|
|
|
/* static */
|
|
void gdk_superwin_add_antiexpose (GdkSuperWin *superwin, unsigned long serial,
|
|
gint x, gint y,
|
|
gint width, gint height)
|
|
|
|
{
|
|
GdkSuperWinTranslate *translate = g_new(GdkSuperWinTranslate, 1);
|
|
translate->type = GDK_SUPERWIN_ANTIEXPOSE;
|
|
translate->serial = serial;
|
|
translate->data.antiexpose.rect.x = x;
|
|
translate->data.antiexpose.rect.y = y;
|
|
translate->data.antiexpose.rect.width = width;
|
|
translate->data.antiexpose.rect.height = height;
|
|
superwin->translate_queue = g_slist_append(superwin->translate_queue, translate);
|
|
}
|
|
|
|
/* static */
|
|
void gdk_superwin_handle_expose (GdkSuperWin *superwin, XEvent *xevent,
|
|
GdkRegion **region, gboolean dont_recurse)
|
|
{
|
|
GSList *tmp_list;
|
|
gboolean send_event = TRUE;
|
|
unsigned long serial = xevent->xany.serial;
|
|
XEvent extra_event;
|
|
GdkRectangle rect;
|
|
GdkRegion *tmp_region = NULL;
|
|
gboolean is_special = TRUE;
|
|
|
|
/* set up our rect for the damaged area */
|
|
rect.x = xevent->xexpose.x;
|
|
rect.y = xevent->xexpose.y;
|
|
rect.width = xevent->xexpose.width;
|
|
rect.height = xevent->xexpose.height;
|
|
|
|
/* try to see if this is a special event that matches an antiexpose */
|
|
tmp_list = superwin->translate_queue;
|
|
while (tmp_list) {
|
|
GdkSuperWinTranslate *xlate = tmp_list->data;
|
|
if (xlate->type == GDK_SUPERWIN_ANTIEXPOSE && serial == xlate->serial) {
|
|
GdkRegion *antiexpose_region = gdk_region_new();
|
|
tmp_region = gdk_region_union_with_rect(antiexpose_region,
|
|
&xlate->data.antiexpose.rect);
|
|
gdk_region_destroy(antiexpose_region);
|
|
antiexpose_region = tmp_region;
|
|
/* if the rect of the expose event is contained in the
|
|
antiexpose then we should just drop it on the floor. */
|
|
if (gdk_region_rect_in(antiexpose_region, &rect) == GDK_OVERLAP_RECTANGLE_IN) {
|
|
gdk_region_destroy(antiexpose_region);
|
|
goto end;
|
|
}
|
|
gdk_region_destroy(antiexpose_region);
|
|
|
|
}
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
|
|
/* we walk the list looking for any transformations */
|
|
tmp_list = superwin->translate_queue;
|
|
while (tmp_list) {
|
|
GdkSuperWinTranslate *xlate = tmp_list->data;
|
|
/* apply translations to this event if we can. */
|
|
if (xlate->type == GDK_SUPERWIN_TRANSLATION && serial < xlate->serial ) {
|
|
rect.x += xlate->data.translation.dx;
|
|
rect.y += xlate->data.translation.dy;
|
|
}
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
|
|
/* add this expose area to our damaged rect */
|
|
|
|
tmp_region = gdk_region_union_with_rect(*region, &rect);
|
|
gdk_region_destroy(*region);
|
|
*region = tmp_region;
|
|
|
|
end:
|
|
|
|
/* remove any events from the queue that are old */
|
|
tmp_list = superwin->translate_queue;
|
|
while (tmp_list) {
|
|
GdkSuperWinTranslate *xlate = tmp_list->data;
|
|
if (serial > xlate->serial) {
|
|
GSList *tmp_link = tmp_list;
|
|
tmp_list = tmp_list->next;
|
|
superwin->translate_queue = g_slist_remove_link(superwin->translate_queue,
|
|
tmp_link);
|
|
g_free(tmp_link->data);
|
|
g_slist_free_1(tmp_link);
|
|
}
|
|
else {
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
}
|
|
|
|
/* if we're not supposed to recurse or paint then return now */
|
|
if (dont_recurse)
|
|
return;
|
|
|
|
/* try to do any expose event compression we can */
|
|
while (XCheckTypedWindowEvent(xevent->xany.display,
|
|
xevent->xany.window,
|
|
Expose,
|
|
&extra_event) == True) {
|
|
gdk_superwin_handle_expose(superwin, &extra_event, region, TRUE);
|
|
}
|
|
|
|
/* if the region isn't empty, send the paint event */
|
|
if (gdk_region_empty(*region) == FALSE) {
|
|
GdkRectangle clip_box;
|
|
gdk_region_get_clipbox(*region, &clip_box);
|
|
if (superwin->paint_func)
|
|
superwin->paint_func(clip_box.x, clip_box.y,
|
|
clip_box.width, clip_box.height,
|
|
superwin->func_data);
|
|
}
|
|
|
|
}
|