Merge branch 'genete_master'
[synfig.git] / synfig-osx / launcher / rootless-common.c
1 /*
2  * Common rootless definitions and code
3  *
4  * Greg Parker     gparker@cs.stanford.edu
5  */
6
7 /* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
8
9    Permission is hereby granted, free of charge, to any person
10    obtaining a copy of this software and associated documentation files
11    (the "Software"), to deal in the Software without restriction,
12    including without limitation the rights to use, copy, modify, merge,
13    publish, distribute, sublicense, and/or sell copies of the Software,
14    and to permit persons to whom the Software is furnished to do so,
15    subject to the following conditions:
16
17    The above copyright notice and this permission notice shall be
18    included in all copies or substantial portions of the Software.
19
20    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23    NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
24    HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27    DEALINGS IN THE SOFTWARE.
28
29    Except as contained in this notice, the name(s) of the above
30    copyright holders shall not be used in advertising or otherwise to
31    promote the sale, use or other dealings in this Software without
32    prior written authorization. */
33
34 /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessCommon.c,v 1.6 2002/07/15 19:58:31 torrey Exp $ */
35
36 #include "rootless-common.h"
37 #include "dri-surface.h"
38 #include "fb.h"
39 #include "colormapst.h"
40
41 RegionRec rootlessHugeRoot = {{-32767, -32767, 32767, 32767}, NULL};
42
43 /* Following two macros from miregion.c */
44
45 /*  true iff two Boxes overlap */
46 #define EXTENTCHECK(r1,r2) \
47       (!( ((r1)->x2 <= (r2)->x1)  || \
48           ((r1)->x1 >= (r2)->x2)  || \
49           ((r1)->y2 <= (r2)->y1)  || \
50           ((r1)->y1 >= (r2)->y2) ) )
51
52 /* true iff Box r1 contains Box r2 */
53 #define SUBSUMES(r1,r2) \
54       ( ((r1)->x1 <= (r2)->x1) && \
55         ((r1)->x2 >= (r2)->x2) && \
56         ((r1)->y1 <= (r2)->y1) && \
57         ((r1)->y2 >= (r2)->y2) )
58
59 int rootlessNoDRIDrawing = 0;
60
61 /* Returns the top-level parent of pWindow. The root is the top-level
62    parent of itself, even though the root is not otherwise considered
63    to be a top-level window. */
64 WindowPtr
65 TopLevelParent (WindowPtr pWindow)
66 {
67     WindowPtr top;
68
69     if (IsRoot (pWindow))
70         return pWindow;
71
72     top = pWindow;
73     while (top != NULL && !IsTopLevel (top))
74         top = top->parent;
75
76     return top;
77 }
78
79 /* Returns TRUE if this window is visible inside a frame (e.g. it is
80    visible and has a top-level parent) */
81 Bool
82 IsFramedWindow (WindowPtr pWin)
83 {
84     WindowPtr top;
85
86     if (!pWin->realized)
87         return FALSE;
88
89     top = TopLevelParent (pWin);
90
91     return top != NULL && WINREC (top) != NULL;
92 }
93
94 void
95 TranslatePixmapBase (PixmapPtr pPix, int dx, int dy)
96 {
97     unsigned diff;
98
99     pPix->devPrivate.ptr = ((char *) pPix->devPrivate.ptr +
100                             ((dx + pPix->drawable.x)
101                              * pPix->drawable.bitsPerPixel / 8 +
102                              dy * pPix->devKind));
103
104     if (pPix->drawable.bitsPerPixel != FB_UNIT)
105     {
106         diff = ((unsigned) pPix->devPrivate.ptr) & (FB_UNIT / CHAR_BIT - 1);
107         pPix->devPrivate.ptr = ((char *) pPix->devPrivate.ptr) - diff;
108
109         if (pPix->drawable.bitsPerPixel == 16)
110             pPix->drawable.x = diff / (16 / CHAR_BIT);
111         else if (pPix->drawable.bitsPerPixel == 8)
112             pPix->drawable.x = diff / (8 / CHAR_BIT);
113         else
114             pPix->drawable.x = diff / (pPix->drawable.bitsPerPixel / CHAR_BIT);
115     }
116 }
117
118 void
119 RootlessDisableUpdate (WindowPtr pWin)
120 {
121     RootlessWindowRec *winRec = WINREC (pWin);
122
123     if (winRec != NULL
124         && !winRec->is_offscreen
125         && !winRec->is_reorder_pending
126         && !winRec->is_update_disabled)
127     {
128         xp_disable_update ();
129         winRec->is_update_disabled = TRUE;
130     }
131 }
132
133 void
134 RootlessReenableUpdate (WindowPtr pWin)
135 {
136     RootlessWindowRec *winRec = WINREC (pWin);
137
138     if (winRec != NULL && winRec->is_update_disabled)
139     {
140         xp_reenable_update ();
141         winRec->is_update_disabled = FALSE;
142     }
143 }
144
145 Bool
146 RootlessResolveColormap (ScreenPtr pScreen, int first_color,
147                          int n_colors, uint32_t *colors)
148 {
149     int last, i;
150     ColormapPtr map;
151
152     map = RootlessGetColormap (pScreen);
153     if (map == NULL || map->class != PseudoColor)
154         return FALSE;
155
156     last = MIN (map->pVisual->ColormapEntries, first_color + n_colors);
157     for (i = MAX (0, first_color); i < last; i++)
158     {
159         Entry *ent = map->red + i;
160         uint16_t red, green, blue;
161
162         if (!ent->refcnt)
163             continue;
164         if (ent->fShared)
165         {
166             red = ent->co.shco.red->color;
167             green = ent->co.shco.green->color;
168             blue = ent->co.shco.blue->color;
169         }
170         else
171         {
172             red = ent->co.local.red;
173             green = ent->co.local.green;
174             blue = ent->co.local.blue;
175         }
176
177         colors[i - first_color] = (0xFF000000UL
178                                    | ((uint32_t) red & 0xff00) << 8
179                                    | (green & 0xff00)
180                                    | (blue >> 8));
181     }
182
183     return TRUE;
184 }
185
186 /* Prepare a window for direct access to its backing buffer. Each
187    top-level parent has a Pixmap representing its backing store, which
188    all of its children inherit. */
189 void
190 RootlessStartDrawing (WindowPtr pWindow)
191 {
192     ScreenPtr pScreen = pWindow->drawable.pScreen;
193     WindowPtr top = TopLevelParent (pWindow);
194     RootlessWindowRec *winRec;
195
196     if (!rootlessNoDRIDrawing && DRIStartDrawing (&pWindow->drawable))
197     {
198         return;
199     }
200
201     /* At the top of the stack now. */
202
203     if (top == NULL || WINREC (top) == NULL)
204         return;
205
206     winRec = WINREC(top);
207
208     /* Make sure the window's top-level parent is prepared for drawing. */
209
210     if (!winRec->is_drawing)
211     {
212         void *data[2];
213         unsigned int rowbytes[2];
214         xp_error err;
215
216         int bw = wBorderWidth (top);
217
218         err = xp_lock_window (winRec->wid, NULL, NULL, data, rowbytes, NULL);
219         if (err != Success)
220             abort ();                   /* FIXME: */
221
222         winRec->data = data[0];
223         winRec->rowbytes = rowbytes[0];
224
225         winRec->pixmap =
226             GetScratchPixmapHeader(pScreen, winRec->width, winRec->height,
227                                    winRec->win->drawable.depth,
228                                    winRec->win->drawable.bitsPerPixel,
229                                    winRec->rowbytes, winRec->data);
230         TranslatePixmapBase (winRec->pixmap,
231                              - (top->drawable.x - bw),
232                              - (top->drawable.y - bw));
233
234         winRec->is_drawing = TRUE;
235     }
236
237     winRec->oldPixmap = pScreen->GetWindowPixmap (pWindow);
238     pScreen->SetWindowPixmap (pWindow, winRec->pixmap);
239 }
240
241 void
242 RootlessFinishedDrawing (WindowPtr pWindow)
243 {
244     /* Called after each drawing primitive, lets us unlock surfaces
245        as often as possible (which is a Good Thing to do.) */
246
247     DRIStopDrawing (&pWindow->drawable, FALSE);
248
249     /* Also, see if we're due a flush. */
250
251     RootlessMayRedisplay (pWindow->drawable.pScreen);
252 }
253
254 void
255 RootlessStopDrawing (WindowPtr pWindow, Bool flush)
256 {
257     WindowPtr top = TopLevelParent (pWindow);
258     RootlessWindowRec *winRec;
259
260     if (top == NULL || WINREC (top) == NULL)
261         return;
262
263     winRec = WINREC(top);
264
265     DRIStopDrawing (&pWindow->drawable, flush);
266
267     if (winRec->is_drawing)
268     {
269         ScreenPtr pScreen = pWindow->drawable.pScreen;
270
271         xp_unlock_window (winRec->wid, flush);
272
273         FreeScratchPixmapHeader (winRec->pixmap);
274         pScreen->SetWindowPixmap (pWindow, winRec->oldPixmap);
275         winRec->pixmap = NULL;
276
277         winRec->is_drawing = FALSE;
278     }
279     else if (flush)
280     {
281         xp_flush_window (winRec->wid);
282     }
283
284     /* FIXME: instead of just checking if we tried to flush (which
285        happens everytime we block for I/O), I used to check if
286        anything was actually marked in the window. But that often
287        caused problems with some window managers, and it didn't really
288        make any noticeable difference, so... */
289
290     if (flush && winRec->is_reorder_pending)
291     {
292         winRec->is_reorder_pending = FALSE;
293         RootlessReorderWindow (pWindow);
294     }
295
296     if (flush && winRec->is_update_disabled)
297     {
298         RootlessReenableUpdate (pWindow);
299     }
300 }
301
302 /* pRegion is GLOBAL */
303 void
304 RootlessDamageRegion (WindowPtr pWindow, RegionPtr pRegion)
305 {
306     RootlessWindowRec *winRec;
307     RegionRec clipped;
308     WindowPtr pTop;
309     BoxPtr b1, b2;
310
311     RL_DEBUG_MSG("Damaged win 0x%x ", pWindow);
312
313     pTop = TopLevelParent (pWindow);
314     if (pTop == NULL)
315         return;
316
317     winRec = WINREC (pTop);
318     if (winRec == NULL)
319         return;
320
321     if (DRIDamageRegion (&pWindow->drawable, pRegion))
322     {
323         return;
324     }
325
326     /* We need to intersect the drawn region with the clip of the window
327        to avoid marking places we didn't actually draw (which can cause
328        problems when the window has an extra client-side backing store)
329
330        But this is a costly operation and since we'll normally just be
331        drawing inside the clip, go to some lengths to avoid the general
332        case intersection. */
333
334     b1 = REGION_EXTENTS (pScreen, &pWindow->borderClip);
335     b2 = REGION_EXTENTS (pScreen, pRegion);
336
337     if (EXTENTCHECK (b1, b2))
338     {
339         /* Regions may overlap. */
340
341         if (REGION_NUM_RECTS (pRegion) == 1)
342         {
343             int in;
344
345             /* Damaged region only has a single rect, so we can
346                just compare that against the region */
347
348             in = RECT_IN_REGION (pScreen, &pWindow->borderClip,
349                                  REGION_RECTS (pRegion));
350             if (in == rgnIN)
351             {
352                 /* clip totally contains pRegion */
353
354                 xp_mark_window (winRec->wid, REGION_NUM_RECTS (pRegion),
355                                 REGION_RECTS (pRegion),
356                                 -winRec->x, -winRec->y);
357
358                 RootlessQueueRedisplay (pTop->drawable.pScreen);
359                 goto out;
360             }
361             else if (in == rgnOUT)
362             {
363                 /* clip doesn't contain pRegion */
364
365                 goto out;
366             }
367         }
368
369         /* clip overlaps pRegion, need to intersect */
370
371         REGION_INIT (pScreen, &clipped, NullBox, 0);
372         REGION_INTERSECT (pScreen, &clipped, &pWindow->borderClip, pRegion);
373
374         xp_mark_window (winRec->wid, REGION_NUM_RECTS (&clipped),
375                         REGION_RECTS (&clipped), -winRec->x, -winRec->y);
376
377         REGION_UNINIT (pScreen, &clipped);
378
379         RootlessQueueRedisplay (pTop->drawable.pScreen);
380     }
381
382 out:
383 #ifdef ROOTLESSDEBUG
384     {
385         BoxRec *box = REGION_RECTS(pRegion), *end;
386         int numBox = REGION_NUM_RECTS(pRegion);
387
388         for (end = box+numBox; box < end; box++) {
389             RL_DEBUG_MSG("Damage rect: %i, %i, %i, %i\n",
390                          box->x1, box->x2, box->y1, box->y2);
391         }
392     }
393 #endif
394     return;
395 }
396
397 /* pBox is GLOBAL */
398 void
399 RootlessDamageBox (WindowPtr pWindow, BoxPtr pBox)
400 {
401     RegionRec region;
402
403     REGION_INIT (pWindow->drawable.pScreen, &region, pBox, 1);
404
405     RootlessDamageRegion (pWindow, &region);
406
407     REGION_UNINIT (pWindow->drawable.pScreen, &region); /* no-op */
408 }
409
410
411 /* (x, y, w, h) is in window-local coordinates. */
412 void
413 RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h)
414 {
415     BoxRec box;
416     RegionRec region;
417
418     x += pWindow->drawable.x;
419     y += pWindow->drawable.y;
420
421     box.x1 = x;
422     box.x2 = x + w;
423     box.y1 = y;
424     box.y2 = y + h;
425
426     REGION_INIT (pWindow->drawable.pScreen, &region, &box, 1);
427
428     RootlessDamageRegion (pWindow, &region);
429
430     REGION_UNINIT (pWindow->drawable.pScreen, &region); /* no-op */
431 }
432
433 /* Stop drawing and redisplay the damaged region of a window. */
434 void
435 RootlessRedisplay (WindowPtr pWindow)
436 {
437     DRISynchronizeDrawable (&pWindow->drawable, TRUE);
438     RootlessStopDrawing(pWindow, TRUE);
439 }
440
441 /* Walk every window on a screen and redisplay the damaged regions. */
442 void
443 RootlessRedisplayScreen (ScreenPtr pScreen)
444 {
445     RootlessScreenRec *screenRec = SCREENREC (pScreen);
446     WindowPtr root = WindowTable[pScreen->myNum];
447     WindowPtr win;
448
449     if (root != NULL)
450     {
451         RootlessRedisplay(root);
452
453         for (win = root->firstChild; win; win = win->nextSib)
454         {
455             if (WINREC (win) != NULL)
456                 RootlessRedisplay (win);
457         }
458     }
459
460     screenRec->last_redisplay = GetTimeInMillis ();
461 }
462
463 void
464 RootlessRepositionWindows (ScreenPtr pScreen)
465 {
466     WindowPtr root = WindowTable[pScreen->myNum];
467     WindowPtr win;
468
469     if (root != NULL)
470     {
471         RootlessRepositionWindow (root);
472
473         for (win = root->firstChild; win; win = win->nextSib)
474         {
475             if (WINREC (win) != NULL)
476                 RootlessRepositionWindow (win);
477         }
478     }
479 }
480
481 void
482 RootlessFlushScreenColormaps (ScreenPtr pScreen)
483 {
484     WindowPtr root = WindowTable[pScreen->myNum];
485     WindowPtr win;
486
487     if (root != NULL)
488     {
489         RootlessRepositionWindow (root);
490
491         for (win = root->firstChild; win; win = win->nextSib)
492         {
493             if (WINREC (win) != NULL)
494                 RootlessFlushWindowColormap (win);
495         }
496     }
497 }