xprFrame.c revision 9ace9065
1/*
2 * Xplugin rootless implementation frame functions
3 *
4 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
5 * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Except as contained in this notice, the name(s) of the above copyright
26 * holders shall not be used in advertising or otherwise to promote the sale,
27 * use or other dealings in this Software without prior written authorization.
28 */
29
30#ifdef HAVE_DIX_CONFIG_H
31#include <dix-config.h>
32#endif
33
34#include "xpr.h"
35#include "rootlessCommon.h"
36#include <Xplugin.h>
37#include "x-hash.h"
38#include "x-list.h"
39#include "applewmExt.h"
40
41#include "propertyst.h"
42#include "dix.h"
43#include <X11/Xatom.h>
44#include "windowstr.h"
45#include "quartz.h"
46
47#include "threadSafety.h"
48
49#include <pthread.h>
50
51#define DEFINE_ATOM_HELPER(func,atom_name)                      \
52static Atom func (void) {                                       \
53    static int generation;                                      \
54    static Atom atom;                                           \
55    if (generation != serverGeneration) {                       \
56        generation = serverGeneration;                          \
57        atom = MakeAtom (atom_name, strlen (atom_name), TRUE);  \
58    }                                                           \
59    return atom;                                                \
60}
61
62DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID")
63
64/* Maps xp_window_id -> RootlessWindowRec */
65static x_hash_table *window_hash;
66static pthread_mutex_t window_hash_mutex;
67
68/* Prototypes for static functions */
69static Bool xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
70               int newX, int newY, RegionPtr pShape);
71static void xprDestroyFrame(RootlessFrameID wid);
72static void xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY);
73static void xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen,
74               int newX, int newY, unsigned int newW, unsigned int newH,
75               unsigned int gravity);
76static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid);
77static void xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape);
78static void xprUnmapFrame(RootlessFrameID wid);
79static void xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow);
80static void xprStopDrawing(RootlessFrameID wid, Bool flush);
81static void xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage);
82static void xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects,
83               int shift_x, int shift_y);
84static void xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin);
85static Bool xprDoReorderWindow(RootlessWindowPtr pFrame);
86static void xprHideWindow(RootlessFrameID wid);
87static void xprUpdateColormap(RootlessFrameID wid, ScreenPtr pScreen);
88static void xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects,
89              int dx, int dy);
90
91
92static inline xp_error
93xprConfigureWindow(xp_window_id id, unsigned int mask,
94                   const xp_window_changes *values)
95{
96    TA_SERVER();
97
98    return xp_configure_window(id, mask, values);
99}
100
101
102static void
103xprSetNativeProperty(RootlessWindowPtr pFrame)
104{
105    xp_error err;
106    unsigned int native_id;
107    long data;
108
109    TA_SERVER();
110
111    err = xp_get_native_window(x_cvt_vptr_to_uint(pFrame->wid), &native_id);
112    if (err == Success)
113    {
114        /* FIXME: move this to AppleWM extension */
115
116        data = native_id;
117        dixChangeWindowProperty(serverClient, pFrame->win, xa_native_window_id(),
118				XA_INTEGER, 32, PropModeReplace, 1, &data, TRUE);
119    }
120}
121
122static xp_error
123xprColormapCallback(void *data, int first_color, int n_colors, uint32_t *colors)
124{
125    return (RootlessResolveColormap (data, first_color, n_colors, colors) ? XP_Success : XP_BadMatch);
126}
127
128/*
129 * Create and display a new frame.
130 */
131static Bool
132xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
133               int newX, int newY, RegionPtr pShape)
134{
135    WindowPtr pWin = pFrame->win;
136    xp_window_changes wc;
137    unsigned int mask = 0;
138    xp_error err;
139
140    TA_SERVER();
141
142    wc.x = newX;
143    wc.y = newY;
144    wc.width = pFrame->width;
145    wc.height = pFrame->height;
146    wc.bit_gravity = XP_GRAVITY_NONE;
147    mask |= XP_BOUNDS;
148
149    if (pWin->drawable.depth == 8)
150    {
151        wc.depth = XP_DEPTH_INDEX8;
152        wc.colormap = xprColormapCallback;
153        wc.colormap_data = pScreen;
154        mask |= XP_COLORMAP;
155    }
156    else if (pWin->drawable.depth == 15)
157        wc.depth = XP_DEPTH_RGB555;
158    else if (pWin->drawable.depth == 24)
159        wc.depth = XP_DEPTH_ARGB8888;
160    else
161        wc.depth = XP_DEPTH_NIL;
162    mask |= XP_DEPTH;
163
164    if (pShape != NULL)
165    {
166        wc.shape_nrects = RegionNumRects(pShape);
167        wc.shape_rects = RegionRects(pShape);
168        wc.shape_tx = wc.shape_ty = 0;
169        mask |= XP_SHAPE;
170    }
171
172    pFrame->level = !IsRoot (pWin) ? AppleWMWindowLevelNormal : AppleWMNumWindowLevels;
173
174    if(XQuartzIsRootless)
175        wc.window_level = normal_window_levels[pFrame->level];
176    else if(XQuartzShieldingWindowLevel)
177        wc.window_level = XQuartzShieldingWindowLevel + 1;
178    else
179        wc.window_level = rooted_window_levels[pFrame->level];
180    mask |= XP_WINDOW_LEVEL;
181
182    err = xp_create_window(mask, &wc, (xp_window_id *) &pFrame->wid);
183
184    if (err != Success)
185    {
186        return FALSE;
187    }
188
189    if (window_hash == NULL)
190    {
191        window_hash = x_hash_table_new(NULL, NULL, NULL, NULL);
192        pthread_mutex_init(&window_hash_mutex, NULL);
193    }
194
195    pthread_mutex_lock(&window_hash_mutex);
196    x_hash_table_insert(window_hash, pFrame->wid, pFrame);
197    pthread_mutex_unlock(&window_hash_mutex);
198
199    xprSetNativeProperty(pFrame);
200
201    return TRUE;
202}
203
204
205/*
206 * Destroy a frame.
207 */
208static void
209xprDestroyFrame(RootlessFrameID wid)
210{
211    xp_error err;
212    TA_SERVER();
213
214    pthread_mutex_lock(&window_hash_mutex);
215    x_hash_table_remove(window_hash, wid);
216    pthread_mutex_unlock(&window_hash_mutex);
217
218    err = xp_destroy_window(x_cvt_vptr_to_uint(wid));
219    if (err != Success)
220        FatalError("Could not destroy window %i.", (int)x_cvt_vptr_to_uint(wid));
221}
222
223
224/*
225 * Move a frame on screen.
226 */
227static void
228xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY)
229{
230    xp_window_changes wc;
231
232    TA_SERVER();
233
234    wc.x = newX;
235    wc.y = newY;
236    //    ErrorF("xprMoveFrame(%d, %p, %d, %d)\n", wid, pScreen, newX, newY);
237    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_ORIGIN, &wc);
238}
239
240
241/*
242 * Resize and move a frame.
243 */
244static void
245xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen,
246               int newX, int newY, unsigned int newW, unsigned int newH,
247               unsigned int gravity)
248{
249    xp_window_changes wc;
250
251    TA_SERVER();
252
253    wc.x = newX;
254    wc.y = newY;
255    wc.width = newW;
256    wc.height = newH;
257    wc.bit_gravity = gravity;
258
259    /* It's unlikely that being async will save us anything here.
260       But it can't hurt. */
261
262    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_BOUNDS, &wc);
263}
264
265
266/*
267 * Change frame stacking.
268 */
269static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) {
270    xp_window_changes wc;
271    unsigned int mask = XP_STACKING;
272
273    TA_SERVER();
274
275    /* Stack frame below nextWid it if it exists, or raise
276       frame above everything otherwise. */
277
278    if(nextWid == NULL) {
279        wc.stack_mode = XP_MAPPED_ABOVE;
280        wc.sibling = 0;
281    } else {
282        wc.stack_mode = XP_MAPPED_BELOW;
283        wc.sibling = x_cvt_vptr_to_uint(nextWid);
284    }
285
286    if(window_hash) {
287        RootlessWindowRec *winRec = x_hash_table_lookup(window_hash, wid, NULL);
288
289        if(winRec) {
290            if(XQuartzIsRootless)
291                wc.window_level = normal_window_levels[winRec->level];
292            else if(XQuartzShieldingWindowLevel)
293                wc.window_level = XQuartzShieldingWindowLevel + 1;
294            else
295                wc.window_level = rooted_window_levels[winRec->level];
296            mask |= XP_WINDOW_LEVEL;
297        }
298    }
299
300    xprConfigureWindow(x_cvt_vptr_to_uint(wid), mask, &wc);
301}
302
303
304/*
305 * Change the frame's shape.
306 */
307static void
308xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape)
309{
310    xp_window_changes wc;
311
312    TA_SERVER();
313
314    if (pShape != NULL)
315    {
316        wc.shape_nrects = RegionNumRects(pShape);
317        wc.shape_rects = RegionRects(pShape);
318    }
319    else
320    {
321        wc.shape_nrects = -1;
322        wc.shape_rects = NULL;
323    }
324
325    wc.shape_tx = wc.shape_ty = 0;
326
327    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_SHAPE, &wc);
328}
329
330
331/*
332 * Unmap a frame.
333 */
334static void
335xprUnmapFrame(RootlessFrameID wid)
336{
337    xp_window_changes wc;
338
339    TA_SERVER();
340
341    wc.stack_mode = XP_UNMAPPED;
342    wc.sibling = 0;
343
344    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_STACKING, &wc);
345}
346
347
348/*
349 * Start drawing to a frame.
350 *  Prepare for direct access to its backing buffer.
351 */
352static void
353xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow)
354{
355    void *data[2];
356    unsigned int rowbytes[2];
357    xp_error err;
358
359    TA_SERVER();
360
361    err = xp_lock_window(x_cvt_vptr_to_uint(wid), NULL, NULL, data, rowbytes, NULL);
362    if (err != Success)
363        FatalError("Could not lock window %i for drawing.", (int)x_cvt_vptr_to_uint(wid));
364
365    *pixelData = data[0];
366    *bytesPerRow = rowbytes[0];
367}
368
369
370/*
371 * Stop drawing to a frame.
372 */
373static void
374xprStopDrawing(RootlessFrameID wid, Bool flush)
375{
376    xp_error err;
377    TA_SERVER();
378
379    err = xp_unlock_window(x_cvt_vptr_to_uint(wid), flush);
380    if(err != Success)
381        FatalError("Could not unlock window %i after drawing.", (int)x_cvt_vptr_to_uint(wid));
382}
383
384
385/*
386 * Flush drawing updates to the screen.
387 */
388static void
389xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage)
390{
391    TA_SERVER();
392
393    xp_flush_window(x_cvt_vptr_to_uint(wid));
394}
395
396
397/*
398 * Mark damaged rectangles as requiring redisplay to screen.
399 */
400static void
401xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects,
402               int shift_x, int shift_y)
403{
404    TA_SERVER();
405
406    xp_mark_window(x_cvt_vptr_to_uint(wid), nrects, rects, shift_x, shift_y);
407}
408
409
410/*
411 * Called after the window associated with a frame has been switched
412 * to a new top-level parent.
413 */
414static void
415xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin)
416{
417    DeleteProperty(serverClient, oldWin, xa_native_window_id());
418
419    TA_SERVER();
420
421    xprSetNativeProperty(pFrame);
422}
423
424
425/*
426 * Called to check if the frame should be reordered when it is restacked.
427 */
428static Bool xprDoReorderWindow(RootlessWindowPtr pFrame)
429{
430    WindowPtr pWin = pFrame->win;
431
432    TA_SERVER();
433
434    return AppleWMDoReorderWindow(pWin);
435}
436
437
438/*
439 * Copy area in frame to another part of frame.
440 *  Used to accelerate scrolling.
441 */
442static void
443xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects,
444              int dx, int dy)
445{
446    TA_SERVER();
447
448    xp_copy_window(x_cvt_vptr_to_uint(wid), x_cvt_vptr_to_uint(wid),
449                   dstNrects, dstRects, dx, dy);
450}
451
452
453static RootlessFrameProcsRec xprRootlessProcs = {
454    xprCreateFrame,
455    xprDestroyFrame,
456    xprMoveFrame,
457    xprResizeFrame,
458    xprRestackFrame,
459    xprReshapeFrame,
460    xprUnmapFrame,
461    xprStartDrawing,
462    xprStopDrawing,
463    xprUpdateRegion,
464    xprDamageRects,
465    xprSwitchWindow,
466    xprDoReorderWindow,
467    xprHideWindow,
468    xprUpdateColormap,
469    xp_copy_bytes,
470    xprCopyWindow
471};
472
473
474/*
475 * Initialize XPR implementation
476 */
477Bool
478xprInit(ScreenPtr pScreen)
479{
480    RootlessInit(pScreen, &xprRootlessProcs);
481
482    TA_SERVER();
483
484    rootless_CopyBytes_threshold = xp_copy_bytes_threshold;
485    rootless_CopyWindow_threshold = xp_scroll_area_threshold;
486
487    return TRUE;
488}
489
490
491/*
492 * Given the id of a physical window, try to find the top-level (or root)
493 * X window that it represents.
494 */
495WindowPtr
496xprGetXWindow(xp_window_id wid)
497{
498    RootlessWindowRec *winRec;
499
500    if (window_hash == NULL)
501        return NULL;
502
503    winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL);
504
505    return winRec != NULL ? winRec->win : NULL;
506}
507
508#ifdef UNUSED_CODE
509/*
510 * Given the id of a physical window, try to find the top-level (or root)
511 * X window that it represents.
512 */
513WindowPtr
514xprGetXWindowFromAppKit(int windowNumber)
515{
516    RootlessWindowRec *winRec;
517    Bool ret;
518    xp_window_id wid;
519
520    if (window_hash == NULL)
521        return FALSE;
522
523    /* need to lock, since this function can be called by any thread */
524
525    pthread_mutex_lock(&window_hash_mutex);
526
527    if (xp_lookup_native_window(windowNumber, &wid))
528        ret = xprGetXWindow(wid) != NULL;
529    else
530        ret = FALSE;
531
532    pthread_mutex_unlock(&window_hash_mutex);
533
534    if (!ret) return NULL;
535    winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL);
536
537    return winRec != NULL ? winRec->win : NULL;
538}
539#endif
540
541/*
542 * The windowNumber is an AppKit window number. Returns TRUE if xpr is
543 * displaying a window with that number.
544 */
545Bool
546xprIsX11Window(void *nsWindow, int windowNumber)
547{
548    Bool ret;
549    xp_window_id wid;
550
551    if (window_hash == NULL)
552        return FALSE;
553
554    /* need to lock, since this function can be called by any thread */
555
556    pthread_mutex_lock(&window_hash_mutex);
557
558    if (xp_lookup_native_window(windowNumber, &wid))
559        ret = xprGetXWindow(wid) != NULL;
560    else
561        ret = FALSE;
562
563    pthread_mutex_unlock(&window_hash_mutex);
564
565    return ret;
566}
567
568
569/*
570 * xprHideWindows
571 *  Hide or unhide all top level windows. This is called for application hide/
572 *  unhide events if the window manager is not Apple-WM aware. Xplugin windows
573 *  do not hide or unhide themselves.
574 */
575void
576xprHideWindows(Bool hide)
577{
578    int screen;
579    WindowPtr pRoot, pWin;
580
581    TA_SERVER();
582
583    for (screen = 0; screen < screenInfo.numScreens; screen++) {
584        RootlessFrameID prevWid = NULL;
585        pRoot = screenInfo.screens[screen]->root;
586
587        for (pWin = pRoot->firstChild; pWin; pWin = pWin->nextSib) {
588            RootlessWindowRec *winRec = WINREC(pWin);
589
590            if (winRec != NULL) {
591                if (hide) {
592                    xprUnmapFrame(winRec->wid);
593                } else {
594                    BoxRec box;
595
596                    xprRestackFrame(winRec->wid, prevWid);
597                    prevWid = winRec->wid;
598
599                    box.x1 = 0;
600                    box.y1 = 0;
601                    box.x2 = winRec->width;
602                    box.y2 = winRec->height;
603
604                    xprDamageRects(winRec->wid, 1, &box, 0, 0);
605                    RootlessQueueRedisplay(screenInfo.screens[screen]);
606                }
607            }
608        }
609    }
610}
611
612// XXX: identical to x_cvt_vptr_to_uint ?
613#define MAKE_WINDOW_ID(x)		((xp_window_id)((size_t)(x)))
614
615Bool no_configure_window;
616
617static inline int
618configure_window (xp_window_id id, unsigned int mask,
619                  const xp_window_changes *values)
620{
621  if (!no_configure_window)
622    return xp_configure_window (id, mask, values);
623  else
624    return XP_Success;
625}
626
627
628static
629void xprUpdateColormap(RootlessFrameID wid, ScreenPtr pScreen)
630{
631  /* This is how we tell xp that the colormap may have changed. */
632  xp_window_changes wc;
633  wc.colormap = xprColormapCallback;
634  wc.colormap_data = pScreen;
635
636  configure_window(MAKE_WINDOW_ID(wid), XP_COLORMAP, &wc);
637}
638
639static
640void xprHideWindow(RootlessFrameID wid)
641{
642  xp_window_changes wc;
643  wc.stack_mode = XP_UNMAPPED;
644  wc.sibling = 0;
645  configure_window(MAKE_WINDOW_ID(wid), XP_STACKING, &wc);
646}
647