/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkwinembed.c
ViewVC logotype

Annotation of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkwinembed.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (hide annotations) (download)
Sat Nov 5 10:54:17 2016 UTC (7 years, 8 months ago) by dashley
Original Path: projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinembed.c
File MIME type: text/plain
File size: 20290 byte(s)
License and property (keyword) changes.
1 dashley 69 /* $Header$ */
2 dashley 25
3     /*
4     * tkWinEmbed.c --
5     *
6     * This file contains platform specific procedures for Windows platforms
7     * to provide basic operations needed for application embedding (where
8     * one application can use as its main window an internal window from
9     * another application).
10     *
11     * Copyright (c) 1996-1997 Sun Microsystems, Inc.
12     *
13     * See the file "license.terms" for information on usage and redistribution
14     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15     *
16     * RCS: @(#) $Id: tkwinembed.c,v 1.1.1.1 2001/06/13 05:13:10 dtashley Exp $
17     */
18    
19     #include "tkWinInt.h"
20    
21    
22     /*
23     * One of the following structures exists for each container in this
24     * application. It keeps track of the container window and its
25     * associated embedded window.
26     */
27    
28     typedef struct Container {
29     HWND parentHWnd; /* Windows HWND to the parent window */
30     TkWindow *parentPtr; /* Tk's information about the container
31     * or NULL if the container isn't
32     * in this process. */
33     HWND embeddedHWnd; /* Windows HWND to the embedded window
34     */
35     TkWindow *embeddedPtr; /* Tk's information about the embedded
36     * window, or NULL if the
37     * embedded application isn't in
38     * this process. */
39     struct Container *nextPtr; /* Next in list of all containers in
40     * this process. */
41     } Container;
42    
43     typedef struct ThreadSpecificData {
44     Container *firstContainerPtr; /* First in list of all containers
45     * managed by this process. */
46     } ThreadSpecificData;
47     static Tcl_ThreadDataKey dataKey;
48    
49     static void CleanupContainerList _ANSI_ARGS_((
50     ClientData clientData));
51     static void ContainerEventProc _ANSI_ARGS_((ClientData clientData,
52     XEvent *eventPtr));
53     static void EmbeddedEventProc _ANSI_ARGS_((
54     ClientData clientData, XEvent *eventPtr));
55     static void EmbedGeometryRequest _ANSI_ARGS_((
56     Container*containerPtr, int width, int height));
57     static void EmbedWindowDeleted _ANSI_ARGS_((TkWindow *winPtr));
58    
59     /*
60     *----------------------------------------------------------------------
61     *
62     * CleanupContainerList --
63     *
64     * Finalizes the list of containers.
65     *
66     * Results:
67     * None.
68     *
69     * Side effects:
70     * Releases memory occupied by containers of embedded windows.
71     *
72     *----------------------------------------------------------------------
73     */
74    
75     /* ARGSUSED */
76     static void
77     CleanupContainerList(clientData)
78     ClientData clientData;
79     {
80     Container *nextPtr;
81     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
82     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
83    
84     for (;
85     tsdPtr->firstContainerPtr != (Container *) NULL;
86     tsdPtr->firstContainerPtr = nextPtr) {
87     nextPtr = tsdPtr->firstContainerPtr->nextPtr;
88     ckfree((char *) tsdPtr->firstContainerPtr);
89     }
90     tsdPtr->firstContainerPtr = (Container *) NULL;
91     }
92    
93     /*
94     *----------------------------------------------------------------------
95     *
96     * TkpTestembedCmd --
97     *
98     * Test command for the embedding facility.
99     *
100     * Results:
101     * Always returns TCL_OK.
102     *
103     * Side effects:
104     * Currently it does not do anything.
105     *
106     *----------------------------------------------------------------------
107     */
108    
109     /* ARGSUSED */
110     int
111     TkpTestembedCmd(clientData, interp, argc, argv)
112     ClientData clientData;
113     Tcl_Interp *interp;
114     int argc;
115     char **argv;
116     {
117     return TCL_OK;
118     }
119    
120     /*
121     *----------------------------------------------------------------------
122     *
123     * TkpUseWindow --
124     *
125     * This procedure causes a Tk window to use a given Windows handle
126     * for a window as its underlying window, rather than a new Windows
127     * window being created automatically. It is invoked by an embedded
128     * application to specify the window in which the application is
129     * embedded.
130     *
131     * Results:
132     * The return value is normally TCL_OK. If an error occurred (such as
133     * if the argument does not identify a legal Windows window handle),
134     * the return value is TCL_ERROR and an error message is left in the
135     * the interp's result if interp is not NULL.
136     *
137     * Side effects:
138     * None.
139     *
140     *----------------------------------------------------------------------
141     */
142    
143     int
144     TkpUseWindow(interp, tkwin, string)
145     Tcl_Interp *interp; /* If not NULL, used for error reporting
146     * if string is bogus. */
147     Tk_Window tkwin; /* Tk window that does not yet have an
148     * associated X window. */
149     char *string; /* String identifying an X window to use
150     * for tkwin; must be an integer value. */
151     {
152     TkWindow *winPtr = (TkWindow *) tkwin;
153     int id;
154     HWND hwnd;
155     Container *containerPtr;
156     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
157     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
158    
159     if (winPtr->window != None) {
160     panic("TkpUseWindow: Already assigned a window");
161     }
162    
163     if (Tcl_GetInt(interp, string, &id) != TCL_OK) {
164     return TCL_ERROR;
165     }
166     hwnd = (HWND) id;
167    
168     /*
169     * Check if the window is a valid handle. If it is invalid, return
170     * TCL_ERROR and potentially leave an error message in the interp's
171     * result.
172     */
173    
174     if (!IsWindow(hwnd)) {
175     if (interp != (Tcl_Interp *) NULL) {
176     Tcl_AppendResult(interp, "window \"", string,
177     "\" doesn't exist", (char *) NULL);
178     }
179     return TCL_ERROR;
180     }
181    
182     /*
183     * Store the parent window in the platform private data slot so
184     * TkWmMapWindow can use it when creating the wrapper window.
185     */
186    
187     winPtr->privatePtr = (struct TkWindowPrivate*) hwnd;
188    
189     /*
190     * Create an event handler to clean up the Container structure when
191     * tkwin is eventually deleted.
192     */
193    
194     Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc,
195     (ClientData) winPtr);
196    
197     /*
198     * If this is the first container, register an exit handler so that
199     * things will get cleaned up at finalization.
200     */
201    
202     if (tsdPtr->firstContainerPtr == (Container *) NULL) {
203     Tcl_CreateExitHandler(CleanupContainerList, (ClientData) NULL);
204     }
205    
206     /*
207     * Save information about the container and the embedded window
208     * in a Container structure. If there is already an existing
209     * Container structure, it means that both container and embedded
210     * app. are in the same process.
211     */
212    
213     for (containerPtr = tsdPtr->firstContainerPtr;
214     containerPtr != NULL; containerPtr = containerPtr->nextPtr) {
215     if (containerPtr->parentHWnd == hwnd) {
216     winPtr->flags |= TK_BOTH_HALVES;
217     containerPtr->parentPtr->flags |= TK_BOTH_HALVES;
218     break;
219     }
220     }
221     if (containerPtr == NULL) {
222     containerPtr = (Container *) ckalloc(sizeof(Container));
223     containerPtr->parentPtr = NULL;
224     containerPtr->parentHWnd = hwnd;
225     containerPtr->nextPtr = tsdPtr->firstContainerPtr;
226     tsdPtr->firstContainerPtr = containerPtr;
227     }
228    
229     /*
230     * embeddedHWnd is not created yet. It will be created by TkWmMapWindow(),
231     * which will send a TK_ATTACHWINDOW to the container window.
232     * TkWinEmbeddedEventProc will process this message and set the embeddedHWnd
233     * variable
234     */
235    
236     containerPtr->embeddedPtr = winPtr;
237     containerPtr->embeddedHWnd = NULL;
238    
239     winPtr->flags |= TK_EMBEDDED;
240     winPtr->flags &= (~(TK_MAPPED));
241    
242     return TCL_OK;
243     }
244    
245     /*
246     *----------------------------------------------------------------------
247     *
248     * TkpMakeContainer --
249     *
250     * This procedure is called to indicate that a particular window will
251     * be a container for an embedded application. This changes certain
252     * aspects of the window's behavior, such as whether it will receive
253     * events anymore.
254     *
255     * Results:
256     * None.
257     *
258     * Side effects:
259     * None.
260     *
261     *----------------------------------------------------------------------
262     */
263    
264     void
265     TkpMakeContainer(tkwin)
266     Tk_Window tkwin;
267     {
268     TkWindow *winPtr = (TkWindow *) tkwin;
269     Container *containerPtr;
270     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
271     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
272    
273     /*
274     * If this is the first container, register an exit handler so that
275     * things will get cleaned up at finalization.
276     */
277    
278     if (tsdPtr->firstContainerPtr == (Container *) NULL) {
279     Tcl_CreateExitHandler(CleanupContainerList, (ClientData) NULL);
280     }
281    
282     /*
283     * Register the window as a container so that, for example, we can
284     * find out later if the embedded app. is in the same process.
285     */
286    
287     Tk_MakeWindowExist(tkwin);
288     containerPtr = (Container *) ckalloc(sizeof(Container));
289     containerPtr->parentPtr = winPtr;
290     containerPtr->parentHWnd = Tk_GetHWND(Tk_WindowId(tkwin));
291     containerPtr->embeddedHWnd = NULL;
292     containerPtr->embeddedPtr = NULL;
293     containerPtr->nextPtr = tsdPtr->firstContainerPtr;
294     tsdPtr->firstContainerPtr = containerPtr;
295     winPtr->flags |= TK_CONTAINER;
296    
297     /*
298     * Unlike in tkUnixEmbed.c, we don't make any requests for events
299     * in the embedded window here. Now we just allow the embedding
300     * of another TK application into TK windows. When the embedded
301     * window makes a request, that will be done by sending to the
302     * container window a WM_USER message, which will be intercepted
303     * by TkWinContainerProc.
304     *
305     * We need to get structure events of the container itself, though.
306     */
307    
308     Tk_CreateEventHandler(tkwin, StructureNotifyMask,
309     ContainerEventProc, (ClientData) containerPtr);
310     }
311    
312     /*
313     *----------------------------------------------------------------------
314     *
315     * EmbeddedEventProc --
316     *
317     * This procedure is invoked by the Tk event dispatcher when various
318     * useful events are received for a window that is embedded in
319     * another application.
320     *
321     * Results:
322     * None.
323     *
324     * Side effects:
325     * Our internal state gets cleaned up when an embedded window is
326     * destroyed.
327     *
328     *----------------------------------------------------------------------
329     */
330    
331     static void
332     EmbeddedEventProc(clientData, eventPtr)
333     ClientData clientData; /* Token for container window. */
334     XEvent *eventPtr; /* ResizeRequest event. */
335     {
336     TkWindow *winPtr = (TkWindow *) clientData;
337    
338     if (eventPtr->type == DestroyNotify) {
339     EmbedWindowDeleted(winPtr);
340     }
341     }
342    
343     /*
344     *----------------------------------------------------------------------
345     *
346     * TkWinEmbeddedEventProc --
347     *
348     * This procedure is invoked by the Tk event dispatcher when
349     * various useful events are received for the *children* of a
350     * container window. It forwards relevant information, such as
351     * geometry requests, from the events into the container's
352     * application.
353     *
354     * Results:
355     * None.
356     *
357     * Side effects:
358     * Depends on the event. For example, when ConfigureRequest events
359     * occur, geometry information gets set for the container window.
360     *
361     *----------------------------------------------------------------------
362     */
363    
364     LRESULT
365     TkWinEmbeddedEventProc(hwnd, message, wParam, lParam)
366     HWND hwnd;
367     UINT message;
368     WPARAM wParam;
369     LPARAM lParam;
370     {
371     Container *containerPtr;
372     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
373     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
374    
375     /*
376     * Find the Container structure associated with the parent window.
377     */
378    
379     for (containerPtr = tsdPtr->firstContainerPtr;
380     containerPtr->parentHWnd != hwnd;
381     containerPtr = containerPtr->nextPtr) {
382     if (containerPtr == NULL) {
383     panic("TkWinContainerProc couldn't find Container record");
384     }
385     }
386    
387     switch (message) {
388     case TK_ATTACHWINDOW:
389     /* An embedded window (either from this application or from
390     * another application) is trying to attach to this container.
391     * We attach it only if this container is not yet containing any
392     * window.
393     */
394     if (containerPtr->embeddedHWnd == NULL) {
395     containerPtr->embeddedHWnd = (HWND)wParam;
396     } else {
397     return 0;
398     }
399    
400     break;
401     case TK_GEOMETRYREQ:
402     EmbedGeometryRequest(containerPtr, wParam, lParam);
403     break;
404     }
405     return 1;
406     }
407    
408     /*
409     *----------------------------------------------------------------------
410     *
411     * EmbedGeometryRequest --
412     *
413     * This procedure is invoked when an embedded application requests
414     * a particular size. It processes the request (which may or may
415     * not actually resize the window) and reflects the results back
416     * to the embedded application.
417     *
418     * Results:
419     * None.
420     *
421     * Side effects:
422     * If we deny the child's size change request, a Configure event
423     * is synthesized to let the child know that the size is the same
424     * as it used to be. Events get processed while we're waiting for
425     * the geometry managers to do their thing.
426     *
427     *----------------------------------------------------------------------
428     */
429    
430     void
431     EmbedGeometryRequest(containerPtr, width, height)
432     Container *containerPtr; /* Information about the container window. */
433     int width, height; /* Size that the child has requested. */
434     {
435     TkWindow * winPtr = containerPtr->parentPtr;
436    
437     /*
438     * Forward the requested size into our geometry management hierarchy
439     * via the container window. We need to send a Configure event back
440     * to the embedded application even if we decide not to resize
441     * the window; to make this happen, process all idle event handlers
442     * synchronously here (so that the geometry managers have had a
443     * chance to do whatever they want to do), and if the window's size
444     * didn't change then generate a configure event.
445     */
446     Tk_GeometryRequest((Tk_Window)winPtr, width, height);
447    
448     if (containerPtr->embeddedHWnd != NULL) {
449     while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {
450     /* Empty loop body. */
451     }
452    
453     SetWindowPos(containerPtr->embeddedHWnd, NULL,
454     0, 0, winPtr->changes.width, winPtr->changes.height, SWP_NOZORDER);
455     }
456     }
457    
458     /*
459     *----------------------------------------------------------------------
460     *
461     * ContainerEventProc --
462     *
463     * This procedure is invoked by the Tk event dispatcher when
464     * various useful events are received for the container window.
465     *
466     * Results:
467     * None.
468     *
469     * Side effects:
470     * Depends on the event. For example, when ConfigureRequest events
471     * occur, geometry information gets set for the container window.
472     *
473     *----------------------------------------------------------------------
474     */
475    
476     static void
477     ContainerEventProc(clientData, eventPtr)
478     ClientData clientData; /* Token for container window. */
479     XEvent *eventPtr; /* ResizeRequest event. */
480     {
481     Container *containerPtr = (Container *)clientData;
482     Tk_Window tkwin = (Tk_Window)containerPtr->parentPtr;
483    
484     if (eventPtr->type == ConfigureNotify) {
485     if (containerPtr->embeddedPtr == NULL) {
486     return;
487     }
488     /* Resize the embedded window, if there is any */
489     if (containerPtr->embeddedHWnd) {
490     SetWindowPos(containerPtr->embeddedHWnd, NULL,
491     0, 0, Tk_Width(tkwin), Tk_Height(tkwin), SWP_NOZORDER);
492     }
493     } else if (eventPtr->type == DestroyNotify) {
494     /* The container is gone, remove it from the list */
495     EmbedWindowDeleted(containerPtr->parentPtr);
496     }
497     }
498    
499     /*
500     *----------------------------------------------------------------------
501     *
502     * TkpGetOtherWindow --
503     *
504     * If both the container and embedded window are in the same
505     * process, this procedure will return either one, given the other.
506     *
507     * Results:
508     * If winPtr is a container, the return value is the token for the
509     * embedded window, and vice versa. If the "other" window isn't in
510     * this process, NULL is returned.
511     *
512     * Side effects:
513     * None.
514     *
515     *----------------------------------------------------------------------
516     */
517    
518     TkWindow *
519     TkpGetOtherWindow(winPtr)
520     TkWindow *winPtr; /* Tk's structure for a container or
521     * embedded window. */
522     {
523     Container *containerPtr;
524     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
525     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
526    
527     for (containerPtr = tsdPtr->firstContainerPtr; containerPtr != NULL;
528     containerPtr = containerPtr->nextPtr) {
529     if (containerPtr->embeddedPtr == winPtr) {
530     return containerPtr->parentPtr;
531     } else if (containerPtr->parentPtr == winPtr) {
532     return containerPtr->embeddedPtr;
533     }
534     }
535     panic("TkpGetOtherWindow couldn't find window");
536     return NULL;
537     }
538    
539     /*
540     *----------------------------------------------------------------------
541     *
542     * TkpClaimFocus --
543     *
544     * This procedure is invoked when someone asks or the input focus
545     * to be put on a window in an embedded application, but the
546     * application doesn't currently have the focus. It requests the
547     * input focus from the container application.
548     *
549     * Results:
550     * None.
551     *
552     * Side effects:
553     * The input focus may change.
554     *
555     *----------------------------------------------------------------------
556     */
557    
558     void
559     TkpClaimFocus(topLevelPtr, force)
560     TkWindow *topLevelPtr; /* Top-level window containing desired
561     * focus window; should be embedded. */
562     int force; /* One means that the container should
563     * claim the focus if it doesn't
564     * currently have it. */
565     {
566     HWND hwnd = GetParent(Tk_GetHWND(topLevelPtr->window));
567     SendMessage(hwnd, TK_CLAIMFOCUS, (WPARAM) force, 0);
568     }
569    
570     /*
571     *----------------------------------------------------------------------
572     *
573     * TkpRedirectKeyEvent --
574     *
575     * This procedure is invoked when a key press or release event
576     * arrives for an application that does not believe it owns the
577     * input focus. This can happen because of embedding; for example,
578     * X can send an event to an embedded application when the real
579     * focus window is in the container application and is an ancestor
580     * of the container. This procedure's job is to forward the event
581     * back to the application where it really belongs.
582     *
583     * Results:
584     * None.
585     *
586     * Side effects:
587     * The event may get sent to a different application.
588     *
589     *----------------------------------------------------------------------
590     */
591    
592     void
593     TkpRedirectKeyEvent(winPtr, eventPtr)
594     TkWindow *winPtr; /* Window to which the event was originally
595     * reported. */
596     XEvent *eventPtr; /* X event to redirect (should be KeyPress
597     * or KeyRelease). */
598     {
599     /* not implemented */
600     }
601    
602     /*
603     *----------------------------------------------------------------------
604     *
605     * EmbedWindowDeleted --
606     *
607     * This procedure is invoked when a window involved in embedding
608     * (as either the container or the embedded application) is
609     * destroyed. It cleans up the Container structure for the window.
610     *
611     * Results:
612     * None.
613     *
614     * Side effects:
615     * A Container structure may be freed.
616     *
617     *----------------------------------------------------------------------
618     */
619    
620     static void
621     EmbedWindowDeleted(winPtr)
622     TkWindow *winPtr; /* Tk's information about window that
623     * was deleted. */
624     {
625     Container *containerPtr, *prevPtr;
626     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
627     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
628    
629     /*
630     * Find the Container structure for this window work. Delete the
631     * information about the embedded application and free the container's
632     * record.
633     */
634    
635     prevPtr = NULL;
636     containerPtr = tsdPtr->firstContainerPtr;
637     while (1) {
638     if (containerPtr->embeddedPtr == winPtr) {
639     containerPtr->embeddedHWnd = NULL;
640     containerPtr->embeddedPtr = NULL;
641     break;
642     }
643     if (containerPtr->parentPtr == winPtr) {
644     containerPtr->parentPtr = NULL;
645     break;
646     }
647     prevPtr = containerPtr;
648     containerPtr = containerPtr->nextPtr;
649     if (containerPtr == NULL) {
650     panic("EmbedWindowDeleted couldn't find window");
651     }
652     }
653     if ((containerPtr->embeddedPtr == NULL)
654     && (containerPtr->parentPtr == NULL)) {
655     if (prevPtr == NULL) {
656     tsdPtr->firstContainerPtr = containerPtr->nextPtr;
657     } else {
658     prevPtr->nextPtr = containerPtr->nextPtr;
659     }
660     ckfree((char *) containerPtr);
661     }
662     }
663    
664 dashley 69 /* End of tkwinembed.c */

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25