Back to index

lightning-sunbird  0.9+nobinonly
gdksuperwin.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org Code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Owen Taylor <otaylor@redhat.com> and Christopher Blizzard <blizzard@redhat.com>.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "gdksuperwin.h"
00040 
00041 static void gdk_superwin_class_init(GdkSuperWinClass *klass);
00042 static void gdk_superwin_init(GdkSuperWin *superwin);
00043 static void gdk_superwin_expose_area  (GdkSuperWin *superwin,
00044                                        gint         x,
00045                                        gint         y,
00046                                        gint         width,
00047                                        gint         height);
00048 static void gdk_superwin_flush(GdkSuperWin *superwin);
00049 static void gdk_superwin_destroy(GtkObject *object);
00050 
00051 static void gdk_superwin_add_translation(GdkSuperWin *superwin, unsigned long serial,
00052                                          gint dx, gint dy);
00053 static void gdk_superwin_add_antiexpose (GdkSuperWin *superwin, unsigned long serial,
00054                                          gint x, gint y,
00055                                          gint width, gint height);
00056 
00057 static void gdk_superwin_handle_expose (GdkSuperWin *superwin, XEvent *xevent,
00058                                         GdkRegion **region, gboolean dont_recurse);
00059 
00060 static Bool gdk_superwin_expose_predicate(Display  *display,
00061                                           XEvent   *xevent,
00062                                           XPointer  arg);
00063 
00064 typedef struct _GdkSuperWinTranslate GdkSuperWinTranslate;
00065 
00066 enum {
00067   GDK_SUPERWIN_TRANSLATION = 1,
00068   GDK_SUPERWIN_ANTIEXPOSE
00069 };
00070   
00071 
00072 struct _GdkSuperWinTranslate
00073 {
00074   int type;
00075   unsigned long serial;
00076   union {
00077     struct {
00078       gint dx;
00079       gint dy;
00080     } translation;
00081     struct {
00082       GdkRectangle rect;
00083     } antiexpose;
00084   } data;
00085 };
00086 
00087 GtkType
00088 gdk_superwin_get_type(void)
00089 {
00090   static GtkType superwin_type = 0;
00091   
00092   if (!superwin_type)
00093     {
00094       static const GtkTypeInfo superwin_info =
00095       {
00096         "GtkSuperWin",
00097           sizeof(GdkSuperWin),
00098           sizeof(GdkSuperWinClass),
00099           (GtkClassInitFunc) gdk_superwin_class_init,
00100           (GtkObjectInitFunc) gdk_superwin_init,
00101           /* reserved_1 */ NULL,
00102           /* reserved_2 */ NULL,
00103           (GtkClassInitFunc) NULL
00104       };
00105       
00106       superwin_type = gtk_type_unique (gtk_object_get_type(), &superwin_info);
00107     }
00108   return superwin_type;
00109 }
00110 
00111 static void
00112 gdk_superwin_class_init(GdkSuperWinClass *klass)
00113 {
00114   GtkObjectClass *object_class;
00115 
00116   object_class = GTK_OBJECT_CLASS(klass);
00117   object_class->destroy = gdk_superwin_destroy;
00118 
00119 }
00120 
00121 static void
00122 gdk_superwin_init(GdkSuperWin *superwin)
00123 {
00124   
00125 }
00126 
00127 static GdkFilterReturn  gdk_superwin_bin_filter   (GdkXEvent *gdk_xevent,
00128                                                    GdkEvent  *event,
00129                                                    gpointer   data);
00130 static GdkFilterReturn  gdk_superwin_shell_filter (GdkXEvent *gdk_xevent,
00131                                                    GdkEvent  *event,
00132                                                    gpointer   data);
00133 
00134 static gboolean gravity_works;
00135 
00136 GdkSuperWin *
00137 gdk_superwin_new (GdkWindow *parent_window,
00138                   guint      x,
00139                   guint      y,
00140                   guint      width,
00141                   guint      height)
00142 {
00143   GdkWindowAttr         attributes;
00144   gint                  attributes_mask;
00145   Window                bin_xwindow;
00146   Display              *xdisplay;
00147   XSetWindowAttributes  xattr;
00148   unsigned long         xattr_mask;
00149 
00150   GdkSuperWin *superwin = gtk_type_new(GDK_TYPE_SUPERWIN);
00151 
00152   superwin->translate_queue = NULL;
00153 
00154   superwin->shell_func = NULL;
00155   superwin->paint_func = NULL;
00156   superwin->flush_func = NULL;
00157   superwin->func_data = NULL;
00158   superwin->notify = NULL;
00159 
00160   /* Create the shell (clipping) window */
00161   attributes.window_type = GDK_WINDOW_CHILD;
00162   attributes.x = x;
00163   attributes.y = y;
00164   attributes.width = width;
00165   attributes.height = height;
00166   attributes.wclass = GDK_INPUT_OUTPUT;
00167   attributes.colormap = gdk_rgb_get_cmap();
00168   attributes.visual = gdk_rgb_get_visual();
00169   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
00170 
00171   attributes_mask = GDK_WA_VISUAL | GDK_WA_X | GDK_WA_Y | GDK_WA_COLORMAP;
00172 
00173   superwin->shell_window = gdk_window_new (parent_window,
00174                                       &attributes, attributes_mask);
00175 
00176   /* set the back pixmap to None so that you don't end up with the gtk
00177      default which is BlackPixel */
00178   gdk_window_set_back_pixmap (superwin->shell_window, NULL, FALSE);
00179 
00180   /* if we failed to create a window, die a horrible death */
00181   g_assert((superwin->shell_window));
00182 
00183   /* Create the bin window for drawing */
00184 
00185   attributes.x = 0;
00186   attributes.y = 0;
00187   attributes.event_mask = GDK_EXPOSURE_MASK;
00188 
00189   superwin->bin_window = gdk_window_new (superwin->shell_window,
00190                                          &attributes, attributes_mask);
00191 
00192   /* set the back pixmap to None so that you don't end up with the gtk
00193      default which is BlackPixel */
00194   gdk_window_set_back_pixmap (superwin->bin_window, NULL, FALSE);
00195 
00196   /* set the backing store for the bin window */
00197   bin_xwindow = GDK_WINDOW_XWINDOW(superwin->bin_window);
00198   xdisplay = GDK_WINDOW_XDISPLAY(superwin->bin_window);
00199   /* XXX should we make this Always? */
00200   xattr.backing_store = WhenMapped;
00201   xattr_mask = CWBackingStore;
00202   /* XChangeWindowAttributes(xdisplay, bin_xwindow, xattr_mask, &xattr); */
00203 
00204   gdk_window_show (superwin->bin_window);
00205 
00206   gdk_window_add_filter (superwin->shell_window, gdk_superwin_shell_filter, superwin);
00207   gdk_window_add_filter (superwin->bin_window, gdk_superwin_bin_filter, superwin);
00208 
00209   gravity_works = gdk_window_set_static_gravities (superwin->bin_window, TRUE);
00210 
00211   return superwin;
00212 }
00213 
00214 /* XXX this should really be part of the object... */
00215 /* XXX and it should chain up to the object's destructor */
00216 
00217 void gdk_superwin_destroy(GtkObject *object)
00218 {
00219   
00220   GdkSuperWin *superwin = NULL;
00221 
00222   g_return_if_fail(object != NULL);
00223   g_return_if_fail(GTK_IS_OBJECT(object));
00224   g_return_if_fail(GTK_OBJECT_CONSTRUCTED(object));
00225   g_return_if_fail(GDK_IS_SUPERWIN(object));
00226 
00227   superwin = GDK_SUPERWIN(object);
00228 
00229   gdk_window_remove_filter(superwin->shell_window,
00230                            gdk_superwin_shell_filter,
00231                            superwin);
00232   gdk_window_remove_filter(superwin->bin_window,
00233                            gdk_superwin_bin_filter,
00234                            superwin);
00235   gdk_window_destroy(superwin->bin_window);
00236   gdk_window_destroy(superwin->shell_window);
00237 
00238   if (superwin->translate_queue) {
00239     GSList *tmp_list = superwin->translate_queue;
00240     while (tmp_list) {
00241       g_free(tmp_list->data);
00242       tmp_list = tmp_list->next;
00243     }
00244     g_slist_free(superwin->translate_queue);
00245   }
00246 }
00247 
00248 void gdk_superwin_reparent(GdkSuperWin *superwin,
00249                            GdkWindow   *parent_window)
00250 {
00251   gdk_window_reparent(superwin->shell_window,
00252                       parent_window, 0, 0);
00253 }
00254 
00255 void         
00256 gdk_superwin_scroll (GdkSuperWin *superwin,
00257                      gint dx,
00258                      gint dy)
00259 {
00260   gint width, height;
00261 
00262   gint first_resize_x = 0;
00263   gint first_resize_y = 0;
00264   gint first_resize_width = 0;
00265   gint first_resize_height = 0;
00266 
00267   unsigned long first_resize_serial = 0;
00268   unsigned long move_serial = 0;
00269   unsigned long last_resize_serial = 0;
00270   gint move_x = 0;
00271   gint move_y = 0;
00272 
00273   /* get the current dimensions of the window */
00274   gdk_window_get_size (superwin->shell_window, &width, &height);
00275 
00276   /* calculate the first resize. */
00277 
00278   /* for the first move resize, the width + height default to the
00279      width and height of the window. */
00280   first_resize_width = width;
00281   first_resize_height = height;
00282 
00283   /* if scrolling left ( dx < 0 ) need to extend window right by
00284      ABS(dx) and left side of window won't move. */
00285   if (dx < 0) {
00286     /* left side of the window doesn't move. */
00287     first_resize_x = 0;
00288     /* right side of window will be the width + the offset of the
00289        scroll */
00290     first_resize_width = width + ABS(dx);
00291   }
00292 
00293   /* if scrolling right ( dx > 0 ) need to extend window left by
00294      ABS(dx) and right side of the window doesn't move */
00295   if (dx > 0) {
00296     /* left side of the window will be offset to the left by ABS(dx) (
00297        x will be < 0 ) */
00298     first_resize_x = -dx;
00299     /* right side of the window won't move.  We have to add the offset
00300        to the width so that it doesn't. */
00301     first_resize_width = width + dx;
00302   }
00303 
00304   /* if scrolling down ( dy < 0 ) need to extend window down by
00305      ABS(dy) and top of window won't move */
00306   if (dy < 0) {
00307     /* top of window not moving */
00308     first_resize_y = 0;
00309     /* bottom of window will be the height + the offset of the scroll */
00310     first_resize_height = height + ABS(dy);
00311   }
00312 
00313   /* if scrolling up ( dy > 0 ) need to extend window up by ABS(dy)
00314      and bottom of window won't move. */
00315   if (dy > 0) {
00316     /* top of the window will be moved up by ABS(dy) ( y will be < 0 ) */
00317     first_resize_y = -dy;
00318     /* this will cause the bottom of the window not to move since
00319        we're moving y by the offset up. */
00320     first_resize_height = height + dy; 
00321   }
00322 
00323   /* calculate our move offsets  */
00324 
00325   /* if scrolling left ( dx < 0 ) we need to move the window left by
00326      ABS(dx) */
00327   if (dx < 0) {
00328     /* dx will be negative - this will move it left */
00329     move_x = dx;
00330   }
00331 
00332   /* if scrolling right ( dx > 0 ) we need to move the window right by
00333      ABS(dx).  Because we already resized the window to -dx by moving
00334      it to zero we are actually moving the window to the right. */
00335   if (dx > 0) {
00336     move_x = 0;
00337   }
00338 
00339   /* If scrolling down ( dy < 0 ) we need to move the window up by
00340      ABS(dy) */
00341   if (dy < 0) {
00342     /* dy will be negative - this will move it up */
00343     move_y = dy;
00344   }
00345 
00346   /* If scrolling up ( dy > 0 ) we need to move the window down by
00347      ABS(dy).  In this case we already resized the top of the window
00348      to -dy so by moving it to zero we are actually moving the window
00349      down. */
00350   if (dy > 0) {
00351     move_y = 0;
00352   }
00353 
00354   /* save the serial of the first request */
00355   first_resize_serial = NextRequest(GDK_DISPLAY());
00356 
00357   /* move our window */
00358   gdk_window_move_resize(superwin->bin_window,
00359                          first_resize_x, first_resize_y,
00360                          first_resize_width, first_resize_height);
00361 
00362   /* window move - this move will cause all of the exposes to happen
00363      and is where all the translation magic has to be applied.  we
00364      need to save the serial of this operation since any expose events
00365      with serial request numbers lower than it will have to have their
00366      coordinates translated into the new coordinate system. */
00367 
00368   move_serial = NextRequest(GDK_DISPLAY());
00369 
00370   gdk_window_move(superwin->bin_window,
00371                   move_x, move_y);
00372 
00373   /* last resize.  This will resize the window to its original
00374      position. */
00375 
00376   /* save the request of the last resize */
00377   last_resize_serial = NextRequest(GDK_DISPLAY());
00378 
00379   gdk_window_move_resize(superwin->bin_window,
00380                          0, 0, width, height);
00381 
00382   /* now that we have moved everything, repaint the damaged areas */
00383 
00384   /* if scrolling left ( dx < 0 ) moving window left so expose area at
00385      the right of the window.  Clip the width of the exposure to the
00386      width of the window or the offset, whichever is smaller.  Also
00387      clip the start to the origin ( 0 ) if the width minus the
00388      absolute value of the offset is < 0 to handle > 1 page
00389      scrolls. */
00390   if (dx < 0) {
00391     gdk_superwin_expose_area(superwin, MAX(0, width - ABS(dx)), 0,
00392                              MIN(width, ABS(dx)), height);
00393     /* If we've exposed this area add an antiexpose for it.  When the
00394        window was moved left the expose will be offset by ABS(dx).
00395        For greated than one page scrolls, the expose will be offset by
00396        the actual offset of the move, hence the MAX(height,
00397        ABS(dy)). */
00398     gdk_superwin_add_antiexpose(superwin, move_serial,
00399                                 MAX(width, ABS(dx)),
00400                                 0, MIN(width, ABS(dx)), height);
00401   }
00402 
00403   /* if scrolling right ( dx > 0 ) moving window right so expose area
00404      at the left of the window.  Clip the width of the exposure to the
00405      width of the window or the offset, whichever is smaller. */
00406   if (dx > 0) {
00407     gdk_superwin_expose_area(superwin, 0, 0, 
00408                              MIN(width, ABS(dx)), height);
00409     /* If we've exposed this area add an antiexpose for it. */
00410     gdk_superwin_add_antiexpose(superwin, move_serial,
00411                                 0, 0, MIN(width, ABS(dx)), height);
00412   }
00413 
00414   /* if scrolling down ( dy < 0 ) moving window up so expose area at
00415      the bottom of the window.  Clip the exposed area to the height of
00416      the window or the offset, whichever is smaller.  Also clip the
00417      start to the origin ( 0 ) if the the height minus the absolute
00418      value of the offset is < 0 to handle > 1 page scrolls. */
00419 
00420   if (dy < 0) {
00421     gdk_superwin_expose_area(superwin, 0, MAX(0, height - ABS(dy)),
00422                              width, MIN(height, ABS(dy)));
00423     /* If we've exposed this area add an antiexpose for it.  When the
00424        was moved up before the second move the expose will be offset
00425        by ABS(dy).  For greater than one page scrolls, the expose will
00426        be offset by actual offset of the move, hence the MAX(height,
00427        ABS(dy)).  */
00428         gdk_superwin_add_antiexpose(superwin, move_serial,
00429                                     0,
00430                                     MAX(height, ABS(dy)),
00431                                     width, MIN(height, ABS(dy)));
00432   }
00433 
00434   /* if scrolling up ( dy > 0 ) moving window down so expose area at
00435      the top of the window.  Clip the exposed area to the height or
00436      the offset, whichever is smaller. */
00437   if (dy > 0) {
00438     gdk_superwin_expose_area(superwin, 0, 0,
00439                              width, MIN(height, ABS(dy)));
00440     /* if we've exposed this area add an antiexpose for it. */
00441     gdk_superwin_add_antiexpose(superwin, move_serial,
00442                                 0, 0, width, MIN(height, ABS(dy)));
00443   }
00444 
00445   /* if we are scrolling right or down ( dx > 0 or dy > 0 ) we need to
00446      add our translation before the fist move_resize.  Once we do this
00447      all previous expose events will be translated into the new
00448      coordinate space */
00449   if (dx > 0 || dy > 0) {
00450     gdk_superwin_add_translation(superwin, first_resize_serial,
00451                                  MAX(0, dx), MAX(0, dy));
00452   }
00453 
00454   /* If we are scrolling left or down ( x < 0 or y < 0 ) we need to
00455      add our translation before the last move_resize.  Once we do this
00456      all previous expose events will be translated in the new
00457      coordinate space. */
00458   if (dx < 0 || dy < 0) {
00459     gdk_superwin_add_translation(superwin, last_resize_serial,
00460                                  MIN(0, dx), MIN(0, dy));
00461   }
00462 
00463   /* sync so we get the windows moved now */
00464   XSync(GDK_DISPLAY(), False);
00465 }
00466 
00467 void  
00468 gdk_superwin_set_event_funcs (GdkSuperWin               *superwin,
00469                               GdkSuperWinFunc            shell_func,
00470                               GdkSuperWinPaintFunc       paint_func,
00471                               GdkSuperWinPaintFlushFunc  flush_func,
00472                               GdkSuperWinKeyPressFunc    keyprs_func,
00473                               GdkSuperWinKeyReleaseFunc  keyrel_func,
00474                               gpointer                   func_data,
00475                               GDestroyNotify             notify)
00476 {
00477   if (superwin->notify && superwin->func_data)
00478     superwin->notify (superwin->func_data);
00479   
00480   superwin->shell_func = shell_func;
00481   superwin->paint_func = paint_func;
00482   superwin->flush_func = flush_func;
00483   superwin->keyprs_func = keyprs_func;
00484   superwin->keyrel_func = keyrel_func;
00485   superwin->func_data = func_data;
00486   superwin->notify = notify;
00487 
00488 }
00489 
00490 void gdk_superwin_resize (GdkSuperWin *superwin,
00491                        gint         width,
00492                        gint         height)
00493 {
00494   gdk_window_resize (superwin->bin_window, width, height);
00495   gdk_window_resize (superwin->shell_window, width, height);
00496 }
00497 
00498 static void
00499 gdk_superwin_expose_area  (GdkSuperWin *superwin,
00500                            gint         x,
00501                            gint         y,
00502                            gint         width,
00503                            gint         height)
00504 {
00505   if (superwin->paint_func)
00506     superwin->paint_func(x, y, width, height, superwin->func_data);
00507 }
00508 
00509 static void
00510 gdk_superwin_flush(GdkSuperWin *superwin)
00511 {
00512   if (superwin->flush_func)
00513     superwin->flush_func(superwin->func_data);
00514 }
00515 
00516 static GdkFilterReturn 
00517 gdk_superwin_bin_filter (GdkXEvent *gdk_xevent,
00518                          GdkEvent  *event,
00519                          gpointer   data)
00520 {
00521   XEvent *xevent = (XEvent *)gdk_xevent;
00522   GdkSuperWin *superwin = data;
00523   GdkFilterReturn retval = GDK_FILTER_CONTINUE;
00524   GdkRegion *region = NULL;
00525 
00526   switch (xevent->xany.type) {
00527   case Expose:
00528     region = gdk_region_new();
00529     retval = GDK_FILTER_REMOVE;
00530     gdk_superwin_handle_expose(superwin, xevent, &region, FALSE);
00531     gdk_region_destroy(region);
00532     break;
00533   case KeyPress:
00534     if (superwin->keyprs_func)
00535       superwin->keyprs_func(&xevent->xkey);
00536     break;
00537   case KeyRelease:
00538     if (superwin->keyrel_func)
00539       superwin->keyrel_func(&xevent->xkey);
00540     break;
00541   default:
00542     break;
00543   }
00544   return retval;
00545 }
00546     
00547 
00548 static GdkFilterReturn 
00549 gdk_superwin_shell_filter (GdkXEvent *gdk_xevent,
00550                        GdkEvent  *event,
00551                        gpointer   data)
00552 {
00553   XEvent *xevent = (XEvent *)gdk_xevent;
00554   GdkSuperWin *superwin = data;
00555 
00556   if (xevent->type == VisibilityNotify)
00557     {
00558       switch (xevent->xvisibility.state)
00559         {
00560         case VisibilityFullyObscured:
00561           superwin->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
00562           break;
00563           
00564         case VisibilityPartiallyObscured:
00565           superwin->visibility = GDK_VISIBILITY_PARTIAL;
00566           break;
00567           
00568         case VisibilityUnobscured:
00569           superwin->visibility = GDK_VISIBILITY_UNOBSCURED;
00570           break;
00571         }
00572       
00573       return GDK_FILTER_REMOVE;
00574     }
00575   
00576   if (superwin->shell_func) {
00577     superwin->shell_func (superwin, xevent, superwin->func_data);
00578   }
00579   return GDK_FILTER_CONTINUE;
00580 }
00581 
00582 /* this function is used to check whether or not a particular event is
00583    for a specific superwin and is a ConfigureNotify or Expose
00584    event. */
00585 
00586 Bool gdk_superwin_expose_predicate(Display  *display,
00587                                    XEvent   *xevent,
00588                                    XPointer  arg) {
00589   GdkSuperWin *superwin = (GdkSuperWin *)arg;
00590   if (xevent->xany.window != GDK_WINDOW_XWINDOW(superwin->bin_window))
00591     return False;
00592   switch (xevent->xany.type) {
00593   case Expose:
00594     return True;
00595     break;
00596   default:
00597     return False;
00598     break;
00599   }
00600 }
00601 
00602 /* static */
00603 void gdk_superwin_add_translation(GdkSuperWin *superwin, unsigned long serial,
00604                                   gint dx, gint dy)
00605 {
00606   GdkSuperWinTranslate *translate = g_new(GdkSuperWinTranslate, 1);
00607   translate->type = GDK_SUPERWIN_TRANSLATION;
00608   translate->serial = serial;
00609   translate->data.translation.dx = dx;
00610   translate->data.translation.dy = dy;
00611   superwin->translate_queue = g_slist_append(superwin->translate_queue, translate);
00612 }
00613 
00614 /* static */
00615 void gdk_superwin_add_antiexpose (GdkSuperWin *superwin, unsigned long serial,
00616                                   gint x, gint y,
00617                                   gint width, gint height)
00618 
00619 {
00620   GdkSuperWinTranslate *translate = g_new(GdkSuperWinTranslate, 1);
00621   translate->type = GDK_SUPERWIN_ANTIEXPOSE;
00622   translate->serial = serial;
00623   translate->data.antiexpose.rect.x = x;
00624   translate->data.antiexpose.rect.y = y;
00625   translate->data.antiexpose.rect.width = width;
00626   translate->data.antiexpose.rect.height = height;
00627   superwin->translate_queue = g_slist_append(superwin->translate_queue, translate);
00628 }
00629 
00630 /* static */
00631 void gdk_superwin_handle_expose (GdkSuperWin *superwin, XEvent *xevent,
00632                                  GdkRegion **region, gboolean dont_recurse)
00633 {
00634   GSList *tmp_list;
00635   gboolean send_event = TRUE;
00636   unsigned long serial = xevent->xany.serial;
00637   XEvent extra_event;
00638   GdkRectangle rect;
00639   GdkRegion *tmp_region = NULL;
00640   gboolean   is_special = TRUE;
00641 
00642   /* set up our rect for the damaged area */
00643   rect.x = xevent->xexpose.x;
00644   rect.y = xevent->xexpose.y;
00645   rect.width = xevent->xexpose.width;
00646   rect.height = xevent->xexpose.height;
00647 
00648   /* try to see if this is a special event that matches an antiexpose */
00649   tmp_list = superwin->translate_queue;
00650   while (tmp_list) {
00651     GdkSuperWinTranslate *xlate = tmp_list->data;
00652     if (xlate->type == GDK_SUPERWIN_ANTIEXPOSE && serial == xlate->serial) {
00653       GdkRegion *antiexpose_region = gdk_region_new();
00654       tmp_region = gdk_region_union_with_rect(antiexpose_region, 
00655                                               &xlate->data.antiexpose.rect);
00656       gdk_region_destroy(antiexpose_region);
00657       antiexpose_region = tmp_region;
00658       /* if the rect of the expose event is contained in the
00659          antiexpose then we should just drop it on the floor. */
00660       if (gdk_region_rect_in(antiexpose_region, &rect) == GDK_OVERLAP_RECTANGLE_IN) {
00661         gdk_region_destroy(antiexpose_region);
00662         goto end;
00663       }
00664       gdk_region_destroy(antiexpose_region);
00665 
00666     }
00667     tmp_list = tmp_list->next;
00668   }
00669 
00670   /* we walk the list looking for any transformations */
00671   tmp_list = superwin->translate_queue;
00672   while (tmp_list) {
00673     GdkSuperWinTranslate *xlate = tmp_list->data;
00674     /* apply translations to this event if we can. */
00675     if (xlate->type == GDK_SUPERWIN_TRANSLATION && serial < xlate->serial ) {
00676       rect.x += xlate->data.translation.dx;
00677       rect.y += xlate->data.translation.dy;
00678     }
00679     tmp_list = tmp_list->next;
00680   }
00681 
00682   /* add this expose area to our damaged rect */
00683 
00684   tmp_region = gdk_region_union_with_rect(*region, &rect);
00685   gdk_region_destroy(*region);
00686   *region = tmp_region;
00687 
00688  end:
00689 
00690   /* remove any events from the queue that are old */
00691   tmp_list = superwin->translate_queue;
00692   while (tmp_list) {
00693     GdkSuperWinTranslate *xlate = tmp_list->data;
00694     if (serial > xlate->serial) {
00695       GSList *tmp_link = tmp_list;
00696       tmp_list = tmp_list->next;
00697       superwin->translate_queue = g_slist_remove_link(superwin->translate_queue,
00698                                                       tmp_link);
00699       g_free(tmp_link->data);
00700       g_slist_free_1(tmp_link);
00701     }
00702     else {
00703       tmp_list = tmp_list->next;
00704     }
00705   }
00706 
00707   /* if we're not supposed to recurse or paint then return now */
00708   if (dont_recurse)
00709     return;
00710 
00711   /* try to do any expose event compression we can */
00712   while (XCheckTypedWindowEvent(xevent->xany.display,
00713                                 xevent->xany.window,
00714                                 Expose,
00715                                 &extra_event) == True) {
00716     gdk_superwin_handle_expose(superwin, &extra_event, region, TRUE);
00717   }
00718 
00719   /* if the region isn't empty, send the paint event */
00720   if (gdk_region_empty(*region) == FALSE) {
00721       GdkRectangle clip_box;
00722       gdk_region_get_clipbox(*region, &clip_box);
00723       if (superwin->paint_func)
00724         superwin->paint_func(clip_box.x, clip_box.y,
00725                              clip_box.width, clip_box.height,
00726                              superwin->func_data);
00727   }
00728 
00729 }