OSDN Git Service

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