~ubuntu-branches/ubuntu/dapper/tk8.0/dapper-updates

« back to all changes in this revision

Viewing changes to mac/tkMacEmbed.c

  • Committer: Bazaar Package Importer
  • Author(s): Mike Markley
  • Date: 2001-07-24 21:57:40 UTC
  • Revision ID: james.westby@ubuntu.com-20010724215740-r70t25rtmbqjil2h
Tags: upstream-8.0.5
ImportĀ upstreamĀ versionĀ 8.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * tkMacEmbed.c --
 
3
 *
 
4
 *      This file contains platform-specific procedures for theMac to provide
 
5
 *      basic operations needed for application embedding (where one
 
6
 *      application can use as its main window an internal window from
 
7
 *      some other application).
 
8
 *      Currently only Toplevel embedding within the same Tk application is
 
9
 *      allowed on the Macintosh.
 
10
 *
 
11
 * Copyright (c) 1996-97 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: tkMacEmbed.c,v 1.3 1998/09/14 18:23:35 stanton Exp $
 
17
 */
 
18
 
 
19
#include "tkInt.h"
 
20
#include "tkPort.h"
 
21
#include "X.h"
 
22
#include "Xlib.h"
 
23
#include <stdio.h>
 
24
 
 
25
#include <Windows.h>
 
26
#include <QDOffscreen.h>
 
27
#include "tkMacInt.h"
 
28
 
 
29
/*
 
30
 * One of the following structures exists for each container in this
 
31
 * application.  It keeps track of the container window and its
 
32
 * associated embedded window.
 
33
 */
 
34
 
 
35
typedef struct Container {
 
36
    Window parent;              /* The Mac Drawable for the parent of
 
37
                                 * the pair (the container). */
 
38
    TkWindow *parentPtr;        /* Tk's information about the container,
 
39
                                 * or NULL if the container isn't
 
40
                                 * in this process. */
 
41
    Window embedded;            /* The MacDrawable for the embedded
 
42
                                 * window.  Starts off as None, but
 
43
                                 * gets filled in when the window is
 
44
                                 * eventually created. */
 
45
    TkWindow *embeddedPtr;      /* Tk's information about the embedded
 
46
                                 * window, or NULL if the
 
47
                                 * embedded application isn't in
 
48
                                 * this process. */
 
49
    struct Container *nextPtr;  /* Next in list of all containers in
 
50
                                 * this process. */
 
51
} Container;
 
52
 
 
53
static Container *firstContainerPtr = NULL;
 
54
                                        /* First in list of all containers
 
55
                                         * managed by this process.  */
 
56
/*
 
57
 * Globals defined in this file
 
58
 */
 
59
 
 
60
TkMacEmbedHandler *gMacEmbedHandler = NULL;
 
61
 
 
62
/*
 
63
 * Prototypes for static procedures defined in this file:
 
64
 */
 
65
 
 
66
static void             ContainerEventProc _ANSI_ARGS_((
 
67
                            ClientData clientData, XEvent *eventPtr));
 
68
static void             EmbeddedEventProc _ANSI_ARGS_((
 
69
                            ClientData clientData, XEvent *eventPtr));
 
70
static void             EmbedActivateProc _ANSI_ARGS_((ClientData clientData, 
 
71
                            XEvent *eventPtr));
 
72
static void             EmbedFocusProc _ANSI_ARGS_((ClientData clientData,
 
73
                            XEvent *eventPtr));
 
74
static void             EmbedGeometryRequest _ANSI_ARGS_((
 
75
                            Container * containerPtr, int width, int height));
 
76
static void             EmbedSendConfigure _ANSI_ARGS_((
 
77
                            Container *containerPtr));
 
78
static void             EmbedStructureProc _ANSI_ARGS_((ClientData clientData,
 
79
                            XEvent *eventPtr));
 
80
static void             EmbedWindowDeleted _ANSI_ARGS_((TkWindow *winPtr));
 
81
 
 
82
 
 
83
/*
 
84
 *----------------------------------------------------------------------
 
85
 *
 
86
 * Tk_MacSetEmbedHandler --
 
87
 *
 
88
 *      Registers a handler for an in process form of embedding, like 
 
89
 *      Netscape plugins, where Tk is loaded into the process, but does
 
90
 *      not control the main window
 
91
 *
 
92
 * Results:
 
93
 *      None
 
94
 *
 
95
 * Side effects:
 
96
 *      The embed handler is set.
 
97
 *
 
98
 *----------------------------------------------------------------------
 
99
 */
 
100
void
 
101
Tk_MacSetEmbedHandler(
 
102
    Tk_MacEmbedRegisterWinProc *registerWinProc,
 
103
    Tk_MacEmbedGetGrafPortProc *getPortProc,
 
104
    Tk_MacEmbedMakeContainerExistProc *containerExistProc,
 
105
    Tk_MacEmbedGetClipProc *getClipProc,
 
106
    Tk_MacEmbedGetOffsetInParentProc *getOffsetProc)
 
107
{
 
108
    if (gMacEmbedHandler == NULL) {
 
109
        gMacEmbedHandler = (TkMacEmbedHandler *) ckalloc(sizeof(TkMacEmbedHandler));
 
110
    }
 
111
    gMacEmbedHandler->registerWinProc = registerWinProc;
 
112
    gMacEmbedHandler->getPortProc = getPortProc;
 
113
    gMacEmbedHandler->containerExistProc = containerExistProc;
 
114
    gMacEmbedHandler->getClipProc = getClipProc;
 
115
    gMacEmbedHandler->getOffsetProc = getOffsetProc;    
 
116
}
 
117
 
 
118
 
 
119
/*
 
120
 *----------------------------------------------------------------------
 
121
 *
 
122
 * TkpMakeWindow --
 
123
 *
 
124
 *      Creates an X Window (Mac subwindow).
 
125
 *
 
126
 * Results:
 
127
 *      The window id is returned.
 
128
 *
 
129
 * Side effects:
 
130
 *      None.
 
131
 *
 
132
 *----------------------------------------------------------------------
 
133
 */
 
134
 
 
135
Window
 
136
TkpMakeWindow(
 
137
    TkWindow *winPtr,
 
138
    Window parent)
 
139
{
 
140
    MacDrawable *macWin;
 
141
    XEvent event;
 
142
 
 
143
    /*
 
144
     * If this window is marked as embedded then
 
145
     * the window structure should have already been
 
146
     * created in the TkpUseWindow function.
 
147
     */
 
148
    
 
149
    if (Tk_IsEmbedded(winPtr)) {
 
150
        return (Window) winPtr->privatePtr;
 
151
    }
 
152
    
 
153
    /*
 
154
     * Allocate sub window
 
155
     */
 
156
    
 
157
    macWin = (MacDrawable *) ckalloc(sizeof(MacDrawable));
 
158
    if (macWin == NULL) {
 
159
        winPtr->privatePtr = NULL;
 
160
        return None;
 
161
    }
 
162
    macWin->winPtr = winPtr;
 
163
    winPtr->privatePtr = macWin;
 
164
    macWin->clipRgn = NewRgn();
 
165
    macWin->aboveClipRgn = NewRgn();
 
166
    macWin->referenceCount = 0;
 
167
    macWin->flags = TK_CLIP_INVALID;
 
168
 
 
169
    if (Tk_IsTopLevel(macWin->winPtr)) {
 
170
        
 
171
        /*
 
172
         *This will be set when we are mapped.
 
173
         */
 
174
        
 
175
        macWin->portPtr = (GWorldPtr) NULL;  
 
176
        macWin->toplevel = macWin;
 
177
        macWin->xOff = 0;
 
178
        macWin->yOff = 0;
 
179
    } else {
 
180
        macWin->portPtr = NULL;
 
181
        macWin->xOff = winPtr->parentPtr->privatePtr->xOff +
 
182
            winPtr->parentPtr->changes.border_width +
 
183
            winPtr->changes.x;
 
184
        macWin->yOff = winPtr->parentPtr->privatePtr->yOff +
 
185
            winPtr->parentPtr->changes.border_width +
 
186
            winPtr->changes.y;
 
187
        macWin->toplevel = winPtr->parentPtr->privatePtr->toplevel;
 
188
    }
 
189
 
 
190
    macWin->toplevel->referenceCount++;
 
191
    
 
192
    /* 
 
193
     * TODO: need general solution for visibility events.
 
194
     */
 
195
    event.xany.serial = Tk_Display(winPtr)->request;
 
196
    event.xany.send_event = False;
 
197
    event.xany.display = Tk_Display(winPtr);
 
198
        
 
199
    event.xvisibility.type = VisibilityNotify;
 
200
    event.xvisibility.window = (Window) macWin;;
 
201
    event.xvisibility.state = VisibilityUnobscured;
 
202
    Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
 
203
 
 
204
    return (Window) macWin;
 
205
}
 
206
 
 
207
/*
 
208
 *----------------------------------------------------------------------
 
209
 *
 
210
 * TkpUseWindow --
 
211
 *
 
212
 *      This procedure causes a Tk window to use a given X window as
 
213
 *      its parent window, rather than the root window for the screen.
 
214
 *      It is invoked by an embedded application to specify the window
 
215
 *      in which it is embedded.
 
216
 *
 
217
 * Results:
 
218
 *      The return value is normally TCL_OK.  If an error occurs (such
 
219
 *      as string not being a valid window spec), then the return value
 
220
 *      is TCL_ERROR and an error message is left in interp->result if
 
221
 *      interp is non-NULL.
 
222
 *
 
223
 * Side effects:
 
224
 *      None.
 
225
 *
 
226
 *----------------------------------------------------------------------
 
227
 */
 
228
 
 
229
int
 
230
TkpUseWindow(
 
231
    Tcl_Interp *interp,         /* If not NULL, used for error reporting
 
232
                                 * if string is bogus. */
 
233
    Tk_Window tkwin,            /* Tk window that does not yet have an
 
234
                                 * associated X window. */
 
235
    char *string)               /* String identifying an X window to use
 
236
                                 * for tkwin;  must be an integer value. */
 
237
{
 
238
    TkWindow *winPtr = (TkWindow *) tkwin;
 
239
    MacDrawable *parent, *macWin;
 
240
    Container *containerPtr;
 
241
    XEvent event;
 
242
    int result;
 
243
 
 
244
    if (winPtr->window != None) {
 
245
        panic("TkpUseWindow: X window already assigned");
 
246
    }
 
247
    
 
248
    /*
 
249
     * Decode the container pointer, and look for it among the 
 
250
     *list of available containers.
 
251
     *
 
252
     * N.B. For now, we are limiting the containers to be in the same Tk
 
253
     * application as tkwin, since otherwise they would not be in our list
 
254
     * of containers.
 
255
     *
 
256
     */
 
257
     
 
258
    if (Tcl_GetInt(interp, string, &result) != TCL_OK) {
 
259
        return TCL_ERROR;
 
260
    }
 
261
 
 
262
    parent = (MacDrawable *) result;
 
263
 
 
264
    /*
 
265
     * Save information about the container and the embedded window
 
266
     * in a Container structure.  Currently, there must already be an existing
 
267
     * Container structure, since we only allow the case where both container 
 
268
     * and embedded app. are in the same process.
 
269
     */
 
270
 
 
271
    for (containerPtr = firstContainerPtr; containerPtr != NULL;
 
272
            containerPtr = containerPtr->nextPtr) {
 
273
        if (containerPtr->parent == (Window) parent) {
 
274
            winPtr->flags |= TK_BOTH_HALVES;
 
275
            containerPtr->parentPtr->flags |= TK_BOTH_HALVES;
 
276
            break;
 
277
        }
 
278
    }
 
279
    
 
280
    /*
 
281
     * Make the embedded window.  
 
282
     */
 
283
 
 
284
    macWin = (MacDrawable *) ckalloc(sizeof(MacDrawable));
 
285
    if (macWin == NULL) {
 
286
        winPtr->privatePtr = NULL;
 
287
        return TCL_ERROR;
 
288
    }
 
289
    
 
290
    macWin->winPtr = winPtr;
 
291
    winPtr->privatePtr = macWin;
 
292
 
 
293
    /*
 
294
     * The portPtr will be NULL for a Tk in Tk embedded window.
 
295
     * It is none of our business what it is for a Tk not in Tk embedded window,
 
296
     * but we will initialize it to NULL, and let the registerWinProc 
 
297
     * set it.  In any case, you must always use TkMacGetDrawablePort 
 
298
     * to get the portPtr.  It will correctly find the container's port.
 
299
     */
 
300
 
 
301
    macWin->portPtr = (GWorldPtr) NULL;
 
302
 
 
303
    macWin->clipRgn = NewRgn();
 
304
    macWin->aboveClipRgn = NewRgn();
 
305
    macWin->referenceCount = 0;
 
306
    macWin->flags = TK_CLIP_INVALID;
 
307
    macWin->toplevel = macWin;
 
308
    macWin->toplevel->referenceCount++;
 
309
   
 
310
    winPtr->flags |= TK_EMBEDDED;
 
311
    
 
312
    
 
313
    /*
 
314
     * Make a copy of the TK_EMBEDDED flag, since sometimes
 
315
     * we need this to get the port after the TkWindow structure
 
316
     * has been freed.
 
317
     */
 
318
     
 
319
    macWin->flags |= TK_EMBEDDED;
 
320
    
 
321
    /*
 
322
     * Now check whether it is embedded in another Tk widget.  If not (the first
 
323
     * case below) we see if there is an in-process embedding handler registered,
 
324
     * and if so, let that fill in the rest of the macWin.
 
325
     */
 
326
    
 
327
    if (containerPtr == NULL) {
 
328
        /*
 
329
         * If someone has registered an in process embedding handler, then 
 
330
         * see if it can handle this window...
 
331
         */
 
332
        
 
333
        if (gMacEmbedHandler == NULL ||
 
334
                gMacEmbedHandler->registerWinProc(result, (Tk_Window) winPtr) != TCL_OK) {
 
335
            Tcl_AppendResult(interp, "The window ID ", string,
 
336
                    " does not correspond to a valid Tk Window.",
 
337
                     (char *) NULL);
 
338
            return TCL_ERROR;   
 
339
        } else {
 
340
            containerPtr = (Container *) ckalloc(sizeof(Container));
 
341
 
 
342
            containerPtr->parentPtr = NULL;
 
343
            containerPtr->embedded = (Window) macWin;
 
344
            containerPtr->embeddedPtr = macWin->winPtr;
 
345
            containerPtr->nextPtr = firstContainerPtr;
 
346
            firstContainerPtr = containerPtr;
 
347
            
 
348
        }    
 
349
    } else {
 
350
        
 
351
        /* 
 
352
         * The window is embedded in another Tk window.
 
353
         */ 
 
354
        
 
355
        macWin->xOff = parent->winPtr->privatePtr->xOff +
 
356
                parent->winPtr->changes.border_width +
 
357
                winPtr->changes.x;
 
358
        macWin->yOff = parent->winPtr->privatePtr->yOff +
 
359
                parent->winPtr->changes.border_width +
 
360
                winPtr->changes.y;
 
361
    
 
362
    
 
363
        /*
 
364
         * Finish filling up the container structure with the embedded window's 
 
365
         * information.
 
366
         */
 
367
     
 
368
        containerPtr->embedded = (Window) macWin;
 
369
        containerPtr->embeddedPtr = macWin->winPtr;
 
370
 
 
371
        /*
 
372
         * Create an event handler to clean up the Container structure when
 
373
         * tkwin is eventually deleted.
 
374
         */
 
375
 
 
376
        Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc,
 
377
                (ClientData) winPtr);
 
378
 
 
379
    }
 
380
 
 
381
   /* 
 
382
     * TODO: need general solution for visibility events.
 
383
     */
 
384
     
 
385
    event.xany.serial = Tk_Display(winPtr)->request;
 
386
    event.xany.send_event = False;
 
387
    event.xany.display = Tk_Display(winPtr);
 
388
        
 
389
    event.xvisibility.type = VisibilityNotify;
 
390
    event.xvisibility.window = (Window) macWin;;
 
391
    event.xvisibility.state = VisibilityUnobscured;
 
392
    Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
 
393
 
 
394
    
 
395
    /* 
 
396
     * TODO: need general solution for visibility events.
 
397
     */
 
398
     
 
399
    event.xany.serial = Tk_Display(winPtr)->request;
 
400
    event.xany.send_event = False;
 
401
    event.xany.display = Tk_Display(winPtr);
 
402
        
 
403
    event.xvisibility.type = VisibilityNotify;
 
404
    event.xvisibility.window = (Window) macWin;;
 
405
    event.xvisibility.state = VisibilityUnobscured;
 
406
    Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
 
407
     
 
408
    return TCL_OK;
 
409
}
 
410
 
 
411
/*
 
412
 *----------------------------------------------------------------------
 
413
 *
 
414
 * TkpMakeContainer --
 
415
 *
 
416
 *      This procedure is called to indicate that a particular window
 
417
 *      will be a container for an embedded application.  This changes
 
418
 *      certain aspects of the window's behavior, such as whether it
 
419
 *      will receive events anymore.
 
420
 *
 
421
 * Results:
 
422
 *      None.
 
423
 *
 
424
 * Side effects:
 
425
 *      None.
 
426
 *
 
427
 *----------------------------------------------------------------------
 
428
 */
 
429
 
 
430
void
 
431
TkpMakeContainer(
 
432
    Tk_Window tkwin)            /* Token for a window that is about to
 
433
                                 * become a container. */
 
434
{
 
435
    TkWindow *winPtr = (TkWindow *) tkwin;
 
436
    Container *containerPtr;
 
437
 
 
438
    /*
 
439
     * Register the window as a container so that, for example, we can
 
440
     * make sure the argument to -use is valid.
 
441
     */
 
442
 
 
443
 
 
444
    Tk_MakeWindowExist(tkwin);
 
445
    containerPtr = (Container *) ckalloc(sizeof(Container));
 
446
    containerPtr->parent = Tk_WindowId(tkwin);
 
447
    containerPtr->parentPtr = winPtr;
 
448
    containerPtr->embedded = None;
 
449
    containerPtr->embeddedPtr = NULL;
 
450
    containerPtr->nextPtr = firstContainerPtr;
 
451
    firstContainerPtr = containerPtr;
 
452
    winPtr->flags |= TK_CONTAINER;
 
453
    
 
454
    /*
 
455
     * Request SubstructureNotify events so that we can find out when
 
456
     * the embedded application creates its window or attempts to
 
457
     * resize it.  Also watch Configure events on the container so that
 
458
     * we can resize the child to match.  Also, pass activate events from
 
459
     * the container down to the embedded toplevel.
 
460
     */
 
461
 
 
462
    Tk_CreateEventHandler(tkwin,
 
463
            SubstructureNotifyMask|SubstructureRedirectMask,
 
464
            ContainerEventProc, (ClientData) winPtr);
 
465
    Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbedStructureProc,
 
466
            (ClientData) containerPtr);
 
467
    Tk_CreateEventHandler(tkwin, ActivateMask, EmbedActivateProc,
 
468
            (ClientData) containerPtr);
 
469
    Tk_CreateEventHandler(tkwin, FocusChangeMask, EmbedFocusProc,
 
470
            (ClientData) containerPtr);
 
471
        
 
472
}
 
473
 
 
474
/*
 
475
 *----------------------------------------------------------------------
 
476
 *
 
477
 * TkMacContainerId --
 
478
 *
 
479
 *      Given an embedded window, this procedure returns the MacDrawable
 
480
 *      identifier for the associated container window.
 
481
 *
 
482
 * Results:
 
483
 *      The return value is the MacDrawable for winPtr's
 
484
 *      container window.
 
485
 *
 
486
 * Side effects:
 
487
 *      None.
 
488
 *
 
489
 *----------------------------------------------------------------------
 
490
 */
 
491
 
 
492
MacDrawable *
 
493
TkMacContainerId(winPtr)
 
494
    TkWindow *winPtr;           /* Tk's structure for an embedded window. */
 
495
{
 
496
    Container *containerPtr;
 
497
 
 
498
    for (containerPtr = firstContainerPtr; containerPtr != NULL;
 
499
            containerPtr = containerPtr->nextPtr) {
 
500
        if (containerPtr->embeddedPtr == winPtr) {
 
501
            return (MacDrawable *) containerPtr->parent;
 
502
        }
 
503
    }
 
504
    panic("TkMacContainerId couldn't find window");
 
505
    return None;
 
506
}
 
507
 
 
508
/*
 
509
 *----------------------------------------------------------------------
 
510
 *
 
511
 * TkMacGetHostToplevel --
 
512
 *
 
513
 *      Given the TkWindow, return the MacDrawable for the outermost
 
514
 *      toplevel containing it.  This will be a real Macintosh window.
 
515
 *
 
516
 * Results:
 
517
 *      Returns a MacDrawable corresponding to a Macintosh Toplevel
 
518
 *
 
519
 * Side effects:
 
520
 *      None.
 
521
 *
 
522
 *----------------------------------------------------------------------
 
523
 */
 
524
 
 
525
MacDrawable *
 
526
TkMacGetHostToplevel(
 
527
    TkWindow *winPtr)           /* Tk's structure for a window. */
 
528
{
 
529
    TkWindow *contWinPtr, *topWinPtr;
 
530
 
 
531
    topWinPtr = winPtr->privatePtr->toplevel->winPtr;
 
532
    if (!Tk_IsEmbedded(topWinPtr)) {
 
533
        return winPtr->privatePtr->toplevel;
 
534
    } else {
 
535
        contWinPtr = TkpGetOtherWindow(topWinPtr);
 
536
 
 
537
        /*
 
538
         * NOTE: Here we should handle out of process embedding.
 
539
         */
 
540
        
 
541
        if (contWinPtr != NULL) {
 
542
            return TkMacGetHostToplevel(contWinPtr);
 
543
        } else {
 
544
            return None;
 
545
        }
 
546
    }
 
547
}
 
548
 
 
549
/*
 
550
 *----------------------------------------------------------------------
 
551
 *
 
552
 * TkpClaimFocus --
 
553
 *
 
554
 *      This procedure is invoked when someone asks for the input focus
 
555
 *      to be put on a window in an embedded application, but the
 
556
 *      application doesn't currently have the focus.  It requests the
 
557
 *      input focus from the container application.
 
558
 *
 
559
 * Results:
 
560
 *      None.
 
561
 *
 
562
 * Side effects:
 
563
 *      The input focus may change.
 
564
 *
 
565
 *----------------------------------------------------------------------
 
566
 */
 
567
 
 
568
void
 
569
TkpClaimFocus(
 
570
    TkWindow *topLevelPtr,              /* Top-level window containing desired
 
571
                                         * focus window; should be embedded. */
 
572
    int force)                          /* One means that the container should
 
573
                                         * claim the focus if it doesn't
 
574
                                         * currently have it. */
 
575
{
 
576
    XEvent event;
 
577
    Container *containerPtr;
 
578
 
 
579
    if (!(topLevelPtr->flags & TK_EMBEDDED)) {
 
580
        return;
 
581
    }
 
582
 
 
583
    for (containerPtr = firstContainerPtr;
 
584
            containerPtr->embeddedPtr != topLevelPtr;
 
585
            containerPtr = containerPtr->nextPtr) {
 
586
        /* Empty loop body. */
 
587
    }
 
588
    
 
589
 
 
590
    event.xfocus.type = FocusIn;
 
591
    event.xfocus.serial = LastKnownRequestProcessed(topLevelPtr->display);
 
592
    event.xfocus.send_event = 1;
 
593
    event.xfocus.display = topLevelPtr->display;
 
594
    event.xfocus.window = containerPtr->parent;
 
595
    event.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
 
596
    event.xfocus.detail = force;
 
597
    Tk_QueueWindowEvent(&event,TCL_QUEUE_TAIL);
 
598
}
 
599
 
 
600
/*
 
601
 *----------------------------------------------------------------------
 
602
 *
 
603
 * TkpTestembedCmd --
 
604
 *
 
605
 *      This procedure implements the "testembed" command.  It returns
 
606
 *      some or all of the information in the list pointed to by
 
607
 *      firstContainerPtr.
 
608
 *
 
609
 * Results:
 
610
 *      A standard Tcl result.
 
611
 *
 
612
 * Side effects:
 
613
 *      None.
 
614
 *
 
615
 *----------------------------------------------------------------------
 
616
 */
 
617
 
 
618
int
 
619
TkpTestembedCmd(
 
620
    ClientData clientData,              /* Main window for application. */
 
621
    Tcl_Interp *interp,                 /* Current interpreter. */
 
622
    int argc,                           /* Number of arguments. */
 
623
    char **argv)                        /* Argument strings. */
 
624
{
 
625
    int all;
 
626
    Container *containerPtr;
 
627
    Tcl_DString dString;
 
628
    char buffer[50];
 
629
 
 
630
    if ((argc > 1) && (strcmp(argv[1], "all") == 0)) {
 
631
        all = 1;
 
632
    } else {
 
633
        all = 0;
 
634
    }
 
635
    Tcl_DStringInit(&dString);
 
636
    for (containerPtr = firstContainerPtr; containerPtr != NULL;
 
637
            containerPtr = containerPtr->nextPtr) {
 
638
        Tcl_DStringStartSublist(&dString);
 
639
        if (containerPtr->parent == None) {
 
640
            Tcl_DStringAppendElement(&dString, "");
 
641
        } else {
 
642
            if (all) {
 
643
                sprintf(buffer, "0x%x", (int) containerPtr->parent);
 
644
                Tcl_DStringAppendElement(&dString, buffer);
 
645
            } else {
 
646
                Tcl_DStringAppendElement(&dString, "XXX");
 
647
            }
 
648
        }
 
649
        if (containerPtr->parentPtr == NULL) {
 
650
            Tcl_DStringAppendElement(&dString, "");
 
651
        } else {
 
652
            Tcl_DStringAppendElement(&dString,
 
653
                    containerPtr->parentPtr->pathName);
 
654
        }
 
655
        if (containerPtr->embedded == None) {
 
656
            Tcl_DStringAppendElement(&dString, "");
 
657
        } else {
 
658
            if (all) {
 
659
                sprintf(buffer, "0x%x", (int) containerPtr->embedded);
 
660
                Tcl_DStringAppendElement(&dString, buffer);
 
661
            } else {
 
662
                Tcl_DStringAppendElement(&dString, "XXX");
 
663
            }
 
664
        }
 
665
        if (containerPtr->embeddedPtr == NULL) {
 
666
            Tcl_DStringAppendElement(&dString, "");
 
667
        } else {
 
668
            Tcl_DStringAppendElement(&dString,
 
669
                    containerPtr->embeddedPtr->pathName);
 
670
        }
 
671
        Tcl_DStringEndSublist(&dString);
 
672
    }
 
673
    Tcl_DStringResult(interp, &dString);
 
674
    return TCL_OK;
 
675
}
 
676
 
 
677
/*
 
678
 *----------------------------------------------------------------------
 
679
 *
 
680
 * TkpRedirectKeyEvent --
 
681
 *
 
682
 *      This procedure is invoked when a key press or release event
 
683
 *      arrives for an application that does not believe it owns the
 
684
 *      input focus.  This can happen because of embedding; for example,
 
685
 *      X can send an event to an embedded application when the real
 
686
 *      focus window is in the container application and is an ancestor
 
687
 *      of the container.  This procedure's job is to forward the event
 
688
 *      back to the application where it really belongs.
 
689
 *
 
690
 * Results:
 
691
 *      None.
 
692
 *
 
693
 * Side effects:
 
694
 *      The event may get sent to a different application.
 
695
 *
 
696
 *----------------------------------------------------------------------
 
697
 */
 
698
 
 
699
void
 
700
TkpRedirectKeyEvent(
 
701
    TkWindow *winPtr,           /* Window to which the event was originally
 
702
                                 * reported. */
 
703
    XEvent *eventPtr)           /* X event to redirect (should be KeyPress
 
704
                                 * or KeyRelease). */
 
705
{
 
706
}
 
707
 
 
708
/*
 
709
 *----------------------------------------------------------------------
 
710
 *
 
711
 * TkpGetOtherWindow --
 
712
 *
 
713
 *      If both the container and embedded window are in the same
 
714
 *      process, this procedure will return either one, given the other.
 
715
 *
 
716
 * Results:
 
717
 *      If winPtr is a container, the return value is the token for the
 
718
 *      embedded window, and vice versa.  If the "other" window isn't in
 
719
 *      this process, NULL is returned.
 
720
 *
 
721
 * Side effects:
 
722
 *      None.
 
723
 *
 
724
 *----------------------------------------------------------------------
 
725
 */
 
726
 
 
727
TkWindow *
 
728
TkpGetOtherWindow(
 
729
    TkWindow *winPtr)           /* Tk's structure for a container or
 
730
                                 * embedded window. */
 
731
{
 
732
    Container *containerPtr;
 
733
 
 
734
    /*
 
735
     * TkpGetOtherWindow returns NULL if both windows are not
 
736
     * in the same process...
 
737
     */
 
738
 
 
739
    if (!(winPtr->flags & TK_BOTH_HALVES)) {
 
740
        return NULL;
 
741
    }
 
742
    
 
743
    for (containerPtr = firstContainerPtr; containerPtr != NULL;
 
744
            containerPtr = containerPtr->nextPtr) {
 
745
        if (containerPtr->embeddedPtr == winPtr) {
 
746
            return containerPtr->parentPtr;
 
747
        } else if (containerPtr->parentPtr == winPtr) {
 
748
            return containerPtr->embeddedPtr;
 
749
        }
 
750
    }
 
751
    return NULL;
 
752
}
 
753
/*
 
754
 *----------------------------------------------------------------------
 
755
 *
 
756
 * EmbeddedEventProc --
 
757
 *
 
758
 *      This procedure is invoked by the Tk event dispatcher when various
 
759
 *      useful events are received for a window that is embedded in
 
760
 *      another application.
 
761
 *
 
762
 * Results:
 
763
 *      None.
 
764
 *
 
765
 * Side effects:
 
766
 *      Our internal state gets cleaned up when an embedded window is
 
767
 *      destroyed.
 
768
 *
 
769
 *----------------------------------------------------------------------
 
770
 */
 
771
 
 
772
static void
 
773
EmbeddedEventProc(clientData, eventPtr)
 
774
    ClientData clientData;              /* Token for container window. */
 
775
    XEvent *eventPtr;                   /* ResizeRequest event. */
 
776
{
 
777
    TkWindow *winPtr = (TkWindow *) clientData;
 
778
 
 
779
    if (eventPtr->type == DestroyNotify) {
 
780
        EmbedWindowDeleted(winPtr);
 
781
    }
 
782
}
 
783
 
 
784
/*
 
785
 *----------------------------------------------------------------------
 
786
 *
 
787
 * ContainerEventProc --
 
788
 *
 
789
 *      This procedure is invoked by the Tk event dispatcher when various
 
790
 *      useful events are received for the children of a container
 
791
 *      window.  It forwards relevant information, such as geometry
 
792
 *      requests, from the events into the container's application.
 
793
 *
 
794
 *      NOTE: on the Mac, only the DestroyNotify branch is ever taken.
 
795
 *      We don't synthesize the other events.
 
796
 *
 
797
 * Results:
 
798
 *      None.
 
799
 *
 
800
 * Side effects:
 
801
 *      Depends on the event.  For example, when ConfigureRequest events
 
802
 *      occur, geometry information gets set for the container window.
 
803
 *
 
804
 *----------------------------------------------------------------------
 
805
 */
 
806
 
 
807
static void
 
808
ContainerEventProc(clientData, eventPtr)
 
809
    ClientData clientData;              /* Token for container window. */
 
810
    XEvent *eventPtr;                   /* ResizeRequest event. */
 
811
{
 
812
    TkWindow *winPtr = (TkWindow *) clientData;
 
813
    Container *containerPtr;
 
814
    Tk_ErrorHandler errHandler;
 
815
 
 
816
    /*
 
817
     * Ignore any X protocol errors that happen in this procedure
 
818
     * (almost any operation could fail, for example, if the embedded
 
819
     * application has deleted its window).
 
820
     */
 
821
 
 
822
    errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1,
 
823
            -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
 
824
 
 
825
    /*
 
826
     * Find the Container structure associated with the parent window.
 
827
     */
 
828
 
 
829
    for (containerPtr = firstContainerPtr;
 
830
            containerPtr->parent != eventPtr->xmaprequest.parent;
 
831
            containerPtr = containerPtr->nextPtr) {
 
832
        if (containerPtr == NULL) {
 
833
            panic("ContainerEventProc couldn't find Container record");
 
834
        }
 
835
    }
 
836
 
 
837
    if (eventPtr->type == CreateNotify) {
 
838
        /*
 
839
         * A new child window has been created in the container. Record
 
840
         * its id in the Container structure (if more than one child is
 
841
         * created, just remember the last one and ignore the earlier
 
842
         * ones).
 
843
         */
 
844
 
 
845
        containerPtr->embedded = eventPtr->xcreatewindow.window;
 
846
    } else if (eventPtr->type == ConfigureRequest) {
 
847
        if ((eventPtr->xconfigurerequest.x != 0)
 
848
                || (eventPtr->xconfigurerequest.y != 0)) {
 
849
            /*
 
850
             * The embedded application is trying to move itself, which
 
851
             * isn't legal.  At this point, the window hasn't actually
 
852
             * moved, but we need to send it a ConfigureNotify event to
 
853
             * let it know that its request has been denied.  If the
 
854
             * embedded application was also trying to resize itself, a
 
855
             * ConfigureNotify will be sent by the geometry management
 
856
             * code below, so we don't need to do anything.  Otherwise,
 
857
             * generate a synthetic event.
 
858
             */
 
859
 
 
860
            if ((eventPtr->xconfigurerequest.width == winPtr->changes.width)
 
861
                    && (eventPtr->xconfigurerequest.height
 
862
                    == winPtr->changes.height)) {
 
863
                EmbedSendConfigure(containerPtr);
 
864
            }
 
865
        }
 
866
        EmbedGeometryRequest(containerPtr,
 
867
                eventPtr->xconfigurerequest.width,
 
868
                eventPtr->xconfigurerequest.height);
 
869
    } else if (eventPtr->type == MapRequest) {
 
870
        /*
 
871
         * The embedded application's map request was ignored and simply
 
872
         * passed on to us, so we have to map the window for it to appear
 
873
         * on the screen.
 
874
         */
 
875
 
 
876
        XMapWindow(eventPtr->xmaprequest.display,
 
877
                eventPtr->xmaprequest.window);
 
878
    } else if (eventPtr->type == DestroyNotify) {
 
879
        /*
 
880
         * The embedded application is gone.  Destroy the container window.
 
881
         */
 
882
 
 
883
        Tk_DestroyWindow((Tk_Window) winPtr);
 
884
    }
 
885
    Tk_DeleteErrorHandler(errHandler);
 
886
}
 
887
 
 
888
/*
 
889
 *----------------------------------------------------------------------
 
890
 *
 
891
 * EmbedStructureProc --
 
892
 *
 
893
 *      This procedure is invoked by the Tk event dispatcher when
 
894
 *      a container window owned by this application gets resized
 
895
 *      (and also at several other times that we don't care about).
 
896
 *      This procedure reflects the size change in the embedded
 
897
 *      window that corresponds to the container.
 
898
 *
 
899
 * Results:
 
900
 *      None.
 
901
 *
 
902
 * Side effects:
 
903
 *      The embedded window gets resized to match the container.
 
904
 *
 
905
 *----------------------------------------------------------------------
 
906
 */
 
907
 
 
908
static void
 
909
EmbedStructureProc(clientData, eventPtr)
 
910
    ClientData clientData;              /* Token for container window. */
 
911
    XEvent *eventPtr;                   /* ResizeRequest event. */
 
912
{
 
913
    Container *containerPtr = (Container *) clientData;
 
914
    Tk_ErrorHandler errHandler;
 
915
 
 
916
    if (eventPtr->type == ConfigureNotify) {
 
917
        if (containerPtr->embedded != None) {
 
918
            /*
 
919
             * Ignore errors, since the embedded application could have
 
920
             * deleted its window.
 
921
             */
 
922
 
 
923
            errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1,
 
924
                    -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
 
925
            Tk_MoveResizeWindow((Tk_Window) containerPtr->embeddedPtr, 0, 0,
 
926
                    (unsigned int) Tk_Width(
 
927
                            (Tk_Window) containerPtr->parentPtr),
 
928
                    (unsigned int) Tk_Height(
 
929
                            (Tk_Window) containerPtr->parentPtr));
 
930
            Tk_DeleteErrorHandler(errHandler);
 
931
        }
 
932
    } else if (eventPtr->type == DestroyNotify) {
 
933
        EmbedWindowDeleted(containerPtr->parentPtr);
 
934
    }
 
935
}
 
936
 
 
937
/*
 
938
 *----------------------------------------------------------------------
 
939
 *
 
940
 * EmbedActivateProc --
 
941
 *
 
942
 *      This procedure is invoked by the Tk event dispatcher when
 
943
 *      Activate and Deactivate events occur for a container window owned
 
944
 *      by this application.  It is responsible for forwarding an activate 
 
945
 *      event down into the embedded toplevel.
 
946
 *
 
947
 * Results:
 
948
 *      None.
 
949
 *
 
950
 * Side effects:
 
951
 *      The X focus may change.
 
952
 *
 
953
 *----------------------------------------------------------------------
 
954
 */
 
955
 
 
956
static void
 
957
EmbedActivateProc(clientData, eventPtr)
 
958
    ClientData clientData;              /* Token for container window. */
 
959
    XEvent *eventPtr;                   /* ResizeRequest event. */
 
960
{
 
961
    Container *containerPtr = (Container *) clientData;
 
962
    
 
963
    if (containerPtr->embeddedPtr != NULL) {
 
964
        if (eventPtr->type == ActivateNotify) {
 
965
            TkGenerateActivateEvents(containerPtr->embeddedPtr,1);
 
966
        } else if (eventPtr->type == DeactivateNotify) {
 
967
            TkGenerateActivateEvents(containerPtr->embeddedPtr,0);
 
968
        }        
 
969
    }
 
970
}
 
971
 
 
972
/*
 
973
 *----------------------------------------------------------------------
 
974
 *
 
975
 * EmbedFocusProc --
 
976
 *
 
977
 *      This procedure is invoked by the Tk event dispatcher when
 
978
 *      FocusIn and FocusOut events occur for a container window owned
 
979
 *      by this application.  It is responsible for moving the focus
 
980
 *      back and forth between a container application and an embedded
 
981
 *      application.
 
982
 *
 
983
 * Results:
 
984
 *      None.
 
985
 *
 
986
 * Side effects:
 
987
 *      The X focus may change.
 
988
 *
 
989
 *----------------------------------------------------------------------
 
990
 */
 
991
 
 
992
static void
 
993
EmbedFocusProc(clientData, eventPtr)
 
994
    ClientData clientData;              /* Token for container window. */
 
995
    XEvent *eventPtr;                   /* ResizeRequest event. */
 
996
{
 
997
    Container *containerPtr = (Container *) clientData;
 
998
    Display *display;
 
999
    XEvent event;
 
1000
 
 
1001
    if (containerPtr->embeddedPtr != NULL) {
 
1002
    display = Tk_Display(containerPtr->parentPtr);
 
1003
        event.xfocus.serial = LastKnownRequestProcessed(display);
 
1004
        event.xfocus.send_event = false;
 
1005
        event.xfocus.display = display;
 
1006
        event.xfocus.mode = NotifyNormal;
 
1007
        event.xfocus.window = containerPtr->embedded; 
 
1008
        
 
1009
    if (eventPtr->type == FocusIn) {
 
1010
        /*
 
1011
         * The focus just arrived at the container.  Change the X focus
 
1012
         * to move it to the embedded application, if there is one. 
 
1013
         * Ignore X errors that occur during this operation (it's
 
1014
         * possible that the new focus window isn't mapped).
 
1015
         */
 
1016
    
 
1017
            event.xfocus.detail = NotifyNonlinear;
 
1018
            event.xfocus.type = FocusIn;
 
1019
 
 
1020
        } else if (eventPtr->type == FocusOut) {
 
1021
        /* When the container gets a FocusOut event, it has to  tell the embedded app
 
1022
         * that it has lost the focus.
 
1023
         */
 
1024
         
 
1025
            event.xfocus.type = FocusOut;
 
1026
            event.xfocus.detail = NotifyNonlinear;
 
1027
         }
 
1028
         
 
1029
        Tk_QueueWindowEvent(&event, TCL_QUEUE_MARK);
 
1030
    } 
 
1031
}
 
1032
 
 
1033
/*
 
1034
 *----------------------------------------------------------------------
 
1035
 *
 
1036
 * EmbedGeometryRequest --
 
1037
 *
 
1038
 *      This procedure is invoked when an embedded application requests
 
1039
 *      a particular size.  It processes the request (which may or may
 
1040
 *      not actually honor the request) and reflects the results back
 
1041
 *      to the embedded application.
 
1042
 *
 
1043
 *      NOTE: On the Mac, this is a stub, since we don't synthesize
 
1044
 *      ConfigureRequest events.
 
1045
 *
 
1046
 * Results:
 
1047
 *      None.
 
1048
 *
 
1049
 * Side effects:
 
1050
 *      If we deny the child's size change request, a Configure event
 
1051
 *      is synthesized to let the child know how big it ought to be.
 
1052
 *      Events get processed while we're waiting for the geometry
 
1053
 *      managers to do their thing.
 
1054
 *
 
1055
 *----------------------------------------------------------------------
 
1056
 */
 
1057
 
 
1058
static void
 
1059
EmbedGeometryRequest(containerPtr, width, height)
 
1060
    Container *containerPtr;    /* Information about the embedding. */
 
1061
    int width, height;          /* Size that the child has requested. */
 
1062
{
 
1063
    TkWindow *winPtr = containerPtr->parentPtr;
 
1064
 
 
1065
    /*
 
1066
     * Forward the requested size into our geometry management hierarchy
 
1067
     * via the container window.  We need to send a Configure event back
 
1068
     * to the embedded application if we decide not to honor its
 
1069
     * request; to make this happen, process all idle event handlers
 
1070
     * synchronously here (so that the geometry managers have had a
 
1071
     * chance to do whatever they want to do), and if the window's size
 
1072
     * didn't change then generate a configure event.
 
1073
     */
 
1074
 
 
1075
    Tk_GeometryRequest((Tk_Window) winPtr, width, height);
 
1076
    while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {
 
1077
        /* Empty loop body. */
 
1078
    }
 
1079
    if ((winPtr->changes.width != width)
 
1080
            || (winPtr->changes.height != height)) {
 
1081
        EmbedSendConfigure(containerPtr);
 
1082
    }
 
1083
}
 
1084
 
 
1085
/*
 
1086
 *----------------------------------------------------------------------
 
1087
 *
 
1088
 * EmbedSendConfigure --
 
1089
 *
 
1090
 *      This is currently a stub.  It is called to notify an
 
1091
 *      embedded application of its current size and location.  This
 
1092
 *      procedure is called when the embedded application made a
 
1093
 *      geometry request that we did not grant, so that the embedded
 
1094
 *      application knows that its geometry didn't change after all.
 
1095
 *      It is a response to ConfigureRequest events, which we do not
 
1096
 *      currently synthesize on the Mac
 
1097
 *
 
1098
 * Results:
 
1099
 *      None.
 
1100
 *
 
1101
 * Side effects:
 
1102
 *      None.
 
1103
 *
 
1104
 *----------------------------------------------------------------------
 
1105
 */
 
1106
 
 
1107
static void
 
1108
EmbedSendConfigure(containerPtr)
 
1109
    Container *containerPtr;    /* Information about the embedding. */
 
1110
{
 
1111
}
 
1112
 
 
1113
/*
 
1114
 *----------------------------------------------------------------------
 
1115
 *
 
1116
 * EmbedWindowDeleted --
 
1117
 *
 
1118
 *      This procedure is invoked when a window involved in embedding
 
1119
 *      (as either the container or the embedded application) is
 
1120
 *      destroyed.  It cleans up the Container structure for the window.
 
1121
 *
 
1122
 * Results:
 
1123
 *      None.
 
1124
 *
 
1125
 * Side effects:
 
1126
 *      A Container structure may be freed.
 
1127
 *
 
1128
 *----------------------------------------------------------------------
 
1129
 */
 
1130
 
 
1131
static void
 
1132
EmbedWindowDeleted(winPtr)
 
1133
    TkWindow *winPtr;           /* Tk's information about window that
 
1134
                                 * was deleted. */
 
1135
{
 
1136
    Container *containerPtr, *prevPtr;
 
1137
 
 
1138
    /*
 
1139
     * Find the Container structure for this window.  Delete the
 
1140
     * information about the embedded application and free the container's
 
1141
     * record.
 
1142
     */
 
1143
 
 
1144
    prevPtr = NULL;
 
1145
    containerPtr = firstContainerPtr;
 
1146
    while (1) {
 
1147
        if (containerPtr->embeddedPtr == winPtr) {
 
1148
 
 
1149
            /*
 
1150
             * We also have to destroy our parent, to clean up the container.
 
1151
             * Fabricate an event to do this.
 
1152
             */
 
1153
             
 
1154
            if (containerPtr->parentPtr != NULL &&
 
1155
                    containerPtr->parentPtr->flags & TK_BOTH_HALVES) {
 
1156
                XEvent event;
 
1157
                
 
1158
                event.xany.serial = 
 
1159
                    Tk_Display(containerPtr->parentPtr)->request;
 
1160
                event.xany.send_event = False;
 
1161
                event.xany.display = Tk_Display(containerPtr->parentPtr);
 
1162
        
 
1163
                event.xany.type = DestroyNotify;
 
1164
                event.xany.window = containerPtr->parent;
 
1165
                event.xdestroywindow.event = containerPtr->parent;
 
1166
                Tk_QueueWindowEvent(&event, TCL_QUEUE_HEAD);
 
1167
 
 
1168
            }
 
1169
            
 
1170
            containerPtr->embedded = None;
 
1171
            containerPtr->embeddedPtr = NULL;
 
1172
            
 
1173
            break;
 
1174
        }
 
1175
        if (containerPtr->parentPtr == winPtr) {
 
1176
            containerPtr->parentPtr = NULL;
 
1177
            break;
 
1178
        }
 
1179
        prevPtr = containerPtr;
 
1180
        containerPtr = containerPtr->nextPtr;
 
1181
    }
 
1182
    if ((containerPtr->embeddedPtr == NULL)
 
1183
            && (containerPtr->parentPtr == NULL)) {
 
1184
        if (prevPtr == NULL) {
 
1185
            firstContainerPtr = containerPtr->nextPtr;
 
1186
        } else {
 
1187
            prevPtr->nextPtr = containerPtr->nextPtr;
 
1188
        }
 
1189
        ckfree((char *) containerPtr);
 
1190
    }
 
1191
}
 
1192