1 
2 /*	$Id: tixMwm.c,v 1.1.1.1 2000/05/17 11:08:42 idiscovery Exp $	*/
3 
4 /*
5  * tixMwm.c --
6  *
7  *	Communicating with the Motif window manager.
8  *
9  *
10  * Copyright (c) 1996, Expert Interface Technologies
11  *
12  * See the file "license.terms" for information on usage and redistribution
13  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14  *
15  */
16 
17 #include <tkInt.h>
18 #include "tixPort.h"
19 #include "tixInt.h"
20 #include "tkVMacro.h"
21 #include <X11/Xlib.h>
22 #include <X11/Xatom.h>
23 #include <X11/Xproto.h>
24 #include <X11/Xutil.h>
25 
26 
27 #ifdef HAS_MOTIF_INC
28 #include <Xm/MwmUtil.h>
29 #else
30 
31 /*
32  * This section is provided for the machines that don't have the Motif
33  * header files installed.
34  */
35 
36 #define MWM_DECOR_ALL           (1L << 0)
37 #define MWM_DECOR_BORDER        (1L << 1)
38 #define MWM_DECOR_RESIZEH       (1L << 2)
39 #define MWM_DECOR_TITLE         (1L << 3)
40 #define MWM_DECOR_MENU          (1L << 4)
41 #define MWM_DECOR_MINIMIZE      (1L << 5)
42 #define MWM_DECOR_MAXIMIZE      (1L << 6)
43 
44 #define MWM_HINTS_DECORATIONS   (1L << 1)
45 
46 #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
47 #define PROP_MWM_HINTS_ELEMENTS         PROP_MOTIF_WM_HINTS_ELEMENTS
48 
49 /* atom name for _MWM_HINTS property */
50 #define _XA_MOTIF_WM_HINTS      "_MOTIF_WM_HINTS"
51 #define _XA_MWM_HINTS           _XA_MOTIF_WM_HINTS
52 
53 #define _XA_MOTIF_WM_MENU       "_MOTIF_WM_MENU"
54 #define _XA_MWM_MENU            _XA_MOTIF_WM_MENU
55 
56 #define _XA_MOTIF_WM_INFO       "_MOTIF_WM_INFO"
57 #define _XA_MWM_INFO            _XA_MOTIF_WM_INFO
58 
59 #define PROP_MOTIF_WM_INFO_ELEMENTS     2
60 #define PROP_MWM_INFO_ELEMENTS          PROP_MOTIF_WM_INFO_ELEMENTS
61 
62 typedef struct
63 {
64     CARD32      flags;
65     CARD32      functions;
66     CARD32      decorations;
67     INT32       inputMode;
68     CARD32      status;
69 } PropMotifWmHints;
70 
71 typedef PropMotifWmHints        PropMwmHints;
72 
73 typedef struct
74 {
75     CARD32 flags;
76     CARD32 wmWindow;
77 } PropMotifWmInfo;
78 
79 typedef PropMotifWmInfo PropMwmInfo;
80 
81 #endif	/* HAS_MOTIF_INC */
82 
83 #define MWM_DECOR_UNKNOWN (-1)
84 #define MWM_DECOR_EVERYTHING (MWM_DECOR_BORDER |\
85 			      MWM_DECOR_RESIZEH |\
86 			      MWM_DECOR_TITLE |\
87 			      MWM_DECOR_MENU |\
88 			      MWM_DECOR_MINIMIZE |\
89 			      MWM_DECOR_MAXIMIZE)
90 
91 typedef struct _Tix_MwmInfo {
92     Tcl_Interp	      * interp;
93     Tk_Window 		tkwin;
94     PropMwmHints	prop;		/* not used */
95     Atom 		mwm_hints_atom;
96     Tcl_HashTable 	protocols;
97     unsigned int	isremapping : 1;
98     unsigned int	resetProtocol : 1;
99     unsigned int	addedMwmMsg : 1;
100 } Tix_MwmInfo;
101 
102 typedef struct Tix_MwmProtocol {
103     Atom 		protocol;
104     char 	      * name;
105     char 	      * menuMessage;
106     size_t 		messageLen;
107     unsigned int	active : 1;
108 } Tix_MwmProtocol;
109 
110 
111 /* Function declaration */
112 
113 static void		AddMwmProtocol _ANSI_ARGS_((Tcl_Interp *interp,
114 			    Tix_MwmInfo *wmPtr, char * name, char * message));
115 static void		ActivateMwmProtocol _ANSI_ARGS_((Tcl_Interp *interp,
116 			    Tix_MwmInfo *wmPtr, char * name));
117 static void		DeactivateMwmProtocol _ANSI_ARGS_((Tcl_Interp *interp,
118 			    Tix_MwmInfo *wmPtr, char * name));
119 static void		DeleteMwmProtocol _ANSI_ARGS_((Tcl_Interp *interp,
120 			    Tix_MwmInfo *wmPtr, char * name));
121 static Tix_MwmInfo *	GetMwmInfo _ANSI_ARGS_((Tcl_Interp *interp,
122 			    Tk_Window tkwin));
123 static Tix_MwmProtocol*	GetMwmProtocol _ANSI_ARGS_((Tcl_Interp * interp,
124 			    Tix_MwmInfo * wmPtr, Atom protocol));
125 static int		IsMwmRunning _ANSI_ARGS_((Tcl_Interp * interp,
126 			    Tix_MwmInfo*wmPtr));
127 static int 		MwmDecor _ANSI_ARGS_((Tcl_Interp * interp,
128 			    char * string));
129 static int		MwmProtocol _ANSI_ARGS_((Tcl_Interp * interp,
130 			    Tix_MwmInfo * wmPtr, int argc, char ** argv));
131 static void		QueryMwmHints _ANSI_ARGS_((Tix_MwmInfo * wmPtr));
132 static void		RemapWindow _ANSI_ARGS_((ClientData clientData));
133 static void		RemapWindowWhenIdle _ANSI_ARGS_((
134 			    Tix_MwmInfo * wmPtr));
135 static void 		ResetProtocols _ANSI_ARGS_((ClientData clientData));
136 static void		ResetProtocolsWhenIdle _ANSI_ARGS_((
137 			    Tix_MwmInfo * wmPtr));
138 static int 		SetMwmDecorations _ANSI_ARGS_((Tcl_Interp *interp,
139 			    Tix_MwmInfo*wmPtr, int argc, char ** argv));
140 static int		SetMwmTransientFor _ANSI_ARGS_((Tcl_Interp *interp,
141 			    Tix_MwmInfo*wmPtr, TkWindow *mainWindow, int argc,
142 			    char ** argv));
143 static void		StructureProc _ANSI_ARGS_((ClientData clientData,
144 			    XEvent *eventPtr));
145 
146 /* Local variables */
147 
148 static Tcl_HashTable mwmTable;
149 
150 
151 /*
152  *----------------------------------------------------------------------
153  *
154  * Tix_MwmCmd --
155  *
156  *	This procedure is invoked to process the "mwm" Tcl command.
157  *	See the user documentation for details on what it does.
158  *
159  * Results:
160  *	A standard Tcl result.
161  *
162  * Side effects:
163  *	See the user documentation.
164  *
165  *----------------------------------------------------------------------
166  */
167 
168 /* ARGSUSED */
169 int
Tix_MwmCmd(clientData,interp,argc,argv)170 Tix_MwmCmd(clientData, interp, argc, argv)
171     ClientData clientData;	/* Main window associated with
172 				 * interpreter. */
173     Tcl_Interp *interp;		/* Current interpreter. */
174     int argc;			/* Number of arguments. */
175     char **argv;		/* Argument strings. */
176 {
177     Tk_Window tkwin = (Tk_Window) clientData;
178     TkWindow *winPtr;
179     char c;
180     size_t length;
181     Tix_MwmInfo * wmPtr;
182 
183     if (argc < 3) {
184 	Tcl_AppendResult(interp, "wrong # args: should be \"",
185 		argv[0], " option pathname ?arg ...?\"", (char *) NULL);
186 	return TCL_ERROR;
187     }
188     c = argv[1][0];
189     length = strlen(argv[1]);
190 
191     if (!(winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin))) {
192 	return TCL_ERROR;
193     }
194     if (!Tk_IsTopLevel(winPtr)) {
195 	Tcl_AppendResult(interp, argv[2], " is not a toplevel window.", NULL);
196 	return TCL_ERROR;
197     }
198     if (!(wmPtr=GetMwmInfo(interp, (Tk_Window) winPtr))) {
199 	return TCL_ERROR;
200     }
201 
202     if ((c == 'd') && (strncmp(argv[1], "decorations", length) == 0)) {
203 	return SetMwmDecorations(interp, wmPtr, argc-3, argv+3);
204     }
205     else if ((c == 'i') && (strncmp(argv[1], "ismwmrunning", length) == 0)) {
206 	if (IsMwmRunning(interp, wmPtr)) {
207 	    Tcl_AppendResult(interp, "1", NULL);
208 	} else {
209 	    Tcl_AppendResult(interp, "0", NULL);
210 	}
211 	return TCL_OK;
212     }
213     else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)) {
214 	return MwmProtocol(interp, wmPtr, argc-3, argv+3);
215     }
216     else if ((c == 't') && (strncmp(argv[1], "transientfor", length) == 0)) {
217 	return SetMwmTransientFor(interp, wmPtr, winPtr, argc-3, argv+3);
218     }
219     else {
220 	Tcl_AppendResult(interp, "unknown or ambiguous option \"",
221 	    argv[1], "\": must be decorations, ismwmrunning, protocol ",
222 	    "or transientfor",
223 	    NULL);
224 	return TCL_ERROR;
225     }
226 }
227 
228 /*
229  *----------------------------------------------------------------------
230  * TixMwmProtocolHandler --
231  *
232  *	A generic X event handler that handles the events from the Mwm
233  *	Window manager.
234  *
235  * Results:
236  *	True iff the event has been handled.
237  *
238  * Side effects:
239  *	None.
240  *----------------------------------------------------------------------
241  */
242 
243 int
TixMwmProtocolHandler(clientData,eventPtr)244 TixMwmProtocolHandler(clientData, eventPtr)
245     ClientData clientData;
246     XEvent *eventPtr;
247 {
248     TkWindow *winPtr;
249     Window handlerWindow;
250 
251     if (eventPtr->type != ClientMessage) {
252 	return 0;
253     }
254 
255     handlerWindow = eventPtr->xany.window;
256     winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
257     if (winPtr != NULL) {
258 	if (eventPtr->xclient.message_type ==
259 	    Tk_InternAtom((Tk_Window) winPtr,"_MOTIF_WM_MESSAGES")) {
260 	    TkWmProtocolEventProc(winPtr, eventPtr);
261 	    return 1;
262 	}
263     }
264     return 0;
265 }
266 
267 static int
MwmDecor(interp,string)268 MwmDecor(interp, string)
269     Tcl_Interp * interp;
270     char * string;
271 {
272     size_t len = strlen(string);
273 
274     if (strncmp(string, "-all", len) == 0) {
275 	return MWM_DECOR_ALL;
276     } else if (strncmp(string, "-border", len) == 0) {
277 	return MWM_DECOR_BORDER;
278     } else if (strncmp(string, "-resizeh", len) == 0) {
279 	return MWM_DECOR_RESIZEH;
280     } else if (strncmp(string, "-title", len) == 0) {
281 	return MWM_DECOR_TITLE;
282     } else if (strncmp(string, "-menu", len) == 0) {
283 	return MWM_DECOR_MENU;
284     } else if (strncmp(string, "-minimize", len) == 0) {
285 	return MWM_DECOR_MINIMIZE;
286     } else if (strncmp(string, "-maximize", len) == 0) {
287 	return MWM_DECOR_MAXIMIZE;
288     } else {
289 	Tcl_AppendResult(interp, "unknown decoration \"", string, "\"", NULL);
290 	return -1;
291     }
292 }
293 
294 
295 static void
QueryMwmHints(wmPtr)296 QueryMwmHints(wmPtr)
297     Tix_MwmInfo * wmPtr;
298 {
299     Atom 		actualType;
300     int 		actualFormat;
301     unsigned long 	numItems, bytesAfter;
302 
303     wmPtr->prop.flags = MWM_HINTS_DECORATIONS;
304 
305     if (XGetWindowProperty(Tk_Display(wmPtr->tkwin),Tk_WindowId(wmPtr->tkwin),
306 	wmPtr->mwm_hints_atom, 0, PROP_MWM_HINTS_ELEMENTS,
307 	False, wmPtr->mwm_hints_atom, &actualType, &actualFormat, &numItems,
308 	&bytesAfter, (unsigned char **) & wmPtr->prop) == Success) {
309 
310 	if ((actualType != wmPtr->mwm_hints_atom) || (actualFormat != 32) ||
311 	    (numItems <= 0)) {
312 	    /* It looks like this window doesn't have a _XA_MWM_HINTS
313 	     * property. Let's give the default value
314 	     */
315 	    wmPtr->prop.decorations = MWM_DECOR_EVERYTHING;
316 	}
317     } else {
318 	/* We get an error somehow. Pretend that the decorations are all
319 	 */
320 	wmPtr->prop.decorations = MWM_DECOR_EVERYTHING;
321     }
322 }
323 
324 static void
RemapWindow(clientData)325 RemapWindow(clientData)
326     ClientData clientData;
327 {
328     Tix_MwmInfo * wmPtr = (Tix_MwmInfo *)clientData;
329 
330     Tk_UnmapWindow(wmPtr->tkwin);
331     Tk_MapWindow(wmPtr->tkwin);
332     wmPtr->isremapping = 0;
333 }
334 
335 static void
RemapWindowWhenIdle(wmPtr)336 RemapWindowWhenIdle(wmPtr)
337     Tix_MwmInfo * wmPtr;
338 {
339     if (!wmPtr->isremapping) {
340 	wmPtr->isremapping = 1;
341 	Tcl_DoWhenIdle(RemapWindow, (ClientData)wmPtr);
342     }
343 }
344 
345 /*
346  * SetMwmDecorations --
347  *
348  *
349  */
350 static
SetMwmDecorations(interp,wmPtr,argc,argv)351 int SetMwmDecorations(interp, wmPtr, argc, argv)
352     Tcl_Interp *interp;
353     Tix_MwmInfo*wmPtr;
354     int 	argc;
355     char     ** argv;
356 {
357     int			i;
358     int			decor;
359     char		buff[40];
360 
361     if (argc == 0 || argc == 1) {
362 	/*
363 	 * Query the existing settings
364 	 */
365 	QueryMwmHints(wmPtr);
366 
367 	if (argc == 0) {
368 	    /*
369 	     * Query all hints
370 	     */
371 	    sprintf(buff, "-border %d",
372 		((wmPtr->prop.decorations & MWM_DECOR_BORDER)!=0));
373 	    Tcl_AppendElement(interp, buff);
374 
375 	    sprintf(buff, "-resizeh %d",
376 		((wmPtr->prop.decorations &MWM_DECOR_RESIZEH)!=0));
377 	    Tcl_AppendElement(interp, buff);
378 
379 	    sprintf(buff, "-title %d",
380 		((wmPtr->prop.decorations & MWM_DECOR_TITLE)!=0));
381 	    Tcl_AppendElement(interp, buff);
382 
383 	    sprintf(buff, "-menu %d",
384 		((wmPtr->prop.decorations & MWM_DECOR_MENU)!=0));
385 	    Tcl_AppendElement(interp, buff);
386 
387 	    sprintf(buff, "-minimize %d",
388 		((wmPtr->prop.decorations&MWM_DECOR_MINIMIZE)!=0));
389 	    Tcl_AppendElement(interp, buff);
390 
391 	    sprintf(buff, "-maximize %d",
392 		((wmPtr->prop.decorations&MWM_DECOR_MAXIMIZE)!=0));
393 	    Tcl_AppendElement(interp, buff);
394 
395 	    return TCL_OK;
396 	} else {
397 	    /*
398 	     * Query only one hint
399 	     */
400 	    if ((decor = MwmDecor(interp, argv[0])) == MWM_DECOR_UNKNOWN) {
401 		return TCL_ERROR;
402 	    }
403 
404 	    if (wmPtr->prop.decorations & decor) {
405 		Tcl_AppendResult(interp, "1", NULL);
406 	    } else {
407 		Tcl_AppendResult(interp, "0", NULL);
408 	    }
409 	    return TCL_OK;
410 	}
411     } else {
412 	if (argc %2) {
413 	    Tcl_AppendResult(interp, "value missing for option \"",
414 		argv[argc-1], "\"", NULL);
415 		return TCL_ERROR;
416 	}
417 
418 	for (i=0; i<argc; i+=2) {
419 	    int value;
420 
421 	    if ((decor = MwmDecor(interp, argv[i])) == MWM_DECOR_UNKNOWN)  {
422 		return TCL_ERROR;
423 	    }
424 
425 	    if (Tcl_GetBooleanFromObj(interp, argv[i+1], &value) != TCL_OK) {
426 		return TCL_ERROR;
427 	    }
428 
429 	    if (value) {
430 		wmPtr->prop.decorations |= decor;
431 	    }
432 	    else {
433 		wmPtr->prop.decorations &= ~decor;
434 	    }
435 
436 	    if (decor == MWM_DECOR_ALL) {
437 		if (value) {
438 		    wmPtr->prop.decorations |= MWM_DECOR_EVERYTHING;
439 		} else {
440 		    wmPtr->prop.decorations &= ~MWM_DECOR_EVERYTHING;
441 		}
442 	    }
443 	}
444 
445 	wmPtr->prop.flags = MWM_HINTS_DECORATIONS;
446 	XChangeProperty(Tk_Display(wmPtr->tkwin), Tk_WindowId(wmPtr->tkwin),
447 	    wmPtr->mwm_hints_atom, wmPtr->mwm_hints_atom, 32, PropModeReplace,
448 	    (unsigned char *) &wmPtr->prop, PROP_MWM_HINTS_ELEMENTS);
449 
450 	if (Tk_IsMapped(wmPtr->tkwin)) {
451 	    /* Needs unmap/map to refresh */
452 	    RemapWindowWhenIdle(wmPtr);
453 	}
454 	return TCL_OK;
455     }
456 }
457 
MwmProtocol(interp,wmPtr,argc,argv)458 static int MwmProtocol(interp, wmPtr, argc, argv)
459     Tcl_Interp * interp;
460     Tix_MwmInfo * wmPtr;
461     int argc;
462     char ** argv;
463 {
464     size_t len;
465 
466     if (argc == 0) {
467 	Tcl_HashSearch 	  hSearch;
468 	Tcl_HashEntry 	* hashPtr;
469 	Tix_MwmProtocol * ptPtr;
470 
471 	/* Iterate over all the entries in the hash table */
472 	for (hashPtr = Tcl_FirstHashEntry(&wmPtr->protocols, &hSearch);
473 	     hashPtr;
474 	     hashPtr = Tcl_NextHashEntry(&hSearch)) {
475 
476 	    ptPtr = (Tix_MwmProtocol *)Tcl_GetHashValue(hashPtr);
477 	    Tcl_AppendElement(interp, ptPtr->name);
478 	}
479 	return TCL_OK;
480     }
481 
482     len = strlen(argv[0]);
483     if (strncmp(argv[0], "add", len) == 0 && argc == 3) {
484 	AddMwmProtocol(interp, wmPtr, argv[1], argv[2]);
485     }
486     else if (strncmp(argv[0], "activate", len) == 0 && argc == 2) {
487 	ActivateMwmProtocol(interp, wmPtr, argv[1]);
488     }
489     else if (strncmp(argv[0], "deactivate", len) == 0 && argc == 2) {
490 	DeactivateMwmProtocol(interp, wmPtr, argv[1]);
491     }
492     else if (strncmp(argv[0], "delete", len) == 0 && argc == 2) {
493 	DeleteMwmProtocol(interp, wmPtr, argv[1]);
494     }
495     else {
496 	Tcl_AppendResult(interp, "unknown option \"", argv[0],
497 	    "\" should be add, activate, deactivate or delete", NULL);
498 	return TCL_ERROR;
499     }
500 
501     return TCL_OK;
502 }
503 
504 
AddMwmProtocol(interp,wmPtr,name,message)505 static void AddMwmProtocol(interp, wmPtr, name, message)
506     Tcl_Interp  *interp;
507     Tix_MwmInfo *wmPtr;
508     char * name;
509     char * message;
510 {
511     Atom protocol;
512     Tix_MwmProtocol *ptPtr;
513 
514     protocol = Tk_InternAtom(wmPtr->tkwin, name);
515     ptPtr = GetMwmProtocol(interp, wmPtr, protocol);
516 
517     if (ptPtr->menuMessage != NULL) {
518 	/* This may happen if "protocol add" called twice for the same name */
519 	ckfree(ptPtr->menuMessage);
520     }
521 
522     if (ptPtr->name == NULL) {
523 	ptPtr->name = tixStrDup(name);
524     }
525     ptPtr->menuMessage = tixStrDup(message);
526     ptPtr->messageLen  = strlen(message);
527     ptPtr->active = 1;
528 
529     ResetProtocolsWhenIdle(wmPtr);
530 }
531 
ActivateMwmProtocol(interp,wmPtr,name)532 static void ActivateMwmProtocol(interp, wmPtr, name)
533     Tcl_Interp  *interp;
534     Tix_MwmInfo *wmPtr;
535     char * name;
536 {
537     Atom protocol;
538     Tix_MwmProtocol *ptPtr;
539 
540     protocol = Tk_InternAtom(wmPtr->tkwin, name);
541     ptPtr = GetMwmProtocol(interp, wmPtr, protocol);
542     ptPtr->active = 1;
543 
544     ResetProtocolsWhenIdle(wmPtr);
545 }
546 
DeactivateMwmProtocol(interp,wmPtr,name)547 static void DeactivateMwmProtocol(interp, wmPtr, name)
548     Tcl_Interp  *interp;
549     Tix_MwmInfo *wmPtr;
550     char * name;
551 {
552     Atom protocol;
553     Tix_MwmProtocol *ptPtr;
554 
555     protocol = Tk_InternAtom(wmPtr->tkwin, name);
556     ptPtr = GetMwmProtocol(interp, wmPtr, protocol);
557     ptPtr->active = 0;
558 
559     ResetProtocolsWhenIdle(wmPtr);
560 }
561 
562 /*
563  * Any "wm protocol" event handlers for the deleted protocol are
564  * *not* automatically deleted. It is the application programmer's
565  * responsibility to delete them using
566  *
567  *	wm protocol SOME_JUNK_PROTOCOL {}
568  */
DeleteMwmProtocol(interp,wmPtr,name)569 static void DeleteMwmProtocol(interp, wmPtr, name)
570     Tcl_Interp  *interp;
571     Tix_MwmInfo *wmPtr;
572     char * name;
573 {
574     Atom protocol;
575     Tix_MwmProtocol *ptPtr;
576     Tcl_HashEntry * hashPtr;
577 
578     protocol = Tk_InternAtom(wmPtr->tkwin, name);
579     hashPtr = Tcl_FindHashEntry(&wmPtr->protocols, (char*)protocol);
580 
581     if (hashPtr) {
582 	ptPtr = (Tix_MwmProtocol *)Tcl_GetHashValue(hashPtr);
583 	ckfree(ptPtr->name);
584 	ckfree(ptPtr->menuMessage);
585 	ckfree((char*)ptPtr);
586 	Tcl_DeleteHashEntry(hashPtr);
587     }
588 
589     ResetProtocolsWhenIdle(wmPtr);
590 }
591 
592 
593 static void
ResetProtocolsWhenIdle(wmPtr)594 ResetProtocolsWhenIdle(wmPtr)
595     Tix_MwmInfo * wmPtr;
596 {
597     if (!wmPtr->resetProtocol) {
598 	wmPtr->resetProtocol = 1;
599 	Tcl_DoWhenIdle(ResetProtocols, (ClientData)wmPtr);
600     }
601 }
602 
ResetProtocols(clientData)603 static void ResetProtocols(clientData)
604     ClientData clientData;
605 {
606     Tix_MwmInfo       * wmPtr = (Tix_MwmInfo *) clientData;
607     int 		numProtocols = wmPtr->protocols.numEntries;
608     Atom 	      * atoms, mwm_menu_atom, motif_msgs;
609     Tcl_HashSearch 	hSearch;
610     Tcl_HashEntry     * hashPtr;
611     Tix_MwmProtocol   * ptPtr;
612     int			n;
613     Tcl_DString		dString;
614 
615     atoms = (Atom*)ckalloc(numProtocols * sizeof(Atom));
616     Tcl_DStringInit(&dString);
617 
618     /* Iterate over all the entries in the hash table */
619     for (hashPtr = Tcl_FirstHashEntry(&wmPtr->protocols, &hSearch), n=0;
620 	 hashPtr;
621 	 hashPtr = Tcl_NextHashEntry(&hSearch)) {
622 	char tmp[100];
623 
624 	ptPtr = (Tix_MwmProtocol *)Tcl_GetHashValue(hashPtr);
625 	if (ptPtr->active) {
626 	    atoms[n++] = ptPtr->protocol;
627 	}
628 
629 	Tcl_DStringAppend(&dString, ptPtr->menuMessage, ptPtr->messageLen);
630 	sprintf(tmp, " f.send_msg %ld\n", ptPtr->protocol);
631 	Tcl_DStringAppend(&dString, tmp, (int)strlen(tmp));
632     }
633 
634     /* Atoms for managing the MWM messages */
635     mwm_menu_atom   = Tk_InternAtom(wmPtr->tkwin, _XA_MWM_MENU);
636     motif_msgs      = Tk_InternAtom(wmPtr->tkwin, "_MOTIF_WM_MESSAGES");
637 
638     /* The _MOTIF_WM_MESSAGES atom must be in the wm_protocols. Otherwise
639      * Mwm refuese to enable our menu items
640      */
641 #if 0
642     if (!wmPtr->addedMwmMsg) {
643 	Tix_GlobalVarEval(wmPtr->interp, "wm protocol ",
644 	    Tk_PathName(wmPtr->tkwin), " _MOTIF_WM_MESSAGES {;}", NULL);
645 	wmPtr->addedMwmMsg = 1;
646     }
647 #endif
648 
649     /*
650      * These are the extra MWM protocols defined by this application.
651      */
652     XChangeProperty(Tk_Display(wmPtr->tkwin), Tk_WindowId(wmPtr->tkwin),
653 	motif_msgs, XA_ATOM, 32, PropModeReplace,
654 	(unsigned char *)atoms, n);
655 
656     /*
657      * Update the MWM menu items
658      */
659     XChangeProperty(Tk_Display(wmPtr->tkwin), Tk_WindowId(wmPtr->tkwin),
660 	mwm_menu_atom, mwm_menu_atom, 8, PropModeReplace,
661 	(unsigned char *)Tcl_DStringValue(&dString), Tcl_DStringLength(&dString));
662 
663     Tcl_DStringFree(&dString);
664     ckfree((char*)atoms);
665 
666     /* Done ! */
667     wmPtr->resetProtocol = 0;
668     if (Tk_IsMapped(wmPtr->tkwin)) {
669 	/* Needs unmap/map to refresh */
670 	RemapWindowWhenIdle(wmPtr);
671     }
672 }
673 
674 
675 static
SetMwmTransientFor(interp,wmPtr,mainWindow,argc,argv)676 int SetMwmTransientFor(interp, wmPtr, mainWindow, argc, argv)
677     Tcl_Interp *interp;
678     Tix_MwmInfo*wmPtr;
679     TkWindow   *mainWindow;
680     int 	argc;
681     char     ** argv;
682 {
683     Atom 	transfor_atom;
684     TkWindow  *	master;
685 
686     transfor_atom = Tk_InternAtom(wmPtr->tkwin, "WM_TRANSIENT_FOR");
687     if (argc == 0) {
688 	return TCL_OK;
689     } else if (argc == 1) {
690 	master = (TkWindow *) Tk_NameToWindow(interp, argv[0],
691 	    (Tk_Window)mainWindow);
692 	if (master == NULL) {
693 	    return TCL_ERROR;
694 	}
695 	XChangeProperty(Tk_Display(wmPtr->tkwin), Tk_WindowId(wmPtr->tkwin),
696 	    transfor_atom, XA_WINDOW, 32, PropModeReplace,
697 	    (unsigned char *)&master->window, 1);
698 	return TCL_OK;
699     } else {
700 	return TCL_ERROR;
701     }
702 }
703 
704 /*
705  *----------------------------------------------------------------------
706  *
707  * StructureProc --
708  *
709  *	Gets called in response to StructureNotify events in toplevels
710  *	operated by the tixMwm command.
711  *
712  * Results:
713  *	none
714  *
715  * Side effects:
716  *	The Tix_MwmInfo for the toplevel is deleted when the toplevel
717  *	is destroyed.
718  *
719  *----------------------------------------------------------------------
720  */
721 static void
StructureProc(clientData,eventPtr)722 StructureProc(clientData, eventPtr)
723     ClientData clientData;		/* Our information about window
724 					 * referred to by eventPtr. */
725     XEvent *eventPtr;			/* Describes what just happened. */
726 {
727     register Tix_MwmInfo * wmPtr = (Tix_MwmInfo *) clientData;
728     Tcl_HashEntry *hashPtr;
729 
730     if (eventPtr->type == DestroyNotify) {
731 	Tcl_HashSearch 	  hSearch;
732 	Tix_MwmProtocol * ptPtr;
733 
734 	/* Delete all protocols in the hash table associated with
735 	 * this toplevel
736 	 */
737 	for (hashPtr = Tcl_FirstHashEntry(&wmPtr->protocols, &hSearch);
738 	     hashPtr;
739 	     hashPtr = Tcl_NextHashEntry(&hSearch)) {
740 
741 	    ptPtr = (Tix_MwmProtocol *)Tcl_GetHashValue(hashPtr);
742 	    ckfree(ptPtr->name);
743 	    ckfree(ptPtr->menuMessage);
744 	    ckfree((char*)ptPtr);
745 	    Tcl_DeleteHashEntry(hashPtr);
746 	}
747 
748 	Tcl_DeleteHashTable(&wmPtr->protocols);
749 
750 	/*
751 	 * Delete info about this toplevel in the table of all toplevels
752 	 * controlled by tixMwm
753 	 */
754 	hashPtr = Tcl_FindHashEntry(&mwmTable, (char*)wmPtr->tkwin);
755 	if (hashPtr != NULL) {
756 	    Tcl_DeleteHashEntry(hashPtr);
757 	}
758 
759 	if (wmPtr->resetProtocol) {
760 	    Tcl_CancelIdleCall(ResetProtocols, (ClientData)wmPtr);
761 	    wmPtr->resetProtocol = 0;
762 	}
763 
764 	ckfree((char*)wmPtr);
765     }
766 }
767 
768 static Tix_MwmInfo *
GetMwmInfo(interp,tkwin)769 GetMwmInfo(interp, tkwin)
770     Tcl_Interp * interp;
771     Tk_Window tkwin;
772 {
773     static int inited = 0;
774     Tcl_HashEntry *hashPtr;
775     int isNew;
776 
777     if (!inited) {
778 	Tcl_InitHashTable(&mwmTable, TCL_ONE_WORD_KEYS);
779 	inited = 1;
780     }
781 
782     hashPtr = Tcl_CreateHashEntry(&mwmTable, (char*)tkwin, &isNew);
783 
784     if (!isNew) {
785 	return (Tix_MwmInfo *)Tcl_GetHashValue(hashPtr);
786     }
787     else {
788 	Tix_MwmInfo * wmPtr;
789 
790 	wmPtr = (Tix_MwmInfo*) ckalloc(sizeof(Tix_MwmInfo));
791 	wmPtr->interp		= interp;
792 	wmPtr->tkwin 	       	= tkwin;
793 	wmPtr->isremapping     	= 0;
794 	wmPtr->resetProtocol   	= 0;
795 	wmPtr->addedMwmMsg    	= 0;
796 	if (Tk_WindowId(wmPtr->tkwin) == 0) {
797 	    Tk_MakeWindowExist(wmPtr->tkwin);
798 	}
799 	wmPtr->mwm_hints_atom  	= Tk_InternAtom(wmPtr->tkwin, _XA_MWM_HINTS);
800 
801 	Tcl_InitHashTable(&wmPtr->protocols, TCL_ONE_WORD_KEYS);
802 
803 	QueryMwmHints(wmPtr);
804 
805 	Tcl_SetHashValue(hashPtr, (char*)wmPtr);
806 
807 	Tk_CreateEventHandler(tkwin, StructureNotifyMask,
808 	    StructureProc, (ClientData)wmPtr);
809 
810 	return wmPtr;
811     }
812 }
813 
814 static Tix_MwmProtocol *
GetMwmProtocol(interp,wmPtr,protocol)815 GetMwmProtocol(interp,  wmPtr, protocol)
816     Tcl_Interp * interp;
817     Tix_MwmInfo * wmPtr;
818     Atom protocol;
819 {
820     Tcl_HashEntry     * hashPtr;
821     int			isNew;
822     Tix_MwmProtocol   * ptPtr;
823 
824     hashPtr = Tcl_CreateHashEntry(&wmPtr->protocols, (char*)protocol, &isNew);
825     if (!isNew) {
826 	ptPtr = (Tix_MwmProtocol *)Tcl_GetHashValue(hashPtr);
827     } else {
828 	ptPtr = (Tix_MwmProtocol *)ckalloc(sizeof(Tix_MwmProtocol));
829 
830 	ptPtr->protocol		= protocol;
831 	ptPtr->name		= NULL;
832 	ptPtr->menuMessage	= NULL;
833 
834 	Tcl_SetHashValue(hashPtr, (char*)ptPtr);
835     }
836 
837     return ptPtr;
838 }
839 
840 
841 static int
IsMwmRunning(interp,wmPtr)842 IsMwmRunning(interp, wmPtr)
843     Tcl_Interp *interp;
844     Tix_MwmInfo*wmPtr;
845 {
846     Atom motif_wm_info_atom;
847     Atom actual_type;
848     int	 actual_format;
849     unsigned long num_items, bytes_after;
850     PropMotifWmInfo *prop = 0;
851     Window root;
852 
853     root = XRootWindow(Tk_Display(wmPtr->tkwin),Tk_ScreenNumber(wmPtr->tkwin));
854     motif_wm_info_atom = Tk_InternAtom(wmPtr->tkwin, _XA_MOTIF_WM_INFO);
855 
856     /*
857      * If mwm is running, it will store info in the _XA_MOTIF_WM_INFO
858      * atom in the root window
859      */
860     XGetWindowProperty (Tk_Display(wmPtr->tkwin),
861 	root, motif_wm_info_atom, 0, (long)PROP_MOTIF_WM_INFO_ELEMENTS,
862 	0, motif_wm_info_atom,	&actual_type, &actual_format,
863 	&num_items, &bytes_after, (unsigned char **) &prop);
864 
865     if ((actual_type != motif_wm_info_atom) || (actual_format != 32) ||
866 	(num_items < PROP_MOTIF_WM_INFO_ELEMENTS)) {
867 
868 	/*
869 	 * The _XA_MOTIF_WM_INFO doesn't exist for the root window.
870 	 * Persumably Mwm is not running.
871 	 */
872 	if (prop) {
873 	    XFree((char *)prop);
874 	}
875 	return(0);
876     }
877     else {
878 	/*
879 	 * We still need to verify that the wm_window is indeed a child of
880 	 * the root window.
881 	 */
882 	Window	wm_window = (Window) prop->wmWindow;
883 	Window	top, parent, *children;
884 	unsigned int num_children;
885 	int	returnVal = 0;
886 	unsigned	i;
887 
888 	if (XQueryTree(Tk_Display(wmPtr->tkwin), root, &top, &parent,
889 	    &children, &num_children)) {
890 
891 	    for (returnVal = 0, i = 0; i < num_children; i++) {
892 		if (children[i] == wm_window) {
893 		    /*
894 		     * is indeed a window of this root: mwm is rinning
895 		     */
896 		    returnVal = 1;
897 		    break;
898 		}
899 	    }
900 	}
901 
902 	if (prop) {
903 	    XFree((char *)prop);
904 	}
905 	if (children) {
906 	    XFree((char *)children);
907 	}
908 
909 	return (returnVal);
910     }
911 }
912