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