2 * Xplugin rootless implementation frame functions
4 * Copyright (c) 2002-2012 Apple Computer, Inc. All rights reserved.
5 * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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.
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.
30 #ifdef HAVE_DIX_CONFIG_H
31 #include <dix-config.h>
35 #include "rootlessCommon.h"
38 #include "applewmExt.h"
40 #include "propertyst.h"
42 #include <X11/Xatom.h>
43 #include "windowstr.h"
46 #ifdef HAVE_LIBDISPATCH
47 #include <dispatch/dispatch.h>
52 #ifdef DEBUG_XP_LOCK_WINDOW
56 #define DEFINE_ATOM_HELPER(func, atom_name) \
57 static Atom func(void) { \
58 static int generation; \
60 if (generation != serverGeneration) { \
61 generation = serverGeneration; \
62 atom = MakeAtom(atom_name, strlen(atom_name), TRUE); \
67 DEFINE_ATOM_HELPER(xa_native_window_id
, "_NATIVE_WINDOW_ID")
69 /* Maps xp_window_id -> RootlessWindowRec */
70 static x_hash_table
* window_hash
;
72 /* Need to guard window_hash since xprIsX11Window can be called from any thread. */
73 #ifdef HAVE_LIBDISPATCH
74 static dispatch_queue_t window_hash_serial_q
;
76 static pthread_rwlock_t window_hash_rwlock
;
79 /* Prototypes for static functions */
81 xprCreateFrame(RootlessWindowPtr pFrame
, ScreenPtr pScreen
, int newX
,
85 xprDestroyFrame(RootlessFrameID wid
);
87 xprMoveFrame(RootlessFrameID wid
, ScreenPtr pScreen
, int newX
, int newY
);
89 xprResizeFrame(RootlessFrameID wid
, ScreenPtr pScreen
, int newX
, int newY
,
90 unsigned int newW
, unsigned int newH
,
91 unsigned int gravity
);
93 xprRestackFrame(RootlessFrameID wid
, RootlessFrameID nextWid
);
95 xprReshapeFrame(RootlessFrameID wid
, RegionPtr pShape
);
97 xprUnmapFrame(RootlessFrameID wid
);
99 xprStartDrawing(RootlessFrameID wid
, char **pixelData
, int *bytesPerRow
);
101 xprStopDrawing(RootlessFrameID wid
, Bool flush
);
103 xprUpdateRegion(RootlessFrameID wid
, RegionPtr pDamage
);
105 xprDamageRects(RootlessFrameID wid
, int nrects
, const BoxRec
*rects
,
109 xprSwitchWindow(RootlessWindowPtr pFrame
, WindowPtr oldWin
);
111 xprDoReorderWindow(RootlessWindowPtr pFrame
);
113 xprHideWindow(RootlessFrameID wid
);
115 xprUpdateColormap(RootlessFrameID wid
, ScreenPtr pScreen
);
117 xprCopyWindow(RootlessFrameID wid
, int dstNrects
, const BoxRec
*dstRects
,
121 static inline xp_error
122 xprConfigureWindow(xp_window_id id
, unsigned int mask
,
123 const xp_window_changes
*values
)
125 return xp_configure_window(id
, mask
, values
);
129 xprSetNativeProperty(RootlessWindowPtr pFrame
)
132 unsigned int native_id
;
135 err
= xp_get_native_window(x_cvt_vptr_to_uint(pFrame
->wid
), &native_id
);
136 if (err
== Success
) {
137 /* FIXME: move this to AppleWM extension */
140 dixChangeWindowProperty(serverClient
, pFrame
->win
,
141 xa_native_window_id(),
142 XA_INTEGER
, 32, PropModeReplace
, 1, &data
,
148 xprColormapCallback(void *data
, int first_color
, int n_colors
,
151 return (RootlessResolveColormap(data
, first_color
, n_colors
,
152 colors
) ? XP_Success
: XP_BadMatch
);
156 * Create and display a new frame.
159 xprCreateFrame(RootlessWindowPtr pFrame
, ScreenPtr pScreen
,
160 int newX
, int newY
, RegionPtr pShape
)
162 WindowPtr pWin
= pFrame
->win
;
163 xp_window_changes wc
;
164 unsigned int mask
= 0;
169 wc
.width
= pFrame
->width
;
170 wc
.height
= pFrame
->height
;
171 wc
.bit_gravity
= XP_GRAVITY_NONE
;
174 if (pWin
->drawable
.depth
== 8) {
175 wc
.depth
= XP_DEPTH_INDEX8
;
176 wc
.colormap
= xprColormapCallback
;
177 wc
.colormap_data
= pScreen
;
180 else if (pWin
->drawable
.depth
== 15)
181 wc
.depth
= XP_DEPTH_RGB555
;
182 else if (pWin
->drawable
.depth
== 24)
183 wc
.depth
= XP_DEPTH_ARGB8888
;
185 wc
.depth
= XP_DEPTH_NIL
;
188 if (pShape
!= NULL
) {
189 wc
.shape_nrects
= RegionNumRects(pShape
);
190 wc
.shape_rects
= RegionRects(pShape
);
191 wc
.shape_tx
= wc
.shape_ty
= 0;
196 !IsRoot(pWin
) ? AppleWMWindowLevelNormal
: AppleWMNumWindowLevels
;
198 if (XQuartzIsRootless
)
199 wc
.window_level
= normal_window_levels
[pFrame
->level
];
200 else if (XQuartzShieldingWindowLevel
)
201 wc
.window_level
= XQuartzShieldingWindowLevel
+ 1;
203 wc
.window_level
= rooted_window_levels
[pFrame
->level
];
204 mask
|= XP_WINDOW_LEVEL
;
206 err
= xp_create_window(mask
, &wc
, (xp_window_id
*)&pFrame
->wid
);
208 if (err
!= Success
) {
212 #ifdef HAVE_LIBDISPATCH
213 dispatch_async(window_hash_serial_q
, ^ {
214 x_hash_table_insert(window_hash
, pFrame
->wid
, pFrame
);
217 pthread_rwlock_wrlock(&window_hash_rwlock
);
218 x_hash_table_insert(window_hash
, pFrame
->wid
, pFrame
);
219 pthread_rwlock_unlock(&window_hash_rwlock
);
222 xprSetNativeProperty(pFrame
);
231 xprDestroyFrame(RootlessFrameID wid
)
235 #ifdef HAVE_LIBDISPATCH
236 dispatch_async(window_hash_serial_q
, ^ {
237 x_hash_table_remove(window_hash
, wid
);
240 pthread_rwlock_wrlock(&window_hash_rwlock
);
241 x_hash_table_remove(window_hash
, wid
);
242 pthread_rwlock_unlock(&window_hash_rwlock
);
245 err
= xp_destroy_window(x_cvt_vptr_to_uint(wid
));
247 FatalError("Could not destroy window %d (%d).",
248 (int)x_cvt_vptr_to_uint(
253 * Move a frame on screen.
256 xprMoveFrame(RootlessFrameID wid
, ScreenPtr pScreen
, int newX
, int newY
)
258 xp_window_changes wc
;
262 // ErrorF("xprMoveFrame(%d, %p, %d, %d)\n", wid, pScreen, newX, newY);
263 xprConfigureWindow(x_cvt_vptr_to_uint(wid
), XP_ORIGIN
, &wc
);
267 * Resize and move a frame.
270 xprResizeFrame(RootlessFrameID wid
, ScreenPtr pScreen
,
271 int newX
, int newY
, unsigned int newW
, unsigned int newH
,
272 unsigned int gravity
)
274 xp_window_changes wc
;
280 wc
.bit_gravity
= gravity
;
282 /* It's unlikely that being async will save us anything here.
283 But it can't hurt. */
285 xprConfigureWindow(x_cvt_vptr_to_uint(wid
), XP_BOUNDS
, &wc
);
289 * Change frame stacking.
292 xprRestackFrame(RootlessFrameID wid
, RootlessFrameID nextWid
)
294 xp_window_changes wc
;
295 unsigned int mask
= XP_STACKING
;
296 #ifdef HAVE_LIBDISPATCH
299 RootlessWindowRec
* winRec
;
301 /* Stack frame below nextWid it if it exists, or raise
302 frame above everything otherwise. */
304 if (nextWid
== NULL
) {
305 wc
.stack_mode
= XP_MAPPED_ABOVE
;
309 wc
.stack_mode
= XP_MAPPED_BELOW
;
310 wc
.sibling
= x_cvt_vptr_to_uint(nextWid
);
313 #ifdef HAVE_LIBDISPATCH
314 dispatch_sync(window_hash_serial_q
, ^ {
315 winRec
= x_hash_table_lookup(window_hash
, wid
, NULL
);
318 pthread_rwlock_rdlock(&window_hash_rwlock
);
319 winRec
= x_hash_table_lookup(window_hash
, wid
, NULL
);
320 pthread_rwlock_unlock(&window_hash_rwlock
);
324 if (XQuartzIsRootless
)
325 wc
.window_level
= normal_window_levels
[winRec
->level
];
326 else if (XQuartzShieldingWindowLevel
)
327 wc
.window_level
= XQuartzShieldingWindowLevel
+ 1;
329 wc
.window_level
= rooted_window_levels
[winRec
->level
];
330 mask
|= XP_WINDOW_LEVEL
;
333 xprConfigureWindow(x_cvt_vptr_to_uint(wid
), mask
, &wc
);
337 * Change the frame's shape.
340 xprReshapeFrame(RootlessFrameID wid
, RegionPtr pShape
)
342 xp_window_changes wc
;
344 if (pShape
!= NULL
) {
345 wc
.shape_nrects
= RegionNumRects(pShape
);
346 wc
.shape_rects
= RegionRects(pShape
);
349 wc
.shape_nrects
= -1;
350 wc
.shape_rects
= NULL
;
353 wc
.shape_tx
= wc
.shape_ty
= 0;
355 xprConfigureWindow(x_cvt_vptr_to_uint(wid
), XP_SHAPE
, &wc
);
362 xprUnmapFrame(RootlessFrameID wid
)
364 xp_window_changes wc
;
366 wc
.stack_mode
= XP_UNMAPPED
;
369 xprConfigureWindow(x_cvt_vptr_to_uint(wid
), XP_STACKING
, &wc
);
373 * Start drawing to a frame.
374 * Prepare for direct access to its backing buffer.
377 xprStartDrawing(RootlessFrameID wid
, char **pixelData
, int *bytesPerRow
)
380 unsigned int rowbytes
[2];
383 #ifdef DEBUG_XP_LOCK_WINDOW
384 void* callstack
[128];
385 int i
, frames
= backtrace(callstack
, 128);
386 char** strs
= backtrace_symbols(callstack
, frames
);
388 ErrorF("=== LOCK %d ===\n", (int)x_cvt_vptr_to_uint(wid
));
389 for (i
= 0; i
< frames
; ++i
) {
390 ErrorF(" %s\n", strs
[i
]);
395 err
= xp_lock_window(x_cvt_vptr_to_uint(
396 wid
), NULL
, NULL
, data
, rowbytes
, NULL
);
398 FatalError("Could not lock window %d for drawing (%d).",
399 (int)x_cvt_vptr_to_uint(
402 *pixelData
= data
[0];
403 *bytesPerRow
= rowbytes
[0];
407 * Stop drawing to a frame.
410 xprStopDrawing(RootlessFrameID wid
, Bool flush
)
414 #ifdef DEBUG_XP_LOCK_WINDOW
415 void* callstack
[128];
416 int i
, frames
= backtrace(callstack
, 128);
417 char** strs
= backtrace_symbols(callstack
, frames
);
419 ErrorF("=== UNLOCK %d ===\n", (int)x_cvt_vptr_to_uint(wid
));
420 for (i
= 0; i
< frames
; ++i
) {
421 ErrorF(" %s\n", strs
[i
]);
426 err
= xp_unlock_window(x_cvt_vptr_to_uint(wid
), flush
);
427 /* This should be a FatalError, but we started tripping over it. Make it a
428 * FatalError after http://xquartz.macosforge.org/trac/ticket/482 is fixed.
431 ErrorF("Could not unlock window %d after drawing (%d).",
432 (int)x_cvt_vptr_to_uint(
437 * Flush drawing updates to the screen.
440 xprUpdateRegion(RootlessFrameID wid
, RegionPtr pDamage
)
442 xp_flush_window(x_cvt_vptr_to_uint(wid
));
446 * Mark damaged rectangles as requiring redisplay to screen.
449 xprDamageRects(RootlessFrameID wid
, int nrects
, const BoxRec
*rects
,
450 int shift_x
, int shift_y
)
452 xp_mark_window(x_cvt_vptr_to_uint(wid
), nrects
, rects
, shift_x
, shift_y
);
456 * Called after the window associated with a frame has been switched
457 * to a new top-level parent.
460 xprSwitchWindow(RootlessWindowPtr pFrame
, WindowPtr oldWin
)
462 DeleteProperty(serverClient
, oldWin
, xa_native_window_id());
464 xprSetNativeProperty(pFrame
);
468 * Called to check if the frame should be reordered when it is restacked.
471 xprDoReorderWindow(RootlessWindowPtr pFrame
)
473 WindowPtr pWin
= pFrame
->win
;
475 return AppleWMDoReorderWindow(pWin
);
479 * Copy area in frame to another part of frame.
480 * Used to accelerate scrolling.
483 xprCopyWindow(RootlessFrameID wid
, int dstNrects
, const BoxRec
*dstRects
,
486 xp_copy_window(x_cvt_vptr_to_uint(wid
), x_cvt_vptr_to_uint(wid
),
487 dstNrects
, dstRects
, dx
, dy
);
490 static RootlessFrameProcsRec xprRootlessProcs
= {
511 * Initialize XPR implementation
514 xprInit(ScreenPtr pScreen
)
516 RootlessInit(pScreen
, &xprRootlessProcs
);
518 rootless_CopyBytes_threshold
= xp_copy_bytes_threshold
;
519 rootless_CopyWindow_threshold
= xp_scroll_area_threshold
;
521 assert((window_hash
= x_hash_table_new(NULL
, NULL
, NULL
, NULL
)));
522 #ifdef HAVE_LIBDISPATCH
523 assert((window_hash_serial_q
=
524 dispatch_queue_create(BUNDLE_ID_PREFIX
".X11.xpr_window_hash",
527 assert(0 == pthread_rwlock_init(&window_hash_rwlock
, NULL
));
534 * Given the id of a physical window, try to find the top-level (or root)
535 * X window that it represents.
538 xprGetXWindow(xp_window_id wid
)
540 #ifdef HAVE_LIBDISPATCH
541 RootlessWindowRec
*winRec __block
;
542 dispatch_sync(window_hash_serial_q
, ^ {
544 x_hash_table_lookup(window_hash
,
545 x_cvt_uint_to_vptr(wid
), NULL
);
548 RootlessWindowRec
*winRec
;
549 pthread_rwlock_rdlock(&window_hash_rwlock
);
550 winRec
= x_hash_table_lookup(window_hash
, x_cvt_uint_to_vptr(wid
), NULL
);
551 pthread_rwlock_unlock(&window_hash_rwlock
);
554 return winRec
!= NULL
? winRec
->win
: NULL
;
558 * The windowNumber is an AppKit window number. Returns TRUE if xpr is
559 * displaying a window with that number.
562 xprIsX11Window(int windowNumber
)
567 if (xp_lookup_native_window(windowNumber
, &wid
))
568 ret
= xprGetXWindow(wid
) != NULL
;
577 * Hide or unhide all top level windows. This is called for application hide/
578 * unhide events if the window manager is not Apple-WM aware. Xplugin windows
579 * do not hide or unhide themselves.
582 xprHideWindows(Bool hide
)
585 WindowPtr pRoot
, pWin
;
587 for (screen
= 0; screen
< screenInfo
.numScreens
; screen
++) {
588 RootlessFrameID prevWid
= NULL
;
589 pRoot
= screenInfo
.screens
[screen
]->root
;
591 for (pWin
= pRoot
->firstChild
; pWin
; pWin
= pWin
->nextSib
) {
592 RootlessWindowRec
*winRec
= WINREC(pWin
);
594 if (winRec
!= NULL
) {
596 xprUnmapFrame(winRec
->wid
);
601 xprRestackFrame(winRec
->wid
, prevWid
);
602 prevWid
= winRec
->wid
;
606 box
.x2
= winRec
->width
;
607 box
.y2
= winRec
->height
;
609 xprDamageRects(winRec
->wid
, 1, &box
, 0, 0);
610 RootlessQueueRedisplay(screenInfo
.screens
[screen
]);
617 // XXX: identical to x_cvt_vptr_to_uint ?
618 #define MAKE_WINDOW_ID(x) ((xp_window_id)((size_t)(x)))
620 Bool no_configure_window
;
623 configure_window(xp_window_id id
, unsigned int mask
,
624 const xp_window_changes
*values
)
626 if (!no_configure_window
)
627 return xp_configure_window(id
, mask
, values
);
634 xprUpdateColormap(RootlessFrameID wid
, ScreenPtr pScreen
)
636 /* This is how we tell xp that the colormap may have changed. */
637 xp_window_changes wc
;
638 wc
.colormap
= xprColormapCallback
;
639 wc
.colormap_data
= pScreen
;
641 configure_window(MAKE_WINDOW_ID(wid
), XP_COLORMAP
, &wc
);
646 xprHideWindow(RootlessFrameID wid
)
648 xp_window_changes wc
;
649 wc
.stack_mode
= XP_UNMAPPED
;
651 configure_window(MAKE_WINDOW_ID(wid
), XP_STACKING
, &wc
);