OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tk/] [unix/] [tkUnixEmbed.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkUnixEmbed.c --
3
 *
4
 *      This file contains platform-specific procedures for UNIX 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
 *
9
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
10
 *
11
 * See the file "license.terms" for information on usage and redistribution
12
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
 *
14
 * RCS: @(#) $Id: tkUnixEmbed.c,v 1.1.1.1 2002-01-16 10:26:01 markom Exp $
15
 */
16
 
17
#include "tkInt.h"
18
#include "tkUnixInt.h"
19
 
20
/*
21
 * One of the following structures exists for each container in this
22
 * application.  It keeps track of the container window and its
23
 * associated embedded window.
24
 */
25
 
26
typedef struct Container {
27
    Window parent;                      /* X's window id for the parent of
28
                                         * the pair (the container). */
29
    Window parentRoot;                  /* Id for the root window of parent's
30
                                         * screen. */
31
    TkWindow *parentPtr;                /* Tk's information about the container,
32
                                         * or NULL if the container isn't
33
                                         * in this process. */
34
    Window wrapper;                     /* X's window id for the wrapper
35
                                         * window for the embedded window.
36
                                         * Starts off as None, but gets
37
                                         * filled in when the window is
38
                                         * eventually created. */
39
    TkWindow *embeddedPtr;              /* Tk's information about the embedded
40
                                         * window, or NULL if the embedded
41
                                         * application isn't in this process.
42
                                         * Note that this is *not* the
43
                                         * same window as wrapper: wrapper is
44
                                         * the parent of embeddedPtr. */
45
    struct Container *nextPtr;          /* Next in list of all containers in
46
                                         * this process. */
47
} Container;
48
 
49
static Container *firstContainerPtr = NULL;
50
                                        /* First in list of all containers
51
                                         * managed by this process.  */
52
 
53
/*
54
 * Prototypes for static procedures defined in this file:
55
 */
56
 
57
static void             ContainerEventProc _ANSI_ARGS_((
58
                            ClientData clientData, XEvent *eventPtr));
59
static void             EmbeddedEventProc _ANSI_ARGS_((
60
                            ClientData clientData, XEvent *eventPtr));
61
static int              EmbedErrorProc _ANSI_ARGS_((ClientData clientData,
62
                            XErrorEvent *errEventPtr));
63
static void             EmbedFocusProc _ANSI_ARGS_((ClientData clientData,
64
                            XEvent *eventPtr));
65
static void             EmbedGeometryRequest _ANSI_ARGS_((
66
                            Container * containerPtr, int width, int height));
67
static void             EmbedSendConfigure _ANSI_ARGS_((
68
                            Container *containerPtr));
69
static void             EmbedStructureProc _ANSI_ARGS_((ClientData clientData,
70
                            XEvent *eventPtr));
71
static void             EmbedWindowDeleted _ANSI_ARGS_((TkWindow *winPtr));
72
 
73
/*
74
 *----------------------------------------------------------------------
75
 *
76
 * TkpUseWindow --
77
 *
78
 *      This procedure causes a Tk window to use a given X window as
79
 *      its parent window, rather than the root window for the screen.
80
 *      It is invoked by an embedded application to specify the window
81
 *      in which it is embedded.
82
 *
83
 * Results:
84
 *      The return value is normally TCL_OK.  If an error occurs (such
85
 *      as string not being a valid window spec), then the return value
86
 *      is TCL_ERROR and an error message is left in interp->result if
87
 *      interp is non-NULL.
88
 *
89
 * Side effects:
90
 *      Changes the colormap and other visual information to match that
91
 *      of the parent window given by "string".
92
 *
93
 *----------------------------------------------------------------------
94
 */
95
 
96
int
97
TkpUseWindow(interp, tkwin, string)
98
    Tcl_Interp *interp;         /* If not NULL, used for error reporting
99
                                 * if string is bogus. */
100
    Tk_Window tkwin;            /* Tk window that does not yet have an
101
                                 * associated X window. */
102
    char *string;               /* String identifying an X window to use
103
                                 * for tkwin;  must be an integer value. */
104
{
105
    TkWindow *winPtr = (TkWindow *) tkwin;
106
    int id, anyError;
107
    Window parent;
108
    Tk_ErrorHandler handler;
109
    Container *containerPtr;
110
    XWindowAttributes parentAtts;
111
 
112
    if (winPtr->window != None) {
113
        panic("TkUseWindow: X window already assigned");
114
    }
115
    if (Tcl_GetInt(interp, string, &id) != TCL_OK) {
116
        return TCL_ERROR;
117
    }
118
    parent = (Window) id;
119
 
120
    /*
121
     * Tk sets the window colormap to the screen default colormap in
122
     * tkWindow.c:AllocWindow. This doesn't work well for embedded
123
     * windows. So we override the colormap and visual settings to be
124
     * the same as the parent window (which is in the container app).
125
     */
126
 
127
    anyError = 0;
128
    handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
129
            EmbedErrorProc, (ClientData) &anyError);
130
    if (!XGetWindowAttributes(winPtr->display, parent, &parentAtts)) {
131
        anyError =  1;
132
    }
133
    XSync(winPtr->display, False);
134
    Tk_DeleteErrorHandler(handler);
135
    if (anyError) {
136
        if (interp != NULL) {
137
            Tcl_AppendResult(interp, "couldn't create child of window \"",
138
                    string, "\"", (char *) NULL);
139
        }
140
        return TCL_ERROR;
141
    }
142
    Tk_SetWindowVisual(tkwin, parentAtts.visual, parentAtts.depth,
143
            parentAtts.colormap);
144
 
145
    /*
146
     * Create an event handler to clean up the Container structure when
147
     * tkwin is eventually deleted.
148
     */
149
 
150
    Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc,
151
            (ClientData) winPtr);
152
 
153
    /*
154
     * Save information about the container and the embedded window
155
     * in a Container structure.  If there is already an existing
156
     * Container structure, it means that both container and embedded
157
     * app. are in the same process.
158
     */
159
 
160
    for (containerPtr = firstContainerPtr; containerPtr != NULL;
161
            containerPtr = containerPtr->nextPtr) {
162
        if (containerPtr->parent == parent) {
163
            winPtr->flags |= TK_BOTH_HALVES;
164
            containerPtr->parentPtr->flags |= TK_BOTH_HALVES;
165
            break;
166
        }
167
    }
168
    if (containerPtr == NULL) {
169
        containerPtr = (Container *) ckalloc(sizeof(Container));
170
        containerPtr->parent = parent;
171
        containerPtr->parentRoot = parentAtts.root;
172
        containerPtr->parentPtr = NULL;
173
        containerPtr->wrapper = None;
174
        containerPtr->nextPtr = firstContainerPtr;
175
        firstContainerPtr = containerPtr;
176
    }
177
    containerPtr->embeddedPtr = winPtr;
178
    winPtr->flags |= TK_EMBEDDED;
179
    return TCL_OK;
180
}
181
 
182
/*
183
 *----------------------------------------------------------------------
184
 *
185
 * TkpMakeWindow --
186
 *
187
 *      Create an actual window system window object based on the
188
 *      current attributes of the specified TkWindow.
189
 *
190
 * Results:
191
 *      Returns the handle to the new window, or None on failure.
192
 *
193
 * Side effects:
194
 *      Creates a new X window.
195
 *
196
 *----------------------------------------------------------------------
197
 */
198
 
199
Window
200
TkpMakeWindow(winPtr, parent)
201
    TkWindow *winPtr;           /* Tk's information about the window that
202
                                 * is to be instantiated. */
203
    Window parent;              /* Window system token for the parent in
204
                                 * which the window is to be created. */
205
{
206
    Container *containerPtr;
207
 
208
    if (winPtr->flags & TK_EMBEDDED) {
209
        /*
210
         * This window is embedded.  Don't create the new window in the
211
         * given parent; instead, create it as a child of the root window
212
         * of the container's screen.  The window will get reparented
213
         * into a wrapper window later.
214
         */
215
 
216
        for (containerPtr = firstContainerPtr; ;
217
                containerPtr = containerPtr->nextPtr) {
218
            if (containerPtr == NULL) {
219
                panic("TkMakeWindow couldn't find container for window");
220
            }
221
            if (containerPtr->embeddedPtr == winPtr) {
222
                break;
223
            }
224
        }
225
        parent = containerPtr->parentRoot;
226
    }
227
 
228
    return XCreateWindow(winPtr->display, parent, winPtr->changes.x,
229
            winPtr->changes.y, (unsigned) winPtr->changes.width,
230
            (unsigned) winPtr->changes.height,
231
            (unsigned) winPtr->changes.border_width, winPtr->depth,
232
            InputOutput, winPtr->visual, winPtr->dirtyAtts,
233
            &winPtr->atts);
234
}
235
 
236
/*
237
 *----------------------------------------------------------------------
238
 *
239
 * TkpMakeContainer --
240
 *
241
 *      This procedure is called to indicate that a particular window
242
 *      will be a container for an embedded application.  This changes
243
 *      certain aspects of the window's behavior, such as whether it
244
 *      will receive events anymore.
245
 *
246
 * Results:
247
 *      None.
248
 *
249
 * Side effects:
250
 *      None.
251
 *
252
 *----------------------------------------------------------------------
253
 */
254
 
255
void
256
TkpMakeContainer(tkwin)
257
    Tk_Window tkwin;            /* Token for a window that is about to
258
                                 * become a container. */
259
{
260
    TkWindow *winPtr = (TkWindow *) tkwin;
261
    Container *containerPtr;
262
 
263
    /*
264
     * Register the window as a container so that, for example, we can
265
     * find out later if the embedded app. is in the same process.
266
     */
267
 
268
    Tk_MakeWindowExist(tkwin);
269
    containerPtr = (Container *) ckalloc(sizeof(Container));
270
    containerPtr->parent = Tk_WindowId(tkwin);
271
    containerPtr->parentRoot = RootWindowOfScreen(Tk_Screen(tkwin));
272
    containerPtr->parentPtr = winPtr;
273
    containerPtr->wrapper = None;
274
    containerPtr->embeddedPtr = NULL;
275
    containerPtr->nextPtr = firstContainerPtr;
276
    firstContainerPtr = containerPtr;
277
    winPtr->flags |= TK_CONTAINER;
278
 
279
    /*
280
     * Request SubstructureNotify events so that we can find out when
281
     * the embedded application creates its window or attempts to
282
     * resize it.  Also watch Configure events on the container so that
283
     * we can resize the child to match.
284
     */
285
 
286
    winPtr->atts.event_mask |= SubstructureRedirectMask|SubstructureNotifyMask;
287
    XSelectInput(winPtr->display, winPtr->window, winPtr->atts.event_mask);
288
    Tk_CreateEventHandler(tkwin,
289
            SubstructureNotifyMask|SubstructureRedirectMask,
290
            ContainerEventProc, (ClientData) winPtr);
291
    Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbedStructureProc,
292
            (ClientData) containerPtr);
293
    Tk_CreateEventHandler(tkwin, FocusChangeMask, EmbedFocusProc,
294
            (ClientData) containerPtr);
295
}
296
 
297
/*
298
 *----------------------------------------------------------------------
299
 *
300
 * EmbedErrorProc --
301
 *
302
 *      This procedure is invoked if an error occurs while creating
303
 *      an embedded window.
304
 *
305
 * Results:
306
 *      Always returns 0 to indicate that the error has been properly
307
 *      handled.
308
 *
309
 * Side effects:
310
 *      The integer pointed to by the clientData argument is set to 1.
311
 *
312
 *----------------------------------------------------------------------
313
 */
314
 
315
static int
316
EmbedErrorProc(clientData, errEventPtr)
317
    ClientData clientData;      /* Points to integer to set. */
318
    XErrorEvent *errEventPtr;   /* Points to information about error
319
                                 * (not used). */
320
{
321
    int *iPtr = (int *) clientData;
322
 
323
    *iPtr = 1;
324
    return 0;
325
}
326
 
327
/*
328
 *----------------------------------------------------------------------
329
 *
330
 * EmbeddedEventProc --
331
 *
332
 *      This procedure is invoked by the Tk event dispatcher when various
333
 *      useful events are received for a window that is embedded in
334
 *      another application.
335
 *
336
 * Results:
337
 *      None.
338
 *
339
 * Side effects:
340
 *      Our internal state gets cleaned up when an embedded window is
341
 *      destroyed.
342
 *
343
 *----------------------------------------------------------------------
344
 */
345
 
346
static void
347
EmbeddedEventProc(clientData, eventPtr)
348
    ClientData clientData;              /* Token for container window. */
349
    XEvent *eventPtr;                   /* ResizeRequest event. */
350
{
351
    TkWindow *winPtr = (TkWindow *) clientData;
352
 
353
    if (eventPtr->type == DestroyNotify) {
354
        EmbedWindowDeleted(winPtr);
355
    }
356
}
357
 
358
/*
359
 *----------------------------------------------------------------------
360
 *
361
 * ContainerEventProc --
362
 *
363
 *      This procedure is invoked by the Tk event dispatcher when various
364
 *      useful events are received for the children of a container
365
 *      window.  It forwards relevant information, such as geometry
366
 *      requests, from the events into the container's application.
367
 *
368
 * Results:
369
 *      None.
370
 *
371
 * Side effects:
372
 *      Depends on the event.  For example, when ConfigureRequest events
373
 *      occur, geometry information gets set for the container window.
374
 *
375
 *----------------------------------------------------------------------
376
 */
377
 
378
static void
379
ContainerEventProc(clientData, eventPtr)
380
    ClientData clientData;              /* Token for container window. */
381
    XEvent *eventPtr;                   /* ResizeRequest event. */
382
{
383
    TkWindow *winPtr = (TkWindow *) clientData;
384
    Container *containerPtr;
385
    Tk_ErrorHandler errHandler;
386
 
387
    /*
388
     * Ignore any X protocol errors that happen in this procedure
389
     * (almost any operation could fail, for example, if the embedded
390
     * application has deleted its window).
391
     */
392
 
393
    errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1,
394
            -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
395
 
396
    /*
397
     * Find the Container structure associated with the parent window.
398
     */
399
 
400
    for (containerPtr = firstContainerPtr;
401
            containerPtr->parent != eventPtr->xmaprequest.parent;
402
            containerPtr = containerPtr->nextPtr) {
403
        if (containerPtr == NULL) {
404
            panic("ContainerEventProc couldn't find Container record");
405
        }
406
    }
407
 
408
    if (eventPtr->type == CreateNotify) {
409
        /*
410
         * A new child window has been created in the container. Record
411
         * its id in the Container structure (if more than one child is
412
         * created, just remember the last one and ignore the earlier
413
         * ones).  Also set the child's size to match the container.
414
         */
415
 
416
        containerPtr->wrapper = eventPtr->xcreatewindow.window;
417
        XMoveResizeWindow(eventPtr->xcreatewindow.display,
418
                containerPtr->wrapper, 0, 0,
419
                (unsigned int) Tk_Width(
420
                        (Tk_Window) containerPtr->parentPtr),
421
                (unsigned int) Tk_Height(
422
                        (Tk_Window) containerPtr->parentPtr));
423
    } else if (eventPtr->type == ConfigureRequest) {
424
        if ((eventPtr->xconfigurerequest.x != 0)
425
                || (eventPtr->xconfigurerequest.y != 0)) {
426
            /*
427
             * The embedded application is trying to move itself, which
428
             * isn't legal.  At this point, the window hasn't actually
429
             * moved, but we need to send it a ConfigureNotify event to
430
             * let it know that its request has been denied.  If the
431
             * embedded application was also trying to resize itself, a
432
             * ConfigureNotify will be sent by the geometry management
433
             * code below, so we don't need to do anything.  Otherwise,
434
             * generate a synthetic event.
435
             */
436
 
437
            if ((eventPtr->xconfigurerequest.width == winPtr->changes.width)
438
                    && (eventPtr->xconfigurerequest.height
439
                    == winPtr->changes.height)) {
440
                EmbedSendConfigure(containerPtr);
441
            }
442
        }
443
        EmbedGeometryRequest(containerPtr,
444
                eventPtr->xconfigurerequest.width,
445
                eventPtr->xconfigurerequest.height);
446
    } else if (eventPtr->type == MapRequest) {
447
        /*
448
         * The embedded application's map request was ignored and simply
449
         * passed on to us, so we have to map the window for it to appear
450
         * on the screen.
451
         */
452
 
453
        XMapWindow(eventPtr->xmaprequest.display,
454
                eventPtr->xmaprequest.window);
455
    } else if (eventPtr->type == DestroyNotify) {
456
        /*
457
         * The embedded application is gone.  Destroy the container window.
458
         */
459
 
460
        Tk_DestroyWindow((Tk_Window) winPtr);
461
    }
462
    Tk_DeleteErrorHandler(errHandler);
463
}
464
 
465
/*
466
 *----------------------------------------------------------------------
467
 *
468
 * EmbedStructureProc --
469
 *
470
 *      This procedure is invoked by the Tk event dispatcher when
471
 *      a container window owned by this application gets resized
472
 *      (and also at several other times that we don't care about).
473
 *      This procedure reflects the size change in the embedded
474
 *      window that corresponds to the container.
475
 *
476
 * Results:
477
 *      None.
478
 *
479
 * Side effects:
480
 *      The embedded window gets resized to match the container.
481
 *
482
 *----------------------------------------------------------------------
483
 */
484
 
485
static void
486
EmbedStructureProc(clientData, eventPtr)
487
    ClientData clientData;              /* Token for container window. */
488
    XEvent *eventPtr;                   /* ResizeRequest event. */
489
{
490
    Container *containerPtr = (Container *) clientData;
491
    Tk_ErrorHandler errHandler;
492
 
493
    if (eventPtr->type == ConfigureNotify) {
494
        if (containerPtr->wrapper != None) {
495
            /*
496
             * Ignore errors, since the embedded application could have
497
             * deleted its window.
498
             */
499
 
500
            errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1,
501
                    -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
502
            XMoveResizeWindow(eventPtr->xconfigure.display,
503
                    containerPtr->wrapper, 0, 0,
504
                    (unsigned int) Tk_Width(
505
                            (Tk_Window) containerPtr->parentPtr),
506
                    (unsigned int) Tk_Height(
507
                            (Tk_Window) containerPtr->parentPtr));
508
            Tk_DeleteErrorHandler(errHandler);
509
        }
510
    } else if (eventPtr->type == DestroyNotify) {
511
        EmbedWindowDeleted(containerPtr->parentPtr);
512
    }
513
}
514
 
515
/*
516
 *----------------------------------------------------------------------
517
 *
518
 * EmbedFocusProc --
519
 *
520
 *      This procedure is invoked by the Tk event dispatcher when
521
 *      FocusIn and FocusOut events occur for a container window owned
522
 *      by this application.  It is responsible for moving the focus
523
 *      back and forth between a container application and an embedded
524
 *      application.
525
 *
526
 * Results:
527
 *      None.
528
 *
529
 * Side effects:
530
 *      The X focus may change.
531
 *
532
 *----------------------------------------------------------------------
533
 */
534
 
535
static void
536
EmbedFocusProc(clientData, eventPtr)
537
    ClientData clientData;              /* Token for container window. */
538
    XEvent *eventPtr;                   /* ResizeRequest event. */
539
{
540
    Container *containerPtr = (Container *) clientData;
541
    Tk_ErrorHandler errHandler;
542
    Display *display;
543
 
544
    display = Tk_Display(containerPtr->parentPtr);
545
    if (eventPtr->type == FocusIn) {
546
        /*
547
         * The focus just arrived at the container.  Change the X focus
548
         * to move it to the embedded application, if there is one.
549
         * Ignore X errors that occur during this operation (it's
550
         * possible that the new focus window isn't mapped).
551
         */
552
 
553
        if (containerPtr->wrapper != None) {
554
            errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1,
555
                    -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
556
            XSetInputFocus(display, containerPtr->wrapper, RevertToParent,
557
                    CurrentTime);
558
            Tk_DeleteErrorHandler(errHandler);
559
        }
560
    }
561
}
562
 
563
/*
564
 *----------------------------------------------------------------------
565
 *
566
 * EmbedGeometryRequest --
567
 *
568
 *      This procedure is invoked when an embedded application requests
569
 *      a particular size.  It processes the request (which may or may
570
 *      not actually honor the request) and reflects the results back
571
 *      to the embedded application.
572
 *
573
 * Results:
574
 *      None.
575
 *
576
 * Side effects:
577
 *      If we deny the child's size change request, a Configure event
578
 *      is synthesized to let the child know how big it ought to be.
579
 *      Events get processed while we're waiting for the geometry
580
 *      managers to do their thing.
581
 *
582
 *----------------------------------------------------------------------
583
 */
584
 
585
static void
586
EmbedGeometryRequest(containerPtr, width, height)
587
    Container *containerPtr;    /* Information about the embedding. */
588
    int width, height;          /* Size that the child has requested. */
589
{
590
    TkWindow *winPtr = containerPtr->parentPtr;
591
 
592
    /*
593
     * Forward the requested size into our geometry management hierarchy
594
     * via the container window.  We need to send a Configure event back
595
     * to the embedded application if we decide not to honor its
596
     * request; to make this happen, process all idle event handlers
597
     * synchronously here (so that the geometry managers have had a
598
     * chance to do whatever they want to do), and if the window's size
599
     * didn't change then generate a configure event.
600
     */
601
 
602
    Tk_GeometryRequest((Tk_Window) winPtr, width, height);
603
    while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {
604
        /* Empty loop body. */
605
    }
606
    if ((winPtr->changes.width != width)
607
            || (winPtr->changes.height != height)) {
608
        EmbedSendConfigure(containerPtr);
609
    }
610
}
611
 
612
/*
613
 *----------------------------------------------------------------------
614
 *
615
 * EmbedSendConfigure --
616
 *
617
 *      This procedure synthesizes a ConfigureNotify event to notify an
618
 *      embedded application of its current size and location.  This
619
 *      procedure is called when the embedded application made a
620
 *      geometry request that we did not grant, so that the embedded
621
 *      application knows that its geometry didn't change after all.
622
 *
623
 * Results:
624
 *      None.
625
 *
626
 * Side effects:
627
 *      None.
628
 *
629
 *----------------------------------------------------------------------
630
 */
631
 
632
static void
633
EmbedSendConfigure(containerPtr)
634
    Container *containerPtr;    /* Information about the embedding. */
635
{
636
    TkWindow *winPtr = containerPtr->parentPtr;
637
    XEvent event;
638
 
639
    event.xconfigure.type = ConfigureNotify;
640
    event.xconfigure.serial =
641
            LastKnownRequestProcessed(winPtr->display);
642
    event.xconfigure.send_event = True;
643
    event.xconfigure.display = winPtr->display;
644
    event.xconfigure.event = containerPtr->wrapper;
645
    event.xconfigure.window = containerPtr->wrapper;
646
    event.xconfigure.x = 0;
647
    event.xconfigure.y = 0;
648
    event.xconfigure.width = winPtr->changes.width;
649
    event.xconfigure.height = winPtr->changes.height;
650
    event.xconfigure.above = None;
651
    event.xconfigure.override_redirect = False;
652
 
653
    /*
654
     * Note:  when sending the event below, the ButtonPressMask
655
     * causes the event to be sent only to applications that have
656
     * selected for ButtonPress events, which should be just the
657
     * embedded application.
658
     */
659
 
660
    XSendEvent(winPtr->display, containerPtr->wrapper, False,
661
            0, &event);
662
 
663
    /*
664
     * The following needs to be done if the embedded window is
665
     * not in the same application as the container window.
666
     */
667
 
668
    if (containerPtr->embeddedPtr == NULL) {
669
        XMoveResizeWindow(winPtr->display, containerPtr->wrapper, 0, 0,
670
            (unsigned int) winPtr->changes.width,
671
            (unsigned int) winPtr->changes.height);
672
    }
673
}
674
 
675
/*
676
 *----------------------------------------------------------------------
677
 *
678
 * TkpGetOtherWindow --
679
 *
680
 *      If both the container and embedded window are in the same
681
 *      process, this procedure will return either one, given the other.
682
 *
683
 * Results:
684
 *      If winPtr is a container, the return value is the token for the
685
 *      embedded window, and vice versa.  If the "other" window isn't in
686
 *      this process, NULL is returned.
687
 *
688
 * Side effects:
689
 *      None.
690
 *
691
 *----------------------------------------------------------------------
692
 */
693
 
694
TkWindow *
695
TkpGetOtherWindow(winPtr)
696
    TkWindow *winPtr;           /* Tk's structure for a container or
697
                                 * embedded window. */
698
{
699
    Container *containerPtr;
700
 
701
    for (containerPtr = firstContainerPtr; containerPtr != NULL;
702
            containerPtr = containerPtr->nextPtr) {
703
        if (containerPtr->embeddedPtr == winPtr) {
704
            return containerPtr->parentPtr;
705
        } else if (containerPtr->parentPtr == winPtr) {
706
            return containerPtr->embeddedPtr;
707
        }
708
    }
709
    panic("TkpGetOtherWindow couldn't find window");
710
    return NULL;
711
}
712
 
713
/*
714
 *----------------------------------------------------------------------
715
 *
716
 * TkpRedirectKeyEvent --
717
 *
718
 *      This procedure is invoked when a key press or release event
719
 *      arrives for an application that does not believe it owns the
720
 *      input focus.  This can happen because of embedding; for example,
721
 *      X can send an event to an embedded application when the real
722
 *      focus window is in the container application and is an ancestor
723
 *      of the container.  This procedure's job is to forward the event
724
 *      back to the application where it really belongs.
725
 *
726
 * Results:
727
 *      None.
728
 *
729
 * Side effects:
730
 *      The event may get sent to a different application.
731
 *
732
 *----------------------------------------------------------------------
733
 */
734
 
735
void
736
TkpRedirectKeyEvent(winPtr, eventPtr)
737
    TkWindow *winPtr;           /* Window to which the event was originally
738
                                 * reported. */
739
    XEvent *eventPtr;           /* X event to redirect (should be KeyPress
740
                                 * or KeyRelease). */
741
{
742
    Container *containerPtr;
743
    Window saved;
744
 
745
    /*
746
     * First, find the top-level window corresponding to winPtr.
747
     */
748
 
749
    while (1) {
750
        if (winPtr == NULL) {
751
            /*
752
             * This window is being deleted.  This is too confusing a
753
             * case to handle so discard the event.
754
             */
755
 
756
            return;
757
        }
758
        if (winPtr->flags & TK_TOP_LEVEL) {
759
            break;
760
        }
761
        winPtr = winPtr->parentPtr;
762
    }
763
 
764
    if (winPtr->flags & TK_EMBEDDED) {
765
        /*
766
         * This application is embedded.  If we got a key event without
767
         * officially having the focus, it means that the focus is
768
         * really in the container, but the mouse was over the embedded
769
         * application.  Send the event back to the container.
770
         */
771
 
772
        for (containerPtr = firstContainerPtr;
773
                containerPtr->embeddedPtr != winPtr;
774
                containerPtr = containerPtr->nextPtr) {
775
            /* Empty loop body. */
776
        }
777
        saved = eventPtr->xkey.window;
778
        eventPtr->xkey.window = containerPtr->parent;
779
        XSendEvent(eventPtr->xkey.display, eventPtr->xkey.window, False,
780
            KeyPressMask|KeyReleaseMask, eventPtr);
781
        eventPtr->xkey.window = saved;
782
    }
783
}
784
 
785
/*
786
 *----------------------------------------------------------------------
787
 *
788
 * TkpClaimFocus --
789
 *
790
 *      This procedure is invoked when someone asks or the input focus
791
 *      to be put on a window in an embedded application, but the
792
 *      application doesn't currently have the focus.  It requests the
793
 *      input focus from the container application.
794
 *
795
 * Results:
796
 *      None.
797
 *
798
 * Side effects:
799
 *      The input focus may change.
800
 *
801
 *----------------------------------------------------------------------
802
 */
803
 
804
void
805
TkpClaimFocus(topLevelPtr, force)
806
    TkWindow *topLevelPtr;              /* Top-level window containing desired
807
                                         * focus window; should be embedded. */
808
    int force;                          /* One means that the container should
809
                                         * claim the focus if it doesn't
810
                                         * currently have it. */
811
{
812
    XEvent event;
813
    Container *containerPtr;
814
 
815
    if (!(topLevelPtr->flags & TK_EMBEDDED)) {
816
        return;
817
    }
818
 
819
    for (containerPtr = firstContainerPtr;
820
            containerPtr->embeddedPtr != topLevelPtr;
821
            containerPtr = containerPtr->nextPtr) {
822
        /* Empty loop body. */
823
    }
824
 
825
    event.xfocus.type = FocusIn;
826
    event.xfocus.serial = LastKnownRequestProcessed(topLevelPtr->display);
827
    event.xfocus.send_event = 1;
828
    event.xfocus.display = topLevelPtr->display;
829
    event.xfocus.window = containerPtr->parent;
830
    event.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
831
    event.xfocus.detail = force;
832
    XSendEvent(event.xfocus.display, event.xfocus.window, False, 0, &event);
833
}
834
 
835
/*
836
 *----------------------------------------------------------------------
837
 *
838
 * TkpTestembedCmd --
839
 *
840
 *      This procedure implements the "testembed" command.  It returns
841
 *      some or all of the information in the list pointed to by
842
 *      firstContainerPtr.
843
 *
844
 * Results:
845
 *      A standard Tcl result.
846
 *
847
 * Side effects:
848
 *      None.
849
 *
850
 *----------------------------------------------------------------------
851
 */
852
 
853
int
854
TkpTestembedCmd(clientData, interp, argc, argv)
855
    ClientData clientData;              /* Main window for application. */
856
    Tcl_Interp *interp;                 /* Current interpreter. */
857
    int argc;                           /* Number of arguments. */
858
    char **argv;                        /* Argument strings. */
859
{
860
    int all;
861
    Container *containerPtr;
862
    Tcl_DString dString;
863
    char buffer[50];
864
 
865
    if ((argc > 1) && (strcmp(argv[1], "all") == 0)) {
866
        all = 1;
867
    } else {
868
        all = 0;
869
    }
870
    Tcl_DStringInit(&dString);
871
    for (containerPtr = firstContainerPtr; containerPtr != NULL;
872
            containerPtr = containerPtr->nextPtr) {
873
        Tcl_DStringStartSublist(&dString);
874
        if (containerPtr->parent == None) {
875
            Tcl_DStringAppendElement(&dString, "");
876
        } else {
877
            if (all) {
878
                sprintf(buffer, "0x%x", (int) containerPtr->parent);
879
                Tcl_DStringAppendElement(&dString, buffer);
880
            } else {
881
                Tcl_DStringAppendElement(&dString, "XXX");
882
            }
883
        }
884
        if (containerPtr->parentPtr == NULL) {
885
            Tcl_DStringAppendElement(&dString, "");
886
        } else {
887
            Tcl_DStringAppendElement(&dString,
888
                    containerPtr->parentPtr->pathName);
889
        }
890
        if (containerPtr->wrapper == None) {
891
            Tcl_DStringAppendElement(&dString, "");
892
        } else {
893
            if (all) {
894
                sprintf(buffer, "0x%x", (int) containerPtr->wrapper);
895
                Tcl_DStringAppendElement(&dString, buffer);
896
            } else {
897
                Tcl_DStringAppendElement(&dString, "XXX");
898
            }
899
        }
900
        if (containerPtr->embeddedPtr == NULL) {
901
            Tcl_DStringAppendElement(&dString, "");
902
        } else {
903
            Tcl_DStringAppendElement(&dString,
904
                    containerPtr->embeddedPtr->pathName);
905
        }
906
        Tcl_DStringEndSublist(&dString);
907
    }
908
    Tcl_DStringResult(interp, &dString);
909
    return TCL_OK;
910
}
911
 
912
/*
913
 *----------------------------------------------------------------------
914
 *
915
 * EmbedWindowDeleted --
916
 *
917
 *      This procedure is invoked when a window involved in embedding
918
 *      (as either the container or the embedded application) is
919
 *      destroyed.  It cleans up the Container structure for the window.
920
 *
921
 * Results:
922
 *      None.
923
 *
924
 * Side effects:
925
 *      A Container structure may be freed.
926
 *
927
 *----------------------------------------------------------------------
928
 */
929
 
930
static void
931
EmbedWindowDeleted(winPtr)
932
    TkWindow *winPtr;           /* Tk's information about window that
933
                                 * was deleted. */
934
{
935
    Container *containerPtr, *prevPtr;
936
 
937
    /*
938
     * Find the Container structure for this window work.  Delete the
939
     * information about the embedded application and free the container's
940
     * record.
941
     */
942
 
943
    prevPtr = NULL;
944
    containerPtr = firstContainerPtr;
945
    while (1) {
946
        if (containerPtr->embeddedPtr == winPtr) {
947
            containerPtr->wrapper = None;
948
            containerPtr->embeddedPtr = NULL;
949
            break;
950
        }
951
        if (containerPtr->parentPtr == winPtr) {
952
            containerPtr->parentPtr = NULL;
953
            break;
954
        }
955
        prevPtr = containerPtr;
956
        containerPtr = containerPtr->nextPtr;
957
    }
958
    if ((containerPtr->embeddedPtr == NULL)
959
            && (containerPtr->parentPtr == NULL)) {
960
        if (prevPtr == NULL) {
961
            firstContainerPtr = containerPtr->nextPtr;
962
        } else {
963
            prevPtr->nextPtr = containerPtr->nextPtr;
964
        }
965
        ckfree((char *) containerPtr);
966
    }
967
}
968
 
969
/*
970
 *----------------------------------------------------------------------
971
 *
972
 * TkUnixContainerId --
973
 *
974
 *      Given an embedded window, this procedure returns the X window
975
 *      identifier for the associated container window.
976
 *
977
 * Results:
978
 *      The return value is the X window identifier for winPtr's
979
 *      container window.
980
 *
981
 * Side effects:
982
 *      None.
983
 *
984
 *----------------------------------------------------------------------
985
 */
986
 
987
Window
988
TkUnixContainerId(winPtr)
989
    TkWindow *winPtr;           /* Tk's structure for an embedded window. */
990
{
991
    Container *containerPtr;
992
 
993
    for (containerPtr = firstContainerPtr; containerPtr != NULL;
994
            containerPtr = containerPtr->nextPtr) {
995
        if (containerPtr->embeddedPtr == winPtr) {
996
            return containerPtr->parent;
997
        }
998
    }
999
    panic("TkUnixContainerId couldn't find window");
1000
    return None;
1001
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.