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

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinembed.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 71 - (show annotations) (download)
Sat Nov 5 11:07:06 2016 UTC (7 years, 11 months ago) by dashley
File MIME type: text/plain
File size: 19626 byte(s)
Set EOL properties appropriately to facilitate simultaneous Linux and Windows development.
1 /* $Header$ */
2
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 /* End of tkwinembed.c */

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25