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