xprFrame.c revision 4642e01f
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
46#include "threadSafety.h"
47
48#include <pthread.h>
49
50#define DEFINE_ATOM_HELPER(func,atom_name)                      \
51static Atom func (void) {                                       \
52    static int generation;                                      \
53    static Atom atom;                                           \
54    if (generation != serverGeneration) {                       \
55        generation = serverGeneration;                          \
56        atom = MakeAtom (atom_name, strlen (atom_name), TRUE);  \
57    }                                                           \
58    return atom;                                                \
59}
60
61DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID")
62
63/* Maps xp_window_id -> RootlessWindowRec */
64static x_hash_table *window_hash;
65static pthread_mutex_t window_hash_mutex;
66
67/* Prototypes for static functions */
68static Bool xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
69               int newX, int newY, RegionPtr pShape);
70static void xprDestroyFrame(RootlessFrameID wid);
71static void xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY);
72static void xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen,
73               int newX, int newY, unsigned int newW, unsigned int newH,
74               unsigned int gravity);
75static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid);
76static void xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape);
77static void xprUnmapFrame(RootlessFrameID wid);
78static void xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow);
79static void xprStopDrawing(RootlessFrameID wid, Bool flush);
80static void xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage);
81static void xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects,
82               int shift_x, int shift_y);
83static void xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin);
84static Bool xprDoReorderWindow(RootlessWindowPtr pFrame);
85static void xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects,
86              int dx, int dy);
87
88
89static inline xp_error
90xprConfigureWindow(xp_window_id id, unsigned int mask,
91                   const xp_window_changes *values)
92{
93    TA_SERVER();
94
95    return xp_configure_window(id, mask, values);
96}
97
98
99static void
100xprSetNativeProperty(RootlessWindowPtr pFrame)
101{
102    xp_error err;
103    unsigned int native_id;
104    long data;
105
106    TA_SERVER();
107
108    err = xp_get_native_window(x_cvt_vptr_to_uint(pFrame->wid), &native_id);
109    if (err == Success)
110    {
111        /* FIXME: move this to AppleWM extension */
112
113        data = native_id;
114        dixChangeWindowProperty(serverClient, pFrame->win, xa_native_window_id(),
115				XA_INTEGER, 32, PropModeReplace, 1, &data, TRUE);
116    }
117}
118
119
120/*
121 * Create and display a new frame.
122 */
123Bool
124xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
125               int newX, int newY, RegionPtr pShape)
126{
127    WindowPtr pWin = pFrame->win;
128    xp_window_changes wc;
129    unsigned int mask = 0;
130    xp_error err;
131
132    TA_SERVER();
133
134    wc.x = newX;
135    wc.y = newY;
136    wc.width = pFrame->width;
137    wc.height = pFrame->height;
138    wc.bit_gravity = XP_GRAVITY_NONE;
139    mask |= XP_BOUNDS;
140
141    if (pWin->drawable.depth == 8)
142    {
143        wc.depth = XP_DEPTH_INDEX8;
144        wc.colormap = RootlessColormapCallback;
145        wc.colormap_data = pScreen;
146        mask |= XP_COLORMAP;
147    }
148    else if (pWin->drawable.depth == 15)
149        wc.depth = XP_DEPTH_RGB555;
150    else if (pWin->drawable.depth == 24)
151        wc.depth = XP_DEPTH_ARGB8888;
152    else
153        wc.depth = XP_DEPTH_NIL;
154    mask |= XP_DEPTH;
155
156    if (pShape != NULL)
157    {
158        wc.shape_nrects = REGION_NUM_RECTS(pShape);
159        wc.shape_rects = REGION_RECTS(pShape);
160        wc.shape_tx = wc.shape_ty = 0;
161        mask |= XP_SHAPE;
162    }
163
164    err = xp_create_window(mask, &wc, (xp_window_id *) &pFrame->wid);
165
166    if (err != Success)
167    {
168        return FALSE;
169    }
170
171    if (window_hash == NULL)
172    {
173        window_hash = x_hash_table_new(NULL, NULL, NULL, NULL);
174        pthread_mutex_init(&window_hash_mutex, NULL);
175    }
176
177    pthread_mutex_lock(&window_hash_mutex);
178    x_hash_table_insert(window_hash, pFrame->wid, pFrame);
179    pthread_mutex_unlock(&window_hash_mutex);
180
181    xprSetNativeProperty(pFrame);
182
183    return TRUE;
184}
185
186
187/*
188 * Destroy a frame.
189 */
190void
191xprDestroyFrame(RootlessFrameID wid)
192{
193    TA_SERVER();
194
195    pthread_mutex_lock(&window_hash_mutex);
196    x_hash_table_remove(window_hash, wid);
197    pthread_mutex_unlock(&window_hash_mutex);
198
199    xp_destroy_window(x_cvt_vptr_to_uint(wid));
200}
201
202
203/*
204 * Move a frame on screen.
205 */
206void
207xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY)
208{
209    TA_SERVER();
210
211    xp_window_changes wc;
212
213    wc.x = newX;
214    wc.y = newY;
215    //    ErrorF("xprMoveFrame(%d, %p, %d, %d)\n", wid, pScreen, newX, newY);
216    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_ORIGIN, &wc);
217}
218
219
220/*
221 * Resize and move a frame.
222 */
223void
224xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen,
225               int newX, int newY, unsigned int newW, unsigned int newH,
226               unsigned int gravity)
227{
228    xp_window_changes wc;
229
230    TA_SERVER();
231
232    wc.x = newX;
233    wc.y = newY;
234    wc.width = newW;
235    wc.height = newH;
236    wc.bit_gravity = gravity;
237
238    /* It's unlikely that being async will save us anything here.
239       But it can't hurt. */
240
241    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_BOUNDS, &wc);
242}
243
244
245/*
246 * Change frame stacking.
247 */
248void
249xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid)
250{
251    xp_window_changes wc;
252
253    TA_SERVER();
254
255   /* Stack frame below nextWid it if it exists, or raise
256       frame above everything otherwise. */
257
258    if (nextWid == NULL)
259    {
260        wc.stack_mode = XP_MAPPED_ABOVE;
261        wc.sibling = 0;
262    }
263    else
264    {
265        wc.stack_mode = XP_MAPPED_BELOW;
266        wc.sibling = x_cvt_vptr_to_uint(nextWid);
267    }
268
269    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_STACKING, &wc);
270}
271
272
273/*
274 * Change the frame's shape.
275 */
276void
277xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape)
278{
279    xp_window_changes wc;
280
281    TA_SERVER();
282
283    if (pShape != NULL)
284    {
285        wc.shape_nrects = REGION_NUM_RECTS(pShape);
286        wc.shape_rects = REGION_RECTS(pShape);
287    }
288    else
289    {
290        wc.shape_nrects = -1;
291        wc.shape_rects = NULL;
292    }
293
294    wc.shape_tx = wc.shape_ty = 0;
295
296    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_SHAPE, &wc);
297}
298
299
300/*
301 * Unmap a frame.
302 */
303void
304xprUnmapFrame(RootlessFrameID wid)
305{
306    xp_window_changes wc;
307
308    TA_SERVER();
309
310    wc.stack_mode = XP_UNMAPPED;
311    wc.sibling = 0;
312
313    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_STACKING, &wc);
314}
315
316
317/*
318 * Start drawing to a frame.
319 *  Prepare for direct access to its backing buffer.
320 */
321void
322xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow)
323{
324    void *data[2];
325    unsigned int rowbytes[2];
326    xp_error err;
327
328    TA_SERVER();
329
330    err = xp_lock_window(x_cvt_vptr_to_uint(wid), NULL, NULL, data, rowbytes, NULL);
331    if (err != Success)
332        FatalError("Could not lock window %i for drawing.", (int)x_cvt_vptr_to_uint(wid));
333
334    *pixelData = data[0];
335    *bytesPerRow = rowbytes[0];
336}
337
338
339/*
340 * Stop drawing to a frame.
341 */
342void
343xprStopDrawing(RootlessFrameID wid, Bool flush)
344{
345    TA_SERVER();
346
347    xp_unlock_window(x_cvt_vptr_to_uint(wid), flush);
348}
349
350
351/*
352 * Flush drawing updates to the screen.
353 */
354void
355xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage)
356{
357    TA_SERVER();
358
359    xp_flush_window(x_cvt_vptr_to_uint(wid));
360}
361
362
363/*
364 * Mark damaged rectangles as requiring redisplay to screen.
365 */
366void
367xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects,
368               int shift_x, int shift_y)
369{
370    TA_SERVER();
371
372    xp_mark_window(x_cvt_vptr_to_uint(wid), nrects, rects, shift_x, shift_y);
373}
374
375
376/*
377 * Called after the window associated with a frame has been switched
378 * to a new top-level parent.
379 */
380void
381xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin)
382{
383    DeleteProperty(serverClient, oldWin, xa_native_window_id());
384
385    TA_SERVER();
386
387    xprSetNativeProperty(pFrame);
388}
389
390
391/*
392 * Called to check if the frame should be reordered when it is restacked.
393 */
394Bool xprDoReorderWindow(RootlessWindowPtr pFrame)
395{
396    WindowPtr pWin = pFrame->win;
397
398    TA_SERVER();
399
400    return AppleWMDoReorderWindow(pWin);
401}
402
403
404/*
405 * Copy area in frame to another part of frame.
406 *  Used to accelerate scrolling.
407 */
408void
409xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects,
410              int dx, int dy)
411{
412    TA_SERVER();
413
414    xp_copy_window(x_cvt_vptr_to_uint(wid), x_cvt_vptr_to_uint(wid),
415                   dstNrects, dstRects, dx, dy);
416}
417
418
419static RootlessFrameProcsRec xprRootlessProcs = {
420    xprCreateFrame,
421    xprDestroyFrame,
422    xprMoveFrame,
423    xprResizeFrame,
424    xprRestackFrame,
425    xprReshapeFrame,
426    xprUnmapFrame,
427    xprStartDrawing,
428    xprStopDrawing,
429    xprUpdateRegion,
430    xprDamageRects,
431    xprSwitchWindow,
432    xprDoReorderWindow,
433    xp_copy_bytes,
434    xp_fill_bytes,
435    xp_composite_pixels,
436    xprCopyWindow
437};
438
439
440/*
441 * Initialize XPR implementation
442 */
443Bool
444xprInit(ScreenPtr pScreen)
445{
446    RootlessInit(pScreen, &xprRootlessProcs);
447
448    TA_SERVER();
449
450    rootless_CopyBytes_threshold = xp_copy_bytes_threshold;
451    rootless_FillBytes_threshold = xp_fill_bytes_threshold;
452    rootless_CompositePixels_threshold = xp_composite_area_threshold;
453    rootless_CopyWindow_threshold = xp_scroll_area_threshold;
454
455    return TRUE;
456}
457
458
459/*
460 * Given the id of a physical window, try to find the top-level (or root)
461 * X window that it represents.
462 */
463WindowPtr
464xprGetXWindow(xp_window_id wid)
465{
466    RootlessWindowRec *winRec;
467
468    if (window_hash == NULL)
469        return NULL;
470
471    winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL);
472
473    return winRec != NULL ? winRec->win : NULL;
474}
475
476/*
477 * Given the id of a physical window, try to find the top-level (or root)
478 * X window that it represents.
479 */
480WindowPtr
481xprGetXWindowFromAppKit(int windowNumber)
482{
483    RootlessWindowRec *winRec;
484    Bool ret;
485    xp_window_id wid;
486
487    if (window_hash == NULL)
488        return FALSE;
489
490    /* need to lock, since this function can be called by any thread */
491
492    pthread_mutex_lock(&window_hash_mutex);
493
494    if (xp_lookup_native_window(windowNumber, &wid))
495        ret = xprGetXWindow(wid) != NULL;
496    else
497        ret = FALSE;
498
499    pthread_mutex_unlock(&window_hash_mutex);
500
501    if (!ret) return NULL;
502    winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL);
503
504    return winRec != NULL ? winRec->win : NULL;
505}
506
507
508/*
509 * The windowNumber is an AppKit window number. Returns TRUE if xpr is
510 * displaying a window with that number.
511 */
512Bool
513xprIsX11Window(void *nsWindow, int windowNumber)
514{
515    Bool ret;
516    xp_window_id wid;
517
518    if (window_hash == NULL)
519        return FALSE;
520
521    /* need to lock, since this function can be called by any thread */
522
523    pthread_mutex_lock(&window_hash_mutex);
524
525    if (xp_lookup_native_window(windowNumber, &wid))
526        ret = xprGetXWindow(wid) != NULL;
527    else
528        ret = FALSE;
529
530    pthread_mutex_unlock(&window_hash_mutex);
531
532    return ret;
533}
534
535
536/*
537 * xprHideWindows
538 *  Hide or unhide all top level windows. This is called for application hide/
539 *  unhide events if the window manager is not Apple-WM aware. Xplugin windows
540 *  do not hide or unhide themselves.
541 */
542void
543xprHideWindows(Bool hide)
544{
545    int screen;
546    WindowPtr pRoot, pWin;
547
548    TA_SERVER();
549
550    for (screen = 0; screen < screenInfo.numScreens; screen++) {
551        pRoot = WindowTable[screenInfo.screens[screen]->myNum];
552        RootlessFrameID prevWid = NULL;
553
554        for (pWin = pRoot->firstChild; pWin; pWin = pWin->nextSib) {
555            RootlessWindowRec *winRec = WINREC(pWin);
556
557            if (winRec != NULL) {
558                if (hide) {
559                    xprUnmapFrame(winRec->wid);
560                } else {
561                    BoxRec box;
562
563                    xprRestackFrame(winRec->wid, prevWid);
564                    prevWid = winRec->wid;
565
566                    box.x1 = 0;
567                    box.y1 = 0;
568                    box.x2 = winRec->width;
569                    box.y2 = winRec->height;
570
571                    xprDamageRects(winRec->wid, 1, &box, 0, 0);
572                    RootlessQueueRedisplay(screenInfo.screens[screen]);
573                }
574            }
575        }
576    }
577}
578