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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkWindow.c] - Blame information for rev 578

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkWindow.c --
3
 *
4
 *      This file provides basic window-manipulation procedures,
5
 *      which are equivalent to procedures in Xlib (and even
6
 *      invoke them) but also maintain the local Tk_Window
7
 *      structure.
8
 *
9
 * Copyright (c) 1989-1994 The Regents of the University of California.
10
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
11
 *
12
 * See the file "license.terms" for information on usage and redistribution
13
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14
 *
15
 * RCS: @(#) $Id: tkWindow.c,v 1.1.1.1 2002-01-16 10:25:53 markom Exp $
16
 */
17
 
18
#include "tkPort.h"
19
#include "tkInt.h"
20
 
21
/*
22
 * Count of number of main windows currently open in this process.
23
 */
24
 
25
static int numMainWindows;
26
 
27
/*
28
 * First in list of all main windows managed by this process.
29
 */
30
 
31
TkMainInfo *tkMainWindowList = NULL;
32
 
33
/*
34
 * List of all displays currently in use.
35
 */
36
 
37
TkDisplay *tkDisplayList = NULL;
38
 
39
/*
40
 * Have statics in this module been initialized?
41
 */
42
 
43
static int initialized = 0;
44
 
45
/*
46
 * The variables below hold several uid's that are used in many places
47
 * in the toolkit.
48
 */
49
 
50
Tk_Uid tkDisabledUid = NULL;
51
Tk_Uid tkActiveUid = NULL;
52
Tk_Uid tkNormalUid = NULL;
53
 
54
/*
55
 * Default values for "changes" and "atts" fields of TkWindows.  Note
56
 * that Tk always requests all events for all windows, except StructureNotify
57
 * events on internal windows:  these events are generated internally.
58
 */
59
 
60
static XWindowChanges defChanges = {
61
    0, 0, 1, 1, 0, 0, Above
62
};
63
#define ALL_EVENTS_MASK \
64
    KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
65
    EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
66
    VisibilityChangeMask|PropertyChangeMask|ColormapChangeMask
67
static XSetWindowAttributes defAtts= {
68
    None,                       /* background_pixmap */
69
    0,                           /* background_pixel */
70
    CopyFromParent,             /* border_pixmap */
71
    0,                           /* border_pixel */
72
    NorthWestGravity,           /* bit_gravity */
73
    NorthWestGravity,           /* win_gravity */
74
    NotUseful,                  /* backing_store */
75
    (unsigned) ~0,               /* backing_planes */
76
    0,                           /* backing_pixel */
77
    False,                      /* save_under */
78
    ALL_EVENTS_MASK,            /* event_mask */
79
    0,                           /* do_not_propagate_mask */
80
    False,                      /* override_redirect */
81
    CopyFromParent,             /* colormap */
82
    None                        /* cursor */
83
};
84
 
85
/*
86
 * The following structure defines all of the commands supported by
87
 * Tk, and the C procedures that execute them.
88
 */
89
 
90
typedef struct {
91
    char *name;                 /* Name of command. */
92
    Tcl_CmdProc *cmdProc;       /* Command's string-based procedure. */
93
    Tcl_ObjCmdProc *objProc;    /* Command's object-based procedure. */
94
    int isSafe;                 /* If !0, this command will be exposed in
95
                                 * a safe interpreter. Otherwise it will be
96
                                 * hidden in a safe interpreter. */
97
} TkCmd;
98
 
99
static TkCmd commands[] = {
100
    /*
101
     * Commands that are part of the intrinsics:
102
     */
103
 
104
    {"bell",            NULL,                   Tk_BellObjCmd,          0},
105
    {"bind",            Tk_BindCmd,             NULL,                   1},
106
    {"bindtags",        Tk_BindtagsCmd,         NULL,                   1},
107
    {"clipboard",       Tk_ClipboardCmd,        NULL,                   0},
108
    {"destroy",         Tk_DestroyCmd,          NULL,                   1},
109
    {"event",           Tk_EventCmd,            NULL,                   1},
110
    {"focus",           Tk_FocusCmd,            NULL,                   1},
111
    {"font",            NULL,                   Tk_FontObjCmd,          1},
112
    {"grab",            Tk_GrabCmd,             NULL,                   0},
113
    {"grid",            Tk_GridCmd,             NULL,                   1},
114
    {"image",           NULL,                   Tk_ImageCmd,            1},
115
    {"lower",           Tk_LowerCmd,            NULL,                   1},
116
    {"option",          Tk_OptionCmd,           NULL,                   1},
117
    {"pack",            Tk_PackCmd,             NULL,                   1},
118
    {"place",           Tk_PlaceCmd,            NULL,                   1},
119
    {"raise",           Tk_RaiseCmd,            NULL,                   1},
120
    {"selection",       Tk_SelectionCmd,        NULL,                   0},
121
    {"tk",              NULL,                   Tk_TkObjCmd,            0},
122
    {"tkwait",          Tk_TkwaitCmd,           NULL,                   1},
123
    {"tk_chooseColor",  Tk_ChooseColorCmd,      NULL,                   0},
124
    {"tk_getOpenFile",  Tk_GetOpenFileCmd,      NULL,                   0},
125
    {"tk_getSaveFile",  Tk_GetSaveFileCmd,      NULL,                   0},
126
    {"tk_messageBox",   Tk_MessageBoxCmd,       NULL,                   0},
127
    {"update",          Tk_UpdateCmd,           NULL,                   1},
128
    {"winfo",           NULL,                   Tk_WinfoObjCmd,         1},
129
    {"wm",              Tk_WmCmd,               NULL,                   0},
130
 
131
    /*
132
     * Widget class commands.
133
     */
134
    {"button",          Tk_ButtonCmd,           NULL,                   1},
135
    {"canvas",          Tk_CanvasCmd,           NULL,                   1},
136
    {"checkbutton",     Tk_CheckbuttonCmd,      NULL,                   1},
137
    {"entry",           Tk_EntryCmd,            NULL,                   1},
138
    {"frame",           Tk_FrameCmd,            NULL,                   1},
139
    {"label",           Tk_LabelCmd,            NULL,                   1},
140
    {"listbox",         Tk_ListboxCmd,          NULL,                   1},
141
    {"menu",            Tk_MenuCmd,             NULL,                   0},
142
    {"menubutton",      Tk_MenubuttonCmd,       NULL,                   1},
143
    {"message",         Tk_MessageCmd,          NULL,                   1},
144
    {"radiobutton",     Tk_RadiobuttonCmd,      NULL,                   1},
145
    {"scale",           Tk_ScaleCmd,            NULL,                   1},
146
    {"scrollbar",       Tk_ScrollbarCmd,        NULL,                   1},
147
    {"text",            Tk_TextCmd,             NULL,                   1},
148
    {"toplevel",        Tk_ToplevelCmd,         NULL,                   0},
149
 
150
    /*
151
     * Misc.
152
     */
153
 
154
#ifdef MAC_TCL
155
    {"unsupported1",    TkUnsupported1Cmd,      NULL,                   1},
156
#endif
157
    {(char *) NULL,     (int (*) _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **))) NULL, NULL, 0}
158
};
159
 
160
/*
161
 * The variables and table below are used to parse arguments from
162
 * the "argv" variable in Tk_Init.
163
 */
164
 
165
static int synchronize = 0;
166
static char *name = NULL;
167
static char *display = NULL;
168
static char *geometry = NULL;
169
static char *colormap = NULL;
170
static char *use = NULL;
171
static char *visual = NULL;
172
static int rest = 0;
173
 
174
static Tk_ArgvInfo argTable[] = {
175
    {"-colormap", TK_ARGV_STRING, (char *) NULL, (char *) &colormap,
176
        "Colormap for main window"},
177
    {"-display", TK_ARGV_STRING, (char *) NULL, (char *) &display,
178
        "Display to use"},
179
    {"-geometry", TK_ARGV_STRING, (char *) NULL, (char *) &geometry,
180
        "Initial geometry for window"},
181
    {"-name", TK_ARGV_STRING, (char *) NULL, (char *) &name,
182
        "Name to use for application"},
183
    {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize,
184
        "Use synchronous mode for display server"},
185
    {"-visual", TK_ARGV_STRING, (char *) NULL, (char *) &visual,
186
        "Visual for main window"},
187
    {"-use", TK_ARGV_STRING, (char *) NULL, (char *) &use,
188
        "Id of window in which to embed application"},
189
    {"--", TK_ARGV_REST, (char *) 1, (char *) &rest,
190
        "Pass all remaining arguments through to script"},
191
    {(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
192
        (char *) NULL}
193
};
194
 
195
/*
196
 * Forward declarations to procedures defined later in this file:
197
 */
198
 
199
static Tk_Window        CreateTopLevelWindow _ANSI_ARGS_((Tcl_Interp *interp,
200
                            Tk_Window parent, char *name, char *screenName));
201
static void             DeleteWindowsExitProc _ANSI_ARGS_((
202
                            ClientData clientData));
203
static TkDisplay *      GetScreen _ANSI_ARGS_((Tcl_Interp *interp,
204
                            char *screenName, int *screenPtr));
205
static int              Initialize _ANSI_ARGS_((Tcl_Interp *interp));
206
static int              NameWindow _ANSI_ARGS_((Tcl_Interp *interp,
207
                            TkWindow *winPtr, TkWindow *parentPtr,
208
                            char *name));
209
static void             OpenIM _ANSI_ARGS_((TkDisplay *dispPtr));
210
static void             UnlinkWindow _ANSI_ARGS_((TkWindow *winPtr));
211
 
212
/*
213
 *----------------------------------------------------------------------
214
 *
215
 * CreateTopLevelWindow --
216
 *
217
 *      Make a new window that will be at top-level (its parent will
218
 *      be the root window of a screen).
219
 *
220
 * Results:
221
 *      The return value is a token for the new window, or NULL if
222
 *      an error prevented the new window from being created.  If
223
 *      NULL is returned, an error message will be left in
224
 *      interp->result.
225
 *
226
 * Side effects:
227
 *      A new window structure is allocated locally.  An X
228
 *      window is NOT initially created, but will be created
229
 *      the first time the window is mapped.
230
 *
231
 *----------------------------------------------------------------------
232
 */
233
 
234
static Tk_Window
235
CreateTopLevelWindow(interp, parent, name, screenName)
236
    Tcl_Interp *interp;         /* Interpreter to use for error reporting. */
237
    Tk_Window parent;           /* Token for logical parent of new window
238
                                 * (used for naming, options, etc.).  May
239
                                 * be NULL. */
240
    char *name;                 /* Name for new window;  if parent is
241
                                 * non-NULL, must be unique among parent's
242
                                 * children. */
243
    char *screenName;           /* Name of screen on which to create
244
                                 * window.  NULL means use DISPLAY environment
245
                                 * variable to determine.  Empty string means
246
                                 * use parent's screen, or DISPLAY if no
247
                                 * parent. */
248
{
249
    register TkWindow *winPtr;
250
    register TkDisplay *dispPtr;
251
    int screenId;
252
 
253
    if (!initialized) {
254
        initialized = 1;
255
        tkActiveUid = Tk_GetUid("active");
256
        tkDisabledUid = Tk_GetUid("disabled");
257
        tkNormalUid = Tk_GetUid("normal");
258
 
259
        /*
260
         * Create built-in image types.
261
         */
262
 
263
        Tk_CreateImageType(&tkBitmapImageType);
264
        Tk_CreateImageType(&tkPhotoImageType);
265
 
266
        /*
267
         * Create built-in photo image formats.
268
         */
269
 
270
        Tk_CreatePhotoImageFormat(&tkImgFmtGIF);
271
        Tk_CreatePhotoImageFormat(&tkImgFmtPPM);
272
 
273
        /*
274
         * Create exit handler to delete all windows when the application
275
         * exits.
276
         */
277
 
278
        Tcl_CreateExitHandler(DeleteWindowsExitProc, (ClientData) NULL);
279
    }
280
 
281
    if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {
282
        dispPtr = ((TkWindow *) parent)->dispPtr;
283
        screenId = Tk_ScreenNumber(parent);
284
    } else {
285
        dispPtr = GetScreen(interp, screenName, &screenId);
286
        if (dispPtr == NULL) {
287
            return (Tk_Window) NULL;
288
        }
289
    }
290
 
291
    winPtr = TkAllocWindow(dispPtr, screenId, (TkWindow *) parent);
292
 
293
    /*
294
     * Force the window to use a border pixel instead of border pixmap.
295
     * This is needed for the case where the window doesn't use the
296
     * default visual.  In this case, the default border is a pixmap
297
     * inherited from the root window, which won't work because it will
298
     * have the wrong visual.
299
     */
300
 
301
    winPtr->dirtyAtts |= CWBorderPixel;
302
 
303
    /*
304
     * (Need to set the TK_TOP_LEVEL flag immediately here;  otherwise
305
     * Tk_DestroyWindow will core dump if it is called before the flag
306
     * has been set.)
307
     */
308
 
309
    winPtr->flags |= TK_TOP_LEVEL;
310
 
311
    if (parent != NULL) {
312
        if (NameWindow(interp, winPtr, (TkWindow *) parent, name) != TCL_OK) {
313
            Tk_DestroyWindow((Tk_Window) winPtr);
314
            return (Tk_Window) NULL;
315
        }
316
    }
317
    TkWmNewWindow(winPtr);
318
 
319
    return (Tk_Window) winPtr;
320
}
321
 
322
/*
323
 *----------------------------------------------------------------------
324
 *
325
 * GetScreen --
326
 *
327
 *      Given a string name for a display-plus-screen, find the
328
 *      TkDisplay structure for the display and return the screen
329
 *      number too.
330
 *
331
 * Results:
332
 *      The return value is a pointer to information about the display,
333
 *      or NULL if the display couldn't be opened.  In this case, an
334
 *      error message is left in interp->result.  The location at
335
 *      *screenPtr is overwritten with the screen number parsed from
336
 *      screenName.
337
 *
338
 * Side effects:
339
 *      A new connection is opened to the display if there is no
340
 *      connection already.  A new TkDisplay data structure is also
341
 *      setup, if necessary.
342
 *
343
 *----------------------------------------------------------------------
344
 */
345
 
346
static TkDisplay *
347
GetScreen(interp, screenName, screenPtr)
348
    Tcl_Interp *interp;         /* Place to leave error message. */
349
    char *screenName;           /* Name for screen.  NULL or empty means
350
                                 * use DISPLAY envariable. */
351
    int *screenPtr;             /* Where to store screen number. */
352
{
353
    register TkDisplay *dispPtr;
354
    char *p;
355
    int screenId;
356
    size_t length;
357
 
358
    /*
359
     * Separate the screen number from the rest of the display
360
     * name.  ScreenName is assumed to have the syntax
361
     * <display>.<screen> with the dot and the screen being
362
     * optional.
363
     */
364
 
365
    screenName = TkGetDefaultScreenName(interp, screenName);
366
    if (screenName == NULL) {
367
        interp->result =
368
            "no display name and no $DISPLAY environment variable";
369
        return (TkDisplay *) NULL;
370
    }
371
    length = strlen(screenName);
372
    screenId = 0;
373
    p = screenName+length-1;
374
    while (isdigit(UCHAR(*p)) && (p != screenName)) {
375
        p--;
376
    }
377
    if ((*p == '.') && (p[1] != '\0')) {
378
        length = p - screenName;
379
        screenId = strtoul(p+1, (char **) NULL, 10);
380
    }
381
 
382
    /*
383
     * See if we already have a connection to this display.  If not,
384
     * then open a new connection.
385
     */
386
 
387
    for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
388
        if (dispPtr == NULL) {
389
            dispPtr = TkpOpenDisplay(screenName);
390
            if (dispPtr == NULL) {
391
                Tcl_AppendResult(interp, "couldn't connect to display \"",
392
                        screenName, "\"", (char *) NULL);
393
                return (TkDisplay *) NULL;
394
            }
395
            dispPtr->nextPtr = tkDisplayList;
396
            dispPtr->name = (char *) ckalloc((unsigned) (length+1));
397
            dispPtr->lastEventTime = CurrentTime;
398
            strncpy(dispPtr->name, screenName, length);
399
            dispPtr->name[length] = '\0';
400
            dispPtr->bindInfoStale = 1;
401
            dispPtr->modeModMask = 0;
402
            dispPtr->metaModMask = 0;
403
            dispPtr->altModMask = 0;
404
            dispPtr->numModKeyCodes = 0;
405
            dispPtr->modKeyCodes = NULL;
406
            OpenIM(dispPtr);
407
            dispPtr->errorPtr = NULL;
408
            dispPtr->deleteCount = 0;
409
            dispPtr->commTkwin = NULL;
410
            dispPtr->selectionInfoPtr = NULL;
411
            dispPtr->multipleAtom = None;
412
            dispPtr->clipWindow = NULL;
413
            dispPtr->clipboardActive = 0;
414
            dispPtr->clipboardAppPtr = NULL;
415
            dispPtr->clipTargetPtr = NULL;
416
            dispPtr->atomInit = 0;
417
            dispPtr->cursorFont = None;
418
            dispPtr->grabWinPtr = NULL;
419
            dispPtr->eventualGrabWinPtr = NULL;
420
            dispPtr->buttonWinPtr = NULL;
421
            dispPtr->serverWinPtr = NULL;
422
            dispPtr->firstGrabEventPtr = NULL;
423
            dispPtr->lastGrabEventPtr = NULL;
424
            dispPtr->grabFlags = 0;
425
            TkInitXId(dispPtr);
426
            dispPtr->destroyCount = 0;
427
            dispPtr->lastDestroyRequest = 0;
428
            dispPtr->cmapPtr = NULL;
429
            dispPtr->implicitWinPtr = NULL;
430
            dispPtr->focusPtr = NULL;
431
            dispPtr->stressPtr = NULL;
432
            dispPtr->delayedMotionPtr = NULL;
433
            Tcl_InitHashTable(&dispPtr->winTable, TCL_ONE_WORD_KEYS);
434
            dispPtr->refCount = 0;
435
 
436
            tkDisplayList = dispPtr;
437
            break;
438
        }
439
        if ((strncmp(dispPtr->name, screenName, length) == 0)
440
                && (dispPtr->name[length] == '\0')) {
441
            break;
442
        }
443
    }
444
    if (screenId >= ScreenCount(dispPtr->display)) {
445
        sprintf(interp->result, "bad screen number \"%d\"", screenId);
446
        return (TkDisplay *) NULL;
447
    }
448
    *screenPtr = screenId;
449
    return dispPtr;
450
}
451
 
452
/*
453
 *----------------------------------------------------------------------
454
 *
455
 * TkGetDisplay --
456
 *
457
 *      Given an X display, TkGetDisplay returns the TkDisplay
458
 *      structure for the display.
459
 *
460
 * Results:
461
 *      The return value is a pointer to information about the display,
462
 *      or NULL if the display did not have a TkDisplay structure.
463
 *
464
 * Side effects:
465
 *      None.
466
 *
467
 *----------------------------------------------------------------------
468
 */
469
 
470
TkDisplay *
471
TkGetDisplay(display)
472
     Display *display;          /* X's display pointer */
473
{
474
    TkDisplay *dispPtr;
475
 
476
    for (dispPtr = tkDisplayList; dispPtr != NULL;
477
            dispPtr = dispPtr->nextPtr) {
478
        if (dispPtr->display == display) {
479
            break;
480
        }
481
    }
482
    return dispPtr;
483
}
484
 
485
/*
486
 *--------------------------------------------------------------
487
 *
488
 * TkAllocWindow --
489
 *
490
 *      This procedure creates and initializes a TkWindow structure.
491
 *
492
 * Results:
493
 *      The return value is a pointer to the new window.
494
 *
495
 * Side effects:
496
 *      A new window structure is allocated and all its fields are
497
 *      initialized.
498
 *
499
 *--------------------------------------------------------------
500
 */
501
 
502
TkWindow *
503
TkAllocWindow(dispPtr, screenNum, parentPtr)
504
    TkDisplay *dispPtr;         /* Display associated with new window. */
505
    int screenNum;              /* Index of screen for new window. */
506
    TkWindow *parentPtr;        /* Parent from which this window should
507
                                 * inherit visual information.  NULL means
508
                                 * use screen defaults instead of
509
                                 * inheriting. */
510
{
511
    register TkWindow *winPtr;
512
 
513
    winPtr = (TkWindow *) ckalloc(sizeof(TkWindow));
514
    winPtr->display = dispPtr->display;
515
    winPtr->dispPtr = dispPtr;
516
    winPtr->screenNum = screenNum;
517
    if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)
518
            && (parentPtr->screenNum == winPtr->screenNum)) {
519
        winPtr->visual = parentPtr->visual;
520
        winPtr->depth = parentPtr->depth;
521
    } else {
522
        winPtr->visual = DefaultVisual(dispPtr->display, screenNum);
523
        winPtr->depth = DefaultDepth(dispPtr->display, screenNum);
524
    }
525
    winPtr->window = None;
526
    winPtr->childList = NULL;
527
    winPtr->lastChildPtr = NULL;
528
    winPtr->parentPtr = NULL;
529
    winPtr->nextPtr = NULL;
530
    winPtr->mainPtr = NULL;
531
    winPtr->pathName = NULL;
532
    winPtr->nameUid = NULL;
533
    winPtr->classUid = NULL;
534
    winPtr->changes = defChanges;
535
    winPtr->dirtyChanges = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
536
    winPtr->atts = defAtts;
537
    if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)
538
            && (parentPtr->screenNum == winPtr->screenNum)) {
539
        winPtr->atts.colormap = parentPtr->atts.colormap;
540
    } else {
541
        winPtr->atts.colormap = DefaultColormap(dispPtr->display, screenNum);
542
    }
543
    winPtr->dirtyAtts = CWEventMask|CWColormap|CWBitGravity;
544
    winPtr->flags = 0;
545
    winPtr->handlerList = NULL;
546
#ifdef TK_USE_INPUT_METHODS
547
    winPtr->inputContext = NULL;
548
#endif /* TK_USE_INPUT_METHODS */
549
    winPtr->tagPtr = NULL;
550
    winPtr->numTags = 0;
551
    winPtr->optionLevel = -1;
552
    winPtr->selHandlerList = NULL;
553
    winPtr->geomMgrPtr = NULL;
554
    winPtr->geomData = NULL;
555
    winPtr->reqWidth = winPtr->reqHeight = 1;
556
    winPtr->internalBorderWidth = 0;
557
    winPtr->wmInfoPtr = NULL;
558
    winPtr->classProcsPtr = NULL;
559
    winPtr->instanceData = NULL;
560
    winPtr->privatePtr = NULL;
561
 
562
    return winPtr;
563
}
564
 
565
/*
566
 *----------------------------------------------------------------------
567
 *
568
 * NameWindow --
569
 *
570
 *      This procedure is invoked to give a window a name and insert
571
 *      the window into the hierarchy associated with a particular
572
 *      application.
573
 *
574
 * Results:
575
 *      A standard Tcl return value.
576
 *
577
 * Side effects:
578
 *      See above.
579
 *
580
 *----------------------------------------------------------------------
581
 */
582
 
583
static int
584
NameWindow(interp, winPtr, parentPtr, name)
585
    Tcl_Interp *interp;         /* Interpreter to use for error reporting. */
586
    register TkWindow *winPtr;  /* Window that is to be named and inserted. */
587
    TkWindow *parentPtr;        /* Pointer to logical parent for winPtr
588
                                 * (used for naming, options, etc.). */
589
    char *name;                 /* Name for winPtr;   must be unique among
590
                                 * parentPtr's children. */
591
{
592
#define FIXED_SIZE 200
593
    char staticSpace[FIXED_SIZE];
594
    char *pathName;
595
    int new;
596
    Tcl_HashEntry *hPtr;
597
    int length1, length2;
598
 
599
    /*
600
     * Setup all the stuff except name right away, then do the name stuff
601
     * last.  This is so that if the name stuff fails, everything else
602
     * will be properly initialized (needed to destroy the window cleanly
603
     * after the naming failure).
604
     */
605
    winPtr->parentPtr = parentPtr;
606
    winPtr->nextPtr = NULL;
607
    if (parentPtr->childList == NULL) {
608
        parentPtr->childList = winPtr;
609
    } else {
610
        parentPtr->lastChildPtr->nextPtr = winPtr;
611
    }
612
    parentPtr->lastChildPtr = winPtr;
613
    winPtr->mainPtr = parentPtr->mainPtr;
614
    winPtr->mainPtr->refCount++;
615
    winPtr->nameUid = Tk_GetUid(name);
616
 
617
    /*
618
     * Don't permit names that start with an upper-case letter:  this
619
     * will just cause confusion with class names in the option database.
620
     */
621
 
622
    if (isupper(UCHAR(name[0]))) {
623
        Tcl_AppendResult(interp,
624
                "window name starts with an upper-case letter: \"",
625
                name, "\"", (char *) NULL);
626
        return TCL_ERROR;
627
    }
628
 
629
    /*
630
     * To permit names of arbitrary length, must be prepared to malloc
631
     * a buffer to hold the new path name.  To run fast in the common
632
     * case where names are short, use a fixed-size buffer on the
633
     * stack.
634
     */
635
 
636
    length1 = strlen(parentPtr->pathName);
637
    length2 = strlen(name);
638
    if ((length1+length2+2) <= FIXED_SIZE) {
639
        pathName = staticSpace;
640
    } else {
641
        pathName = (char *) ckalloc((unsigned) (length1+length2+2));
642
    }
643
    if (length1 == 1) {
644
        pathName[0] = '.';
645
        strcpy(pathName+1, name);
646
    } else {
647
        strcpy(pathName, parentPtr->pathName);
648
        pathName[length1] = '.';
649
        strcpy(pathName+length1+1, name);
650
    }
651
    hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new);
652
    if (pathName != staticSpace) {
653
        ckfree(pathName);
654
    }
655
    if (!new) {
656
        Tcl_AppendResult(interp, "window name \"", name,
657
                "\" already exists in parent", (char *) NULL);
658
        return TCL_ERROR;
659
    }
660
    Tcl_SetHashValue(hPtr, winPtr);
661
    winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr);
662
    return TCL_OK;
663
}
664
 
665
/*
666
 *----------------------------------------------------------------------
667
 *
668
 * TkCreateMainWindow --
669
 *
670
 *      Make a new main window.  A main window is a special kind of
671
 *      top-level window used as the outermost window in an
672
 *      application.
673
 *
674
 * Results:
675
 *      The return value is a token for the new window, or NULL if
676
 *      an error prevented the new window from being created.  If
677
 *      NULL is returned, an error message will be left in
678
 *      interp->result.
679
 *
680
 * Side effects:
681
 *      A new window structure is allocated locally;  "interp" is
682
 *      associated with the window and registered for "send" commands
683
 *      under "baseName".  BaseName may be extended with an instance
684
 *      number in the form "#2" if necessary to make it globally
685
 *      unique.  Tk-related commands are bound into interp.
686
 *
687
 *----------------------------------------------------------------------
688
 */
689
 
690
Tk_Window
691
TkCreateMainWindow(interp, screenName, baseName)
692
    Tcl_Interp *interp;         /* Interpreter to use for error reporting. */
693
    char *screenName;           /* Name of screen on which to create
694
                                 * window.  Empty or NULL string means
695
                                 * use DISPLAY environment variable. */
696
    char *baseName;             /* Base name for application;  usually of the
697
                                 * form "prog instance". */
698
{
699
    Tk_Window tkwin;
700
    int dummy;
701
    int isSafe;
702
    Tcl_HashEntry *hPtr;
703
    register TkMainInfo *mainPtr;
704
    register TkWindow *winPtr;
705
    register TkCmd *cmdPtr;
706
 
707
    /*
708
     * Panic if someone updated the TkWindow structure without
709
     * also updating the Tk_FakeWin structure (or vice versa).
710
     */
711
 
712
    if (sizeof(TkWindow) != sizeof(Tk_FakeWin)) {
713
        panic("TkWindow and Tk_FakeWin are not the same size");
714
    }
715
 
716
    /*
717
     * Create the basic TkWindow structure.
718
     */
719
 
720
    tkwin = CreateTopLevelWindow(interp, (Tk_Window) NULL, baseName,
721
            screenName);
722
    if (tkwin == NULL) {
723
        return NULL;
724
    }
725
 
726
    /*
727
     * Create the TkMainInfo structure for this application, and set
728
     * up name-related information for the new window.
729
     */
730
 
731
    winPtr = (TkWindow *) tkwin;
732
    mainPtr = (TkMainInfo *) ckalloc(sizeof(TkMainInfo));
733
    mainPtr->winPtr = winPtr;
734
    mainPtr->refCount = 1;
735
    mainPtr->interp = interp;
736
    Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS);
737
    TkBindInit(mainPtr);
738
    TkFontPkgInit(mainPtr);
739
    mainPtr->tlFocusPtr = NULL;
740
    mainPtr->displayFocusPtr = NULL;
741
    mainPtr->optionRootPtr = NULL;
742
    Tcl_InitHashTable(&mainPtr->imageTable, TCL_STRING_KEYS);
743
    mainPtr->strictMotif = 0;
744
    if (Tcl_LinkVar(interp, "tk_strictMotif", (char *) &mainPtr->strictMotif,
745
            TCL_LINK_BOOLEAN) != TCL_OK) {
746
        Tcl_ResetResult(interp);
747
    }
748
    mainPtr->nextPtr = tkMainWindowList;
749
    tkMainWindowList = mainPtr;
750
    winPtr->mainPtr = mainPtr;
751
    hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy);
752
    Tcl_SetHashValue(hPtr, winPtr);
753
    winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr);
754
 
755
    /*
756
     * We have just created another Tk application; increment the refcount
757
     * on the display pointer.
758
     */
759
 
760
    winPtr->dispPtr->refCount++;
761
 
762
    /*
763
     * Register the interpreter for "send" purposes.
764
     */
765
 
766
    winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, baseName));
767
 
768
    /*
769
     * Bind in Tk's commands.
770
     */
771
 
772
    isSafe = Tcl_IsSafe(interp);
773
    for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
774
        if ((cmdPtr->cmdProc == NULL) && (cmdPtr->objProc == NULL)) {
775
            panic("TkCreateMainWindow: builtin command with NULL string and object procs");
776
        }
777
        if (cmdPtr->cmdProc != NULL) {
778
            Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc,
779
                    (ClientData) tkwin, (void (*) _ANSI_ARGS_((ClientData))) NULL);
780
        } else {
781
            Tcl_CreateObjCommand(interp, cmdPtr->name, cmdPtr->objProc,
782
                    (ClientData) tkwin, NULL);
783
        }
784
        if (isSafe) {
785
            if (!(cmdPtr->isSafe)) {
786
                Tcl_HideCommand(interp, cmdPtr->name, cmdPtr->name);
787
            }
788
        }
789
    }
790
 
791
    /*
792
     * Set variables for the intepreter.
793
     */
794
 
795
    Tcl_SetVar(interp, "tk_patchLevel", TK_PATCH_LEVEL, TCL_GLOBAL_ONLY);
796
    Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY);
797
 
798
    numMainWindows++;
799
    return tkwin;
800
}
801
 
802
/*
803
 *--------------------------------------------------------------
804
 *
805
 * Tk_CreateWindow --
806
 *
807
 *      Create a new internal or top-level window as a child of an
808
 *      existing window.
809
 *
810
 * Results:
811
 *      The return value is a token for the new window.  This
812
 *      is not the same as X's token for the window.  If an error
813
 *      occurred in creating the window (e.g. no such display or
814
 *      screen), then an error message is left in interp->result and
815
 *      NULL is returned.
816
 *
817
 * Side effects:
818
 *      A new window structure is allocated locally.  An X
819
 *      window is not initially created, but will be created
820
 *      the first time the window is mapped.
821
 *
822
 *--------------------------------------------------------------
823
 */
824
 
825
Tk_Window
826
Tk_CreateWindow(interp, parent, name, screenName)
827
    Tcl_Interp *interp;         /* Interpreter to use for error reporting.
828
                                 * Interp->result is assumed to be
829
                                 * initialized by the caller. */
830
    Tk_Window parent;           /* Token for parent of new window. */
831
    char *name;                 /* Name for new window.  Must be unique
832
                                 * among parent's children. */
833
    char *screenName;           /* If NULL, new window will be internal on
834
                                 * same screen as its parent.  If non-NULL,
835
                                 * gives name of screen on which to create
836
                                 * new window;  window will be a top-level
837
                                 * window. */
838
{
839
    TkWindow *parentPtr = (TkWindow *) parent;
840
    TkWindow *winPtr;
841
 
842
    if ((parentPtr != NULL) && (parentPtr->flags & TK_ALREADY_DEAD)) {
843
        Tcl_AppendResult(interp,
844
                "can't create window: parent has been destroyed",
845
                (char *) NULL);
846
        return NULL;
847
    } else if ((parentPtr != NULL) &&
848
            (parentPtr->flags & TK_CONTAINER)) {
849
        Tcl_AppendResult(interp,
850
                "can't create window: its parent has -container = yes",
851
                (char *) NULL);
852
        return NULL;
853
    }
854
    if (screenName == NULL) {
855
        winPtr = TkAllocWindow(parentPtr->dispPtr, parentPtr->screenNum,
856
                parentPtr);
857
        if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) {
858
            Tk_DestroyWindow((Tk_Window) winPtr);
859
            return NULL;
860
        } else {
861
            return (Tk_Window) winPtr;
862
        }
863
    } else {
864
        return CreateTopLevelWindow(interp, parent, name, screenName);
865
    }
866
}
867
 
868
/*
869
 *----------------------------------------------------------------------
870
 *
871
 * Tk_CreateWindowFromPath --
872
 *
873
 *      This procedure is similar to Tk_CreateWindow except that
874
 *      it uses a path name to create the window, rather than a
875
 *      parent and a child name.
876
 *
877
 * Results:
878
 *      The return value is a token for the new window.  This
879
 *      is not the same as X's token for the window.  If an error
880
 *      occurred in creating the window (e.g. no such display or
881
 *      screen), then an error message is left in interp->result and
882
 *      NULL is returned.
883
 *
884
 * Side effects:
885
 *      A new window structure is allocated locally.  An X
886
 *      window is not initially created, but will be created
887
 *      the first time the window is mapped.
888
 *
889
 *----------------------------------------------------------------------
890
 */
891
 
892
Tk_Window
893
Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName)
894
    Tcl_Interp *interp;         /* Interpreter to use for error reporting.
895
                                 * Interp->result is assumed to be
896
                                 * initialized by the caller. */
897
    Tk_Window tkwin;            /* Token for any window in application
898
                                 * that is to contain new window. */
899
    char *pathName;             /* Path name for new window within the
900
                                 * application of tkwin.  The parent of
901
                                 * this window must already exist, but
902
                                 * the window itself must not exist. */
903
    char *screenName;           /* If NULL, new window will be on same
904
                                 * screen as its parent.  If non-NULL,
905
                                 * gives name of screen on which to create
906
                                 * new window;  window will be a top-level
907
                                 * window. */
908
{
909
#define FIXED_SPACE 5
910
    char fixedSpace[FIXED_SPACE+1];
911
    char *p;
912
    Tk_Window parent;
913
    int numChars;
914
 
915
    /*
916
     * Strip the parent's name out of pathName (it's everything up
917
     * to the last dot).  There are two tricky parts: (a) must
918
     * copy the parent's name somewhere else to avoid modifying
919
     * the pathName string (for large names, space for the copy
920
     * will have to be malloc'ed);  (b) must special-case the
921
     * situation where the parent is ".".
922
     */
923
 
924
    p = strrchr(pathName, '.');
925
    if (p == NULL) {
926
        Tcl_AppendResult(interp, "bad window path name \"", pathName,
927
                "\"", (char *) NULL);
928
        return NULL;
929
    }
930
    numChars = p-pathName;
931
    if (numChars > FIXED_SPACE) {
932
        p = (char *) ckalloc((unsigned) (numChars+1));
933
    } else {
934
        p = fixedSpace;
935
    }
936
    if (numChars == 0) {
937
        *p = '.';
938
        p[1] = '\0';
939
    } else {
940
        strncpy(p, pathName, (size_t) numChars);
941
        p[numChars] = '\0';
942
    }
943
 
944
    /*
945
     * Find the parent window.
946
     */
947
 
948
    parent = Tk_NameToWindow(interp, p, tkwin);
949
    if (p != fixedSpace) {
950
        ckfree(p);
951
    }
952
    if (parent == NULL) {
953
        return NULL;
954
    }
955
    if (((TkWindow *) parent)->flags & TK_ALREADY_DEAD) {
956
        Tcl_AppendResult(interp,
957
            "can't create window: parent has been destroyed", (char *) NULL);
958
        return NULL;
959
    } else if (((TkWindow *) parent)->flags & TK_CONTAINER) {
960
        Tcl_AppendResult(interp,
961
            "can't create window: its parent has -container = yes",
962
                (char *) NULL);
963
        return NULL;
964
    }
965
 
966
    /*
967
     * Create the window.
968
     */
969
 
970
    if (screenName == NULL) {
971
        TkWindow *parentPtr = (TkWindow *) parent;
972
        TkWindow *winPtr;
973
 
974
        winPtr = TkAllocWindow(parentPtr->dispPtr, parentPtr->screenNum,
975
                parentPtr);
976
        if (NameWindow(interp, winPtr, parentPtr, pathName+numChars+1)
977
                != TCL_OK) {
978
            Tk_DestroyWindow((Tk_Window) winPtr);
979
            return NULL;
980
        } else {
981
            return (Tk_Window) winPtr;
982
        }
983
    } else {
984
        return CreateTopLevelWindow(interp, parent, pathName+numChars+1,
985
                screenName);
986
    }
987
}
988
 
989
/*
990
 *--------------------------------------------------------------
991
 *
992
 * Tk_DestroyWindow --
993
 *
994
 *      Destroy an existing window.  After this call, the caller
995
 *      should never again use the token.
996
 *
997
 * Results:
998
 *      None.
999
 *
1000
 * Side effects:
1001
 *      The window is deleted, along with all of its children.
1002
 *      Relevant callback procedures are invoked.
1003
 *
1004
 *--------------------------------------------------------------
1005
 */
1006
 
1007
void
1008
Tk_DestroyWindow(tkwin)
1009
    Tk_Window tkwin;            /* Window to destroy. */
1010
{
1011
    TkWindow *winPtr = (TkWindow *) tkwin;
1012
    TkDisplay *dispPtr = winPtr->dispPtr;
1013
    XEvent event;
1014
 
1015
    if (winPtr->flags & TK_ALREADY_DEAD) {
1016
        /*
1017
         * A destroy event binding caused the window to be destroyed
1018
         * again.  Ignore the request.
1019
         */
1020
 
1021
        return;
1022
    }
1023
    winPtr->flags |= TK_ALREADY_DEAD;
1024
 
1025
    /*
1026
     * Some cleanup needs to be done immediately, rather than later,
1027
     * because it needs information that will be destoyed before we
1028
     * get to the main cleanup point.  For example, TkFocusDeadWindow
1029
     * needs to access the parentPtr field from a window, but if
1030
     * a Destroy event handler deletes the window's parent this
1031
     * field will be NULL before the main cleanup point is reached.
1032
     */
1033
 
1034
    TkFocusDeadWindow(winPtr);
1035
 
1036
    /*
1037
     * If this is a main window, remove it from the list of main
1038
     * windows.  This needs to be done now (rather than later with
1039
     * all the other main window cleanup) to handle situations where
1040
     * a destroy binding for a window calls "exit".  In this case
1041
     * the child window cleanup isn't complete when exit is called,
1042
     * so the reference count of its application doesn't go to zero
1043
     * when exit calls Tk_DestroyWindow on ".", so the main window
1044
     * doesn't get removed from the list and exit loops infinitely.
1045
     * Even worse, if "destroy ." is called by the destroy binding
1046
     * before calling "exit", "exit" will attempt to destroy
1047
     * mainPtr->winPtr, which no longer exists, and there may be a
1048
     * core dump.
1049
     *
1050
     * Also decrement the display refcount so that if this is the
1051
     * last Tk application in this process on this display, the display
1052
     * can be closed and its data structures deleted.
1053
     */
1054
 
1055
    if (winPtr->mainPtr->winPtr == winPtr) {
1056
        dispPtr->refCount--;
1057
        if (tkMainWindowList == winPtr->mainPtr) {
1058
            tkMainWindowList = winPtr->mainPtr->nextPtr;
1059
        } else {
1060
            TkMainInfo *prevPtr;
1061
 
1062
            for (prevPtr = tkMainWindowList;
1063
                    prevPtr->nextPtr != winPtr->mainPtr;
1064
                    prevPtr = prevPtr->nextPtr) {
1065
                /* Empty loop body. */
1066
            }
1067
            prevPtr->nextPtr = winPtr->mainPtr->nextPtr;
1068
        }
1069
        numMainWindows--;
1070
    }
1071
 
1072
    /*
1073
     * Recursively destroy children.
1074
     */
1075
 
1076
    dispPtr->destroyCount++;
1077
    while (winPtr->childList != NULL) {
1078
        TkWindow *childPtr;
1079
        childPtr = winPtr->childList;
1080
        childPtr->flags |= TK_DONT_DESTROY_WINDOW;
1081
        Tk_DestroyWindow((Tk_Window) childPtr);
1082
        if (winPtr->childList == childPtr) {
1083
            /*
1084
             * The child didn't remove itself from the child list, so
1085
             * let's remove it here.  This can happen in some strange
1086
             * conditions, such as when a Delete event handler for a
1087
             * window deletes the window's parent.
1088
             */
1089
 
1090
            winPtr->childList = childPtr->nextPtr;
1091
            childPtr->parentPtr = NULL;
1092
        }
1093
    }
1094
    if ((winPtr->flags & (TK_CONTAINER|TK_BOTH_HALVES))
1095
            == (TK_CONTAINER|TK_BOTH_HALVES)) {
1096
        /*
1097
         * This is the container for an embedded application, and
1098
         * the embedded application is also in this process.  Delete
1099
         * the embedded window in-line here, for the same reasons we
1100
         * delete children in-line (otherwise, for example, the Tk
1101
         * window may appear to exist even though its X window is
1102
         * gone; this could cause errors).  Special note: it's possible
1103
         * that the embedded window has already been deleted, in which
1104
         * case TkpGetOtherWindow will return NULL.
1105
         */
1106
 
1107
        TkWindow *childPtr;
1108
        childPtr = TkpGetOtherWindow(winPtr);
1109
        if (childPtr != NULL) {
1110
            childPtr->flags |= TK_DONT_DESTROY_WINDOW;
1111
            Tk_DestroyWindow((Tk_Window) childPtr);
1112
        }
1113
    }
1114
 
1115
    /*
1116
     * Generate a DestroyNotify event.  In order for the DestroyNotify
1117
     * event to be processed correctly, need to make sure the window
1118
     * exists.  This is a bit of a kludge, and may be unnecessarily
1119
     * expensive, but without it no event handlers will get called for
1120
     * windows that don't exist yet.
1121
     *
1122
     * Note: if the window's pathName is NULL it means that the window
1123
     * was not successfully initialized in the first place, so we should
1124
     * not make the window exist or generate the event.
1125
     */
1126
 
1127
    if (winPtr->pathName != NULL) {
1128
        if (winPtr->window == None) {
1129
            Tk_MakeWindowExist(tkwin);
1130
        }
1131
        event.type = DestroyNotify;
1132
        event.xdestroywindow.serial =
1133
                LastKnownRequestProcessed(winPtr->display);
1134
        event.xdestroywindow.send_event = False;
1135
        event.xdestroywindow.display = winPtr->display;
1136
        event.xdestroywindow.event = winPtr->window;
1137
        event.xdestroywindow.window = winPtr->window;
1138
        Tk_HandleEvent(&event);
1139
    }
1140
 
1141
    /*
1142
     * Cleanup the data structures associated with this window.
1143
     */
1144
 
1145
    if (winPtr->flags & TK_TOP_LEVEL) {
1146
        TkWmDeadWindow(winPtr);
1147
    } else if (winPtr->flags & TK_WM_COLORMAP_WINDOW) {
1148
        TkWmRemoveFromColormapWindows(winPtr);
1149
    }
1150
    if (winPtr->window != None) {
1151
#if defined(MAC_TCL) || defined(__WIN32__)
1152
        XDestroyWindow(winPtr->display, winPtr->window);
1153
#else
1154
        if ((winPtr->flags & TK_TOP_LEVEL)
1155
                || !(winPtr->flags & TK_DONT_DESTROY_WINDOW)) {
1156
            /*
1157
             * The parent has already been destroyed and this isn't
1158
             * a top-level window, so this window will be destroyed
1159
             * implicitly when the parent's X window is destroyed;
1160
             * it's much faster not to do an explicit destroy of this
1161
             * X window.
1162
             */
1163
 
1164
            dispPtr->lastDestroyRequest = NextRequest(winPtr->display);
1165
            XDestroyWindow(winPtr->display, winPtr->window);
1166
        }
1167
#endif
1168
        TkFreeWindowId(dispPtr, winPtr->window);
1169
        Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->winTable,
1170
                (char *) winPtr->window));
1171
        winPtr->window = None;
1172
    }
1173
    dispPtr->destroyCount--;
1174
    UnlinkWindow(winPtr);
1175
    TkEventDeadWindow(winPtr);
1176
    TkBindDeadWindow(winPtr);
1177
#ifdef TK_USE_INPUT_METHODS
1178
    if (winPtr->inputContext != NULL) {
1179
        XDestroyIC(winPtr->inputContext);
1180
    }
1181
#endif /* TK_USE_INPUT_METHODS */
1182
    if (winPtr->tagPtr != NULL) {
1183
        TkFreeBindingTags(winPtr);
1184
    }
1185
    TkOptionDeadWindow(winPtr);
1186
    TkSelDeadWindow(winPtr);
1187
    TkGrabDeadWindow(winPtr);
1188
    if (winPtr->mainPtr != NULL) {
1189
        if (winPtr->pathName != NULL) {
1190
            Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable,
1191
                    (ClientData) winPtr->pathName);
1192
            Tcl_DeleteHashEntry(Tcl_FindHashEntry(&winPtr->mainPtr->nameTable,
1193
                    winPtr->pathName));
1194
        }
1195
        winPtr->mainPtr->refCount--;
1196
        if (winPtr->mainPtr->refCount == 0) {
1197
            register TkCmd *cmdPtr;
1198
 
1199
            /*
1200
             * We just deleted the last window in the application.  Delete
1201
             * the TkMainInfo structure too and replace all of Tk's commands
1202
             * with dummy commands that return errors.  Also delete the
1203
             * "send" command to unregister the interpreter.
1204
             *
1205
             * NOTE: Only replace the commands it if the interpreter is
1206
             * not being deleted. If it *is*, the interpreter cleanup will
1207
             * do all the needed work.
1208
             */
1209
 
1210
            if ((winPtr->mainPtr->interp != NULL) &&
1211
                    (!Tcl_InterpDeleted(winPtr->mainPtr->interp))) {
1212
                for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
1213
                    Tcl_CreateCommand(winPtr->mainPtr->interp, cmdPtr->name,
1214
                            TkDeadAppCmd, (ClientData) NULL,
1215
                            (void (*) _ANSI_ARGS_((ClientData))) NULL);
1216
                }
1217
                Tcl_CreateCommand(winPtr->mainPtr->interp, "send",
1218
                        TkDeadAppCmd, (ClientData) NULL,
1219
                        (void (*) _ANSI_ARGS_((ClientData))) NULL);
1220
                Tcl_UnlinkVar(winPtr->mainPtr->interp, "tk_strictMotif");
1221
            }
1222
 
1223
            Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable);
1224
            TkBindFree(winPtr->mainPtr);
1225
            TkFontPkgFree(winPtr->mainPtr);
1226
            TkDeleteAllImages(winPtr->mainPtr);
1227
 
1228
            /*
1229
             * When embedding Tk into other applications, make sure
1230
             * that all destroy events reach the server. Otherwise
1231
             * the embedding application may also attempt to destroy
1232
             * the windows, resulting in an X error
1233
             */
1234
 
1235
            if (winPtr->flags & TK_EMBEDDED) {
1236
                XSync(winPtr->display,False) ;
1237
            }
1238
            ckfree((char *) winPtr->mainPtr);
1239
 
1240
            /*
1241
             * If no other applications are using the display, close the
1242
             * display now and relinquish its data structures.
1243
             */
1244
 
1245
            if (dispPtr->refCount <= 0) {
1246
#ifdef  NOT_YET
1247
                /*
1248
                 * I have disabled this code because on Windows there are
1249
                 * still order dependencies in close-down. All displays
1250
                 * and resources will get closed down properly anyway at
1251
                 * exit, through the exit handler.
1252
                 */
1253
 
1254
                TkDisplay *theDispPtr, *backDispPtr;
1255
 
1256
                /*
1257
                 * Splice this display out of the list of displays.
1258
                 */
1259
 
1260
                for (theDispPtr = tkDisplayList, backDispPtr = NULL;
1261
                         (theDispPtr != winPtr->dispPtr) &&
1262
                             (theDispPtr != NULL);
1263
                         theDispPtr = theDispPtr->nextPtr) {
1264
                    backDispPtr = theDispPtr;
1265
                }
1266
                if (theDispPtr == NULL) {
1267
                    panic("could not find display to close!");
1268
                }
1269
                if (backDispPtr == NULL) {
1270
                    tkDisplayList = theDispPtr->nextPtr;
1271
                } else {
1272
                    backDispPtr->nextPtr = theDispPtr->nextPtr;
1273
                }
1274
 
1275
                /*
1276
                 * Found and spliced it out, now actually do the cleanup.
1277
                 */
1278
 
1279
                if (dispPtr->name != NULL) {
1280
                    ckfree(dispPtr->name);
1281
                }
1282
 
1283
                Tcl_DeleteHashTable(&(dispPtr->winTable));
1284
 
1285
                /*
1286
                 * Cannot yet close the display because we still have
1287
                 * order of deletion problems. Defer until exit handling
1288
                 * instead. At that time, the display will cleanly shut
1289
                 * down (hopefully..). (JYL)
1290
                 */
1291
 
1292
                TkpCloseDisplay(dispPtr);
1293
 
1294
                /*
1295
                 * There is lots more to clean up, we leave it at this for
1296
                 * the time being.
1297
                 */
1298
#endif
1299
            }
1300
        }
1301
    }
1302
    ckfree((char *) winPtr);
1303
}
1304
 
1305
/*
1306
 *--------------------------------------------------------------
1307
 *
1308
 * Tk_MapWindow --
1309
 *
1310
 *      Map a window within its parent.  This may require the
1311
 *      window and/or its parents to actually be created.
1312
 *
1313
 * Results:
1314
 *      None.
1315
 *
1316
 * Side effects:
1317
 *      The given window will be mapped.  Windows may also
1318
 *      be created.
1319
 *
1320
 *--------------------------------------------------------------
1321
 */
1322
 
1323
void
1324
Tk_MapWindow(tkwin)
1325
    Tk_Window tkwin;            /* Token for window to map. */
1326
{
1327
    register TkWindow *winPtr = (TkWindow *) tkwin;
1328
    XEvent event;
1329
 
1330
    if (winPtr->flags & TK_MAPPED) {
1331
        return;
1332
    }
1333
    if (winPtr->window == None) {
1334
        Tk_MakeWindowExist(tkwin);
1335
    }
1336
    if (winPtr->flags & TK_TOP_LEVEL) {
1337
        /*
1338
         * Lots of special processing has to be done for top-level
1339
         * windows.  Let tkWm.c handle everything itself.
1340
         */
1341
 
1342
        TkWmMapWindow(winPtr);
1343
        return;
1344
    }
1345
    winPtr->flags |= TK_MAPPED;
1346
    XMapWindow(winPtr->display, winPtr->window);
1347
    event.type = MapNotify;
1348
    event.xmap.serial = LastKnownRequestProcessed(winPtr->display);
1349
    event.xmap.send_event = False;
1350
    event.xmap.display = winPtr->display;
1351
    event.xmap.event = winPtr->window;
1352
    event.xmap.window = winPtr->window;
1353
    event.xmap.override_redirect = winPtr->atts.override_redirect;
1354
    Tk_HandleEvent(&event);
1355
}
1356
 
1357
/*
1358
 *--------------------------------------------------------------
1359
 *
1360
 * Tk_MakeWindowExist --
1361
 *
1362
 *      Ensure that a particular window actually exists.  This
1363
 *      procedure shouldn't normally need to be invoked from
1364
 *      outside the Tk package, but may be needed if someone
1365
 *      wants to manipulate a window before mapping it.
1366
 *
1367
 * Results:
1368
 *      None.
1369
 *
1370
 * Side effects:
1371
 *      When the procedure returns, the X window associated with
1372
 *      tkwin is guaranteed to exist.  This may require the
1373
 *      window's ancestors to be created also.
1374
 *
1375
 *--------------------------------------------------------------
1376
 */
1377
 
1378
void
1379
Tk_MakeWindowExist(tkwin)
1380
    Tk_Window tkwin;            /* Token for window. */
1381
{
1382
    register TkWindow *winPtr = (TkWindow *) tkwin;
1383
    TkWindow *winPtr2;
1384
    Window parent;
1385
    Tcl_HashEntry *hPtr;
1386
    int new;
1387
 
1388
    if (winPtr->window != None) {
1389
        return;
1390
    }
1391
 
1392
    if ((winPtr->parentPtr == NULL) || (winPtr->flags & TK_TOP_LEVEL)) {
1393
        parent = XRootWindow(winPtr->display, winPtr->screenNum);
1394
    } else {
1395
        if (winPtr->parentPtr->window == None) {
1396
            Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr);
1397
        }
1398
        parent = winPtr->parentPtr->window;
1399
    }
1400
 
1401
    if (winPtr->classProcsPtr != NULL
1402
            && winPtr->classProcsPtr->createProc != NULL) {
1403
        winPtr->window = (*winPtr->classProcsPtr->createProc)(tkwin, parent,
1404
                winPtr->instanceData);
1405
    } else {
1406
        winPtr->window = TkpMakeWindow(winPtr, parent);
1407
    }
1408
 
1409
    hPtr = Tcl_CreateHashEntry(&winPtr->dispPtr->winTable,
1410
            (char *) winPtr->window, &new);
1411
    Tcl_SetHashValue(hPtr, winPtr);
1412
    winPtr->dirtyAtts = 0;
1413
    winPtr->dirtyChanges = 0;
1414
#ifdef TK_USE_INPUT_METHODS
1415
    winPtr->inputContext = NULL;
1416
#endif /* TK_USE_INPUT_METHODS */
1417
 
1418
    if (!(winPtr->flags & TK_TOP_LEVEL)) {
1419
        /*
1420
         * If any siblings higher up in the stacking order have already
1421
         * been created then move this window to its rightful position
1422
         * in the stacking order.
1423
         *
1424
         * NOTE: this code ignores any changes anyone might have made
1425
         * to the sibling and stack_mode field of the window's attributes,
1426
         * so it really isn't safe for these to be manipulated except
1427
         * by calling Tk_RestackWindow.
1428
         */
1429
 
1430
        for (winPtr2 = winPtr->nextPtr; winPtr2 != NULL;
1431
                winPtr2 = winPtr2->nextPtr) {
1432
            if ((winPtr2->window != None)
1433
                    && !(winPtr2->flags & (TK_TOP_LEVEL|TK_REPARENTED))) {
1434
                XWindowChanges changes;
1435
                changes.sibling = winPtr2->window;
1436
                changes.stack_mode = Below;
1437
                XConfigureWindow(winPtr->display, winPtr->window,
1438
                        CWSibling|CWStackMode, &changes);
1439
                break;
1440
            }
1441
        }
1442
 
1443
        /*
1444
         * If this window has a different colormap than its parent, add
1445
         * the window to the WM_COLORMAP_WINDOWS property for its top-level.
1446
         */
1447
 
1448
        if ((winPtr->parentPtr != NULL) &&
1449
                (winPtr->atts.colormap != winPtr->parentPtr->atts.colormap)) {
1450
            TkWmAddToColormapWindows(winPtr);
1451
            winPtr->flags |= TK_WM_COLORMAP_WINDOW;
1452
        }
1453
    }
1454
 
1455
    /*
1456
     * Issue a ConfigureNotify event if there were deferred configuration
1457
     * changes (but skip it if the window is being deleted;  the
1458
     * ConfigureNotify event could cause problems if we're being called
1459
     * from Tk_DestroyWindow under some conditions).
1460
     */
1461
 
1462
    if ((winPtr->flags & TK_NEED_CONFIG_NOTIFY)
1463
            && !(winPtr->flags & TK_ALREADY_DEAD)){
1464
        winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY;
1465
        TkDoConfigureNotify(winPtr);
1466
    }
1467
}
1468
 
1469
/*
1470
 *--------------------------------------------------------------
1471
 *
1472
 * Tk_UnmapWindow, etc. --
1473
 *
1474
 *      There are several procedures under here, each of which
1475
 *      mirrors an existing X procedure.  In addition to performing
1476
 *      the functions of the corresponding procedure, each
1477
 *      procedure also updates the local window structure and
1478
 *      synthesizes an X event (if the window's structure is being
1479
 *      managed internally).
1480
 *
1481
 * Results:
1482
 *      See the manual entries.
1483
 *
1484
 * Side effects:
1485
 *      See the manual entries.
1486
 *
1487
 *--------------------------------------------------------------
1488
 */
1489
 
1490
void
1491
Tk_UnmapWindow(tkwin)
1492
    Tk_Window tkwin;            /* Token for window to unmap. */
1493
{
1494
    register TkWindow *winPtr = (TkWindow *) tkwin;
1495
 
1496
    if (!(winPtr->flags & TK_MAPPED) || (winPtr->flags & TK_ALREADY_DEAD)) {
1497
        return;
1498
    }
1499
    if (winPtr->flags & TK_TOP_LEVEL) {
1500
        /*
1501
         * Special processing has to be done for top-level windows.  Let
1502
         * tkWm.c handle everything itself.
1503
         */
1504
 
1505
        TkWmUnmapWindow(winPtr);
1506
        return;
1507
    }
1508
    winPtr->flags &= ~TK_MAPPED;
1509
    XUnmapWindow(winPtr->display, winPtr->window);
1510
    if (!(winPtr->flags & TK_TOP_LEVEL)) {
1511
        XEvent event;
1512
 
1513
        event.type = UnmapNotify;
1514
        event.xunmap.serial = LastKnownRequestProcessed(winPtr->display);
1515
        event.xunmap.send_event = False;
1516
        event.xunmap.display = winPtr->display;
1517
        event.xunmap.event = winPtr->window;
1518
        event.xunmap.window = winPtr->window;
1519
        event.xunmap.from_configure = False;
1520
        Tk_HandleEvent(&event);
1521
    }
1522
}
1523
 
1524
void
1525
Tk_ConfigureWindow(tkwin, valueMask, valuePtr)
1526
    Tk_Window tkwin;            /* Window to re-configure. */
1527
    unsigned int valueMask;     /* Mask indicating which parts of
1528
                                 * *valuePtr are to be used. */
1529
    XWindowChanges *valuePtr;   /* New values. */
1530
{
1531
    register TkWindow *winPtr = (TkWindow *) tkwin;
1532
 
1533
    if (valueMask & CWX) {
1534
        winPtr->changes.x = valuePtr->x;
1535
    }
1536
    if (valueMask & CWY) {
1537
        winPtr->changes.y = valuePtr->y;
1538
    }
1539
    if (valueMask & CWWidth) {
1540
        winPtr->changes.width = valuePtr->width;
1541
    }
1542
    if (valueMask & CWHeight) {
1543
        winPtr->changes.height = valuePtr->height;
1544
    }
1545
    if (valueMask & CWBorderWidth) {
1546
        winPtr->changes.border_width = valuePtr->border_width;
1547
    }
1548
    if (valueMask & (CWSibling|CWStackMode)) {
1549
        panic("Can't set sibling or stack mode from Tk_ConfigureWindow.");
1550
    }
1551
 
1552
    if (winPtr->window != None) {
1553
        XConfigureWindow(winPtr->display, winPtr->window,
1554
                valueMask, valuePtr);
1555
        TkDoConfigureNotify(winPtr);
1556
    } else {
1557
        winPtr->dirtyChanges |= valueMask;
1558
        winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
1559
    }
1560
}
1561
 
1562
void
1563
Tk_MoveWindow(tkwin, x, y)
1564
    Tk_Window tkwin;            /* Window to move. */
1565
    int x, y;                   /* New location for window (within
1566
                                 * parent). */
1567
{
1568
    register TkWindow *winPtr = (TkWindow *) tkwin;
1569
 
1570
    winPtr->changes.x = x;
1571
    winPtr->changes.y = y;
1572
    if (winPtr->window != None) {
1573
        XMoveWindow(winPtr->display, winPtr->window, x, y);
1574
        TkDoConfigureNotify(winPtr);
1575
    } else {
1576
        winPtr->dirtyChanges |= CWX|CWY;
1577
        winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
1578
    }
1579
}
1580
 
1581
void
1582
Tk_ResizeWindow(tkwin, width, height)
1583
    Tk_Window tkwin;            /* Window to resize. */
1584
    int width, height;          /* New dimensions for window. */
1585
{
1586
    register TkWindow *winPtr = (TkWindow *) tkwin;
1587
 
1588
    winPtr->changes.width = (unsigned) width;
1589
    winPtr->changes.height = (unsigned) height;
1590
    if (winPtr->window != None) {
1591
        XResizeWindow(winPtr->display, winPtr->window, (unsigned) width,
1592
                (unsigned) height);
1593
        TkDoConfigureNotify(winPtr);
1594
    } else {
1595
        winPtr->dirtyChanges |= CWWidth|CWHeight;
1596
        winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
1597
    }
1598
}
1599
 
1600
void
1601
Tk_MoveResizeWindow(tkwin, x, y, width, height)
1602
    Tk_Window tkwin;            /* Window to move and resize. */
1603
    int x, y;                   /* New location for window (within
1604
                                 * parent). */
1605
    int width, height;          /* New dimensions for window. */
1606
{
1607
    register TkWindow *winPtr = (TkWindow *) tkwin;
1608
 
1609
    winPtr->changes.x = x;
1610
    winPtr->changes.y = y;
1611
    winPtr->changes.width = (unsigned) width;
1612
    winPtr->changes.height = (unsigned) height;
1613
    if (winPtr->window != None) {
1614
        XMoveResizeWindow(winPtr->display, winPtr->window, x, y,
1615
                (unsigned) width, (unsigned) height);
1616
        TkDoConfigureNotify(winPtr);
1617
    } else {
1618
        winPtr->dirtyChanges |= CWX|CWY|CWWidth|CWHeight;
1619
        winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
1620
    }
1621
}
1622
 
1623
void
1624
Tk_SetWindowBorderWidth(tkwin, width)
1625
    Tk_Window tkwin;            /* Window to modify. */
1626
    int width;                  /* New border width for window. */
1627
{
1628
    register TkWindow *winPtr = (TkWindow *) tkwin;
1629
 
1630
    winPtr->changes.border_width = width;
1631
    if (winPtr->window != None) {
1632
        XSetWindowBorderWidth(winPtr->display, winPtr->window,
1633
                (unsigned) width);
1634
        TkDoConfigureNotify(winPtr);
1635
    } else {
1636
        winPtr->dirtyChanges |= CWBorderWidth;
1637
        winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
1638
    }
1639
}
1640
 
1641
void
1642
Tk_ChangeWindowAttributes(tkwin, valueMask, attsPtr)
1643
    Tk_Window tkwin;            /* Window to manipulate. */
1644
    unsigned long valueMask;    /* OR'ed combination of bits,
1645
                                 * indicating which fields of
1646
                                 * *attsPtr are to be used. */
1647
    register XSetWindowAttributes *attsPtr;
1648
                                /* New values for some attributes. */
1649
{
1650
    register TkWindow *winPtr = (TkWindow *) tkwin;
1651
 
1652
    if (valueMask & CWBackPixmap) {
1653
        winPtr->atts.background_pixmap = attsPtr->background_pixmap;
1654
    }
1655
    if (valueMask & CWBackPixel) {
1656
        winPtr->atts.background_pixel = attsPtr->background_pixel;
1657
    }
1658
    if (valueMask & CWBorderPixmap) {
1659
        winPtr->atts.border_pixmap = attsPtr->border_pixmap;
1660
    }
1661
    if (valueMask & CWBorderPixel) {
1662
        winPtr->atts.border_pixel = attsPtr->border_pixel;
1663
    }
1664
    if (valueMask & CWBitGravity) {
1665
        winPtr->atts.bit_gravity = attsPtr->bit_gravity;
1666
    }
1667
    if (valueMask & CWWinGravity) {
1668
        winPtr->atts.win_gravity = attsPtr->win_gravity;
1669
    }
1670
    if (valueMask & CWBackingStore) {
1671
        winPtr->atts.backing_store = attsPtr->backing_store;
1672
    }
1673
    if (valueMask & CWBackingPlanes) {
1674
        winPtr->atts.backing_planes = attsPtr->backing_planes;
1675
    }
1676
    if (valueMask & CWBackingPixel) {
1677
        winPtr->atts.backing_pixel = attsPtr->backing_pixel;
1678
    }
1679
    if (valueMask & CWOverrideRedirect) {
1680
        winPtr->atts.override_redirect = attsPtr->override_redirect;
1681
    }
1682
    if (valueMask & CWSaveUnder) {
1683
        winPtr->atts.save_under = attsPtr->save_under;
1684
    }
1685
    if (valueMask & CWEventMask) {
1686
        winPtr->atts.event_mask = attsPtr->event_mask;
1687
    }
1688
    if (valueMask & CWDontPropagate) {
1689
        winPtr->atts.do_not_propagate_mask
1690
                = attsPtr->do_not_propagate_mask;
1691
    }
1692
    if (valueMask & CWColormap) {
1693
        winPtr->atts.colormap = attsPtr->colormap;
1694
    }
1695
    if (valueMask & CWCursor) {
1696
        winPtr->atts.cursor = attsPtr->cursor;
1697
    }
1698
 
1699
    if (winPtr->window != None) {
1700
        XChangeWindowAttributes(winPtr->display, winPtr->window,
1701
                valueMask, attsPtr);
1702
    } else {
1703
        winPtr->dirtyAtts |= valueMask;
1704
    }
1705
}
1706
 
1707
void
1708
Tk_SetWindowBackground(tkwin, pixel)
1709
    Tk_Window tkwin;            /* Window to manipulate. */
1710
    unsigned long pixel;        /* Pixel value to use for
1711
                                 * window's background. */
1712
{
1713
    register TkWindow *winPtr = (TkWindow *) tkwin;
1714
 
1715
    winPtr->atts.background_pixel = pixel;
1716
 
1717
    if (winPtr->window != None) {
1718
        XSetWindowBackground(winPtr->display, winPtr->window, pixel);
1719
    } else {
1720
        winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixmap)
1721
                | CWBackPixel;
1722
    }
1723
}
1724
 
1725
void
1726
Tk_SetWindowBackgroundPixmap(tkwin, pixmap)
1727
    Tk_Window tkwin;            /* Window to manipulate. */
1728
    Pixmap pixmap;              /* Pixmap to use for window's
1729
                                 * background. */
1730
{
1731
    register TkWindow *winPtr = (TkWindow *) tkwin;
1732
 
1733
    winPtr->atts.background_pixmap = pixmap;
1734
 
1735
    if (winPtr->window != None) {
1736
        XSetWindowBackgroundPixmap(winPtr->display,
1737
                winPtr->window, pixmap);
1738
    } else {
1739
        winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixel)
1740
                | CWBackPixmap;
1741
    }
1742
}
1743
 
1744
void
1745
Tk_SetWindowBorder(tkwin, pixel)
1746
    Tk_Window tkwin;            /* Window to manipulate. */
1747
    unsigned long pixel;        /* Pixel value to use for
1748
                                 * window's border. */
1749
{
1750
    register TkWindow *winPtr = (TkWindow *) tkwin;
1751
 
1752
    winPtr->atts.border_pixel = pixel;
1753
 
1754
    if (winPtr->window != None) {
1755
        XSetWindowBorder(winPtr->display, winPtr->window, pixel);
1756
    } else {
1757
        winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixmap)
1758
                | CWBorderPixel;
1759
    }
1760
}
1761
 
1762
void
1763
Tk_SetWindowBorderPixmap(tkwin, pixmap)
1764
    Tk_Window tkwin;            /* Window to manipulate. */
1765
    Pixmap pixmap;              /* Pixmap to use for window's
1766
                                 * border. */
1767
{
1768
    register TkWindow *winPtr = (TkWindow *) tkwin;
1769
 
1770
    winPtr->atts.border_pixmap = pixmap;
1771
 
1772
    if (winPtr->window != None) {
1773
        XSetWindowBorderPixmap(winPtr->display,
1774
                winPtr->window, pixmap);
1775
    } else {
1776
        winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixel)
1777
                | CWBorderPixmap;
1778
    }
1779
}
1780
 
1781
void
1782
Tk_DefineCursor(tkwin, cursor)
1783
    Tk_Window tkwin;            /* Window to manipulate. */
1784
    Tk_Cursor cursor;           /* Cursor to use for window (may be None). */
1785
{
1786
    register TkWindow *winPtr = (TkWindow *) tkwin;
1787
 
1788
#ifdef MAC_TCL
1789
    winPtr->atts.cursor = (XCursor) cursor;
1790
#else
1791
    winPtr->atts.cursor = (Cursor) cursor;
1792
#endif
1793
 
1794
    if (winPtr->window != None) {
1795
        XDefineCursor(winPtr->display, winPtr->window, winPtr->atts.cursor);
1796
    } else {
1797
        winPtr->dirtyAtts = winPtr->dirtyAtts | CWCursor;
1798
    }
1799
}
1800
 
1801
void
1802
Tk_UndefineCursor(tkwin)
1803
    Tk_Window tkwin;            /* Window to manipulate. */
1804
{
1805
    Tk_DefineCursor(tkwin, None);
1806
}
1807
 
1808
void
1809
Tk_SetWindowColormap(tkwin, colormap)
1810
    Tk_Window tkwin;            /* Window to manipulate. */
1811
    Colormap colormap;          /* Colormap to use for window. */
1812
{
1813
    register TkWindow *winPtr = (TkWindow *) tkwin;
1814
 
1815
    winPtr->atts.colormap = colormap;
1816
 
1817
    if (winPtr->window != None) {
1818
        XSetWindowColormap(winPtr->display, winPtr->window, colormap);
1819
        if (!(winPtr->flags & TK_TOP_LEVEL)) {
1820
            TkWmAddToColormapWindows(winPtr);
1821
            winPtr->flags |= TK_WM_COLORMAP_WINDOW;
1822
        }
1823
    } else {
1824
        winPtr->dirtyAtts |= CWColormap;
1825
    }
1826
}
1827
 
1828
/*
1829
 *----------------------------------------------------------------------
1830
 *
1831
 * Tk_SetWindowVisual --
1832
 *
1833
 *      This procedure is called to specify a visual to be used
1834
 *      for a Tk window when it is created.  This procedure, if
1835
 *      called at all, must be called before the X window is created
1836
 *      (i.e. before Tk_MakeWindowExist is called).
1837
 *
1838
 * Results:
1839
 *      The return value is 1 if successful, or 0 if the X window has
1840
 *      been already created.
1841
 *
1842
 * Side effects:
1843
 *      The information given is stored for when the window is created.
1844
 *
1845
 *----------------------------------------------------------------------
1846
 */
1847
 
1848
int
1849
Tk_SetWindowVisual(tkwin, visual, depth, colormap)
1850
    Tk_Window tkwin;            /* Window to manipulate. */
1851
    Visual *visual;             /* New visual for window. */
1852
    int depth;                  /* New depth for window. */
1853
    Colormap colormap;          /* An appropriate colormap for the visual. */
1854
{
1855
    register TkWindow *winPtr = (TkWindow *) tkwin;
1856
 
1857
    if( winPtr->window != None ){
1858
        /* Too late! */
1859
        return 0;
1860
    }
1861
 
1862
    winPtr->visual = visual;
1863
    winPtr->depth = depth;
1864
    winPtr->atts.colormap = colormap;
1865
    winPtr->dirtyAtts |= CWColormap;
1866
 
1867
    /*
1868
     * The following code is needed to make sure that the window doesn't
1869
     * inherit the parent's border pixmap, which would result in a BadMatch
1870
     * error.
1871
     */
1872
 
1873
    if (!(winPtr->dirtyAtts & CWBorderPixmap)) {
1874
        winPtr->dirtyAtts |= CWBorderPixel;
1875
    }
1876
    return 1;
1877
}
1878
 
1879
/*
1880
 *----------------------------------------------------------------------
1881
 *
1882
 * TkDoConfigureNotify --
1883
 *
1884
 *      Generate a ConfigureNotify event describing the current
1885
 *      configuration of a window.
1886
 *
1887
 * Results:
1888
 *      None.
1889
 *
1890
 * Side effects:
1891
 *      An event is generated and processed by Tk_HandleEvent.
1892
 *
1893
 *----------------------------------------------------------------------
1894
 */
1895
 
1896
void
1897
TkDoConfigureNotify(winPtr)
1898
    register TkWindow *winPtr;          /* Window whose configuration
1899
                                         * was just changed. */
1900
{
1901
    XEvent event;
1902
 
1903
    event.type = ConfigureNotify;
1904
    event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display);
1905
    event.xconfigure.send_event = False;
1906
    event.xconfigure.display = winPtr->display;
1907
    event.xconfigure.event = winPtr->window;
1908
    event.xconfigure.window = winPtr->window;
1909
    event.xconfigure.x = winPtr->changes.x;
1910
    event.xconfigure.y = winPtr->changes.y;
1911
    event.xconfigure.width = winPtr->changes.width;
1912
    event.xconfigure.height = winPtr->changes.height;
1913
    event.xconfigure.border_width = winPtr->changes.border_width;
1914
    if (winPtr->changes.stack_mode == Above) {
1915
        event.xconfigure.above = winPtr->changes.sibling;
1916
    } else {
1917
        event.xconfigure.above = None;
1918
    }
1919
    event.xconfigure.override_redirect = winPtr->atts.override_redirect;
1920
    Tk_HandleEvent(&event);
1921
}
1922
 
1923
/*
1924
 *----------------------------------------------------------------------
1925
 *
1926
 * Tk_SetClass --
1927
 *
1928
 *      This procedure is used to give a window a class.
1929
 *
1930
 * Results:
1931
 *      None.
1932
 *
1933
 * Side effects:
1934
 *      A new class is stored for tkwin, replacing any existing
1935
 *      class for it.
1936
 *
1937
 *----------------------------------------------------------------------
1938
 */
1939
 
1940
void
1941
Tk_SetClass(tkwin, className)
1942
    Tk_Window tkwin;            /* Token for window to assign class. */
1943
    char *className;            /* New class for tkwin. */
1944
{
1945
    register TkWindow *winPtr = (TkWindow *) tkwin;
1946
 
1947
    winPtr->classUid = Tk_GetUid(className);
1948
    if (winPtr->flags & TK_TOP_LEVEL) {
1949
        TkWmSetClass(winPtr);
1950
    }
1951
    TkOptionClassChanged(winPtr);
1952
}
1953
 
1954
/*
1955
 *----------------------------------------------------------------------
1956
 *
1957
 * TkSetClassProcs --
1958
 *
1959
 *      This procedure is used to set the class procedures and
1960
 *      instance data for a window.
1961
 *
1962
 * Results:
1963
 *      None.
1964
 *
1965
 * Side effects:
1966
 *      A new set of class procedures and instance data is stored
1967
 *      for tkwin, replacing any existing values.
1968
 *
1969
 *----------------------------------------------------------------------
1970
 */
1971
 
1972
void
1973
TkSetClassProcs(tkwin, procs, instanceData)
1974
    Tk_Window tkwin;            /* Token for window to modify. */
1975
    TkClassProcs *procs;        /* Class procs structure. */
1976
    ClientData instanceData;    /* Data to be passed to class procedures. */
1977
{
1978
    register TkWindow *winPtr = (TkWindow *) tkwin;
1979
 
1980
    winPtr->classProcsPtr = procs;
1981
    winPtr->instanceData = instanceData;
1982
}
1983
 
1984
/*
1985
 *----------------------------------------------------------------------
1986
 *
1987
 * Tk_NameToWindow --
1988
 *
1989
 *      Given a string name for a window, this procedure
1990
 *      returns the token for the window, if there exists a
1991
 *      window corresponding to the given name.
1992
 *
1993
 * Results:
1994
 *      The return result is either a token for the window corresponding
1995
 *      to "name", or else NULL to indicate that there is no such
1996
 *      window.  In this case, an error message is left in interp->result.
1997
 *
1998
 * Side effects:
1999
 *      None.
2000
 *
2001
 *----------------------------------------------------------------------
2002
 */
2003
 
2004
Tk_Window
2005
Tk_NameToWindow(interp, pathName, tkwin)
2006
    Tcl_Interp *interp;         /* Where to report errors. */
2007
    char *pathName;             /* Path name of window. */
2008
    Tk_Window tkwin;            /* Token for window:  name is assumed to
2009
                                 * belong to the same main window as tkwin. */
2010
{
2011
    Tcl_HashEntry *hPtr;
2012
 
2013
    hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable,
2014
            pathName);
2015
    if (hPtr == NULL) {
2016
        Tcl_AppendResult(interp, "bad window path name \"",
2017
                pathName, "\"", (char *) NULL);
2018
        return NULL;
2019
    }
2020
    return (Tk_Window) Tcl_GetHashValue(hPtr);
2021
}
2022
 
2023
/*
2024
 *----------------------------------------------------------------------
2025
 *
2026
 * Tk_IdToWindow --
2027
 *
2028
 *      Given an X display and window ID, this procedure returns the
2029
 *      Tk token for the window, if there exists a Tk window corresponding
2030
 *      to the given ID.
2031
 *
2032
 * Results:
2033
 *      The return result is either a token for the window corresponding
2034
 *      to the given X id, or else NULL to indicate that there is no such
2035
 *      window.
2036
 *
2037
 * Side effects:
2038
 *      None.
2039
 *
2040
 *----------------------------------------------------------------------
2041
 */
2042
 
2043
Tk_Window
2044
Tk_IdToWindow(display, window)
2045
    Display *display;           /* X display containing the window. */
2046
    Window window;              /* X window window id. */
2047
{
2048
    TkDisplay *dispPtr;
2049
    Tcl_HashEntry *hPtr;
2050
 
2051
    for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
2052
        if (dispPtr == NULL) {
2053
            return NULL;
2054
        }
2055
        if (dispPtr->display == display) {
2056
            break;
2057
        }
2058
    }
2059
 
2060
    hPtr = Tcl_FindHashEntry(&dispPtr->winTable, (char *) window);
2061
    if (hPtr == NULL) {
2062
        return NULL;
2063
    }
2064
    return (Tk_Window) Tcl_GetHashValue(hPtr);
2065
}
2066
 
2067
/*
2068
 *----------------------------------------------------------------------
2069
 *
2070
 * Tk_DisplayName --
2071
 *
2072
 *      Return the textual name of a window's display.
2073
 *
2074
 * Results:
2075
 *      The return value is the string name of the display associated
2076
 *      with tkwin.
2077
 *
2078
 * Side effects:
2079
 *      None.
2080
 *
2081
 *----------------------------------------------------------------------
2082
 */
2083
 
2084
char *
2085
Tk_DisplayName(tkwin)
2086
    Tk_Window tkwin;            /* Window whose display name is desired. */
2087
{
2088
    return ((TkWindow *) tkwin)->dispPtr->name;
2089
}
2090
 
2091
/*
2092
 *----------------------------------------------------------------------
2093
 *
2094
 * UnlinkWindow --
2095
 *
2096
 *      This procedure removes a window from the childList of its
2097
 *      parent.
2098
 *
2099
 * Results:
2100
 *      None.
2101
 *
2102
 * Side effects:
2103
 *      The window is unlinked from its childList.
2104
 *
2105
 *----------------------------------------------------------------------
2106
 */
2107
 
2108
static void
2109
UnlinkWindow(winPtr)
2110
    TkWindow *winPtr;                   /* Child window to be unlinked. */
2111
{
2112
    TkWindow *prevPtr;
2113
 
2114
    if (winPtr->parentPtr == NULL) {
2115
        return;
2116
    }
2117
    prevPtr = winPtr->parentPtr->childList;
2118
    if (prevPtr == winPtr) {
2119
        winPtr->parentPtr->childList = winPtr->nextPtr;
2120
        if (winPtr->nextPtr == NULL) {
2121
            winPtr->parentPtr->lastChildPtr = NULL;
2122
        }
2123
    } else {
2124
        while (prevPtr->nextPtr != winPtr) {
2125
            prevPtr = prevPtr->nextPtr;
2126
            if (prevPtr == NULL) {
2127
                panic("UnlinkWindow couldn't find child in parent");
2128
            }
2129
        }
2130
        prevPtr->nextPtr = winPtr->nextPtr;
2131
        if (winPtr->nextPtr == NULL) {
2132
            winPtr->parentPtr->lastChildPtr = prevPtr;
2133
        }
2134
    }
2135
}
2136
 
2137
/*
2138
 *----------------------------------------------------------------------
2139
 *
2140
 * Tk_RestackWindow --
2141
 *
2142
 *      Change a window's position in the stacking order.
2143
 *
2144
 * Results:
2145
 *      TCL_OK is normally returned.  If other is not a descendant
2146
 *      of tkwin's parent then TCL_ERROR is returned and tkwin is
2147
 *      not repositioned.
2148
 *
2149
 * Side effects:
2150
 *      Tkwin is repositioned in the stacking order.
2151
 *
2152
 *----------------------------------------------------------------------
2153
 */
2154
 
2155
int
2156
Tk_RestackWindow(tkwin, aboveBelow, other)
2157
    Tk_Window tkwin;            /* Token for window whose position in
2158
                                 * the stacking order is to change. */
2159
    int aboveBelow;             /* Indicates new position of tkwin relative
2160
                                 * to other;  must be Above or Below. */
2161
    Tk_Window other;            /* Tkwin will be moved to a position that
2162
                                 * puts it just above or below this window.
2163
                                 * If NULL then tkwin goes above or below
2164
                                 * all windows in the same parent. */
2165
{
2166
    TkWindow *winPtr = (TkWindow *) tkwin;
2167
    TkWindow *otherPtr = (TkWindow *) other;
2168
    XWindowChanges changes;
2169
    unsigned int mask;
2170
 
2171
 
2172
    /*
2173
     * Special case:  if winPtr is a top-level window then just find
2174
     * the top-level ancestor of otherPtr and restack winPtr above
2175
     * otherPtr without changing any of Tk's childLists.
2176
     */
2177
 
2178
    changes.stack_mode = aboveBelow;
2179
    mask = CWStackMode;
2180
    if (winPtr->flags & TK_TOP_LEVEL) {
2181
        while ((otherPtr != NULL) && !(otherPtr->flags & TK_TOP_LEVEL)) {
2182
            otherPtr = otherPtr->parentPtr;
2183
        }
2184
        TkWmRestackToplevel(winPtr, aboveBelow, otherPtr);
2185
        return TCL_OK;
2186
    }
2187
 
2188
    /*
2189
     * Find an ancestor of otherPtr that is a sibling of winPtr.
2190
     */
2191
 
2192
    if (winPtr->parentPtr == NULL) {
2193
        /*
2194
         * Window is going to be deleted shortly;  don't do anything.
2195
         */
2196
 
2197
        return TCL_OK;
2198
    }
2199
    if (otherPtr == NULL) {
2200
        if (aboveBelow == Above) {
2201
            otherPtr = winPtr->parentPtr->lastChildPtr;
2202
        } else {
2203
            otherPtr = winPtr->parentPtr->childList;
2204
        }
2205
    } else {
2206
        while (winPtr->parentPtr != otherPtr->parentPtr) {
2207
            if ((otherPtr == NULL) || (otherPtr->flags & TK_TOP_LEVEL)) {
2208
                return TCL_ERROR;
2209
            }
2210
            otherPtr = otherPtr->parentPtr;
2211
        }
2212
    }
2213
    if (otherPtr == winPtr) {
2214
        return TCL_OK;
2215
    }
2216
 
2217
    /*
2218
     * Reposition winPtr in the stacking order.
2219
     */
2220
 
2221
    UnlinkWindow(winPtr);
2222
    if (aboveBelow == Above) {
2223
        winPtr->nextPtr = otherPtr->nextPtr;
2224
        if (winPtr->nextPtr == NULL) {
2225
            winPtr->parentPtr->lastChildPtr = winPtr;
2226
        }
2227
        otherPtr->nextPtr = winPtr;
2228
    } else {
2229
        TkWindow *prevPtr;
2230
 
2231
        prevPtr = winPtr->parentPtr->childList;
2232
        if (prevPtr == otherPtr) {
2233
            winPtr->parentPtr->childList = winPtr;
2234
        } else {
2235
            while (prevPtr->nextPtr != otherPtr) {
2236
                prevPtr = prevPtr->nextPtr;
2237
            }
2238
            prevPtr->nextPtr = winPtr;
2239
        }
2240
        winPtr->nextPtr = otherPtr;
2241
    }
2242
 
2243
    /*
2244
     * Notify the X server of the change.  If winPtr hasn't yet been
2245
     * created then there's no need to tell the X server now, since
2246
     * the stacking order will be handled properly when the window
2247
     * is finally created.
2248
     */
2249
 
2250
    if (winPtr->window != None) {
2251
        changes.stack_mode = Above;
2252
        for (otherPtr = winPtr->nextPtr; otherPtr != NULL;
2253
                otherPtr = otherPtr->nextPtr) {
2254
            if ((otherPtr->window != None)
2255
                    && !(otherPtr->flags & (TK_TOP_LEVEL|TK_REPARENTED))){
2256
                changes.sibling = otherPtr->window;
2257
                changes.stack_mode = Below;
2258
                mask = CWStackMode|CWSibling;
2259
                break;
2260
            }
2261
        }
2262
        XConfigureWindow(winPtr->display, winPtr->window, mask, &changes);
2263
    }
2264
    return TCL_OK;
2265
}
2266
 
2267
/*
2268
 *----------------------------------------------------------------------
2269
 *
2270
 * Tk_MainWindow --
2271
 *
2272
 *      Returns the main window for an application.
2273
 *
2274
 * Results:
2275
 *      If interp has a Tk application associated with it, the main
2276
 *      window for the application is returned.  Otherwise NULL is
2277
 *      returned and an error message is left in interp->result.
2278
 *
2279
 * Side effects:
2280
 *      None.
2281
 *
2282
 *----------------------------------------------------------------------
2283
 */
2284
 
2285
Tk_Window
2286
Tk_MainWindow(interp)
2287
    Tcl_Interp *interp;                 /* Interpreter that embodies the
2288
                                         * application.  Used for error
2289
                                         * reporting also. */
2290
{
2291
    TkMainInfo *mainPtr;
2292
 
2293
    for (mainPtr = tkMainWindowList; mainPtr != NULL;
2294
            mainPtr = mainPtr->nextPtr) {
2295
        if (mainPtr->interp == interp) {
2296
            return (Tk_Window) mainPtr->winPtr;
2297
        }
2298
    }
2299
    interp->result = "this isn't a Tk application";
2300
    return NULL;
2301
}
2302
 
2303
/*
2304
 *----------------------------------------------------------------------
2305
 *
2306
 * Tk_StrictMotif --
2307
 *
2308
 *      Indicates whether strict Motif compliance has been specified
2309
 *      for the given window.
2310
 *
2311
 * Results:
2312
 *      The return value is 1 if strict Motif compliance has been
2313
 *      requested for tkwin's application by setting the tk_strictMotif
2314
 *      variable in its interpreter to a true value.  0 is returned
2315
 *      if tk_strictMotif has a false value.
2316
 *
2317
 * Side effects:
2318
 *      None.
2319
 *
2320
 *----------------------------------------------------------------------
2321
 */
2322
 
2323
int
2324
Tk_StrictMotif(tkwin)
2325
    Tk_Window tkwin;                    /* Window whose application is
2326
                                         * to be checked. */
2327
{
2328
    return ((TkWindow *) tkwin)->mainPtr->strictMotif;
2329
}
2330
 
2331
/*
2332
 *--------------------------------------------------------------
2333
 *
2334
 * OpenIM --
2335
 *
2336
 *      Tries to open an X input method, associated with the
2337
 *      given display.  Right now we can only deal with a bare-bones
2338
 *      input style:  no preedit, and no status.
2339
 *
2340
 * Results:
2341
 *      Stores the input method in dispPtr->inputMethod;  if there isn't
2342
 *      a suitable input method, then NULL is stored in dispPtr->inputMethod.
2343
 *
2344
 * Side effects:
2345
 *      An input method gets opened.
2346
 *
2347
 *--------------------------------------------------------------
2348
 */
2349
 
2350
static void
2351
OpenIM(dispPtr)
2352
    TkDisplay *dispPtr;         /* Tk's structure for the display. */
2353
{
2354
#ifndef TK_USE_INPUT_METHODS
2355
    return;
2356
#else
2357
    unsigned short i;
2358
    XIMStyles *stylePtr;
2359
 
2360
    dispPtr->inputMethod = XOpenIM(dispPtr->display, NULL, NULL, NULL);
2361
    if (dispPtr->inputMethod == NULL) {
2362
        return;
2363
    }
2364
 
2365
    if ((XGetIMValues(dispPtr->inputMethod, XNQueryInputStyle, &stylePtr,
2366
            NULL) != NULL) || (stylePtr == NULL)) {
2367
        goto error;
2368
    }
2369
    for (i = 0; i < stylePtr->count_styles; i++) {
2370
        if (stylePtr->supported_styles[i]
2371
                == (XIMPreeditNothing|XIMStatusNothing)) {
2372
            XFree(stylePtr);
2373
            return;
2374
        }
2375
    }
2376
    XFree(stylePtr);
2377
 
2378
    error:
2379
 
2380
    /*
2381
     * Should close the input method, but this causes core dumps on some
2382
     * systems (e.g. Solaris 2.3 as of 1/6/95).
2383
     * XCloseIM(dispPtr->inputMethod);
2384
     */
2385
    dispPtr->inputMethod = NULL;
2386
    return;
2387
#endif /* TK_USE_INPUT_METHODS */
2388
}
2389
 
2390
/*
2391
 *----------------------------------------------------------------------
2392
 *
2393
 * Tk_GetNumMainWindows --
2394
 *
2395
 *      This procedure returns the number of main windows currently
2396
 *      open in this process.
2397
 *
2398
 * Results:
2399
 *      The number of main windows open in this process.
2400
 *
2401
 * Side effects:
2402
 *      None.
2403
 *
2404
 *----------------------------------------------------------------------
2405
 */
2406
 
2407
int
2408
Tk_GetNumMainWindows()
2409
{
2410
    return numMainWindows;
2411
}
2412
 
2413
/*
2414
 *----------------------------------------------------------------------
2415
 *
2416
 * DeleteWindowsExitProc --
2417
 *
2418
 *      This procedure is invoked as an exit handler.  It deletes all
2419
 *      of the main windows in the process.
2420
 *
2421
 * Results:
2422
 *      None.
2423
 *
2424
 * Side effects:
2425
 *      None.
2426
 *
2427
 *----------------------------------------------------------------------
2428
 */
2429
 
2430
static void
2431
DeleteWindowsExitProc(clientData)
2432
    ClientData clientData;              /* Not used. */
2433
{
2434
    TkDisplay *displayPtr, *nextPtr;
2435
    Tcl_Interp *interp;
2436
 
2437
    while (tkMainWindowList != NULL) {
2438
        /*
2439
         * We must protect the interpreter while deleting the window,
2440
         * because of <Destroy> bindings which could destroy the interpreter
2441
         * while the window is being deleted. This would leave frames on
2442
         * the call stack pointing at deleted memory, causing core dumps.
2443
         */
2444
 
2445
        interp = tkMainWindowList->winPtr->mainPtr->interp;
2446
        Tcl_Preserve((ClientData) interp);
2447
        Tk_DestroyWindow((Tk_Window) tkMainWindowList->winPtr);
2448
        Tcl_Release((ClientData) interp);
2449
    }
2450
 
2451
    displayPtr = tkDisplayList;
2452
    tkDisplayList = NULL;
2453
 
2454
    /*
2455
     * Iterate destroying the displays until no more displays remain.
2456
     * It is possible for displays to get recreated during exit by any
2457
     * code that calls GetScreen, so we must destroy these new displays
2458
     * as well as the old ones.
2459
     */
2460
 
2461
    for (displayPtr = tkDisplayList;
2462
         displayPtr != NULL;
2463
         displayPtr = tkDisplayList) {
2464
 
2465
        /*
2466
         * Now iterate over the current list of open displays, and first
2467
         * set the global pointer to NULL so we will be able to notice if
2468
         * any new displays got created during deletion of the current set.
2469
         * We must also do this to ensure that Tk_IdToWindow does not find
2470
         * the old display as it is being destroyed, when it wants to see
2471
         * if it needs to dispatch a message.
2472
         */
2473
 
2474
        for (tkDisplayList = NULL; displayPtr != NULL; displayPtr = nextPtr) {
2475
            nextPtr = displayPtr->nextPtr;
2476
            if (displayPtr->name != (char *) NULL) {
2477
                ckfree(displayPtr->name);
2478
            }
2479
            Tcl_DeleteHashTable(&(displayPtr->winTable));
2480
            TkpCloseDisplay(displayPtr);
2481
        }
2482
    }
2483
 
2484
    numMainWindows = 0;
2485
    tkMainWindowList = NULL;
2486
    initialized = 0;
2487
    tkDisabledUid = NULL;
2488
    tkActiveUid = NULL;
2489
    tkNormalUid = NULL;
2490
}
2491
 
2492
/*
2493
 *----------------------------------------------------------------------
2494
 *
2495
 * Tk_Init --
2496
 *
2497
 *      This procedure is invoked to add Tk to an interpreter.  It
2498
 *      incorporates all of Tk's commands into the interpreter and
2499
 *      creates the main window for a new Tk application.  If the
2500
 *      interpreter contains a variable "argv", this procedure
2501
 *      extracts several arguments from that variable, uses them
2502
 *      to configure the main window, and modifies argv to exclude
2503
 *      the arguments (see the "wish" documentation for a list of
2504
 *      the arguments that are extracted).
2505
 *
2506
 * Results:
2507
 *      Returns a standard Tcl completion code and sets interp->result
2508
 *      if there is an error.
2509
 *
2510
 * Side effects:
2511
 *      Depends on various initialization scripts that get invoked.
2512
 *
2513
 *----------------------------------------------------------------------
2514
 */
2515
 
2516
int
2517
Tk_Init(interp)
2518
    Tcl_Interp *interp;         /* Interpreter to initialize. */
2519
{
2520
    return Initialize(interp);
2521
}
2522
 
2523
/*
2524
 *----------------------------------------------------------------------
2525
 *
2526
 * Tk_SafeInit --
2527
 *
2528
 *      This procedure is invoked to add Tk to a safe interpreter. It
2529
 *      invokes the internal procedure that does the real work.
2530
 *
2531
 * Results:
2532
 *      Returns a standard Tcl completion code and sets interp->result
2533
 *      if there is an error.
2534
 *
2535
 * Side effects:
2536
 *      Depends on various initialization scripts that are invoked.
2537
 *
2538
 *----------------------------------------------------------------------
2539
 */
2540
 
2541
int
2542
Tk_SafeInit(interp)
2543
    Tcl_Interp *interp;         /* Interpreter to initialize. */
2544
{
2545
    /*
2546
     * Initialize the interpreter with Tk, safely. This removes
2547
     * all the Tk commands that are unsafe.
2548
     *
2549
     * Rationale:
2550
     *
2551
     * - Toplevel and menu are unsafe because they can be used to cover
2552
     *   the entire screen and to steal input from the user.
2553
     * - Continuous ringing of the bell is a nuisance.
2554
     * - Cannot allow access to the clipboard because a malicious script
2555
     *   can replace the contents with the string "rm -r *" and lead to
2556
     *   surprises when the contents of the clipboard are pasted. We do
2557
     *   not currently hide the selection command.. Should we?
2558
     * - Cannot allow send because it can be used to cause unsafe
2559
     *   interpreters to execute commands. The tk command recreates the
2560
     *   send command, so that too must be hidden.
2561
     * - Focus can be used to grab the focus away from another window,
2562
     *   in effect stealing user input. Cannot allow that.
2563
     *   NOTE: We currently do *not* hide focus as it would make it
2564
     *   impossible to provide keyboard input to Tk in a safe interpreter.
2565
     * - Grab can be used to block the user from using any other apps
2566
     *   on the screen.
2567
     * - Tkwait can block the containing process forever. Use bindings,
2568
     *   fileevents and split the protocol into before-the-wait and
2569
     *   after-the-wait parts. More work but necessary.
2570
     * - Wm is unsafe because (if toplevels are allowed, in the future)
2571
     *   it can be used to remove decorations, move windows around, cover
2572
     *   the entire screen etc etc.
2573
     *
2574
     * Current risks:
2575
     *
2576
     * - No CPU time limit, no memory allocation limits, no color limits.
2577
     *
2578
     *  The actual code called is the same as Tk_Init but Tcl_IsSafe()
2579
     *  is checked at several places to differentiate the two initialisations.
2580
     */
2581
 
2582
    return Initialize(interp);
2583
}
2584
 
2585
/*
2586
 *----------------------------------------------------------------------
2587
 *
2588
 * Initialize --
2589
 *
2590
 *
2591
 * Results:
2592
 *      A standard Tcl result. Also leaves an error message in interp->result
2593
 *      if there was an error.
2594
 *
2595
 * Side effects:
2596
 *      Depends on the initialization scripts that are invoked.
2597
 *
2598
 *----------------------------------------------------------------------
2599
 */
2600
 
2601
static int
2602
Initialize(interp)
2603
    Tcl_Interp *interp;         /* Interpreter to initialize. */
2604
{
2605
    char *p;
2606
    int argc, code;
2607
    char **argv, *args[20];
2608
    Tcl_DString class;
2609
    char buffer[30];
2610
 
2611
    /*
2612
     * Start by initializing all the static variables to default acceptable
2613
     * values so that no information is leaked from a previous run of this
2614
     * code.
2615
     */
2616
 
2617
    synchronize = 0;
2618
    name = NULL;
2619
    display = NULL;
2620
    geometry = NULL;
2621
    colormap = NULL;
2622
    use = NULL;
2623
    visual = NULL;
2624
    rest = 0;
2625
 
2626
    /*
2627
     * We start by resetting the result because it might not be clean
2628
     */
2629
    Tcl_ResetResult(interp);
2630
 
2631
    if (Tcl_IsSafe(interp)) {
2632
        /*
2633
         * Get the clearance to start Tk and the "argv" parameters
2634
         * from the master.
2635
         */
2636
        Tcl_DString ds;
2637
 
2638
        /*
2639
         * Step 1 : find the master and construct the interp name
2640
         * (could be a function if new APIs were ok).
2641
         * We could also construct the path while walking, but there
2642
         * is no API to get the name of an interp either.
2643
         */
2644
        Tcl_Interp *master = interp;
2645
 
2646
        while (1) {
2647
            master = Tcl_GetMaster(master);
2648
            if (master == NULL) {
2649
                Tcl_DStringFree(&ds);
2650
                Tcl_AppendResult(interp, "NULL master", (char *) NULL);
2651
                return TCL_ERROR;
2652
            }
2653
            if (!Tcl_IsSafe(master)) {
2654
                /* Found the trusted master. */
2655
                break;
2656
            }
2657
        }
2658
        /*
2659
         * Construct the name (rewalk...)
2660
         */
2661
        if (Tcl_GetInterpPath(master, interp) != TCL_OK) {
2662
            Tcl_AppendResult(interp, "error in Tcl_GetInterpPath",
2663
                    (char *) NULL);
2664
            return TCL_ERROR;
2665
        }
2666
        /*
2667
         * Build the string to eval.
2668
         */
2669
        Tcl_DStringInit(&ds);
2670
        Tcl_DStringAppendElement(&ds, "::safe::TkInit");
2671
        Tcl_DStringAppendElement(&ds, Tcl_GetStringResult(master));
2672
 
2673
        /*
2674
         * Step 2 : Eval in the master. The argument is the *reversed*
2675
         * interp path of the slave.
2676
         */
2677
 
2678
        if (Tcl_Eval(master, Tcl_DStringValue(&ds)) != TCL_OK) {
2679
            /*
2680
             * We might want to transfer the error message or not.
2681
             * We don't. (no API to do it and maybe security reasons).
2682
             */
2683
            Tcl_DStringFree(&ds);
2684
            Tcl_AppendResult(interp,
2685
                    "not allowed to start Tk by master's safe::TkInit",
2686
                    (char *) NULL);
2687
            return TCL_ERROR;
2688
        }
2689
        Tcl_DStringFree(&ds);
2690
        /*
2691
         * Use the master's result as argv.
2692
         * Note: We don't use the Obj interfaces to avoid dealing with
2693
         * cross interp refcounting and changing the code below.
2694
         */
2695
 
2696
        p = Tcl_GetStringResult(master);
2697
    } else {
2698
        /*
2699
         * If there is an "argv" variable, get its value, extract out
2700
         * relevant arguments from it, and rewrite the variable without
2701
         * the arguments that we used.
2702
         */
2703
 
2704
        p = Tcl_GetVar2(interp, "argv", (char *) NULL, TCL_GLOBAL_ONLY);
2705
    }
2706
    argv = NULL;
2707
    if (p != NULL) {
2708
        if (Tcl_SplitList(interp, p, &argc, &argv) != TCL_OK) {
2709
            argError:
2710
            Tcl_AddErrorInfo(interp,
2711
                    "\n    (processing arguments in argv variable)");
2712
            return TCL_ERROR;
2713
        }
2714
        if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv,
2715
                argTable, TK_ARGV_DONT_SKIP_FIRST_ARG|TK_ARGV_NO_DEFAULTS)
2716
                != TCL_OK) {
2717
            ckfree((char *) argv);
2718
            goto argError;
2719
        }
2720
        p = Tcl_Merge(argc, argv);
2721
        Tcl_SetVar2(interp, "argv", (char *) NULL, p, TCL_GLOBAL_ONLY);
2722
        sprintf(buffer, "%d", argc);
2723
        Tcl_SetVar2(interp, "argc", (char *) NULL, buffer, TCL_GLOBAL_ONLY);
2724
        ckfree(p);
2725
    }
2726
 
2727
    /*
2728
     * Figure out the application's name and class.
2729
     */
2730
 
2731
    Tcl_DStringInit(&class);
2732
    if (name == NULL) {
2733
        int offset;
2734
        TkpGetAppName(interp, &class);
2735
        offset = Tcl_DStringLength(&class)+1;
2736
        Tcl_DStringSetLength(&class, offset);
2737
        Tcl_DStringAppend(&class, Tcl_DStringValue(&class), offset-1);
2738
        name = Tcl_DStringValue(&class) + offset;
2739
    } else {
2740
        Tcl_DStringAppend(&class, name, -1);
2741
    }
2742
 
2743
    p = Tcl_DStringValue(&class);
2744
    if (islower(UCHAR(*p))) {
2745
        *p = toupper(UCHAR(*p));
2746
    }
2747
 
2748
    /*
2749
     * Create an argument list for creating the top-level window,
2750
     * using the information parsed from argv, if any.
2751
     */
2752
 
2753
    args[0] = "toplevel";
2754
    args[1] = ".";
2755
    args[2] = "-class";
2756
    args[3] = Tcl_DStringValue(&class);
2757
    argc = 4;
2758
    if (display != NULL) {
2759
        args[argc] = "-screen";
2760
        args[argc+1] = display;
2761
        argc += 2;
2762
 
2763
        /*
2764
         * If this is the first application for this process, save
2765
         * the display name in the DISPLAY environment variable so
2766
         * that it will be available to subprocesses created by us.
2767
         */
2768
 
2769
        if (numMainWindows == 0) {
2770
            Tcl_SetVar2(interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY);
2771
        }
2772
    }
2773
    if (colormap != NULL) {
2774
        args[argc] = "-colormap";
2775
        args[argc+1] = colormap;
2776
        argc += 2;
2777
        colormap = NULL;
2778
    }
2779
    if (use != NULL) {
2780
        args[argc] = "-use";
2781
        args[argc+1] = use;
2782
        argc += 2;
2783
        use = NULL;
2784
    }
2785
    if (visual != NULL) {
2786
        args[argc] = "-visual";
2787
        args[argc+1] = visual;
2788
        argc += 2;
2789
        visual = NULL;
2790
    }
2791
    args[argc] = NULL;
2792
    code = TkCreateFrame((ClientData) NULL, interp, argc, args, 1, name);
2793
 
2794
    Tcl_DStringFree(&class);
2795
    if (code != TCL_OK) {
2796
        goto done;
2797
    }
2798
    Tcl_ResetResult(interp);
2799
    if (synchronize) {
2800
        XSynchronize(Tk_Display(Tk_MainWindow(interp)), True);
2801
    }
2802
 
2803
    /*
2804
     * Set the geometry of the main window, if requested.  Put the
2805
     * requested geometry into the "geometry" variable.
2806
     */
2807
 
2808
    if (geometry != NULL) {
2809
        Tcl_SetVar(interp, "geometry", geometry, TCL_GLOBAL_ONLY);
2810
        code = Tcl_VarEval(interp, "wm geometry . ", geometry, (char *) NULL);
2811
        if (code != TCL_OK) {
2812
            goto done;
2813
        }
2814
        geometry = NULL;
2815
    }
2816
    if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) {
2817
        code = TCL_ERROR;
2818
        goto done;
2819
    }
2820
    code = Tcl_PkgProvide(interp, "Tk", TK_VERSION);
2821
    if (code != TCL_OK) {
2822
        goto done;
2823
    }
2824
 
2825
    /*
2826
     * Invoke platform-specific initialization.
2827
     */
2828
 
2829
    code = TkpInit(interp);
2830
 
2831
    done:
2832
    if (argv != NULL) {
2833
        ckfree((char *) argv);
2834
    }
2835
    return code;
2836
}

powered by: WebSVN 2.1.0

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