WmColormap.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*
  24. * (c) Copyright 1989, 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC.
  25. * ALL RIGHTS RESERVED
  26. */
  27. /*
  28. * Motif Release 1.2.3
  29. */
  30. /*
  31. * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
  32. /*
  33. * Included Files:
  34. */
  35. #include "WmGlobal.h"
  36. /*
  37. * include extern functions
  38. */
  39. #include "WmColormap.h"
  40. #include "WmKeyFocus.h"
  41. static Bool ProcessEvents(Display *dpy, XEvent *Event, char *c_pCD);
  42. /* Global variables */
  43. static unsigned long firstRequest, lastRequest;
  44. /*************************************<->*************************************
  45. *
  46. * InitWorkspaceColormap ()
  47. *
  48. *
  49. * Description:
  50. * -----------
  51. * This function sets up the default workspace colormap and prepares for
  52. * workspace colormap processing.
  53. *
  54. *
  55. * Inputs:
  56. * -------
  57. * pSD = ptr to screen data
  58. *
  59. * Outputs:
  60. * -------
  61. * wmGD = (workspaceColormap)
  62. *
  63. *************************************<->***********************************/
  64. void InitWorkspaceColormap (WmScreenData *pSD)
  65. {
  66. /*
  67. * Setup the default (workspace) colormap:
  68. * !!! this should be made more general to get the colormap for the !!!
  69. * !!! workspace (root) and then track colormap changes !!!
  70. */
  71. pSD->workspaceColormap = DefaultColormap (DISPLAY, pSD->screen);
  72. } /* END OF FUNCTION InitWorkspaceColormap */
  73. /*************************************<->*************************************
  74. *
  75. * InitColormapFocus (pSD)
  76. *
  77. *
  78. * Description:
  79. * -----------
  80. * This function prepares for managing the colormap focus and sets the
  81. * initial colormap focus (if the focus policy is "keyboard" - i.e. the
  82. * colormap focus tracks the keyboard focus) the initial colormap
  83. * installation is done in InitKeyboardFocus.
  84. *
  85. * Inputs:
  86. * -------
  87. * pSD = pointer to screen data
  88. *
  89. * Outputs:
  90. * -------
  91. * *pSD = (colormapFocus)
  92. *
  93. *************************************<->***********************************/
  94. void InitColormapFocus (WmScreenData *pSD)
  95. {
  96. ClientData *pCD;
  97. Boolean sameScreen;
  98. /*
  99. * Set up the initial colormap focus. If the colormapFocusPolicy is
  100. * "keyboard" or it is "pointer" and the keyboard input focus policy
  101. * is "pointer" then set up the initial colormap focus when the
  102. * initial keyboard input focus is set up.
  103. */
  104. pSD->colormapFocus = NULL;
  105. if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
  106. {
  107. if (wmGD.keyboardFocusPolicy != KEYBOARD_FOCUS_POINTER)
  108. {
  109. if ((pCD = GetClientUnderPointer (&sameScreen)) != NULL)
  110. {
  111. SetColormapFocus (pSD, pCD);
  112. }
  113. else
  114. {
  115. WmInstallColormap (pSD, pSD->workspaceColormap);
  116. }
  117. }
  118. }
  119. else
  120. {
  121. WmInstallColormap (pSD, pSD->workspaceColormap);
  122. }
  123. } /* END OF FUNCTION InitColormapFocus */
  124. /*************************************<->*************************************
  125. *
  126. * ForceColormapFocus (pSD, pCD)
  127. *
  128. *
  129. * Description:
  130. * -----------
  131. * ForceColormapFocus is the working part of the original SetColormapFocus.
  132. * This function is used to unconditionally set the colormap focus to a
  133. * particular client window or to clear the colormap focus (set focus to
  134. * the root window).
  135. *
  136. * The reason is to permit focus to be dtrced. We need to do this because
  137. * we can already have colormap focus, but still need to set the colormaps.
  138. * Examples of when this occurs are:
  139. *
  140. * * after the window manager itself has forced a colormap,
  141. * as happens when it draws transients in the overlay planes.
  142. * * when WM_COLORMAP_WINDOWS changes.
  143. * * when a ColormapNotify (new) event is received.
  144. *
  145. *
  146. * Inputs:
  147. * ------
  148. * pSD = pointer to Screen Data
  149. * pCD = pointer to client data (clientColormap ...)
  150. *
  151. *************************************<->***********************************/
  152. void ForceColormapFocus (WmScreenData *pSD, ClientData *pCD)
  153. {
  154. if (pCD && ((pCD->clientState == NORMAL_STATE) ||
  155. (pCD->clientState == MAXIMIZED_STATE)))
  156. {
  157. pSD->colormapFocus = pCD;
  158. ProcessColormapList (pSD, pCD);
  159. }
  160. else
  161. {
  162. /*
  163. * The default colormap is installed for minimized windows that have
  164. * the colormap focus.
  165. * !!! should colormaps be installed for icons with client !!!
  166. * !!! icon windows? should the client colormap be installed ? !!!
  167. */
  168. pSD->colormapFocus = NULL;
  169. WmInstallColormap (pSD, pSD->workspaceColormap);
  170. }
  171. } /* END OF FUNCTION ForceColormapFocus */
  172. /*************************************<->*************************************
  173. *
  174. * SetColormapFocus (pSD, pCD)
  175. *
  176. *
  177. * Description:
  178. * -----------
  179. * This function is used to set the colormap focus to a particular client
  180. * window or to clear the colormap focus (set focus to the root window).
  181. *
  182. *
  183. * Inputs:
  184. * ------
  185. * pSD = pointer to Screen Data
  186. * pCD = pointer to client data (clientColormap ...)
  187. *
  188. *************************************<->***********************************/
  189. void SetColormapFocus (WmScreenData *pSD, ClientData *pCD)
  190. {
  191. if (pCD == pSD->colormapFocus)
  192. {
  193. /*
  194. * The focus is already set to the right place.
  195. */
  196. return;
  197. }
  198. ForceColormapFocus (pSD, pCD);
  199. } /* END OF FUNCTION SetColormapFocus */
  200. /*************************************<->*************************************
  201. *
  202. * WmInstallColormap (pSD, colormap)
  203. *
  204. *
  205. * Description:
  206. * -----------
  207. * This function installs colormaps for the window manager. It trys to be
  208. * intelligent and avoid unnecessary installations. It assumes that no
  209. * other program is installing colormaps.
  210. *
  211. *
  212. * Inputs:
  213. * ------
  214. * pSD = ptr to screen data
  215. * colormap = the id for the colormap to be installed
  216. *
  217. *************************************<->***********************************/
  218. void WmInstallColormap (WmScreenData *pSD, Colormap colormap)
  219. {
  220. /*
  221. * !!! this could be generalized to work better for systems that !!!
  222. * !!! support multiple installed colormaps !!!
  223. */
  224. if (colormap != pSD->lastInstalledColormap)
  225. {
  226. XInstallColormap (DISPLAY, colormap);
  227. pSD->lastInstalledColormap = colormap;
  228. }
  229. } /* END OF FUNCTION WmInstallColormap */
  230. /*************************************<->*************************************
  231. *
  232. * ResetColormapData (pCD, pWindows, count)
  233. *
  234. *
  235. * Description:
  236. * -----------
  237. * This function is used to release old colormap data (contexts, malloc'ed
  238. * space).
  239. *
  240. *
  241. * Inputs:
  242. * ------
  243. * pCD = pointer to client data (cmapWindows ...)
  244. *
  245. * pWindows = new list of colormap windows
  246. *
  247. * count = number of windows in new colormap windows list
  248. *
  249. *************************************<->***********************************/
  250. void ResetColormapData (ClientData *pCD, Window *pWindows, int count)
  251. {
  252. int i;
  253. if (pCD->clientCmapCount)
  254. {
  255. if (count == 0)
  256. {
  257. /* reset the client colormap to the toplevel window colormap */
  258. for (i = 0; i < pCD->clientCmapCount; i++)
  259. {
  260. if (pCD->cmapWindows[i] == pCD->client)
  261. {
  262. pCD->clientColormap = pCD->clientCmapList[i];
  263. break;
  264. }
  265. }
  266. }
  267. /*
  268. * Free up old contexts.
  269. */
  270. for (i = 0; i < pCD->clientCmapCount; i++)
  271. {
  272. if (pCD->cmapWindows[i] != pCD->client)
  273. {
  274. #ifndef IBM_169380
  275. RemoveColormapWindowReference(pCD, pCD->cmapWindows[i]);
  276. #else
  277. XDeleteContext (DISPLAY, pCD->cmapWindows[i],
  278. wmGD.windowContextType);
  279. #endif
  280. }
  281. }
  282. /*
  283. * Free up old colormap data.
  284. */
  285. XtFree ((char *)(pCD->cmapWindows));
  286. XtFree ((char *)(pCD->clientCmapList));
  287. pCD->clientCmapCount = 0;
  288. XtFree ((char *)(pCD->clientCmapFlags));
  289. pCD->clientCmapFlags = 0; /* DEBUG: */
  290. pCD->clientCmapFlagsInitialized = 0;
  291. }
  292. if (count)
  293. {
  294. /*
  295. * Set new contexts.
  296. */
  297. for (i = 0; i < count; i++)
  298. {
  299. if (pWindows[i] != pCD->client)
  300. {
  301. #ifndef IBM_169380
  302. AddColormapWindowReference(pCD, pWindows[i]);
  303. #else
  304. XSaveContext (DISPLAY, pWindows[i], wmGD.windowContextType,
  305. (caddr_t)pCD);
  306. #endif
  307. }
  308. }
  309. }
  310. } /* END OF FUNCTION ResetColormapData */
  311. #ifndef IBM_169380
  312. /*************************************<->*************************************
  313. *
  314. * AddColormapWindowReference (pCD, window)
  315. *
  316. * Description:
  317. * -----------
  318. * This function is used to update (or create, if necessary) the structure
  319. * that keeps track of all references to a Window from a toplevel window
  320. * WM_COLORMAP_DATA property.
  321. *
  322. *************************************<->***********************************/
  323. void AddColormapWindowReference (ClientData *pCD, Window window)
  324. {
  325. ClientData **cmap_window_data;
  326. Boolean context_exists;
  327. int i;
  328. ClientData **new_cmap_window_data;
  329. context_exists = (!XFindContext (DISPLAY, window,
  330. wmGD.cmapWindowContextType,
  331. (XPointer *) &cmap_window_data));
  332. if (context_exists)
  333. {
  334. for (i = 0; cmap_window_data[i] != NULL; i++)
  335. {
  336. if (cmap_window_data[i] == pCD)
  337. {
  338. /* Reference already exists - return */
  339. return;
  340. }
  341. }
  342. new_cmap_window_data = (ClientData **)
  343. XtMalloc((i + 2 ) * sizeof(ClientData *));
  344. memcpy((void *)new_cmap_window_data,(void *)cmap_window_data,
  345. (i + 1) * sizeof(ClientData *));
  346. XtFree((char *) cmap_window_data);
  347. XDeleteContext(DISPLAY, window, wmGD.cmapWindowContextType);
  348. }
  349. else
  350. {
  351. i = 0;
  352. new_cmap_window_data = (ClientData **)
  353. XtMalloc(2 * sizeof(ClientData *));
  354. }
  355. new_cmap_window_data[i] = pCD;
  356. new_cmap_window_data[i + 1] = NULL;
  357. XSaveContext (DISPLAY, window, wmGD.cmapWindowContextType,
  358. (caddr_t)new_cmap_window_data);
  359. }
  360. /*************************************<->*************************************
  361. *
  362. * RemoveColormapWindowReference (pCD, window)
  363. *
  364. * Description:
  365. * -----------
  366. * This function is used to update (or delete, if necessary) the structure
  367. * that keeps track of all references to a Window from a toplevel window
  368. * WM_COLORMAP_DATA property.
  369. *
  370. *************************************<->***********************************/
  371. void RemoveColormapWindowReference (ClientData *pCD, Window window)
  372. {
  373. ClientData **cmap_window_data;
  374. Boolean context_exists;
  375. int i;
  376. int reference_idx = -1;
  377. ClientData **new_cmap_window_data;
  378. context_exists = (!XFindContext (DISPLAY, window,
  379. wmGD.cmapWindowContextType,
  380. (XPointer *) &cmap_window_data));
  381. if (context_exists)
  382. {
  383. for (i = 0; cmap_window_data[i] != NULL; i++)
  384. {
  385. if (cmap_window_data[i] == pCD)
  386. reference_idx = i;
  387. }
  388. if (reference_idx < 0)
  389. return;
  390. if (i > 1)
  391. {
  392. int j,idx;
  393. new_cmap_window_data = (ClientData **)
  394. XtMalloc(i * sizeof(ClientData *));
  395. idx = 0;
  396. for (j = 0; cmap_window_data[j] != NULL; j++)
  397. {
  398. if (j != reference_idx)
  399. {
  400. new_cmap_window_data[idx] = cmap_window_data[j];
  401. idx++;
  402. }
  403. }
  404. new_cmap_window_data[idx] = NULL;
  405. }
  406. XtFree((char *) cmap_window_data);
  407. XDeleteContext(DISPLAY, window, wmGD.cmapWindowContextType);
  408. if (i > 1)
  409. {
  410. XSaveContext (DISPLAY, window,
  411. wmGD.cmapWindowContextType,
  412. (caddr_t)new_cmap_window_data);
  413. }
  414. }
  415. }
  416. #endif /* IBM_169380 */
  417. /*******************************************************************************
  418. **
  419. ** The rest of this module contains the SGI-added colormap handling.
  420. **
  421. ** mwm 1.1.3 didn't even try to deal with multiple colormaps, except to rotate
  422. ** them. We need to see that all of the colormaps from WM_COLORMAP_WINDOWS
  423. ** are installed when a window gets colormap focus.
  424. **
  425. ** The general idea is to keep track of which colormaps bounce which other
  426. ** ones, so we only flash the first time (usually not even then).
  427. **
  428. ** The conflict record of a window is cleared whenever:
  429. ** * WM_COLORMAP_WINDOWS property changes
  430. ** * ColormapNotify for a new colormap happens
  431. ** * windows are rotated (prev_cmap, next_cmap)
  432. ** This is because with a changed colormap list, we need to recalculate
  433. ** which ones get bounced out during a full colormap installation.
  434. **
  435. ** We don't just lift the twm code because, after carefully looking over
  436. ** the twm code, it appears to have some problems of its own. In
  437. ** particular, it assumes that if a given colormap displaces another one
  438. ** once, it will always do so. This isn't necessarily so for a multiple
  439. ** hardware colormaps machine.
  440. **
  441. ** We still need to add code to keep track of which color maps are really
  442. ** installed at any one time. The current code is ready for this, but it has
  443. ** not yet been done. Then we could do two things:
  444. **
  445. ** * refrain from installing a colormap if it is already installed
  446. **
  447. ** * have a way to restore all installed colormaps after the window
  448. ** manager overwrites with it's own.
  449. **
  450. ******************************************************************************/
  451. void
  452. ProcessColormapList (WmScreenData *pSD, ClientData *pCD)
  453. {
  454. int i;
  455. XEvent event;
  456. /*
  457. * If there is no client, return. This can happen when the root gets focus.
  458. */
  459. if (!pCD) return;
  460. /*
  461. * If the window does not have colormap focus, return. We only install
  462. * colormaps for windows with focus. We'll get another chance when the
  463. * window does get focus.
  464. */
  465. if (pCD != pSD->colormapFocus) return;
  466. /*
  467. * If window is iconified, return.
  468. */
  469. if ( (pCD->clientState != NORMAL_STATE)
  470. && (pCD->clientState != MAXIMIZED_STATE)
  471. ) return;
  472. /*
  473. * If the list doesn't exist, or has just a single item, no conflicts
  474. * exist -- just go ahead and install the indicated colormap.
  475. */
  476. if (pCD->clientCmapCount == 0) {
  477. WmInstallColormap (pSD, pCD->clientColormap);
  478. return;
  479. }
  480. if (pCD->clientCmapCount == 1) {
  481. WmInstallColormap (pSD, pCD->clientCmapList[0]);
  482. return;
  483. }
  484. /*
  485. * If the list has already been initialized, we just need to do installs.
  486. * Separate out these loops for performance, and because it isn't nice
  487. * to grab the server unnecessarily.
  488. *
  489. * This code should also check for already-installed, once we put in that
  490. * capability.
  491. */
  492. if (pCD->clientCmapFlagsInitialized) {
  493. /* Do the part between the index and zero */
  494. for (i=pCD->clientCmapIndex; --i>=0; ) {
  495. if (pCD->clientCmapFlags[i] == ColormapInstalled) {
  496. WmInstallColormap (pSD, pCD->clientCmapList[i]);
  497. }
  498. };
  499. /* Do the part from the end of the list to the index */
  500. for (i=pCD->clientCmapCount; --i>= pCD->clientCmapIndex; ) {
  501. if (pCD->clientCmapFlags[i] == ColormapInstalled) {
  502. WmInstallColormap (pSD, pCD->clientCmapList[i]);
  503. }
  504. }
  505. /**/
  506. return;
  507. }
  508. /*
  509. * If we get this far, the list has not yet been initialized.
  510. *
  511. * Stabilize the input queue -- the issue is that we need to know
  512. * which colormap notify install and uninstall events are ours.
  513. */
  514. XGrabServer (DISPLAY); /* Ensure no one else's events for awhile */
  515. XSync (DISPLAY, FALSE); /* Let pending events settle */
  516. firstRequest = NextRequest (DISPLAY); /* First one that can be ours */
  517. /*
  518. * Install the colormaps from last to first -- first is the "highest
  519. * priority". "First" is pCD->clientCmapIndex.
  520. *
  521. * If the list has not been proocessed before, we need to unconditionally
  522. * install each colormap. Colormap flashing is possible this once.
  523. *
  524. * If the list has already been processed once, all conflict checking
  525. * was done then. All we need to do this time is to install the colormaps
  526. * we know we need.
  527. */
  528. /* Do the part between the index and zero */
  529. for (i=pCD->clientCmapIndex; --i>=0; ) {
  530. WmInstallColormap (pSD, pCD->clientCmapList[i]);
  531. pCD->clientCmapFlags[i] = ColormapInstalled;
  532. };
  533. /* Do the part from the end of the list to the index */
  534. for (i=pCD->clientCmapCount; --i>= pCD->clientCmapIndex; ) {
  535. WmInstallColormap (pSD, pCD->clientCmapList[i]);
  536. pCD->clientCmapFlags[i] = ColormapInstalled;
  537. }
  538. /*
  539. * Stabilize the input queue again -- the issue is that we need to know
  540. * which colormap notify install and uninstall events we caused.
  541. */
  542. XSync (DISPLAY, FALSE); /* Let pending events settle */
  543. lastRequest = NextRequest (DISPLAY); /* Last one that can be ours */
  544. XUngrabServer (DISPLAY); /* Let others use it again */
  545. /* Process the install & uninstall events */
  546. XCheckIfEvent (DISPLAY, (XEvent *) &event, ProcessEvents, (char *)pCD);
  547. /* Set that the list has been processed once */
  548. pCD->clientCmapFlagsInitialized = True;
  549. }
  550. /*
  551. * Look over the queue for install and uninstall events on colormap/window
  552. * combinations we care about. We don't actually disturb the queue, so
  553. * events can be delivered in undisturbed order to the normal event handling
  554. * routines.
  555. *
  556. * For each appropriate install/uninstall ColormapNotify event that is queued:
  557. * *) if uninstall event
  558. * *) Set the conflict flag for this colormap window
  559. * else if install event
  560. * *) Clear the conflict flag for this colormap window
  561. */
  562. static Bool
  563. ProcessEvents(Display *dpy, XEvent *Event, char *c_pCD)
  564. {
  565. int i;
  566. XColormapEvent *pEvent = (XColormapEvent *) Event;
  567. ClientData *pCD = (ClientData *) c_pCD;
  568. if ( (pEvent->type == ColormapNotify)
  569. && (pEvent->serial >= firstRequest)
  570. && (pEvent->serial < lastRequest)
  571. && (pEvent->colormap != None)
  572. && (!pEvent->new)
  573. ) {
  574. switch (pEvent->state) {
  575. case ColormapInstalled:
  576. for (i=0; i<pCD->clientCmapCount; i++) {
  577. if ( (pCD->clientCmapList[i]==pEvent->colormap)
  578. &&(pCD->cmapWindows[i]==pEvent->window)
  579. ) {
  580. pCD->clientCmapFlags[i]
  581. = ColormapInstalled;
  582. break;
  583. }
  584. }
  585. break;
  586. case ColormapUninstalled:
  587. for (i=0; i<pCD->clientCmapCount; i++) {
  588. if ( (pCD->clientCmapList[i]==pEvent->colormap)
  589. &&(pCD->cmapWindows[i]==pEvent->window)
  590. ) {
  591. pCD->clientCmapFlags[i]
  592. = ColormapUninstalled;
  593. break;
  594. }
  595. }
  596. break;
  597. default: /* Should never get here */
  598. break;
  599. }
  600. }
  601. /*
  602. * Always return false:
  603. * * so that we get to search the entire queue -- it isn't very long
  604. * * so all events remain on the queue to be handled normally elsewhere
  605. */
  606. return False; /* Always, so no events are lost from the queue */
  607. }