2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * (c) Copyright 1989, 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC.
32 static char rcsid[] = "$XConsortium: WmColormap.c /main/5 1996/10/30 11:14:44 drk $"
36 * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
45 * include extern functions
48 #include "WmColormap.h"
49 #include "WmKeyFocus.h"
51 static Bool ProcessEvents(Display *dpy, XEvent *Event, char *c_pCD);
54 /* Global variables */
55 static unsigned long firstRequest, lastRequest;
58 /*************************************<->*************************************
60 * InitWorkspaceColormap ()
65 * This function sets up the default workspace colormap and prepares for
66 * workspace colormap processing.
71 * pSD = ptr to screen data
75 * wmGD = (workspaceColormap)
77 *************************************<->***********************************/
79 void InitWorkspaceColormap (WmScreenData *pSD)
82 * Setup the default (workspace) colormap:
83 * !!! this should be made more general to get the colormap for the !!!
84 * !!! workspace (root) and then track colormap changes !!!
87 pSD->workspaceColormap = DefaultColormap (DISPLAY, pSD->screen);
89 } /* END OF FUNCTION InitWorkspaceColormap */
93 /*************************************<->*************************************
95 * InitColormapFocus (pSD)
100 * This function prepares for managing the colormap focus and sets the
101 * initial colormap focus (if the focus policy is "keyboard" - i.e. the
102 * colormap focus tracks the keyboard focus) the initial colormap
103 * installation is done in InitKeyboardFocus.
107 * pSD = pointer to screen data
111 * *pSD = (colormapFocus)
113 *************************************<->***********************************/
115 void InitColormapFocus (WmScreenData *pSD)
122 * Set up the initial colormap focus. If the colormapFocusPolicy is
123 * "keyboard" or it is "pointer" and the keyboard input focus policy
124 * is "pointer" then set up the initial colormap focus when the
125 * initial keyboard input focus is set up.
128 pSD->colormapFocus = NULL;
130 if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
132 if (wmGD.keyboardFocusPolicy != KEYBOARD_FOCUS_POINTER)
134 if ((pCD = GetClientUnderPointer (&sameScreen)) != NULL)
136 SetColormapFocus (pSD, pCD);
140 WmInstallColormap (pSD, pSD->workspaceColormap);
146 WmInstallColormap (pSD, pSD->workspaceColormap);
149 } /* END OF FUNCTION InitColormapFocus */
154 /*************************************<->*************************************
156 * ForceColormapFocus (pSD, pCD)
161 * ForceColormapFocus is the working part of the original SetColormapFocus.
162 * This function is used to unconditionally set the colormap focus to a
163 * particular client window or to clear the colormap focus (set focus to
166 * The reason is to permit focus to be dtrced. We need to do this because
167 * we can already have colormap focus, but still need to set the colormaps.
168 * Examples of when this occurs are:
170 * * after the window manager itself has forced a colormap,
171 * as happens when it draws transients in the overlay planes.
172 * * when WM_COLORMAP_WINDOWS changes.
173 * * when a ColormapNotify (new) event is received.
178 * pSD = pointer to Screen Data
179 * pCD = pointer to client data (clientColormap ...)
181 *************************************<->***********************************/
183 void ForceColormapFocus (WmScreenData *pSD, ClientData *pCD)
185 if (pCD && ((pCD->clientState == NORMAL_STATE) ||
186 (pCD->clientState == MAXIMIZED_STATE)))
188 pSD->colormapFocus = pCD;
189 #ifndef OLD_COLORMAP /* colormaps */
190 ProcessColormapList (pSD, pCD);
191 #else /* OSF original */
192 WmInstallColormap (pSD, pCD->clientColormap);
198 * The default colormap is installed for minimized windows that have
199 * the colormap focus.
200 * !!! should colormaps be installed for icons with client !!!
201 * !!! icon windows? should the client colormap be installed ? !!!
204 pSD->colormapFocus = NULL;
205 WmInstallColormap (pSD, pSD->workspaceColormap);
208 } /* END OF FUNCTION ForceColormapFocus */
213 /*************************************<->*************************************
215 * SetColormapFocus (pSD, pCD)
220 * This function is used to set the colormap focus to a particular client
221 * window or to clear the colormap focus (set focus to the root window).
226 * pSD = pointer to Screen Data
227 * pCD = pointer to client data (clientColormap ...)
229 *************************************<->***********************************/
231 void SetColormapFocus (WmScreenData *pSD, ClientData *pCD)
233 if (pCD == pSD->colormapFocus)
236 * The focus is already set to the right place.
242 ForceColormapFocus (pSD, pCD);
243 #else /* OSF original */
245 if (pCD && ((pCD->clientState == NORMAL_STATE) ||
246 (pCD->clientState == MAXIMIZED_STATE)))
248 pSD->colormapFocus = pCD;
249 #ifndef OLD_COLORMAP /* colormaps */
250 ProcessColormapList (pSD, pCD);
251 #else /* OSF original */
252 WmInstallColormap (pSD, pCD->clientColormap);
258 * The default colormap is installed for minimized windows that have
259 * the colormap focus.
260 * !!! should colormaps be installed for icons with client !!!
261 * !!! icon windows? should the client colormap be installed ? !!!
264 pSD->colormapFocus = NULL;
265 WmInstallColormap (pSD, pSD->workspaceColormap);
269 } /* END OF FUNCTION SetColormapFocus */
273 /*************************************<->*************************************
275 * WmInstallColormap (pSD, colormap)
280 * This function installs colormaps for the window manager. It trys to be
281 * intelligent and avoid unnecessary installations. It assumes that no
282 * other program is installing colormaps.
287 * pSD = ptr to screen data
288 * colormap = the id for the colormap to be installed
290 *************************************<->***********************************/
292 void WmInstallColormap (WmScreenData *pSD, Colormap colormap)
295 * !!! this could be generalized to work better for systems that !!!
296 * !!! support multiple installed colormaps !!!
299 if (colormap != pSD->lastInstalledColormap)
301 XInstallColormap (DISPLAY, colormap);
302 pSD->lastInstalledColormap = colormap;
305 } /* END OF FUNCTION WmInstallColormap */
309 /*************************************<->*************************************
311 * ResetColormapData (pCD, pWindows, count)
316 * This function is used to release old colormap data (contexts, malloc'ed
322 * pCD = pointer to client data (cmapWindows ...)
324 * pWindows = new list of colormap windows
326 * count = number of windows in new colormap windows list
328 *************************************<->***********************************/
330 void ResetColormapData (ClientData *pCD, Window *pWindows, int count)
335 if (pCD->clientCmapCount)
339 /* reset the client colormap to the toplevel window colormap */
340 for (i = 0; i < pCD->clientCmapCount; i++)
342 if (pCD->cmapWindows[i] == pCD->client)
344 pCD->clientColormap = pCD->clientCmapList[i];
351 * Free up old contexts.
354 for (i = 0; i < pCD->clientCmapCount; i++)
356 if (pCD->cmapWindows[i] != pCD->client)
359 RemoveColormapWindowReference(pCD, pCD->cmapWindows[i]);
361 XDeleteContext (DISPLAY, pCD->cmapWindows[i],
362 wmGD.windowContextType);
368 * Free up old colormap data.
371 XtFree ((char *)(pCD->cmapWindows));
372 XtFree ((char *)(pCD->clientCmapList));
373 pCD->clientCmapCount = 0;
374 #ifndef OLD_COLORMAP /* colormap */
375 XtFree ((char *)(pCD->clientCmapFlags));
376 pCD->clientCmapFlags = 0; /* DEBUG: */
377 pCD->clientCmapFlagsInitialized = 0;
387 for (i = 0; i < count; i++)
389 if (pWindows[i] != pCD->client)
392 AddColormapWindowReference(pCD, pWindows[i]);
394 XSaveContext (DISPLAY, pWindows[i], wmGD.windowContextType,
401 } /* END OF FUNCTION ResetColormapData */
404 /*************************************<->*************************************
406 * AddColormapWindowReference (pCD, window)
410 * This function is used to update (or create, if necessary) the structure
411 * that keeps track of all references to a Window from a toplevel window
412 * WM_COLORMAP_DATA property.
414 *************************************<->***********************************/
416 void AddColormapWindowReference (ClientData *pCD, Window window)
418 ClientData **cmap_window_data;
419 Boolean context_exists;
421 ClientData **new_cmap_window_data;
423 context_exists = (!XFindContext (DISPLAY, window,
424 wmGD.cmapWindowContextType,
425 (XPointer *) &cmap_window_data));
428 for (i = 0; cmap_window_data[i] != NULL; i++)
430 if (cmap_window_data[i] == pCD)
432 /* Reference already exists - return */
436 new_cmap_window_data = (ClientData **)
437 XtMalloc((i + 2 ) * sizeof(ClientData *));
438 memcpy((void *)new_cmap_window_data,(void *)cmap_window_data,
439 (i + 1) * sizeof(ClientData *));
440 XtFree((char *) cmap_window_data);
441 XDeleteContext(DISPLAY, window, wmGD.cmapWindowContextType);
446 new_cmap_window_data = (ClientData **)
447 XtMalloc(2 * sizeof(ClientData *));
449 new_cmap_window_data[i] = pCD;
450 new_cmap_window_data[i + 1] = NULL;
451 XSaveContext (DISPLAY, window, wmGD.cmapWindowContextType,
452 (caddr_t)new_cmap_window_data);
455 /*************************************<->*************************************
457 * RemoveColormapWindowReference (pCD, window)
461 * This function is used to update (or delete, if necessary) the structure
462 * that keeps track of all references to a Window from a toplevel window
463 * WM_COLORMAP_DATA property.
465 *************************************<->***********************************/
467 void RemoveColormapWindowReference (ClientData *pCD, Window window)
469 ClientData **cmap_window_data;
470 Boolean context_exists;
472 int reference_idx = -1;
473 ClientData **new_cmap_window_data;
475 context_exists = (!XFindContext (DISPLAY, window,
476 wmGD.cmapWindowContextType,
477 (XPointer *) &cmap_window_data));
480 for (i = 0; cmap_window_data[i] != NULL; i++)
482 if (cmap_window_data[i] == pCD)
485 if (reference_idx < 0)
492 new_cmap_window_data = (ClientData **)
493 XtMalloc(i * sizeof(ClientData *));
495 for (j = 0; cmap_window_data[j] != NULL; j++)
497 if (j != reference_idx)
499 new_cmap_window_data[idx] = cmap_window_data[j];
503 new_cmap_window_data[idx] = NULL;
505 XtFree((char *) cmap_window_data);
506 XDeleteContext(DISPLAY, window, wmGD.cmapWindowContextType);
509 XSaveContext (DISPLAY, window,
510 wmGD.cmapWindowContextType,
511 (caddr_t)new_cmap_window_data);
515 #endif /* IBM_169380 */
517 /*******************************************************************************
519 ** The rest of this module contains the SGI-added colormap handling.
521 ** mwm 1.1.3 didn't even try to deal with multiple colormaps, except to rotate
522 ** them. We need to see that all of the colormaps from WM_COLORMAP_WINDOWS
523 ** are installed when a window gets colormap focus.
525 ** The general idea is to keep track of which colormaps bounce which other
526 ** ones, so we only flash the first time (usually not even then).
528 ** The conflict record of a window is cleared whenever:
529 ** * WM_COLORMAP_WINDOWS property changes
530 ** * ColormapNotify for a new colormap happens
531 ** * windows are rotated (prev_cmap, next_cmap)
532 ** This is because with a changed colormap list, we need to recalculate
533 ** which ones get bounced out during a full colormap installation.
535 ** We don't just lift the twm code because, after carefully looking over
536 ** the twm code, it appears to have some problems of its own. In
537 ** particular, it assumes that if a given colormap displaces another one
538 ** once, it will always do so. This isn't necessarily so for a multiple
539 ** hardware colormaps machine.
541 ** We still need to add code to keep track of which color maps are really
542 ** installed at any one time. The current code is ready for this, but it has
543 ** not yet been done. Then we could do two things:
545 ** * refrain from installing a colormap if it is already installed
547 ** * have a way to restore all installed colormaps after the window
548 ** manager overwrites with it's own.
550 ******************************************************************************/
554 ProcessColormapList (WmScreenData *pSD, ClientData *pCD)
562 * If there is no client, return. This can happen when the root gets focus.
567 * If the window does not have colormap focus, return. We only install
568 * colormaps for windows with focus. We'll get another chance when the
569 * window does get focus.
571 if (pCD != pSD->colormapFocus) return;
574 * If window is iconified, return.
576 if ( (pCD->clientState != NORMAL_STATE)
577 && (pCD->clientState != MAXIMIZED_STATE)
581 * If the list doesn't exist, or has just a single item, no conflicts
582 * exist -- just go ahead and install the indicated colormap.
584 if (pCD->clientCmapCount == 0) {
585 WmInstallColormap (pSD, pCD->clientColormap);
588 if (pCD->clientCmapCount == 1) {
589 WmInstallColormap (pSD, pCD->clientCmapList[0]);
594 * If the list has already been initialized, we just need to do installs.
595 * Separate out these loops for performance, and because it isn't nice
596 * to grab the server unnecessarily.
598 * This code should also check for already-installed, once we put in that
601 if (pCD->clientCmapFlagsInitialized) {
603 /* Do the part between the index and zero */
604 for (i=pCD->clientCmapIndex; --i>=0; ) {
605 if (pCD->clientCmapFlags[i] == ColormapInstalled) {
606 WmInstallColormap (pSD, pCD->clientCmapList[i]);
610 /* Do the part from the end of the list to the index */
611 for (i=pCD->clientCmapCount; --i>= pCD->clientCmapIndex; ) {
612 if (pCD->clientCmapFlags[i] == ColormapInstalled) {
613 WmInstallColormap (pSD, pCD->clientCmapList[i]);
622 * If we get this far, the list has not yet been initialized.
624 * Stabilize the input queue -- the issue is that we need to know
625 * which colormap notify install and uninstall events are ours.
627 XGrabServer (DISPLAY); /* Ensure no one else's events for awhile */
628 XSync (DISPLAY, FALSE); /* Let pending events settle */
629 firstRequest = NextRequest (DISPLAY); /* First one that can be ours */
632 * Install the colormaps from last to first -- first is the "highest
633 * priority". "First" is pCD->clientCmapIndex.
635 * If the list has not been proocessed before, we need to unconditionally
636 * install each colormap. Colormap flashing is possible this once.
638 * If the list has already been processed once, all conflict checking
639 * was done then. All we need to do this time is to install the colormaps
643 /* Do the part between the index and zero */
644 for (i=pCD->clientCmapIndex; --i>=0; ) {
645 WmInstallColormap (pSD, pCD->clientCmapList[i]);
646 pCD->clientCmapFlags[i] = ColormapInstalled;
649 /* Do the part from the end of the list to the index */
650 for (i=pCD->clientCmapCount; --i>= pCD->clientCmapIndex; ) {
651 WmInstallColormap (pSD, pCD->clientCmapList[i]);
652 pCD->clientCmapFlags[i] = ColormapInstalled;
656 * Stabilize the input queue again -- the issue is that we need to know
657 * which colormap notify install and uninstall events we caused.
659 XSync (DISPLAY, FALSE); /* Let pending events settle */
660 lastRequest = NextRequest (DISPLAY); /* Last one that can be ours */
661 XUngrabServer (DISPLAY); /* Let others use it again */
663 /* Process the install & uninstall events */
664 XCheckIfEvent (DISPLAY, (XEvent *) &event, ProcessEvents, (char *)pCD);
666 /* Set that the list has been processed once */
667 pCD->clientCmapFlagsInitialized = True;
672 * Look over the queue for install and uninstall events on colormap/window
673 * combinations we care about. We don't actually disturb the queue, so
674 * events can be delivered in undisturbed order to the normal event handling
677 * For each appropriate install/uninstall ColormapNotify event that is queued:
678 * *) if uninstall event
679 * *) Set the conflict flag for this colormap window
680 * else if install event
681 * *) Clear the conflict flag for this colormap window
684 ProcessEvents(Display *dpy, XEvent *Event, char *c_pCD)
687 XColormapEvent *pEvent = (XColormapEvent *) Event;
688 ClientData *pCD = (ClientData *) c_pCD;
690 if ( (pEvent->type == ColormapNotify)
691 && (pEvent->serial >= firstRequest)
692 && (pEvent->serial < lastRequest)
693 && (pEvent->colormap != None)
696 switch (pEvent->state) {
697 case ColormapInstalled:
698 for (i=0; i<pCD->clientCmapCount; i++) {
699 if ( (pCD->clientCmapList[i]==pEvent->colormap)
700 &&(pCD->cmapWindows[i]==pEvent->window)
702 pCD->clientCmapFlags[i]
708 case ColormapUninstalled:
709 for (i=0; i<pCD->clientCmapCount; i++) {
710 if ( (pCD->clientCmapList[i]==pEvent->colormap)
711 &&(pCD->cmapWindows[i]==pEvent->window)
713 pCD->clientCmapFlags[i]
714 = ColormapUninstalled;
719 default: /* Should never get here */
725 * Always return false:
726 * * so that we get to search the entire queue -- it isn't very long
727 * * so all events remain on the queue to be handled normally elsewhere
729 return False; /* Always, so no events are lost from the queue */