2
* @OPENGROUP_COPYRIGHT@
4
* Copyright (c) 1989, 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
5
* Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
6
* ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
7
* the full copyright text.
9
* This software is subject to an open license. It may only be
10
* used on, with or for operating systems which are themselves open
11
* source systems. You must contact The Open Group for a license
12
* allowing distribution and sublicensing of this software on, with,
13
* or for operating systems which are not Open Source programs.
15
* See http://www.opengroup.org/openmotif/license for full
16
* details of the license agreement. Any use, reproduction, or
17
* distribution of the program constitutes recipient's acceptance of
20
* EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
21
* PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22
* KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
23
* WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
24
* OR FITNESS FOR A PARTICULAR PURPOSE
26
* EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
27
* NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
28
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
30
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32
* ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
33
* EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
34
* POSSIBILITY OF SUCH DAMAGES.
46
static char rcsid[] = "$XConsortium: WmColormap.c /main/5 1996/10/30 11:14:44 drk $"
50
* (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
59
* include extern functions
62
#include "WmColormap.h"
63
#include "WmKeyFocus.h"
65
static Bool ProcessEvents(Display *dpy, XEvent *Event, char *c_pCD);
68
/* Global variables */
69
static unsigned long firstRequest, lastRequest;
72
/*************************************<->*************************************
74
* InitWorkspaceColormap ()
79
* This function sets up the default workspace colormap and prepares for
80
* workspace colormap processing.
85
* pSD = ptr to screen data
89
* wmGD = (workspaceColormap)
91
*************************************<->***********************************/
93
void InitWorkspaceColormap (WmScreenData *pSD)
96
* Setup the default (workspace) colormap:
97
* !!! this should be made more general to get the colormap for the !!!
98
* !!! workspace (root) and then track colormap changes !!!
101
pSD->workspaceColormap = DefaultColormap (DISPLAY, pSD->screen);
103
} /* END OF FUNCTION InitWorkspaceColormap */
107
/*************************************<->*************************************
109
* InitColormapFocus (pSD)
114
* This function prepares for managing the colormap focus and sets the
115
* initial colormap focus (if the focus policy is "keyboard" - i.e. the
116
* colormap focus tracks the keyboard focus) the initial colormap
117
* installation is done in InitKeyboardFocus.
121
* pSD = pointer to screen data
125
* *pSD = (colormapFocus)
127
*************************************<->***********************************/
129
void InitColormapFocus (WmScreenData *pSD)
136
* Set up the initial colormap focus. If the colormapFocusPolicy is
137
* "keyboard" or it is "pointer" and the keyboard input focus policy
138
* is "pointer" then set up the initial colormap focus when the
139
* initial keyboard input focus is set up.
142
pSD->colormapFocus = NULL;
144
if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
146
if (wmGD.keyboardFocusPolicy != KEYBOARD_FOCUS_POINTER)
148
if ((pCD = GetClientUnderPointer (&sameScreen)) != NULL)
150
SetColormapFocus (pSD, pCD);
154
WmInstallColormap (pSD, pSD->workspaceColormap);
160
WmInstallColormap (pSD, pSD->workspaceColormap);
163
} /* END OF FUNCTION InitColormapFocus */
168
/*************************************<->*************************************
170
* ForceColormapFocus (pSD, pCD)
175
* ForceColormapFocus is the working part of the original SetColormapFocus.
176
* This function is used to unconditionally set the colormap focus to a
177
* particular client window or to clear the colormap focus (set focus to
180
* The reason is to permit focus to be dtrced. We need to do this because
181
* we can already have colormap focus, but still need to set the colormaps.
182
* Examples of when this occurs are:
184
* * after the window manager itself has forced a colormap,
185
* as happens when it draws transients in the overlay planes.
186
* * when WM_COLORMAP_WINDOWS changes.
187
* * when a ColormapNotify (new) event is received.
192
* pSD = pointer to Screen Data
193
* pCD = pointer to client data (clientColormap ...)
195
*************************************<->***********************************/
197
void ForceColormapFocus (WmScreenData *pSD, ClientData *pCD)
199
if (pCD && ((pCD->clientState == NORMAL_STATE) ||
200
(pCD->clientState == MAXIMIZED_STATE)))
202
pSD->colormapFocus = pCD;
203
#ifndef OLD_COLORMAP /* colormaps */
204
ProcessColormapList (pSD, pCD);
205
#else /* OSF original */
206
WmInstallColormap (pSD, pCD->clientColormap);
212
* The default colormap is installed for minimized windows that have
213
* the colormap focus.
214
* !!! should colormaps be installed for icons with client !!!
215
* !!! icon windows? should the client colormap be installed ? !!!
218
pSD->colormapFocus = NULL;
219
WmInstallColormap (pSD, pSD->workspaceColormap);
222
} /* END OF FUNCTION ForceColormapFocus */
227
/*************************************<->*************************************
229
* SetColormapFocus (pSD, pCD)
234
* This function is used to set the colormap focus to a particular client
235
* window or to clear the colormap focus (set focus to the root window).
240
* pSD = pointer to Screen Data
241
* pCD = pointer to client data (clientColormap ...)
243
*************************************<->***********************************/
245
void SetColormapFocus (WmScreenData *pSD, ClientData *pCD)
247
if (pCD == pSD->colormapFocus)
250
* The focus is already set to the right place.
256
ForceColormapFocus (pSD, pCD);
257
#else /* OSF original */
259
if (pCD && ((pCD->clientState == NORMAL_STATE) ||
260
(pCD->clientState == MAXIMIZED_STATE)))
262
pSD->colormapFocus = pCD;
263
#ifndef OLD_COLORMAP /* colormaps */
264
ProcessColormapList (pSD, pCD);
265
#else /* OSF original */
266
WmInstallColormap (pSD, pCD->clientColormap);
272
* The default colormap is installed for minimized windows that have
273
* the colormap focus.
274
* !!! should colormaps be installed for icons with client !!!
275
* !!! icon windows? should the client colormap be installed ? !!!
278
pSD->colormapFocus = NULL;
279
WmInstallColormap (pSD, pSD->workspaceColormap);
283
} /* END OF FUNCTION SetColormapFocus */
287
/*************************************<->*************************************
289
* WmInstallColormap (pSD, colormap)
294
* This function installs colormaps for the window manager. It trys to be
295
* intelligent and avoid unnecessary installations. It assumes that no
296
* other program is installing colormaps.
301
* pSD = ptr to screen data
302
* colormap = the id for the colormap to be installed
304
*************************************<->***********************************/
306
void WmInstallColormap (WmScreenData *pSD, Colormap colormap)
309
* !!! this could be generalized to work better for systems that !!!
310
* !!! support multiple installed colormaps !!!
313
if (colormap != pSD->lastInstalledColormap)
315
XInstallColormap (DISPLAY, colormap);
316
pSD->lastInstalledColormap = colormap;
319
} /* END OF FUNCTION WmInstallColormap */
323
/*************************************<->*************************************
325
* ResetColormapData (pCD, pWindows, count)
330
* This function is used to release old colormap data (contexts, malloc'ed
336
* pCD = pointer to client data (cmapWindows ...)
338
* pWindows = new list of colormap windows
340
* count = number of windows in new colormap windows list
342
*************************************<->***********************************/
344
void ResetColormapData (ClientData *pCD, Window *pWindows, int count)
349
if (pCD->clientCmapCount)
353
/* reset the client colormap to the toplevel window colormap */
354
for (i = 0; i < pCD->clientCmapCount; i++)
356
if (pCD->cmapWindows[i] == pCD->client)
358
pCD->clientColormap = pCD->clientCmapList[i];
365
* Free up old contexts.
368
for (i = 0; i < pCD->clientCmapCount; i++)
370
if (pCD->cmapWindows[i] != pCD->client)
373
RemoveColormapWindowReference(pCD, pCD->cmapWindows[i]);
375
XDeleteContext (DISPLAY, pCD->cmapWindows[i],
376
wmGD.windowContextType);
382
* Free up old colormap data.
385
XtFree ((char *)(pCD->cmapWindows));
386
XtFree ((char *)(pCD->clientCmapList));
387
pCD->clientCmapCount = 0;
388
#ifndef OLD_COLORMAP /* colormap */
389
XtFree ((char *)(pCD->clientCmapFlags));
390
pCD->clientCmapFlags = 0; /* DEBUG: */
391
pCD->clientCmapFlagsInitialized = 0;
401
for (i = 0; i < count; i++)
403
if (pWindows[i] != pCD->client)
406
AddColormapWindowReference(pCD, pWindows[i]);
408
XSaveContext (DISPLAY, pWindows[i], wmGD.windowContextType,
415
} /* END OF FUNCTION ResetColormapData */
418
/*************************************<->*************************************
420
* AddColormapWindowReference (pCD, window)
424
* This function is used to update (or create, if necessary) the structure
425
* that keeps track of all references to a Window from a toplevel window
426
* WM_COLORMAP_DATA property.
428
*************************************<->***********************************/
430
void AddColormapWindowReference (ClientData *pCD, Window window)
432
ClientData **cmap_window_data;
433
Boolean context_exists;
435
ClientData **new_cmap_window_data;
437
context_exists = (!XFindContext (DISPLAY, window,
438
wmGD.cmapWindowContextType,
439
(XPointer *) &cmap_window_data));
442
for (i = 0; cmap_window_data[i] != NULL; i++)
444
if (cmap_window_data[i] == pCD)
446
/* Reference already exists - return */
450
new_cmap_window_data = (ClientData **)
451
XtMalloc((i + 2 ) * sizeof(ClientData *));
452
memcpy((void *)new_cmap_window_data,(void *)cmap_window_data,
453
(i + 1) * sizeof(ClientData *));
454
XtFree((char *) cmap_window_data);
455
XDeleteContext(DISPLAY, window, wmGD.cmapWindowContextType);
460
new_cmap_window_data = (ClientData **)
461
XtMalloc(2 * sizeof(ClientData *));
463
new_cmap_window_data[i] = pCD;
464
new_cmap_window_data[i + 1] = NULL;
465
XSaveContext (DISPLAY, window, wmGD.cmapWindowContextType,
466
(caddr_t)new_cmap_window_data);
469
/*************************************<->*************************************
471
* RemoveColormapWindowReference (pCD, window)
475
* This function is used to update (or delete, if necessary) the structure
476
* that keeps track of all references to a Window from a toplevel window
477
* WM_COLORMAP_DATA property.
479
*************************************<->***********************************/
481
void RemoveColormapWindowReference (ClientData *pCD, Window window)
483
ClientData **cmap_window_data;
484
Boolean context_exists;
486
int reference_idx = -1;
487
ClientData **new_cmap_window_data;
489
context_exists = (!XFindContext (DISPLAY, window,
490
wmGD.cmapWindowContextType,
491
(XPointer *) &cmap_window_data));
494
for (i = 0; cmap_window_data[i] != NULL; i++)
496
if (cmap_window_data[i] == pCD)
499
if (reference_idx < 0)
506
new_cmap_window_data = (ClientData **)
507
XtMalloc(i * sizeof(ClientData *));
509
for (j = 0; cmap_window_data[j] != NULL; j++)
511
if (j != reference_idx)
513
new_cmap_window_data[idx] = cmap_window_data[j];
517
new_cmap_window_data[idx] = NULL;
519
XtFree((char *) cmap_window_data);
520
XDeleteContext(DISPLAY, window, wmGD.cmapWindowContextType);
523
XSaveContext (DISPLAY, window,
524
wmGD.cmapWindowContextType,
525
(caddr_t)new_cmap_window_data);
529
#endif /* IBM_169380 */
531
/*******************************************************************************
533
** The rest of this module contains the SGI-added colormap handling.
535
** mwm 1.1.3 didn't even try to deal with multiple colormaps, except to rotate
536
** them. We need to see that all of the colormaps from WM_COLORMAP_WINDOWS
537
** are installed when a window gets colormap focus.
539
** The general idea is to keep track of which colormaps bounce which other
540
** ones, so we only flash the first time (usually not even then).
542
** The conflict record of a window is cleared whenever:
543
** * WM_COLORMAP_WINDOWS property changes
544
** * ColormapNotify for a new colormap happens
545
** * windows are rotated (prev_cmap, next_cmap)
546
** This is because with a changed colormap list, we need to recalculate
547
** which ones get bounced out during a full colormap installation.
549
** We don't just lift the twm code because, after carefully looking over
550
** the twm code, it appears to have some problems of its own. In
551
** particular, it assumes that if a given colormap displaces another one
552
** once, it will always do so. This isn't necessarily so for a multiple
553
** hardware colormaps machine.
555
** We still need to add code to keep track of which color maps are really
556
** installed at any one time. The current code is ready for this, but it has
557
** not yet been done. Then we could do two things:
559
** * refrain from installing a colormap if it is already installed
561
** * have a way to restore all installed colormaps after the window
562
** manager overwrites with it's own.
564
******************************************************************************/
568
ProcessColormapList (WmScreenData *pSD, ClientData *pCD)
576
* If there is no client, return. This can happen when the root gets focus.
581
* If the window does not have colormap focus, return. We only install
582
* colormaps for windows with focus. We'll get another chance when the
583
* window does get focus.
585
if (pCD != pSD->colormapFocus) return;
588
* If window is iconified, return.
590
if ( (pCD->clientState != NORMAL_STATE)
591
&& (pCD->clientState != MAXIMIZED_STATE)
595
* If the list doesn't exist, or has just a single item, no conflicts
596
* exist -- just go ahead and install the indicated colormap.
598
if (pCD->clientCmapCount == 0) {
599
WmInstallColormap (pSD, pCD->clientColormap);
602
if (pCD->clientCmapCount == 1) {
603
WmInstallColormap (pSD, pCD->clientCmapList[0]);
608
* If the list has already been initialized, we just need to do installs.
609
* Separate out these loops for performance, and because it isn't nice
610
* to grab the server unnecessarily.
612
* This code should also check for already-installed, once we put in that
615
if (pCD->clientCmapFlagsInitialized) {
617
/* Do the part between the index and zero */
618
for (i=pCD->clientCmapIndex; --i>=0; ) {
619
if (pCD->clientCmapFlags[i] == ColormapInstalled) {
620
WmInstallColormap (pSD, pCD->clientCmapList[i]);
624
/* Do the part from the end of the list to the index */
625
for (i=pCD->clientCmapCount; --i>= pCD->clientCmapIndex; ) {
626
if (pCD->clientCmapFlags[i] == ColormapInstalled) {
627
WmInstallColormap (pSD, pCD->clientCmapList[i]);
636
* If we get this far, the list has not yet been initialized.
638
* Stabilize the input queue -- the issue is that we need to know
639
* which colormap notify install and uninstall events are ours.
641
XGrabServer (DISPLAY); /* Ensure no one else's events for awhile */
642
XSync (DISPLAY, FALSE); /* Let pending events settle */
643
firstRequest = NextRequest (DISPLAY); /* First one that can be ours */
646
* Install the colormaps from last to first -- first is the "highest
647
* priority". "First" is pCD->clientCmapIndex.
649
* If the list has not been proocessed before, we need to unconditionally
650
* install each colormap. Colormap flashing is possible this once.
652
* If the list has already been processed once, all conflict checking
653
* was done then. All we need to do this time is to install the colormaps
657
/* Do the part between the index and zero */
658
for (i=pCD->clientCmapIndex; --i>=0; ) {
659
WmInstallColormap (pSD, pCD->clientCmapList[i]);
660
pCD->clientCmapFlags[i] = ColormapInstalled;
663
/* Do the part from the end of the list to the index */
664
for (i=pCD->clientCmapCount; --i>= pCD->clientCmapIndex; ) {
665
WmInstallColormap (pSD, pCD->clientCmapList[i]);
666
pCD->clientCmapFlags[i] = ColormapInstalled;
670
* Stabilize the input queue again -- the issue is that we need to know
671
* which colormap notify install and uninstall events we caused.
673
XSync (DISPLAY, FALSE); /* Let pending events settle */
674
lastRequest = NextRequest (DISPLAY); /* Last one that can be ours */
675
XUngrabServer (DISPLAY); /* Let others use it again */
677
/* Process the install & uninstall events */
678
XCheckIfEvent (DISPLAY, (XEvent *) &event, ProcessEvents, (char *)pCD);
680
/* Set that the list has been processed once */
681
pCD->clientCmapFlagsInitialized = True;
686
* Look over the queue for install and uninstall events on colormap/window
687
* combinations we care about. We don't actually disturb the queue, so
688
* events can be delivered in undisturbed order to the normal event handling
691
* For each appropriate install/uninstall ColormapNotify event that is queued:
692
* *) if uninstall event
693
* *) Set the conflict flag for this colormap window
694
* else if install event
695
* *) Clear the conflict flag for this colormap window
698
ProcessEvents(Display *dpy, XEvent *Event, char *c_pCD)
701
XColormapEvent *pEvent = (XColormapEvent *) Event;
702
ClientData *pCD = (ClientData *) c_pCD;
704
if ( (pEvent->type == ColormapNotify)
705
&& (pEvent->serial >= firstRequest)
706
&& (pEvent->serial < lastRequest)
707
&& (pEvent->colormap != None)
710
switch (pEvent->state) {
711
case ColormapInstalled:
712
for (i=0; i<pCD->clientCmapCount; i++) {
713
if ( (pCD->clientCmapList[i]==pEvent->colormap)
714
&&(pCD->cmapWindows[i]==pEvent->window)
716
pCD->clientCmapFlags[i]
722
case ColormapUninstalled:
723
for (i=0; i<pCD->clientCmapCount; i++) {
724
if ( (pCD->clientCmapList[i]==pEvent->colormap)
725
&&(pCD->cmapWindows[i]==pEvent->window)
727
pCD->clientCmapFlags[i]
728
= ColormapUninstalled;
733
default: /* Should never get here */
739
* Always return false:
740
* * so that we get to search the entire queue -- it isn't very long
741
* * so all events remain on the queue to be handled normally elsewhere
743
return False; /* Always, so no events are lost from the queue */