1 /*
2  * bltWindow.c --
3  *
4  *	This module implements additional window functionality for
5  *	the BLT toolkit, such as transparent Tk windows,
6  *	and reparenting Tk windows.
7  *
8  * Copyright 1991-1998 Lucent Technologies, Inc.
9  *
10  * Permission to use, copy, modify, and distribute this software and
11  * its documentation for any purpose and without fee is hereby
12  * granted, provided that the above copyright notice appear in all
13  * copies and that both that the copyright notice and warranty
14  * disclaimer appear in supporting documentation, and that the names
15  * of Lucent Technologies any of their entities not be used in
16  * advertising or publicity pertaining to distribution of the software
17  * without specific, written prior permission.
18  *
19  * Lucent Technologies disclaims all warranties with regard to this
20  * software, including all implied warranties of merchantability and
21  * fitness.  In no event shall Lucent Technologies be liable for any
22  * special, indirect or consequential damages or any damages
23  * whatsoever resulting from loss of use, data or profits, whether in
24  * an action of contract, negligence or other tortuous action, arising
25  * out of or in connection with the use or performance of this
26  * software.
27  */
28 
29 #include "bltInt.h"
30 
31 #include <X11/Xlib.h>
32 #ifndef WIN32
33 #include <X11/Xproto.h>
34 #endif
35 
36 #include <tkInt.h>
37 
38 #ifdef XNQueryInputStyle
39 #define TK_USE_INPUT_METHODS
40 #endif
41 
42 /*
43  * This defines whether we should try to use XIM over-the-spot style
44  * input.  Allow users to override it.  It is a much more elegant use
45  * of XIM, but uses a bit more memory.
46  */
47 #ifndef TK_XIM_SPOT
48 #   define TK_XIM_SPOT	1
49 #endif
50 
51 #ifndef TK_REPARENTED
52 #define TK_REPARENTED 	0
53 #endif
54 
55 #ifdef WIN32
56 /*
57  *----------------------------------------------------------------------
58  *
59  * GetWindowHandle --
60  *
61  *      Returns the XID for the Tk_Window given.  Starting in Tk 8.0,
62  *      the toplevel widgets are wrapped by another window.
63  *      Currently there's no way to get at that window, other than
64  *      what is done here: query the X window hierarchy and grab the
65  *      parent.
66  *
67  * Results:
68  *      Returns the X Window ID of the widget.  If it's a toplevel, then
69  *	the XID of the wrapper is returned.
70  *
71  *----------------------------------------------------------------------
72  */
73 static HWND
GetWindowHandle(Tk_Window tkwin)74 GetWindowHandle(Tk_Window tkwin)
75 {
76     HWND hWnd;
77     Window window;
78 
79     window = Tk_WindowId(tkwin);
80     if (window == None) {
81 	Tk_MakeWindowExist(tkwin);
82     }
83     hWnd = Tk_GetHWND(Tk_WindowId(tkwin));
84 #if (TK_MAJOR_VERSION > 4)
85     if (Tk_IsTopLevel(tkwin)) {
86 	hWnd = GetParent(hWnd);
87     }
88 #endif /* TK_MAJOR_VERSION > 4 */
89     return hWnd;
90 }
91 
92 Window
Blt_GetParent(display,window)93 Blt_GetParent(display, window)
94     Display *display;
95     Window window;
96 {
97     HWND hWnd;
98     hWnd = GetWindowHandle(window);
99     return (Window)hWnd;
100 }
101 
102 #else
103 
104 Window
Blt_GetParent(display,window)105 Blt_GetParent(display, window)
106     Display *display;
107     Window window;
108 {
109     Window root, parent;
110     Window *dummy;
111     unsigned int count;
112 
113     if (XQueryTree(display, window, &root, &parent, &dummy, &count) > 0) {
114 	XFree(dummy);
115 	return parent;
116     }
117     return None;
118 }
119 
120 static Window
GetWindowId(tkwin)121 GetWindowId(tkwin)
122     Tk_Window tkwin;
123 {
124     Window window;
125 
126     Tk_MakeWindowExist(tkwin);
127     window = Tk_WindowId(tkwin);
128 #if (TK_MAJOR_VERSION > 4)
129     if (Tk_IsTopLevel(tkwin)) {
130 	Window parent;
131 
132 	parent = Blt_GetParent(Tk_Display(tkwin), window);
133         if (parent != None && parent != XRootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin))) {
134 	    window = parent;
135 	}
136 	/*window = parent; */
137     }
138 #endif /* TK_MAJOR_VERSION > 4 */
139     return window;
140 }
141 
142 #endif /* WIN32 */
143 
144 /*
145  *----------------------------------------------------------------------
146  *
147  * DoConfigureNotify --
148  *
149  *	Generate a ConfigureNotify event describing the current
150  *	configuration of a window.
151  *
152  * Results:
153  *	None.
154  *
155  * Side effects:
156  *	An event is generated and processed by Tk_HandleEvent.
157  *
158  *----------------------------------------------------------------------
159  */
160 static void
DoConfigureNotify(winPtr)161 DoConfigureNotify(winPtr)
162     Tk_FakeWin *winPtr;		/* Window whose configuration was just
163 				 * changed. */
164 {
165     XEvent event;
166 
167     event.type = ConfigureNotify;
168     event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display);
169     event.xconfigure.send_event = False;
170     event.xconfigure.display = winPtr->display;
171     event.xconfigure.event = winPtr->window;
172     event.xconfigure.window = winPtr->window;
173     event.xconfigure.x = winPtr->changes.x;
174     event.xconfigure.y = winPtr->changes.y;
175     event.xconfigure.width = winPtr->changes.width;
176     event.xconfigure.height = winPtr->changes.height;
177     event.xconfigure.border_width = winPtr->changes.border_width;
178     if (winPtr->changes.stack_mode == Above) {
179 	event.xconfigure.above = winPtr->changes.sibling;
180     } else {
181 	event.xconfigure.above = None;
182     }
183     event.xconfigure.override_redirect = winPtr->atts.override_redirect;
184     Tk_HandleEvent(&event);
185 }
186 
187 /*
188  *--------------------------------------------------------------
189  *
190  * Blt_MakeTransparentWindowExist --
191  *
192  *	Similar to Tk_MakeWindowExist but instead creates a
193  *	transparent window to block for user events from sibling
194  *	windows.
195  *
196  *	Differences from Tk_MakeWindowExist.
197  *
198  *	1. This is always a "busy" window. There's never a
199  *	   platform-specific class procedure to execute instead.
200  *	2. The window is transparent and never will contain children,
201  *	   so colormap information is irrelevant.
202  *
203  * Results:
204  *	None.
205  *
206  * Side effects:
207  *	When the procedure returns, the internal window associated
208  *	with tkwin is guaranteed to exist.  This may require the
209  *	window's ancestors to be created too.
210  *
211  *--------------------------------------------------------------
212  */
213 void
Blt_MakeTransparentWindowExist(tkwin,parent,isBusy)214 Blt_MakeTransparentWindowExist(tkwin, parent, isBusy)
215     Tk_Window tkwin;		/* Token for window. */
216     Window parent;		/* Parent window. */
217     int isBusy;			/*  */
218 {
219     TkWindow *winPtr = (TkWindow *) tkwin;
220     TkWindow *winPtr2;
221     Tcl_HashEntry *hPtr;
222     int notUsed;
223     TkDisplay *dispPtr;
224 #ifdef WIN32
225     HWND hParent;
226     int style;
227     DWORD exStyle;
228     HWND hWnd;
229 #else
230     long int mask;
231 #endif /* WIN32 */
232 
233     if (winPtr->window != None) {
234 	return;			/* Window already exists. */
235     }
236 #ifdef notdef
237     if ((winPtr->parentPtr == NULL) || (winPtr->flags & TK_TOP_LEVEL)) {
238 	parent = XRootWindow(winPtr->display, winPtr->screenNum);
239 	/* TODO: Make the entire screen busy */
240     } else {
241 	if (Tk_WindowId(winPtr->parentPtr) == None) {
242 	    Tk_MakeWindowExist((Tk_Window)winPtr->parentPtr);
243 	}
244     }
245 #endif
246 
247     /* Create a transparent window and put it on top.  */
248 
249 #ifdef WIN32
250     hParent = (HWND) parent;
251     style = (WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
252     exStyle = (WS_EX_TRANSPARENT | WS_EX_TOPMOST);
253 #define TK_WIN_CHILD_CLASS_NAME "TkChild"
254     hWnd = CreateWindowEx(exStyle, TK_WIN_CHILD_CLASS_NAME, NULL, style,
255 	Tk_X(tkwin), Tk_Y(tkwin), Tk_Width(tkwin), Tk_Height(tkwin),
256 	hParent, NULL, (HINSTANCE) Tk_GetHINSTANCE(), NULL);
257     winPtr->window = Tk_AttachHWND(tkwin, hWnd);
258 #else
259     mask = (!isBusy) ? 0 : (CWDontPropagate | CWEventMask);
260     /* Ignore the important events while the window is mapped.  */
261 #define USER_EVENTS  (EnterWindowMask | LeaveWindowMask | KeyPressMask | \
262 	KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask)
263 #define PROP_EVENTS  (KeyPressMask | KeyReleaseMask | ButtonPressMask | \
264 	ButtonReleaseMask | PointerMotionMask)
265 
266     winPtr->atts.do_not_propagate_mask = PROP_EVENTS;
267     winPtr->atts.event_mask = USER_EVENTS;
268     winPtr->changes.border_width = 0;
269     winPtr->depth = 0;
270 
271     winPtr->window = XCreateWindow(winPtr->display, parent,
272 	winPtr->changes.x, winPtr->changes.y,
273 	(unsigned)winPtr->changes.width,	/* width */
274 	(unsigned)winPtr->changes.height,	/* height */
275 	(unsigned)winPtr->changes.border_width,	/* border_width */
276 	winPtr->depth,		/* depth */
277 	InputOnly,		/* class */
278 	winPtr->visual,		/* visual */
279         mask,			/* valuemask */
280 	&(winPtr->atts)		/* attributes */ );
281 #endif /* WIN32 */
282 
283     dispPtr = winPtr->dispPtr;
284     hPtr = Tcl_CreateHashEntry(&(dispPtr->winTable), (char *)winPtr->window,
285 	&notUsed);
286     Tcl_SetHashValue(hPtr, winPtr);
287     winPtr->dirtyAtts = 0;
288     winPtr->dirtyChanges = 0;
289 #ifdef TK_USE_INPUT_METHODS
290     winPtr->inputContext = NULL;
291 #endif /* TK_USE_INPUT_METHODS */
292     if (!(winPtr->flags & TK_TOP_LEVEL)) {
293 	/*
294 	 * If any siblings higher up in the stacking order have already
295 	 * been created then move this window to its rightful position
296 	 * in the stacking order.
297 	 *
298 	 * NOTE: this code ignores any changes anyone might have made
299 	 * to the sibling and stack_mode field of the window's attributes,
300 	 * so it really isn't safe for these to be manipulated except
301 	 * by calling Tk_RestackWindow.
302 	 */
303 	for (winPtr2 = winPtr->nextPtr; winPtr2 != NULL;
304 	    winPtr2 = winPtr2->nextPtr) {
305 	    if ((winPtr2->window != None) && !(winPtr2->flags & TK_TOP_LEVEL)) {
306 		XWindowChanges changes;
307 		changes.sibling = winPtr2->window;
308 		changes.stack_mode = Below;
309 		XConfigureWindow(winPtr->display, winPtr->window,
310 		    CWSibling | CWStackMode, &changes);
311 		break;
312 	    }
313 	}
314     }
315 
316     /*
317      * Issue a ConfigureNotify event if there were deferred configuration
318      * changes (but skip it if the window is being deleted;  the
319      * ConfigureNotify event could cause problems if we're being called
320      * from Tk_DestroyWindow under some conditions).
321      */
322     if ((winPtr->flags & TK_NEED_CONFIG_NOTIFY)
323 	&& !(winPtr->flags & TK_ALREADY_DEAD)) {
324 	winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY;
325 	DoConfigureNotify((Tk_FakeWin *) tkwin);
326     }
327 }
328 
329 /*
330  *----------------------------------------------------------------------
331  *
332  * Blt_FindChild --
333  *
334  *      Performs a linear search for the named child window in a given
335  *	parent window.
336  *
337  *	This can be done via Tcl, but not through Tk's C API.  It's
338  *	simple enough, if you peek into the Tk_Window structure.
339  *
340  * Results:
341  *      The child Tk_Window. If the named child can't be found, NULL
342  *	is returned.
343  *
344  *----------------------------------------------------------------------
345  */
346 
347 /*LINTLIBRARY*/
348 Tk_Window
Blt_FindChild(parent,name)349 Blt_FindChild(parent, name)
350     Tk_Window parent;
351     char *name;
352 {
353     register TkWindow *winPtr;
354     TkWindow *parentPtr = (TkWindow *)parent;
355 
356     for (winPtr = parentPtr->childList; winPtr != NULL;
357 	winPtr = winPtr->nextPtr) {
358 	if (strcmp(name, winPtr->nameUid) == 0) {
359 	    return (Tk_Window)winPtr;
360 	}
361     }
362     return NULL;
363 }
364 
365 /*
366  *----------------------------------------------------------------------
367  *
368  * Blt_FirstChildWindow --
369  *
370  *      Performs a linear search for the named child window in a given
371  *	parent window.
372  *
373  *	This can be done via Tcl, but not through Tk's C API.  It's
374  *	simple enough, if you peek into the Tk_Window structure.
375  *
376  * Results:
377  *      The child Tk_Window. If the named child can't be found, NULL
378  *	is returned.
379  *
380  *----------------------------------------------------------------------
381  */
382 /*LINTLIBRARY*/
383 Tk_Window
Blt_FirstChild(parent)384 Blt_FirstChild(parent)
385     Tk_Window parent;
386 {
387     TkWindow *parentPtr = (TkWindow *)parent;
388     return (Tk_Window)parentPtr->childList;
389 }
390 
391 /*
392  *----------------------------------------------------------------------
393  *
394  * Blt_FindChild --
395  *
396  *      Performs a linear search for the named child window in a given
397  *	parent window.
398  *
399  *	This can be done via Tcl, but not through Tk's C API.  It's
400  *	simple enough, if you peek into the Tk_Window structure.
401  *
402  * Results:
403  *      The child Tk_Window. If the named child can't be found, NULL
404  *	is returned.
405  *
406  *----------------------------------------------------------------------
407  */
408 
409 /*LINTLIBRARY*/
410 Tk_Window
Blt_NextChild(tkwin)411 Blt_NextChild(tkwin)
412     Tk_Window tkwin;
413 {
414     TkWindow *winPtr = (TkWindow *)tkwin;
415 
416     if (winPtr == NULL) {
417 	return NULL;
418     }
419     return (Tk_Window)winPtr->nextPtr;
420 }
421 
422 /*
423  *----------------------------------------------------------------------
424  *
425  * UnlinkWindow --
426  *
427  *	This procedure removes a window from the childList of its
428  *	parent.
429  *
430  * Results:
431  *	None.
432  *
433  * Side effects:
434  *	The window is unlinked from its childList.
435  *
436  *----------------------------------------------------------------------
437  */
438 static void
UnlinkWindow(winPtr)439 UnlinkWindow(winPtr)
440     TkWindow *winPtr;	/* Child window to be unlinked. */
441 {
442     TkWindow *prevPtr;
443 
444     prevPtr = winPtr->parentPtr->childList;
445     if (prevPtr == winPtr) {
446 	winPtr->parentPtr->childList = winPtr->nextPtr;
447 	if (winPtr->nextPtr == NULL) {
448 	    winPtr->parentPtr->lastChildPtr = NULL;
449 	}
450     } else {
451 	while (prevPtr->nextPtr != winPtr) {
452 	    prevPtr = prevPtr->nextPtr;
453 	    if (prevPtr == NULL) {
454 		panic("UnlinkWindow couldn't find child in parent");
455 	    }
456 	}
457 	prevPtr->nextPtr = winPtr->nextPtr;
458 	if (winPtr->nextPtr == NULL) {
459 	    winPtr->parentPtr->lastChildPtr = prevPtr;
460 	}
461     }
462 }
463 
464 /*
465  *----------------------------------------------------------------------
466  *
467  * Blt_RelinkWindow --
468  *
469  *	Relinks a window into a new parent.  The window is unlinked
470  *	from its original parent's child list and added onto the end
471  *	of the new parent's list.
472  *
473  *	FIXME:  If the window has focus, the focus should be moved
474  *		to an ancestor.  Otherwise, Tk becomes confused
475  *		about which Toplevel turns on focus for the window.
476  *		Right now this is done at the Tcl layer.  For example,
477  *		see blt::CreateTearoff in tabset.tcl.
478  *
479  * Results:
480  *	None.
481  *
482  * Side effects:
483  *	The window is unlinked from its childList.
484  *
485  *----------------------------------------------------------------------
486  */
487 void
Blt_RelinkWindow(tkwin,newParent,x,y)488 Blt_RelinkWindow(tkwin, newParent, x, y)
489     Tk_Window tkwin;		/* Child window to be linked. */
490     Tk_Window newParent;
491     int x, y;
492 {
493     TkWindow *winPtr, *parentWinPtr;
494 
495     if (Blt_ReparentWindow(Tk_Display(tkwin), Tk_WindowId(tkwin),
496 	    Tk_WindowId(newParent), x, y) != TCL_OK) {
497 	return;
498     }
499     winPtr = (TkWindow *)tkwin;
500     parentWinPtr = (TkWindow *)newParent;
501 
502     winPtr->flags &= ~TK_REPARENTED;
503     UnlinkWindow(winPtr);	/* Remove the window from its parent's list */
504 
505     /* Append the window onto the end of the parent's list of children */
506     winPtr->parentPtr = parentWinPtr;
507     winPtr->nextPtr = NULL;
508     if (parentWinPtr->childList == NULL) {
509 	parentWinPtr->childList = winPtr;
510     } else {
511 	parentWinPtr->lastChildPtr->nextPtr = winPtr;
512     }
513     parentWinPtr->lastChildPtr = winPtr;
514 }
515 
516 /*
517  *----------------------------------------------------------------------
518  *
519  * Blt_RelinkWindow --
520  *
521  *	Relinks a window into a new parent.  The window is unlinked
522  *	from its original parent's child list and added onto the end
523  *	of the new parent's list.
524  *
525  *	FIXME:  If the window has focus, the focus should be moved
526  *		to an ancestor.  Otherwise, Tk becomes confused
527  *		about which Toplevel turns on focus for the window.
528  *		Right now this is done at the Tcl layer.  For example,
529  *		see blt::CreateTearoff in tabset.tcl.
530  *
531  * Results:
532  *	None.
533  *
534  * Side effects:
535  *	The window is unlinked from its childList.
536  *
537  *----------------------------------------------------------------------
538  */
539 void
Blt_RelinkWindow2(tkwin,window,newParent,x,y)540 Blt_RelinkWindow2(tkwin, window, newParent, x, y)
541     Tk_Window tkwin;		/* Child window to be linked. */
542     Window window;
543     Tk_Window newParent;
544     int x, y;
545 {
546 #ifdef notdef
547     TkWindow *winPtr, *parentWinPtr;
548 #endif
549     if (Blt_ReparentWindow(Tk_Display(tkwin), window,
550 	    Tk_WindowId(newParent), x, y) != TCL_OK) {
551 	return;
552     }
553 #ifdef notdef
554     winPtr = (TkWindow *)tkwin;
555     parentWinPtr = (TkWindow *)newParent;
556 
557     winPtr->flags &= ~TK_REPARENTED;
558     UnlinkWindow(winPtr);	/* Remove the window from its parent's list */
559 
560     /* Append the window onto the end of the parent's list of children */
561     winPtr->parentPtr = parentWinPtr;
562     winPtr->nextPtr = NULL;
563     if (parentWinPtr->childList == NULL) {
564 	parentWinPtr->childList = winPtr;
565     } else {
566 	parentWinPtr->lastChildPtr->nextPtr = winPtr;
567     }
568     parentWinPtr->lastChildPtr = winPtr;
569 #endif
570 }
571 
572 void
Blt_UnlinkWindow(tkwin)573 Blt_UnlinkWindow(tkwin)
574     Tk_Window tkwin;		/* Child window to be linked. */
575 {
576     TkWindow *winPtr;
577     Window root;
578 
579     root = XRootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
580     if (Blt_ReparentWindow(Tk_Display(tkwin), Tk_WindowId(tkwin),
581 	    root, 0, 0) != TCL_OK) {
582 	return;
583     }
584     winPtr = (TkWindow *)tkwin;
585     winPtr->flags &= ~TK_REPARENTED;
586 #ifdef notdef
587     UnlinkWindow(winPtr);	/* Remove the window from its parent's list */
588 #endif
589 }
590 
591 /*
592  *----------------------------------------------------------------------
593  *
594  * Blt_Toplevel --
595  *
596  *      Climbs up the widget hierarchy to find the top level window of
597  *      the window given.
598  *
599  * Results:
600  *      Returns the Tk_Window of the toplevel widget.
601  *
602  *----------------------------------------------------------------------
603  */
604 Tk_Window
Blt_Toplevel(tkwin)605 Blt_Toplevel(tkwin)
606     register Tk_Window tkwin;
607 {
608     while (!Tk_IsTopLevel(tkwin)) {
609 	tkwin = Tk_Parent(tkwin);
610     }
611     return tkwin;
612 }
613 
614 void
Blt_RootCoordinates(tkwin,x,y,rootXPtr,rootYPtr)615 Blt_RootCoordinates(tkwin, x, y, rootXPtr, rootYPtr)
616     Tk_Window tkwin;
617     int x, y;
618     int *rootXPtr, *rootYPtr;
619 {
620     int vx, vy, vw, vh;
621     int rootX, rootY;
622 
623     Tk_GetRootCoords(tkwin, &rootX, &rootY);
624     x += rootX;
625     y += rootY;
626     Tk_GetVRootGeometry(tkwin, &vx, &vy, &vw, &vh);
627     x += vx;
628     y += vy;
629     *rootXPtr = x;
630     *rootYPtr = y;
631 }
632 
633 
634 /* Find the toplevel then  */
635 int
Blt_RootX(tkwin)636 Blt_RootX(tkwin)
637     Tk_Window tkwin;
638 {
639     int x;
640 
641     for (x = 0; tkwin != NULL;  tkwin = Tk_Parent(tkwin)) {
642 	x += Tk_X(tkwin) + Tk_Changes(tkwin)->border_width;
643 	if (Tk_IsTopLevel(tkwin)) {
644 	    break;
645 	}
646     }
647     return x;
648 }
649 
650 int
Blt_RootY(tkwin)651 Blt_RootY(tkwin)
652     Tk_Window tkwin;
653 {
654     int y;
655 
656     for (y = 0; tkwin != NULL;  tkwin = Tk_Parent(tkwin)) {
657 	y += Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width;
658 	if (Tk_IsTopLevel(tkwin)) {
659 	    break;
660 	}
661     }
662     return y;
663 }
664 
665 #ifdef WIN32
666 /*
667  *----------------------------------------------------------------------
668  *
669  * Blt_GetRealWindowId --
670  *
671  *      Returns the XID for the Tk_Window given.  Starting in Tk 8.0,
672  *      the toplevel widgets are wrapped by another window.
673  *      Currently there's no way to get at that window, other than
674  *      what is done here: query the X window hierarchy and grab the
675  *      parent.
676  *
677  * Results:
678  *      Returns the X Window ID of the widget.  If it's a toplevel, then
679  *	the XID of the wrapper is returned.
680  *
681  *----------------------------------------------------------------------
682  */
683 Window
Blt_GetRealWindowId(Tk_Window tkwin)684 Blt_GetRealWindowId(Tk_Window tkwin)
685 {
686     return (Window) GetWindowHandle(tkwin);
687 }
688 
689 /*
690  *----------------------------------------------------------------------
691  *
692  * Blt_GetToplevel --
693  *
694  *      Retrieves the toplevel window which is the nearest ancestor of
695  *      of the specified window.
696  *
697  * Results:
698  *      Returns the toplevel window or NULL if the window has no
699  *      ancestor which is a toplevel.
700  *
701  * Side effects:
702  *      None.
703  *
704  *----------------------------------------------------------------------
705  */
706 Tk_Window
Blt_GetToplevel(Tk_Window tkwin)707 Blt_GetToplevel(Tk_Window tkwin) /* Window for which the toplevel
708 				  * should be deterined. */
709 {
710      while (!Tk_IsTopLevel(tkwin)) {
711          tkwin = Tk_Parent(tkwin);
712 	 if (tkwin == NULL) {
713              return NULL;
714          }
715      }
716      return tkwin;
717 }
718 
719 /*
720  *----------------------------------------------------------------------
721  *
722  * Blt_RaiseToLevelWindow --
723  *
724  * Results:
725  *	None.
726  *
727  *----------------------------------------------------------------------
728  */
729 void
Blt_RaiseToplevel(Tk_Window tkwin)730 Blt_RaiseToplevel(Tk_Window tkwin)
731 {
732     SetWindowPos(GetWindowHandle(tkwin), HWND_TOP, 0, 0, 0, 0,
733 	SWP_NOMOVE | SWP_NOSIZE);
734 }
735 
736 /*
737  *----------------------------------------------------------------------
738  *
739  * Blt_MapToplevel --
740  *
741  * Results:
742  *	None.
743  *
744  *----------------------------------------------------------------------
745  */
746 void
Blt_MapToplevel(Tk_Window tkwin)747 Blt_MapToplevel(Tk_Window tkwin)
748 {
749     ShowWindow(GetWindowHandle(tkwin), SW_SHOWNORMAL);
750 }
751 
752 /*
753  *----------------------------------------------------------------------
754  *
755  * Blt_UnmapToplevel --
756  *
757  * Results:
758  *	None.
759  *
760  *----------------------------------------------------------------------
761  */
762 void
Blt_UnmapToplevel(Tk_Window tkwin)763 Blt_UnmapToplevel(Tk_Window tkwin)
764 {
765     ShowWindow(GetWindowHandle(tkwin), SW_HIDE);
766 }
767 
768 /*
769  *----------------------------------------------------------------------
770  *
771  * Blt_MoveResizeToplevel --
772  *
773  * Results:
774  *	None.
775  *
776  *----------------------------------------------------------------------
777  */
778 void
Blt_MoveResizeToplevel(tkwin,x,y,width,height)779 Blt_MoveResizeToplevel(tkwin, x, y, width, height)
780     Tk_Window tkwin;
781     int x, y, width, height;
782 {
783     SetWindowPos(GetWindowHandle(tkwin), HWND_TOP, x, y, width, height, 0);
784 }
785 
786 int
Blt_ReparentWindow(Display * display,Window window,Window newParent,int x,int y)787 Blt_ReparentWindow(
788     Display *display,
789     Window window,
790     Window newParent,
791     int x, int y)
792 {
793     XReparentWindow(display, window, newParent, x, y);
794     return TCL_OK;
795 }
796 
797 #else  /* WIN32 */
798 
799 /*
800  *----------------------------------------------------------------------
801  *
802  * Blt_GetRealWindowId --
803  *
804  *      Returns the XID for the Tk_Window given.  Starting in Tk 8.0,
805  *      the toplevel widgets are wrapped by another window.
806  *      Currently there's no way to get at that window, other than
807  *      what is done here: query the X window hierarchy and grab the
808  *      parent.
809  *
810  * Results:
811  *      Returns the X Window ID of the widget.  If it's a toplevel, then
812  *	the XID of the wrapper is returned.
813  *
814  *----------------------------------------------------------------------
815  */
816 Window
Blt_GetRealWindowId(tkwin)817 Blt_GetRealWindowId(tkwin)
818     Tk_Window tkwin;
819 {
820     return GetWindowId(tkwin);
821 }
822 
823 /*
824  *----------------------------------------------------------------------
825  *
826  * Blt_RaiseToplevel --
827  *
828  * Results:
829  *	None.
830  *
831  *----------------------------------------------------------------------
832  */
833 void
Blt_RaiseToplevel(tkwin)834 Blt_RaiseToplevel(tkwin)
835     Tk_Window tkwin;
836 {
837     XRaiseWindow(Tk_Display(tkwin), GetWindowId(tkwin));
838 }
839 
840 /*
841  *----------------------------------------------------------------------
842  *
843  * Blt_LowerToplevel --
844  *
845  * Results:
846  *	None.
847  *
848  *----------------------------------------------------------------------
849  */
850 void
Blt_LowerToplevel(tkwin)851 Blt_LowerToplevel(tkwin)
852     Tk_Window tkwin;
853 {
854     XLowerWindow(Tk_Display(tkwin), GetWindowId(tkwin));
855 }
856 
857 /*
858  *----------------------------------------------------------------------
859  *
860  * Blt_ResizeToplevel --
861  *
862  * Results:
863  *	None.
864  *
865  *----------------------------------------------------------------------
866  */
867 void
Blt_ResizeToplevel(tkwin,width,height)868 Blt_ResizeToplevel(tkwin, width, height)
869     Tk_Window tkwin;
870     int width, height;
871 {
872     XResizeWindow(Tk_Display(tkwin), GetWindowId(tkwin), width, height);
873 }
874 
875 /*
876  *----------------------------------------------------------------------
877  *
878  * Blt_MoveResizeToplevel --
879  *
880  * Results:
881  *	None.
882  *
883  *----------------------------------------------------------------------
884  */
885 void
Blt_MoveResizeToplevel(tkwin,x,y,width,height)886 Blt_MoveResizeToplevel(tkwin, x, y, width, height)
887     Tk_Window tkwin;
888     int x, y, width, height;
889 {
890     XMoveResizeWindow(Tk_Display(tkwin), GetWindowId(tkwin), x, y,
891 	      width, height);
892 }
893 
894 /*
895  *----------------------------------------------------------------------
896  *
897  * Blt_ResizeToplevel --
898  *
899  * Results:
900  *	None.
901  *
902  *----------------------------------------------------------------------
903  */
904 void
Blt_MoveToplevel(tkwin,x,y)905 Blt_MoveToplevel(tkwin, x, y)
906     Tk_Window tkwin;
907     int x, y;
908 {
909     XMoveWindow(Tk_Display(tkwin), GetWindowId(tkwin), x, y);
910 }
911 
912 /*
913  *----------------------------------------------------------------------
914  *
915  * Blt_MapToplevel --
916  *
917  * Results:
918  *	None.
919  *
920  *----------------------------------------------------------------------
921  */
922 void
Blt_MapToplevel(tkwin)923 Blt_MapToplevel(tkwin)
924     Tk_Window tkwin;
925 {
926     XMapWindow(Tk_Display(tkwin), GetWindowId(tkwin));
927 }
928 
929 /*
930  *----------------------------------------------------------------------
931  *
932  * Blt_UnmapToplevel --
933  *
934  * Results:
935  *	None.
936  *
937  *----------------------------------------------------------------------
938  */
939 void
Blt_UnmapToplevel(tkwin)940 Blt_UnmapToplevel(tkwin)
941     Tk_Window tkwin;
942 {
943     XUnmapWindow(Tk_Display(tkwin), GetWindowId(tkwin));
944 }
945 
946 /* ARGSUSED */
947 static int
XReparentWindowErrorProc(clientData,errEventPtr)948 XReparentWindowErrorProc(clientData, errEventPtr)
949     ClientData clientData;
950     XErrorEvent *errEventPtr;
951 {
952     int *errorPtr = clientData;
953 
954     *errorPtr = TCL_ERROR;
955     return 0;
956 }
957 
958 int
Blt_ReparentWindow(display,window,newParent,x,y)959 Blt_ReparentWindow(display, window, newParent, x, y)
960     Display *display;
961     Window window, newParent;
962     int x, y;
963 {
964     Tk_ErrorHandler handler;
965     int result;
966     int any = -1;
967 
968     result = TCL_OK;
969     handler = Tk_CreateErrorHandler(display, any, X_ReparentWindow, any,
970 	XReparentWindowErrorProc, &result);
971     XReparentWindow(display, window, newParent, x, y);
972     Tk_DeleteErrorHandler(handler);
973     XSync(display, False);
974     return result;
975 }
976 
977 #endif /* WIN32 */
978 
979 #if (TK_MAJOR_VERSION == 4)
980 #include <bltHash.h>
981 static int initialized = FALSE;
982 static Blt_HashTable windowTable;
983 
984 void
Blt_SetWindowInstanceData(tkwin,instanceData)985 Blt_SetWindowInstanceData(tkwin, instanceData)
986     Tk_Window tkwin;
987     ClientData instanceData;
988 {
989     Blt_HashEntry *hPtr;
990     int isNew;
991 
992     if (!initialized) {
993 	Blt_InitHashTable(&windowTable, BLT_ONE_WORD_KEYS);
994 	initialized = TRUE;
995     }
996     hPtr = Blt_CreateHashEntry(&windowTable, (char *)tkwin, &isNew);
997     assert(isNew);
998     Blt_SetHashValue(hPtr, instanceData);
999 }
1000 
1001 ClientData
Blt_GetWindowInstanceData(tkwin)1002 Blt_GetWindowInstanceData(tkwin)
1003     Tk_Window tkwin;
1004 {
1005     Blt_HashEntry *hPtr;
1006 
1007     hPtr = Blt_FindHashEntry(&windowTable, (char *)tkwin);
1008     if (hPtr == NULL) {
1009 	return NULL;
1010     }
1011     return Blt_GetHashValue(hPtr);
1012 }
1013 
1014 void
Blt_DeleteWindowInstanceData(tkwin)1015 Blt_DeleteWindowInstanceData(tkwin)
1016     Tk_Window tkwin;
1017 {
1018     Blt_HashEntry *hPtr;
1019 
1020     hPtr = Blt_FindHashEntry(&windowTable, (char *)tkwin);
1021     assert(hPtr);
1022     Blt_DeleteHashEntry(&windowTable, hPtr);
1023 }
1024 
1025 #else
1026 
1027 void
Blt_SetWindowInstanceData(tkwin,instanceData)1028 Blt_SetWindowInstanceData(tkwin, instanceData)
1029     Tk_Window tkwin;
1030     ClientData instanceData;
1031 {
1032     TkWindow *winPtr = (TkWindow *)tkwin;
1033 
1034     winPtr->instanceData = instanceData;
1035 }
1036 
1037 ClientData
Blt_GetWindowInstanceData(tkwin)1038 Blt_GetWindowInstanceData(tkwin)
1039     Tk_Window tkwin;
1040 {
1041     TkWindow *winPtr = (TkWindow *)tkwin;
1042 
1043     return winPtr->instanceData;
1044 }
1045 
1046 void
Blt_DeleteWindowInstanceData(tkwin)1047 Blt_DeleteWindowInstanceData(tkwin)
1048     Tk_Window tkwin;
1049 {
1050 }
1051 
1052 #endif
1053 
1054