xprFrame.c revision 6747b715
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
177        wc.window_level = rooted_window_levels[pFrame->level];
178    mask |= XP_WINDOW_LEVEL;
179
180    err = xp_create_window(mask, &wc, (xp_window_id *) &pFrame->wid);
181
182    if (err != Success)
183    {
184        return FALSE;
185    }
186
187    if (window_hash == NULL)
188    {
189        window_hash = x_hash_table_new(NULL, NULL, NULL, NULL);
190        pthread_mutex_init(&window_hash_mutex, NULL);
191    }
192
193    pthread_mutex_lock(&window_hash_mutex);
194    x_hash_table_insert(window_hash, pFrame->wid, pFrame);
195    pthread_mutex_unlock(&window_hash_mutex);
196
197    xprSetNativeProperty(pFrame);
198
199    return TRUE;
200}
201
202
203/*
204 * Destroy a frame.
205 */
206static void
207xprDestroyFrame(RootlessFrameID wid)
208{
209    xp_error err;
210    TA_SERVER();
211
212    pthread_mutex_lock(&window_hash_mutex);
213    x_hash_table_remove(window_hash, wid);
214    pthread_mutex_unlock(&window_hash_mutex);
215
216    err = xp_destroy_window(x_cvt_vptr_to_uint(wid));
217    if (err != Success)
218        FatalError("Could not destroy window %i.", (int)x_cvt_vptr_to_uint(wid));
219}
220
221
222/*
223 * Move a frame on screen.
224 */
225static void
226xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY)
227{
228    xp_window_changes wc;
229
230    TA_SERVER();
231
232    wc.x = newX;
233    wc.y = newY;
234    //    ErrorF("xprMoveFrame(%d, %p, %d, %d)\n", wid, pScreen, newX, newY);
235    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_ORIGIN, &wc);
236}
237
238
239/*
240 * Resize and move a frame.
241 */
242static void
243xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen,
244               int newX, int newY, unsigned int newW, unsigned int newH,
245               unsigned int gravity)
246{
247    xp_window_changes wc;
248
249    TA_SERVER();
250
251    wc.x = newX;
252    wc.y = newY;
253    wc.width = newW;
254    wc.height = newH;
255    wc.bit_gravity = gravity;
256
257    /* It's unlikely that being async will save us anything here.
258       But it can't hurt. */
259
260    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_BOUNDS, &wc);
261}
262
263
264/*
265 * Change frame stacking.
266 */
267static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) {
268    xp_window_changes wc;
269    unsigned int mask = XP_STACKING;
270
271    TA_SERVER();
272
273    /* Stack frame below nextWid it if it exists, or raise
274       frame above everything otherwise. */
275
276    if(nextWid == NULL) {
277        wc.stack_mode = XP_MAPPED_ABOVE;
278        wc.sibling = 0;
279    } else {
280        wc.stack_mode = XP_MAPPED_BELOW;
281        wc.sibling = x_cvt_vptr_to_uint(nextWid);
282    }
283
284    if(window_hash) {
285        RootlessWindowRec *winRec = x_hash_table_lookup(window_hash, wid, NULL);
286
287        if(winRec) {
288            if(XQuartzIsRootless)
289                wc.window_level = normal_window_levels[winRec->level];
290            else
291                wc.window_level = rooted_window_levels[winRec->level];
292            mask |= XP_WINDOW_LEVEL;
293        }
294    }
295
296    xprConfigureWindow(x_cvt_vptr_to_uint(wid), mask, &wc);
297}
298
299
300/*
301 * Change the frame's shape.
302 */
303static void
304xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape)
305{
306    xp_window_changes wc;
307
308    TA_SERVER();
309
310    if (pShape != NULL)
311    {
312        wc.shape_nrects = RegionNumRects(pShape);
313        wc.shape_rects = RegionRects(pShape);
314    }
315    else
316    {
317        wc.shape_nrects = -1;
318        wc.shape_rects = NULL;
319    }
320
321    wc.shape_tx = wc.shape_ty = 0;
322
323    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_SHAPE, &wc);
324}
325
326
327/*
328 * Unmap a frame.
329 */
330static void
331xprUnmapFrame(RootlessFrameID wid)
332{
333    xp_window_changes wc;
334
335    TA_SERVER();
336
337    wc.stack_mode = XP_UNMAPPED;
338    wc.sibling = 0;
339
340    xprConfigureWindow(x_cvt_vptr_to_uint(wid), XP_STACKING, &wc);
341}
342
343
344/*
345 * Start drawing to a frame.
346 *  Prepare for direct access to its backing buffer.
347 */
348static void
349xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow)
350{
351    void *data[2];
352    unsigned int rowbytes[2];
353    xp_error err;
354
355    TA_SERVER();
356
357    err = xp_lock_window(x_cvt_vptr_to_uint(wid), NULL, NULL, data, rowbytes, NULL);
358    if (err != Success)
359        FatalError("Could not lock window %i for drawing.", (int)x_cvt_vptr_to_uint(wid));
360
361    *pixelData = data[0];
362    *bytesPerRow = rowbytes[0];
363}
364
365
366/*
367 * Stop drawing to a frame.
368 */
369static void
370xprStopDrawing(RootlessFrameID wid, Bool flush)
371{
372    xp_error err;
373    TA_SERVER();
374
375    err = xp_unlock_window(x_cvt_vptr_to_uint(wid), flush);
376    if(err != Success)
377        FatalError("Could not unlock window %i after drawing.", (int)x_cvt_vptr_to_uint(wid));
378}
379
380
381/*
382 * Flush drawing updates to the screen.
383 */
384static void
385xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage)
386{
387    TA_SERVER();
388
389    xp_flush_window(x_cvt_vptr_to_uint(wid));
390}
391
392
393/*
394 * Mark damaged rectangles as requiring redisplay to screen.
395 */
396static void
397xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects,
398               int shift_x, int shift_y)
399{
400    TA_SERVER();
401
402    xp_mark_window(x_cvt_vptr_to_uint(wid), nrects, rects, shift_x, shift_y);
403}
404
405
406/*
407 * Called after the window associated with a frame has been switched
408 * to a new top-level parent.
409 */
410static void
411xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin)
412{
413    DeleteProperty(serverClient, oldWin, xa_native_window_id());
414
415    TA_SERVER();
416
417    xprSetNativeProperty(pFrame);
418}
419
420
421/*
422 * Called to check if the frame should be reordered when it is restacked.
423 */
424static Bool xprDoReorderWindow(RootlessWindowPtr pFrame)
425{
426    WindowPtr pWin = pFrame->win;
427
428    TA_SERVER();
429
430    return AppleWMDoReorderWindow(pWin);
431}
432
433
434/*
435 * Copy area in frame to another part of frame.
436 *  Used to accelerate scrolling.
437 */
438static void
439xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects,
440              int dx, int dy)
441{
442    TA_SERVER();
443
444    xp_copy_window(x_cvt_vptr_to_uint(wid), x_cvt_vptr_to_uint(wid),
445                   dstNrects, dstRects, dx, dy);
446}
447
448
449static RootlessFrameProcsRec xprRootlessProcs = {
450    xprCreateFrame,
451    xprDestroyFrame,
452    xprMoveFrame,
453    xprResizeFrame,
454    xprRestackFrame,
455    xprReshapeFrame,
456    xprUnmapFrame,
457    xprStartDrawing,
458    xprStopDrawing,
459    xprUpdateRegion,
460    xprDamageRects,
461    xprSwitchWindow,
462    xprDoReorderWindow,
463    xprHideWindow,
464    xprUpdateColormap,
465    xp_copy_bytes,
466    xp_fill_bytes,
467    xp_composite_pixels,
468    xprCopyWindow
469};
470
471
472/*
473 * Initialize XPR implementation
474 */
475Bool
476xprInit(ScreenPtr pScreen)
477{
478    RootlessInit(pScreen, &xprRootlessProcs);
479
480    TA_SERVER();
481
482    rootless_CopyBytes_threshold = xp_copy_bytes_threshold;
483    rootless_FillBytes_threshold = xp_fill_bytes_threshold;
484    rootless_CompositePixels_threshold = xp_composite_area_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