dmxcursor.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. /*
  2. * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
  3. *
  4. * All Rights Reserved.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining
  7. * a copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation on the rights to use, copy, modify, merge,
  10. * publish, distribute, sublicense, and/or sell copies of the Software,
  11. * and to permit persons to whom the Software is furnished to do so,
  12. * subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice (including the
  15. * next paragraph) shall be included in all copies or substantial
  16. * portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  19. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21. * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
  22. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  23. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  24. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  25. * SOFTWARE.
  26. */
  27. /*
  28. * Authors:
  29. * David H. Dawes <dawes@xfree86.org>
  30. * Kevin E. Martin <kem@redhat.com>
  31. * Rickard E. (Rik) Faith <faith@redhat.com>
  32. *
  33. */
  34. /** \file
  35. * This file contains code than supports cursor movement, including the
  36. * code that initializes and reinitializes the screen positions and
  37. * computes screen overlap.
  38. *
  39. * "This code is based very closely on the XFree86 equivalent
  40. * (xfree86/common/xf86Cursor.c)." --David Dawes.
  41. *
  42. * "This code was then extensively re-written, as explained here."
  43. * --Rik Faith
  44. *
  45. * The code in xf86Cursor.c used edge lists to implement the
  46. * CursorOffScreen function. The edge list computation was complex
  47. * (especially in the face of arbitrarily overlapping screens) compared
  48. * with the speed savings in the CursorOffScreen function. The new
  49. * implementation has erred on the side of correctness, readability, and
  50. * maintainability over efficiency. For the common (non-edge) case, the
  51. * dmxCursorOffScreen function does avoid a loop over all the screens.
  52. * When the cursor has left the screen, all the screens are searched,
  53. * and the first screen (in dmxScreens order) containing the cursor will
  54. * be returned. If run-time profiling shows that this routing is a
  55. * performance bottle-neck, then an edge list may have to be
  56. * reimplemented. An edge list algorithm is O(edges) whereas the new
  57. * algorithm is O(dmxNumScreens). Since edges is usually 1-3 and
  58. * dmxNumScreens may be 30-60 for large backend walls, this trade off
  59. * may be compelling.
  60. *
  61. * The xf86InitOrigins routine uses bit masks during the computation and
  62. * is therefore limited to the length of a word (e.g., 32 or 64 bits)
  63. * screens. Because Xdmx is expected to be used with a large number of
  64. * backend displays, this limitation was removed. The new
  65. * implementation has erred on the side of readability over efficiency,
  66. * using the dmxSL* routines to manage a screen list instead of a
  67. * bitmap, and a function call to decrease the length of the main
  68. * routine. Both algorithms are of the same order, and both are called
  69. * only at server generation time, so trading clarity and long-term
  70. * maintainability for efficiency does not seem justified in this case.
  71. */
  72. #ifdef HAVE_DMX_CONFIG_H
  73. #include <dmx-config.h>
  74. #endif
  75. #define DMX_CURSOR_DEBUG 0
  76. #include "dmx.h"
  77. #include "dmxsync.h"
  78. #include "dmxcursor.h"
  79. #include "dmxlog.h"
  80. #include "dmxprop.h"
  81. #include "dmxinput.h"
  82. #include "mipointer.h"
  83. #include "windowstr.h"
  84. #include "globals.h"
  85. #include "cursorstr.h"
  86. #include "dixevents.h" /* For GetSpriteCursor() */
  87. #include "inputstr.h" /* for inputInfo.pointer */
  88. #if DMX_CURSOR_DEBUG
  89. #define DMXDBG0(f) dmxLog(dmxDebug,f)
  90. #define DMXDBG1(f,a) dmxLog(dmxDebug,f,a)
  91. #define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b)
  92. #define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
  93. #define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d)
  94. #define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e)
  95. #define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g)
  96. #define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h)
  97. #else
  98. #define DMXDBG0(f)
  99. #define DMXDBG1(f,a)
  100. #define DMXDBG2(f,a,b)
  101. #define DMXDBG3(f,a,b,c)
  102. #define DMXDBG4(f,a,b,c,d)
  103. #define DMXDBG5(f,a,b,c,d,e)
  104. #define DMXDBG6(f,a,b,c,d,e,g)
  105. #define DMXDBG7(f,a,b,c,d,e,g,h)
  106. #endif
  107. static int dmxCursorDoMultiCursors = 1;
  108. /** Turn off support for displaying multiple cursors on overlapped
  109. back-end displays. See #dmxCursorDoMultiCursors. */
  110. void
  111. dmxCursorNoMulti(void)
  112. {
  113. dmxCursorDoMultiCursors = 0;
  114. }
  115. static Bool
  116. dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
  117. {
  118. DMXScreenInfo *dmxScreen;
  119. int i;
  120. int localX = *x;
  121. int localY = *y;
  122. int globalX;
  123. int globalY;
  124. if (screenInfo.numScreens == 1)
  125. return FALSE;
  126. /* On current screen? */
  127. dmxScreen = &dmxScreens[(*ppScreen)->myNum];
  128. if (localX >= 0
  129. && localX < dmxScreen->rootWidth
  130. && localY >= 0 && localY < dmxScreen->rootHeight)
  131. return FALSE;
  132. /* Convert to global coordinate space */
  133. globalX = dmxScreen->rootXOrigin + localX;
  134. globalY = dmxScreen->rootYOrigin + localY;
  135. /* Is cursor on the current screen?
  136. * This efficiently exits this routine
  137. * for the most common case. */
  138. if (ppScreen && *ppScreen) {
  139. dmxScreen = &dmxScreens[(*ppScreen)->myNum];
  140. if (globalX >= dmxScreen->rootXOrigin
  141. && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth
  142. && globalY >= dmxScreen->rootYOrigin
  143. && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight)
  144. return FALSE;
  145. }
  146. /* Find first screen cursor is on */
  147. for (i = 0; i < dmxNumScreens; i++) {
  148. dmxScreen = &dmxScreens[i];
  149. if (globalX >= dmxScreen->rootXOrigin
  150. && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth
  151. && globalY >= dmxScreen->rootYOrigin
  152. && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) {
  153. if (dmxScreen->index == (*ppScreen)->myNum)
  154. return FALSE;
  155. *ppScreen = screenInfo.screens[dmxScreen->index];
  156. *x = globalX - dmxScreen->rootXOrigin;
  157. *y = globalY - dmxScreen->rootYOrigin;
  158. return TRUE;
  159. }
  160. }
  161. return FALSE;
  162. }
  163. static void
  164. dmxCrossScreen(ScreenPtr pScreen, Bool entering)
  165. {
  166. }
  167. static void
  168. dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
  169. {
  170. DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
  171. #if 11 /*BP*/
  172. /* This call is depracated. Replace with???? */
  173. miPointerWarpCursor(pDev, pScreen, x, y);
  174. #else
  175. pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE);
  176. #endif
  177. }
  178. miPointerScreenFuncRec dmxPointerCursorFuncs = {
  179. dmxCursorOffScreen,
  180. dmxCrossScreen,
  181. dmxWarpCursor,
  182. };
  183. /** Create a list of screens that we'll manipulate. */
  184. static int *
  185. dmxSLCreate(void)
  186. {
  187. int *list = malloc(dmxNumScreens * sizeof(*list));
  188. int i;
  189. for (i = 0; i < dmxNumScreens; i++)
  190. list[i] = 1;
  191. return list;
  192. }
  193. /** Free list. */
  194. static void
  195. dmxSLFree(int *list)
  196. {
  197. free(list);
  198. }
  199. /** Find next uninitialized entry in list. */
  200. static int
  201. dmxSLFindNext(int *list)
  202. {
  203. int i;
  204. for (i = 0; i < dmxNumScreens; i++)
  205. if (list[i])
  206. return i;
  207. return -1;
  208. }
  209. /** Make one pass over all the screens and return the number updated. */
  210. static int
  211. dmxTryComputeScreenOrigins(int *screensLeft)
  212. {
  213. ScreenPtr pScreen, refScreen;
  214. DMXScreenInfo *screen;
  215. int i, ref;
  216. int changed = 0;
  217. for (i = 0; i < dmxNumScreens; i++) {
  218. if (!screensLeft[i])
  219. continue;
  220. screen = &dmxScreens[i];
  221. pScreen = screenInfo.screens[i];
  222. switch (screen->where) {
  223. case PosAbsolute:
  224. pScreen->x = screen->whereX;
  225. pScreen->y = screen->whereY;
  226. ++changed, screensLeft[i] = 0;
  227. break;
  228. case PosRelative:
  229. ref = screen->whereRefScreen;
  230. if (screensLeft[ref])
  231. break;
  232. refScreen = screenInfo.screens[ref];
  233. pScreen->x = refScreen->x + screen->whereX;
  234. pScreen->y = refScreen->y + screen->whereY;
  235. ++changed, screensLeft[i] = 0;
  236. break;
  237. case PosRightOf:
  238. ref = screen->whereRefScreen;
  239. if (screensLeft[ref])
  240. break;
  241. refScreen = screenInfo.screens[ref];
  242. pScreen->x = refScreen->x + refScreen->width;
  243. pScreen->y = refScreen->y;
  244. ++changed, screensLeft[i] = 0;
  245. break;
  246. case PosLeftOf:
  247. ref = screen->whereRefScreen;
  248. if (screensLeft[ref])
  249. break;
  250. refScreen = screenInfo.screens[ref];
  251. pScreen->x = refScreen->x - pScreen->width;
  252. pScreen->y = refScreen->y;
  253. ++changed, screensLeft[i] = 0;
  254. break;
  255. case PosBelow:
  256. ref = screen->whereRefScreen;
  257. if (screensLeft[ref])
  258. break;
  259. refScreen = screenInfo.screens[ref];
  260. pScreen->x = refScreen->x;
  261. pScreen->y = refScreen->y + refScreen->height;
  262. ++changed, screensLeft[i] = 0;
  263. break;
  264. case PosAbove:
  265. ref = screen->whereRefScreen;
  266. if (screensLeft[ref])
  267. break;
  268. refScreen = screenInfo.screens[ref];
  269. pScreen->x = refScreen->x;
  270. pScreen->y = refScreen->y - pScreen->height;
  271. ++changed, screensLeft[i] = 0;
  272. break;
  273. case PosNone:
  274. dmxLog(dmxFatal, "No position information for screen %d\n", i);
  275. }
  276. }
  277. return changed;
  278. }
  279. static void
  280. dmxComputeScreenOrigins(void)
  281. {
  282. ScreenPtr pScreen;
  283. int *screensLeft;
  284. int i, ref;
  285. int minX, minY;
  286. /* Compute origins based on
  287. * configuration information. */
  288. screensLeft = dmxSLCreate();
  289. while ((i = dmxSLFindNext(screensLeft)) >= 0) {
  290. while (dmxTryComputeScreenOrigins(screensLeft));
  291. if ((i = dmxSLFindNext(screensLeft)) >= 0) {
  292. /* All of the remaining screens are referencing each other.
  293. * Assign a value to one of them and go through again. This
  294. * guarantees that we will eventually terminate.
  295. */
  296. ref = dmxScreens[i].whereRefScreen;
  297. pScreen = screenInfo.screens[ref];
  298. pScreen->x = pScreen->y = 0;
  299. screensLeft[ref] = 0;
  300. }
  301. }
  302. dmxSLFree(screensLeft);
  303. /* Justify the topmost and leftmost to
  304. * (0,0). */
  305. minX = screenInfo.screens[0]->x;
  306. minY = screenInfo.screens[0]->y;
  307. for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */
  308. if (screenInfo.screens[i]->x < minX)
  309. minX = screenInfo.screens[i]->x;
  310. if (screenInfo.screens[i]->y < minY)
  311. minY = screenInfo.screens[i]->y;
  312. }
  313. if (minX || minY) {
  314. for (i = 0; i < dmxNumScreens; i++) {
  315. screenInfo.screens[i]->x -= minX;
  316. screenInfo.screens[i]->y -= minY;
  317. }
  318. }
  319. update_desktop_dimensions();
  320. }
  321. /** Recompute origin information in the #dmxScreens list. This is
  322. * called from #dmxInitOrigins. */
  323. void
  324. dmxReInitOrigins(void)
  325. {
  326. int i;
  327. if (dmxNumScreens > MAXSCREENS)
  328. dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
  329. dmxNumScreens, MAXSCREENS);
  330. for (i = 0; i < dmxNumScreens; i++) {
  331. DMXScreenInfo *dmxScreen = &dmxScreens[i];
  332. dmxLogOutput(dmxScreen,
  333. "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d"
  334. " (be=%dx%d depth=%d bpp=%d)\n",
  335. dmxScreen->scrnWidth, dmxScreen->scrnHeight,
  336. dmxScreen->scrnX, dmxScreen->scrnY,
  337. dmxScreen->rootWidth, dmxScreen->rootHeight,
  338. dmxScreen->rootX, dmxScreen->rootY,
  339. dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
  340. dmxScreen->beWidth, dmxScreen->beHeight,
  341. dmxScreen->beDepth, dmxScreen->beBPP);
  342. }
  343. }
  344. /** Initialize screen origins (and relative position). This is called
  345. * for each server generation. For dynamic reconfiguration, use
  346. * #dmxReInitOrigins() instead. */
  347. void
  348. dmxInitOrigins(void)
  349. {
  350. int i;
  351. if (dmxNumScreens > MAXSCREENS)
  352. dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
  353. dmxNumScreens, MAXSCREENS);
  354. for (i = 0; i < dmxNumScreens; i++) {
  355. DMXScreenInfo *dmxScreen = &dmxScreens[i];
  356. dmxLogOutput(dmxScreen,
  357. "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)"
  358. " (be=%dx%d depth=%d bpp=%d)\n",
  359. dmxScreen->scrnWidth, dmxScreen->scrnHeight,
  360. dmxScreen->scrnX, dmxScreen->scrnY,
  361. dmxScreen->rootWidth, dmxScreen->rootHeight,
  362. dmxScreen->rootX, dmxScreen->rootY,
  363. dmxScreen->whereX, dmxScreen->whereY,
  364. dmxScreen->where,
  365. dmxScreen->beWidth, dmxScreen->beHeight,
  366. dmxScreen->beDepth, dmxScreen->beBPP);
  367. }
  368. dmxComputeScreenOrigins();
  369. for (i = 0; i < dmxNumScreens; i++) {
  370. DMXScreenInfo *dmxScreen = &dmxScreens[i];
  371. dmxScreen->rootXOrigin = screenInfo.screens[i]->x;
  372. dmxScreen->rootYOrigin = screenInfo.screens[i]->y;
  373. }
  374. dmxReInitOrigins();
  375. }
  376. /** Returns non-zero if the global \a x, \a y coordinate is on the
  377. * screen window of the \a dmxScreen. */
  378. int
  379. dmxOnScreen(int x, int y, DMXScreenInfo * dmxScreen)
  380. {
  381. #if DMX_CURSOR_DEBUG > 1
  382. dmxLog(dmxDebug,
  383. "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n",
  384. dmxScreen->index, x, y,
  385. dmxScreen->rootWidth, dmxScreen->rootHeight,
  386. dmxScreen->rootX, dmxScreen->rootY,
  387. dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
  388. dmxScreen->scrnWidth, dmxScreen->scrnHeight,
  389. dmxScreen->scrnX, dmxScreen->scrnY);
  390. #endif
  391. if (x >= dmxScreen->rootXOrigin
  392. && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth
  393. && y >= dmxScreen->rootYOrigin
  394. && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight)
  395. return 1;
  396. return 0;
  397. }
  398. /** Returns non-zero if \a a overlaps \a b. */
  399. static int
  400. dmxDoesOverlap(DMXScreenInfo * a, DMXScreenInfo * b)
  401. {
  402. if (dmxOnScreen(a->rootXOrigin, a->rootYOrigin, b))
  403. return 1;
  404. if (dmxOnScreen(a->rootXOrigin, a->rootYOrigin + a->scrnWidth, b))
  405. return 1;
  406. if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, a->rootYOrigin, b))
  407. return 1;
  408. if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
  409. a->rootYOrigin + a->scrnWidth, b))
  410. return 1;
  411. if (dmxOnScreen(b->rootXOrigin, b->rootYOrigin, a))
  412. return 1;
  413. if (dmxOnScreen(b->rootXOrigin, b->rootYOrigin + b->scrnWidth, a))
  414. return 1;
  415. if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, b->rootYOrigin, a))
  416. return 1;
  417. if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
  418. b->rootYOrigin + b->scrnWidth, a))
  419. return 1;
  420. return 0;
  421. }
  422. /** Used with \a dmxInterateOverlap to print out a list of screens which
  423. * overlap each other. */
  424. static void *
  425. dmxPrintOverlap(DMXScreenInfo * dmxScreen, void *closure)
  426. {
  427. DMXScreenInfo *a = closure;
  428. if (dmxScreen != a) {
  429. if (dmxScreen->cursorNotShared)
  430. dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name);
  431. else
  432. dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name);
  433. }
  434. return NULL;
  435. }
  436. /** Iterate over the screens which overlap with the \a start screen,
  437. * calling \a f with the \a closure for each argument. Often used with
  438. * #dmxPrintOverlap. */
  439. static void *
  440. dmxIterateOverlap(DMXScreenInfo * start,
  441. void *(*f) (DMXScreenInfo * dmxScreen, void *), void *closure)
  442. {
  443. DMXScreenInfo *pt;
  444. if (!start->over)
  445. return f(start, closure);
  446. for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
  447. void *retval;
  448. if ((retval = f(pt, closure)))
  449. return retval;
  450. if (pt == start)
  451. break;
  452. }
  453. return NULL;
  454. }
  455. /** Used with #dmxPropertyIterate to determine if screen \a a is the
  456. * same as the screen \a closure. */
  457. static void *
  458. dmxTestSameDisplay(DMXScreenInfo * a, void *closure)
  459. {
  460. DMXScreenInfo *b = closure;
  461. if (a == b)
  462. return a;
  463. return NULL;
  464. }
  465. /** Detects overlapping dmxScreens and creates circular lists. This
  466. * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and
  467. * the computation only needs to be performed for every server
  468. * generation or dynamic reconfiguration . */
  469. void
  470. dmxInitOverlap(void)
  471. {
  472. int i, j;
  473. DMXScreenInfo *a, *b, *pt;
  474. for (i = 0; i < dmxNumScreens; i++)
  475. dmxScreens[i].over = NULL;
  476. for (i = 0; i < dmxNumScreens; i++) {
  477. a = &dmxScreens[i];
  478. for (j = i + 1; j < dmxNumScreens; j++) {
  479. b = &dmxScreens[j];
  480. if (b->over)
  481. continue;
  482. if (dmxDoesOverlap(a, b)) {
  483. DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n",
  484. a->index, b->index, a, a->over, b, b->over);
  485. b->over = (a->over ? a->over : a);
  486. a->over = b;
  487. }
  488. }
  489. }
  490. for (i = 0; i < dmxNumScreens; i++) {
  491. a = &dmxScreens[i];
  492. if (!a->over)
  493. continue;
  494. /* Flag all pairs that are on same display */
  495. for (pt = a->over; pt != a; pt = pt->over) {
  496. if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) {
  497. /* The ->over sets contain the transitive set of screens
  498. * that overlap. For screens that are on the same
  499. * backend display, we only want to exclude pairs of
  500. * screens that mutually overlap on the backend display,
  501. * so we call dmxDoesOverlap, which is stricter than the
  502. * ->over set. */
  503. if (!dmxDoesOverlap(a, pt))
  504. continue;
  505. a->cursorNotShared = 1;
  506. pt->cursorNotShared = 1;
  507. dmxLog(dmxInfo,
  508. "Screen %d and %d overlap on %s\n",
  509. a->index, pt->index, a->name);
  510. }
  511. }
  512. }
  513. for (i = 0; i < dmxNumScreens; i++) {
  514. a = &dmxScreens[i];
  515. if (a->over) {
  516. dmxLogOutput(a, "Overlaps");
  517. dmxIterateOverlap(a, dmxPrintOverlap, a);
  518. dmxLogOutputCont(a, "\n");
  519. }
  520. }
  521. }
  522. /** Create \a pCursor on the back-end associated with \a pScreen. */
  523. void
  524. dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor)
  525. {
  526. DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
  527. dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
  528. CursorBitsPtr pBits = pCursor->bits;
  529. Pixmap src, msk;
  530. XColor fg, bg;
  531. XImage *img;
  532. XlibGC gc = NULL;
  533. XGCValues v;
  534. unsigned long m;
  535. int i;
  536. if (!pCursorPriv)
  537. return;
  538. m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask;
  539. v.function = GXcopy;
  540. v.plane_mask = AllPlanes;
  541. v.foreground = 1L;
  542. v.background = 0L;
  543. v.clip_mask = None;
  544. for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
  545. if (dmxScreen->bePixmapFormats[i].depth == 1) {
  546. /* Create GC in the back-end servers */
  547. gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i],
  548. m, &v);
  549. break;
  550. }
  551. }
  552. if (!gc)
  553. dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n");
  554. src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
  555. pBits->width, pBits->height, 1);
  556. msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
  557. pBits->width, pBits->height, 1);
  558. img = XCreateImage(dmxScreen->beDisplay,
  559. dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
  560. 1, XYBitmap, 0, (char *) pBits->source,
  561. pBits->width, pBits->height,
  562. BitmapPad(dmxScreen->beDisplay), 0);
  563. XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0,
  564. pBits->width, pBits->height);
  565. XFree(img);
  566. img = XCreateImage(dmxScreen->beDisplay,
  567. dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
  568. 1, XYBitmap, 0, (char *) pBits->mask,
  569. pBits->width, pBits->height,
  570. BitmapPad(dmxScreen->beDisplay), 0);
  571. XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0,
  572. pBits->width, pBits->height);
  573. XFree(img);
  574. fg.red = pCursor->foreRed;
  575. fg.green = pCursor->foreGreen;
  576. fg.blue = pCursor->foreBlue;
  577. bg.red = pCursor->backRed;
  578. bg.green = pCursor->backGreen;
  579. bg.blue = pCursor->backBlue;
  580. pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay,
  581. src, msk,
  582. &fg, &bg,
  583. pBits->xhot, pBits->yhot);
  584. XFreePixmap(dmxScreen->beDisplay, src);
  585. XFreePixmap(dmxScreen->beDisplay, msk);
  586. XFreeGC(dmxScreen->beDisplay, gc);
  587. dmxSync(dmxScreen, FALSE);
  588. }
  589. static Bool
  590. _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
  591. {
  592. DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
  593. dmxCursorPrivPtr pCursorPriv;
  594. DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
  595. DMX_SET_CURSOR_PRIV(pCursor, pScreen, malloc(sizeof(*pCursorPriv)));
  596. if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen))
  597. return FALSE;
  598. pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
  599. pCursorPriv->cursor = (Cursor) 0;
  600. if (!dmxScreen->beDisplay)
  601. return TRUE;
  602. dmxBECreateCursor(pScreen, pCursor);
  603. return TRUE;
  604. }
  605. /** Free \a pCursor on the back-end associated with \a pScreen. */
  606. Bool
  607. dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor)
  608. {
  609. DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
  610. dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
  611. if (pCursorPriv) {
  612. XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor);
  613. pCursorPriv->cursor = (Cursor) 0;
  614. return TRUE;
  615. }
  616. return FALSE;
  617. }
  618. static Bool
  619. _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
  620. {
  621. DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
  622. DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
  623. if (dmxScreen->beDisplay) {
  624. if (dmxBEFreeCursor(pScreen, pCursor))
  625. free(DMX_GET_CURSOR_PRIV(pCursor, pScreen));
  626. }
  627. DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL);
  628. return TRUE;
  629. }
  630. static void
  631. _dmxMoveCursor(ScreenPtr pScreen, int x, int y)
  632. {
  633. DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
  634. int newX = x + dmxScreen->rootX;
  635. int newY = y + dmxScreen->rootY;
  636. if (newX < 0)
  637. newX = 0;
  638. if (newY < 0)
  639. newY = 0;
  640. DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n",
  641. pScreen->myNum, x, y, newX, newY);
  642. if (dmxScreen->beDisplay) {
  643. XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin,
  644. 0, 0, 0, 0, newX, newY);
  645. dmxSync(dmxScreen, TRUE);
  646. }
  647. }
  648. static void
  649. _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
  650. {
  651. DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
  652. DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y);
  653. if (pCursor) {
  654. dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
  655. if (pCursorPriv && dmxScreen->curCursor != pCursorPriv->cursor) {
  656. if (dmxScreen->beDisplay)
  657. XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
  658. pCursorPriv->cursor);
  659. dmxScreen->cursor = pCursor;
  660. dmxScreen->curCursor = pCursorPriv->cursor;
  661. dmxScreen->cursorVisible = 1;
  662. }
  663. _dmxMoveCursor(pScreen, x, y);
  664. }
  665. else {
  666. if (dmxScreen->beDisplay)
  667. XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
  668. dmxScreen->noCursor);
  669. dmxScreen->cursor = NULL;
  670. dmxScreen->curCursor = (Cursor) 0;
  671. dmxScreen->cursorVisible = 0;
  672. }
  673. if (dmxScreen->beDisplay)
  674. dmxSync(dmxScreen, TRUE);
  675. }
  676. static Bool
  677. dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
  678. {
  679. DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
  680. DMXScreenInfo *pt;
  681. if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
  682. return _dmxRealizeCursor(pScreen, pCursor);
  683. for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
  684. if (pt->cursorNotShared)
  685. continue;
  686. _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor);
  687. if (pt == start)
  688. break;
  689. }
  690. return TRUE;
  691. }
  692. static Bool
  693. dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
  694. {
  695. DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
  696. DMXScreenInfo *pt;
  697. if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
  698. return _dmxUnrealizeCursor(pScreen, pCursor);
  699. for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
  700. if (pt->cursorNotShared)
  701. continue;
  702. _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor);
  703. if (pt == start)
  704. break;
  705. }
  706. return TRUE;
  707. }
  708. static CursorPtr
  709. dmxFindCursor(DMXScreenInfo * start)
  710. {
  711. DMXScreenInfo *pt;
  712. if (!start || !start->over)
  713. return GetSpriteCursor(inputInfo.pointer);
  714. for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
  715. if (pt->cursor)
  716. return pt->cursor;
  717. if (pt == start)
  718. break;
  719. }
  720. return GetSpriteCursor(inputInfo.pointer);
  721. }
  722. /** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This
  723. * function is usually called via #dmxPointerSpriteFuncs, except during
  724. * reconfiguration when the cursor is repositioned to force an update on
  725. * newley overlapping screens and on screens that no longer overlap.
  726. *
  727. * The coords (x,y) are in global coord space. We'll loop over the
  728. * back-end screens and see if they contain the global coord. If so, call
  729. * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen.
  730. */
  731. void
  732. dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
  733. {
  734. DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
  735. DMXScreenInfo *pt;
  736. DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
  737. if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
  738. _dmxMoveCursor(pScreen, x, y);
  739. return;
  740. }
  741. for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
  742. if (pt->cursorNotShared)
  743. continue;
  744. if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
  745. if ( /* pt != start && */ !pt->cursorVisible) {
  746. if (!pt->cursor) {
  747. /* This only happens during
  748. * reconfiguration when a new overlap
  749. * occurs. */
  750. CursorPtr pCursor;
  751. if ((pCursor = dmxFindCursor(start)))
  752. _dmxRealizeCursor(screenInfo.screens[pt->index],
  753. pt->cursor = pCursor);
  754. }
  755. _dmxSetCursor(screenInfo.screens[pt->index],
  756. pt->cursor,
  757. x + start->rootXOrigin - pt->rootXOrigin,
  758. y + start->rootYOrigin - pt->rootYOrigin);
  759. }
  760. _dmxMoveCursor(screenInfo.screens[pt->index],
  761. x + start->rootXOrigin - pt->rootXOrigin,
  762. y + start->rootYOrigin - pt->rootYOrigin);
  763. }
  764. else if ( /* pt != start && */ pt->cursorVisible) {
  765. _dmxSetCursor(screenInfo.screens[pt->index],
  766. NULL,
  767. x + start->rootXOrigin - pt->rootXOrigin,
  768. y + start->rootYOrigin - pt->rootYOrigin);
  769. }
  770. if (pt == start)
  771. break;
  772. }
  773. }
  774. static void
  775. dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x,
  776. int y)
  777. {
  778. DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
  779. DMXScreenInfo *pt;
  780. int GX, GY, gx, gy;
  781. DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n",
  782. pScreen->myNum, start, pCursor, x, y);
  783. /* We do this check here because of two cases:
  784. *
  785. * 1) if a client calls XWarpPointer()
  786. * and Xinerama is not running, we can
  787. * have mi's notion of the pointer
  788. * position out of phase with DMX's
  789. * notion.
  790. *
  791. * 2) if a down button is held while the
  792. * cursor moves outside the root window,
  793. * mi's notion of the pointer position
  794. * is out of phase with DMX's notion and
  795. * the cursor can remain visible when it
  796. * shouldn't be. */
  797. dmxGetGlobalPosition(&GX, &GY);
  798. gx = start->rootXOrigin + x;
  799. gy = start->rootYOrigin + y;
  800. if (x && y && (GX != gx || GY != gy))
  801. dmxCoreMotion(NULL, gx, gy, 0, DMX_NO_BLOCK);
  802. if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
  803. _dmxSetCursor(pScreen, pCursor, x, y);
  804. return;
  805. }
  806. for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
  807. if (pt->cursorNotShared)
  808. continue;
  809. if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
  810. _dmxSetCursor(screenInfo.screens[pt->index], pCursor,
  811. x + start->rootXOrigin - pt->rootXOrigin,
  812. y + start->rootYOrigin - pt->rootYOrigin);
  813. }
  814. else {
  815. _dmxSetCursor(screenInfo.screens[pt->index], NULL,
  816. x + start->rootXOrigin - pt->rootXOrigin,
  817. y + start->rootYOrigin - pt->rootYOrigin);
  818. }
  819. if (pt == start)
  820. break;
  821. }
  822. }
  823. /** This routine is used by the backend input routines to hide the
  824. * cursor on a screen that is being used for relative input. \see
  825. * dmxbackend.c */
  826. void
  827. dmxHideCursor(DMXScreenInfo * dmxScreen)
  828. {
  829. int x, y;
  830. ScreenPtr pScreen = screenInfo.screens[dmxScreen->index];
  831. dmxGetGlobalPosition(&x, &y);
  832. _dmxSetCursor(pScreen, NULL, x, y);
  833. }
  834. /** This routine is called during reconfiguration to make sure the
  835. * cursor is visible. */
  836. void
  837. dmxCheckCursor(void)
  838. {
  839. int i;
  840. int x, y;
  841. ScreenPtr pScreen;
  842. DMXScreenInfo *firstScreen;
  843. dmxGetGlobalPosition(&x, &y);
  844. firstScreen = dmxFindFirstScreen(x, y);
  845. DMXDBG2("dmxCheckCursor %d %d\n", x, y);
  846. for (i = 0; i < dmxNumScreens; i++) {
  847. DMXScreenInfo *dmxScreen = &dmxScreens[i];
  848. pScreen = screenInfo.screens[dmxScreen->index];
  849. if (!dmxOnScreen(x, y, dmxScreen)) {
  850. if (firstScreen &&
  851. i == miPointerGetScreen(inputInfo.pointer)->myNum)
  852. miPointerSetScreen(inputInfo.pointer, firstScreen->index, x,
  853. y);
  854. _dmxSetCursor(pScreen, NULL, x - dmxScreen->rootXOrigin,
  855. y - dmxScreen->rootYOrigin);
  856. }
  857. else {
  858. if (!dmxScreen->cursor) {
  859. CursorPtr pCursor;
  860. if ((pCursor = dmxFindCursor(dmxScreen))) {
  861. _dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor);
  862. }
  863. }
  864. _dmxSetCursor(pScreen, dmxScreen->cursor,
  865. x - dmxScreen->rootXOrigin,
  866. y - dmxScreen->rootYOrigin);
  867. }
  868. }
  869. DMXDBG2(" leave dmxCheckCursor %d %d\n", x, y);
  870. }
  871. static Bool
  872. dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr)
  873. {
  874. return TRUE;
  875. }
  876. static void
  877. dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr)
  878. {
  879. }
  880. miPointerSpriteFuncRec dmxPointerSpriteFuncs = {
  881. dmxRealizeCursor,
  882. dmxUnrealizeCursor,
  883. dmxSetCursor,
  884. dmxMoveCursor,
  885. dmxDeviceCursorInitialize,
  886. dmxDeviceCursorCleanup
  887. };