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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkTextWind.c --
3
 *
4
 *      This file contains code that allows arbitrary windows to be
5
 *      nested inside text widgets.  It also implements the "window"
6
 *      widget command for texts.
7
 *
8
 * Copyright (c) 1994 The Regents of the University of California.
9
 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
10
 *
11
 * See the file "license.terms" for information on usage and redistribution
12
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
 *
14
 * RCS: @(#) $Id: tkTextWind.c,v 1.1.1.1 2002-01-16 10:25:53 markom Exp $
15
 */
16
 
17
#include "tk.h"
18
#include "tkText.h"
19
#include "tkPort.h"
20
 
21
/*
22
 * The following structure is the official type record for the
23
 * embedded window geometry manager:
24
 */
25
 
26
static void             EmbWinRequestProc _ANSI_ARGS_((ClientData clientData,
27
                            Tk_Window tkwin));
28
static void             EmbWinLostSlaveProc _ANSI_ARGS_((ClientData clientData,
29
                            Tk_Window tkwin));
30
 
31
static Tk_GeomMgr textGeomType = {
32
    "text",                     /* name */
33
    EmbWinRequestProc,          /* requestProc */
34
    EmbWinLostSlaveProc,        /* lostSlaveProc */
35
};
36
 
37
/*
38
 * Definitions for alignment values:
39
 */
40
 
41
#define ALIGN_BOTTOM            0
42
#define ALIGN_CENTER            1
43
#define ALIGN_TOP               2
44
#define ALIGN_BASELINE          3
45
 
46
/*
47
 * Macro that determines the size of an embedded window segment:
48
 */
49
 
50
#define EW_SEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \
51
        + sizeof(TkTextEmbWindow)))
52
 
53
/*
54
 * Prototypes for procedures defined in this file:
55
 */
56
 
57
static int              AlignParseProc _ANSI_ARGS_((ClientData clientData,
58
                            Tcl_Interp *interp, Tk_Window tkwin, char *value,
59
                            char *widgRec, int offset));
60
static char *           AlignPrintProc _ANSI_ARGS_((ClientData clientData,
61
                            Tk_Window tkwin, char *widgRec, int offset,
62
                            Tcl_FreeProc **freeProcPtr));
63
static TkTextSegment *  EmbWinCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr,
64
                            TkTextLine *linePtr));
65
static void             EmbWinCheckProc _ANSI_ARGS_((TkTextSegment *segPtr,
66
                            TkTextLine *linePtr));
67
static void             EmbWinBboxProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr,
68
                            int index, int y, int lineHeight, int baseline,
69
                            int *xPtr, int *yPtr, int *widthPtr,
70
                            int *heightPtr));
71
static int              EmbWinConfigure _ANSI_ARGS_((TkText *textPtr,
72
                            TkTextSegment *ewPtr, int argc, char **argv));
73
static void             EmbWinDelayedUnmap _ANSI_ARGS_((
74
                            ClientData clientData));
75
static int              EmbWinDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr,
76
                            TkTextLine *linePtr, int treeGone));
77
static void             EmbWinDisplayProc _ANSI_ARGS_((
78
                            TkTextDispChunk *chunkPtr, int x, int y,
79
                            int lineHeight, int baseline, Display *display,
80
                            Drawable dst, int screenY));
81
static int              EmbWinLayoutProc _ANSI_ARGS_((TkText *textPtr,
82
                            TkTextIndex *indexPtr, TkTextSegment *segPtr,
83
                            int offset, int maxX, int maxChars,
84
                            int noCharsYet, Tk_Uid wrapMode,
85
                            TkTextDispChunk *chunkPtr));
86
static void             EmbWinStructureProc _ANSI_ARGS_((ClientData clientData,
87
                            XEvent *eventPtr));
88
static void             EmbWinUndisplayProc _ANSI_ARGS_((TkText *textPtr,
89
                            TkTextDispChunk *chunkPtr));
90
 
91
/*
92
 * The following structure declares the "embedded window" segment type.
93
 */
94
 
95
static Tk_SegType tkTextEmbWindowType = {
96
    "window",                                   /* name */
97
    0,                                           /* leftGravity */
98
    (Tk_SegSplitProc *) NULL,                   /* splitProc */
99
    EmbWinDeleteProc,                           /* deleteProc */
100
    EmbWinCleanupProc,                          /* cleanupProc */
101
    (Tk_SegLineChangeProc *) NULL,              /* lineChangeProc */
102
    EmbWinLayoutProc,                           /* layoutProc */
103
    EmbWinCheckProc                             /* checkProc */
104
};
105
 
106
/*
107
 * Information used for parsing window configuration options:
108
 */
109
 
110
static Tk_CustomOption alignOption = {AlignParseProc, AlignPrintProc,
111
        (ClientData) NULL};
112
 
113
static Tk_ConfigSpec configSpecs[] = {
114
    {TK_CONFIG_CUSTOM, "-align", (char *) NULL, (char *) NULL,
115
        "center", 0, TK_CONFIG_DONT_SET_DEFAULT, &alignOption},
116
    {TK_CONFIG_STRING, "-create", (char *) NULL, (char *) NULL,
117
        (char *) NULL, Tk_Offset(TkTextEmbWindow, create),
118
        TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},
119
    {TK_CONFIG_INT, "-padx", (char *) NULL, (char *) NULL,
120
        "0", Tk_Offset(TkTextEmbWindow, padX),
121
        TK_CONFIG_DONT_SET_DEFAULT},
122
    {TK_CONFIG_INT, "-pady", (char *) NULL, (char *) NULL,
123
        "0", Tk_Offset(TkTextEmbWindow, padY),
124
        TK_CONFIG_DONT_SET_DEFAULT},
125
    {TK_CONFIG_BOOLEAN, "-stretch", (char *) NULL, (char *) NULL,
126
        "0", Tk_Offset(TkTextEmbWindow, stretch),
127
        TK_CONFIG_DONT_SET_DEFAULT},
128
    {TK_CONFIG_WINDOW, "-window", (char *) NULL, (char *) NULL,
129
        (char *) NULL, Tk_Offset(TkTextEmbWindow, tkwin),
130
        TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},
131
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
132
        (char *) NULL, 0, 0}
133
};
134
 
135
/*
136
 *--------------------------------------------------------------
137
 *
138
 * TkTextWindowCmd --
139
 *
140
 *      This procedure implements the "window" widget command
141
 *      for text widgets.  See the user documentation for details
142
 *      on what it does.
143
 *
144
 * Results:
145
 *      A standard Tcl result or error.
146
 *
147
 * Side effects:
148
 *      See the user documentation.
149
 *
150
 *--------------------------------------------------------------
151
 */
152
 
153
int
154
TkTextWindowCmd(textPtr, interp, argc, argv)
155
    register TkText *textPtr;   /* Information about text widget. */
156
    Tcl_Interp *interp;         /* Current interpreter. */
157
    int argc;                   /* Number of arguments. */
158
    char **argv;                /* Argument strings.  Someone else has already
159
                                 * parsed this command enough to know that
160
                                 * argv[1] is "window". */
161
{
162
    size_t length;
163
    register TkTextSegment *ewPtr;
164
 
165
    if (argc < 3) {
166
        Tcl_AppendResult(interp, "wrong # args: should be \"",
167
                argv[0], " window option ?arg arg ...?\"", (char *) NULL);
168
        return TCL_ERROR;
169
    }
170
    length = strlen(argv[2]);
171
    if ((strncmp(argv[2], "cget", length) == 0) && (length >= 2)) {
172
        TkTextIndex index;
173
        TkTextSegment *ewPtr;
174
 
175
        if (argc != 5) {
176
            Tcl_AppendResult(interp, "wrong # args: should be \"",
177
                    argv[0], " window cget index option\"",
178
                    (char *) NULL);
179
            return TCL_ERROR;
180
        }
181
        if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
182
            return TCL_ERROR;
183
        }
184
        ewPtr = TkTextIndexToSeg(&index, (int *) NULL);
185
        if (ewPtr->typePtr != &tkTextEmbWindowType) {
186
            Tcl_AppendResult(interp, "no embedded window at index \"",
187
                    argv[3], "\"", (char *) NULL);
188
            return TCL_ERROR;
189
        }
190
        return Tk_ConfigureValue(interp, textPtr->tkwin, configSpecs,
191
                (char *) &ewPtr->body.ew, argv[4], 0);
192
    } else if ((strncmp(argv[2], "configure", length) == 0) && (length >= 2)) {
193
        TkTextIndex index;
194
        TkTextSegment *ewPtr;
195
 
196
        if (argc < 4) {
197
            Tcl_AppendResult(interp, "wrong # args: should be \"",
198
                    argv[0], " window configure index ?option value ...?\"",
199
                    (char *) NULL);
200
            return TCL_ERROR;
201
        }
202
        if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
203
            return TCL_ERROR;
204
        }
205
        ewPtr = TkTextIndexToSeg(&index, (int *) NULL);
206
        if (ewPtr->typePtr != &tkTextEmbWindowType) {
207
            Tcl_AppendResult(interp, "no embedded window at index \"",
208
                    argv[3], "\"", (char *) NULL);
209
            return TCL_ERROR;
210
        }
211
        if (argc == 4) {
212
            return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs,
213
                    (char *) &ewPtr->body.ew, (char *) NULL, 0);
214
        } else if (argc == 5) {
215
            return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs,
216
                    (char *) &ewPtr->body.ew, argv[4], 0);
217
        } else {
218
            TkTextChanged(textPtr, &index, &index);
219
            return EmbWinConfigure(textPtr, ewPtr, argc-4, argv+4);
220
        }
221
    } else if ((strncmp(argv[2], "create", length) == 0) && (length >= 2)) {
222
        TkTextIndex index;
223
        int lineIndex;
224
 
225
        /*
226
         * Add a new window.  Find where to put the new window, and
227
         * mark that position for redisplay.
228
         */
229
 
230
        if (argc < 4) {
231
            Tcl_AppendResult(interp, "wrong # args: should be \"",
232
                    argv[0], " window create index ?option value ...?\"",
233
                    (char *) NULL);
234
            return TCL_ERROR;
235
        }
236
        if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
237
            return TCL_ERROR;
238
        }
239
 
240
        /*
241
         * Don't allow insertions on the last (dummy) line of the text.
242
         */
243
 
244
        lineIndex = TkBTreeLineIndex(index.linePtr);
245
        if (lineIndex == TkBTreeNumLines(textPtr->tree)) {
246
            lineIndex--;
247
            TkTextMakeIndex(textPtr->tree, lineIndex, 1000000, &index);
248
        }
249
 
250
        /*
251
         * Create the new window segment and initialize it.
252
         */
253
 
254
        ewPtr = (TkTextSegment *) ckalloc(EW_SEG_SIZE);
255
        ewPtr->typePtr = &tkTextEmbWindowType;
256
        ewPtr->size = 1;
257
        ewPtr->body.ew.textPtr = textPtr;
258
        ewPtr->body.ew.linePtr = NULL;
259
        ewPtr->body.ew.tkwin = NULL;
260
        ewPtr->body.ew.create = NULL;
261
        ewPtr->body.ew.align = ALIGN_CENTER;
262
        ewPtr->body.ew.padX = ewPtr->body.ew.padY = 0;
263
        ewPtr->body.ew.stretch = 0;
264
        ewPtr->body.ew.chunkCount = 0;
265
        ewPtr->body.ew.displayed = 0;
266
 
267
        /*
268
         * Link the segment into the text widget, then configure it (delete
269
         * it again if the configuration fails).
270
         */
271
 
272
        TkTextChanged(textPtr, &index, &index);
273
        TkBTreeLinkSegment(ewPtr, &index);
274
        if (EmbWinConfigure(textPtr, ewPtr, argc-4, argv+4) != TCL_OK) {
275
            TkTextIndex index2;
276
 
277
            TkTextIndexForwChars(&index, 1, &index2);
278
            TkBTreeDeleteChars(&index, &index2);
279
            return TCL_ERROR;
280
        }
281
    } else if (strncmp(argv[2], "names", length) == 0) {
282
        Tcl_HashSearch search;
283
        Tcl_HashEntry *hPtr;
284
 
285
        if (argc != 3) {
286
            Tcl_AppendResult(interp, "wrong # args: should be \"",
287
                    argv[0], " window names\"", (char *) NULL);
288
            return TCL_ERROR;
289
        }
290
        for (hPtr = Tcl_FirstHashEntry(&textPtr->windowTable, &search);
291
                hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
292
            Tcl_AppendElement(interp,
293
                    Tcl_GetHashKey(&textPtr->markTable, hPtr));
294
        }
295
    } else {
296
        Tcl_AppendResult(interp, "bad window option \"", argv[2],
297
                "\": must be cget, configure, create, or names",
298
                (char *) NULL);
299
        return TCL_ERROR;
300
    }
301
    return TCL_OK;
302
}
303
 
304
/*
305
 *--------------------------------------------------------------
306
 *
307
 * EmbWinConfigure --
308
 *
309
 *      This procedure is called to handle configuration options
310
 *      for an embedded window, using an argc/argv list.
311
 *
312
 * Results:
313
 *      The return value is a standard Tcl result.  If TCL_ERROR is
314
 *      returned, then interp->result contains an error message..
315
 *
316
 * Side effects:
317
 *      Configuration information for the embedded window changes,
318
 *      such as alignment, stretching, or name of the embedded
319
 *      window.
320
 *
321
 *--------------------------------------------------------------
322
 */
323
 
324
static int
325
EmbWinConfigure(textPtr, ewPtr, argc, argv)
326
    TkText *textPtr;            /* Information about text widget that
327
                                 * contains embedded window. */
328
    TkTextSegment *ewPtr;       /* Embedded window to be configured. */
329
    int argc;                   /* Number of strings in argv. */
330
    char **argv;                /* Array of strings describing configuration
331
                                 * options. */
332
{
333
    Tk_Window oldWindow;
334
    Tcl_HashEntry *hPtr;
335
    int new;
336
 
337
    oldWindow = ewPtr->body.ew.tkwin;
338
    if (Tk_ConfigureWidget(textPtr->interp, textPtr->tkwin, configSpecs,
339
            argc, argv, (char *) &ewPtr->body.ew, TK_CONFIG_ARGV_ONLY)
340
            != TCL_OK) {
341
        return TCL_ERROR;
342
    }
343
    if (oldWindow != ewPtr->body.ew.tkwin) {
344
        if (oldWindow != NULL) {
345
            Tcl_DeleteHashEntry(Tcl_FindHashEntry(&textPtr->windowTable,
346
                    Tk_PathName(oldWindow)));
347
            Tk_DeleteEventHandler(oldWindow, StructureNotifyMask,
348
                    EmbWinStructureProc, (ClientData) ewPtr);
349
            Tk_ManageGeometry(oldWindow, (Tk_GeomMgr *) NULL,
350
                    (ClientData) NULL);
351
            if (textPtr->tkwin != Tk_Parent(oldWindow)) {
352
                Tk_UnmaintainGeometry(oldWindow, textPtr->tkwin);
353
            } else {
354
                Tk_UnmapWindow(oldWindow);
355
            }
356
        }
357
        if (ewPtr->body.ew.tkwin != NULL) {
358
            Tk_Window ancestor, parent;
359
 
360
            /*
361
             * Make sure that the text is either the parent of the
362
             * embedded window or a descendant of that parent.  Also,
363
             * don't allow a top-level window to be managed inside
364
             * a text.
365
             */
366
 
367
            parent = Tk_Parent(ewPtr->body.ew.tkwin);
368
            for (ancestor = textPtr->tkwin; ;
369
                    ancestor = Tk_Parent(ancestor)) {
370
                if (ancestor == parent) {
371
                    break;
372
                }
373
                if (Tk_IsTopLevel(ancestor)) {
374
                    badMaster:
375
                    Tcl_AppendResult(textPtr->interp, "can't embed ",
376
                            Tk_PathName(ewPtr->body.ew.tkwin), " in ",
377
                            Tk_PathName(textPtr->tkwin), (char *) NULL);
378
                    ewPtr->body.ew.tkwin = NULL;
379
                    return TCL_ERROR;
380
                }
381
            }
382
            if (Tk_IsTopLevel(ewPtr->body.ew.tkwin)
383
                    || (ewPtr->body.ew.tkwin == textPtr->tkwin)) {
384
                goto badMaster;
385
            }
386
 
387
            /*
388
             * Take over geometry management for the window, plus create
389
             * an event handler to find out when it is deleted.
390
             */
391
 
392
            Tk_ManageGeometry(ewPtr->body.ew.tkwin, &textGeomType,
393
                    (ClientData) ewPtr);
394
            Tk_CreateEventHandler(ewPtr->body.ew.tkwin, StructureNotifyMask,
395
                    EmbWinStructureProc, (ClientData) ewPtr);
396
 
397
            /*
398
             * Special trick!  Must enter into the hash table *after*
399
             * calling Tk_ManageGeometry:  if the window was already managed
400
             * elsewhere in this text, the Tk_ManageGeometry call will cause
401
             * the entry to be removed, which could potentially lose the new
402
             * entry.
403
             */
404
 
405
            hPtr = Tcl_CreateHashEntry(&textPtr->windowTable,
406
                    Tk_PathName(ewPtr->body.ew.tkwin), &new);
407
            Tcl_SetHashValue(hPtr, ewPtr);
408
 
409
        }
410
    }
411
    return TCL_OK;
412
}
413
 
414
/*
415
 *--------------------------------------------------------------
416
 *
417
 * AlignParseProc --
418
 *
419
 *      This procedure is invoked by Tk_ConfigureWidget during
420
 *      option processing to handle "-align" options for embedded
421
 *      windows.
422
 *
423
 * Results:
424
 *      A standard Tcl return value.
425
 *
426
 * Side effects:
427
 *      The alignment for the embedded window may change.
428
 *
429
 *--------------------------------------------------------------
430
 */
431
 
432
        /* ARGSUSED */
433
static int
434
AlignParseProc(clientData, interp, tkwin, value, widgRec, offset)
435
    ClientData clientData;              /* Not used.*/
436
    Tcl_Interp *interp;                 /* Used for reporting errors. */
437
    Tk_Window tkwin;                    /* Window for text widget. */
438
    char *value;                        /* Value of option. */
439
    char *widgRec;                      /* Pointer to TkTextEmbWindow
440
                                         * structure. */
441
    int offset;                         /* Offset into item (ignored). */
442
{
443
    register TkTextEmbWindow *embPtr = (TkTextEmbWindow *) widgRec;
444
 
445
    if (strcmp(value, "baseline") == 0) {
446
        embPtr->align = ALIGN_BASELINE;
447
    } else if (strcmp(value, "bottom") == 0) {
448
        embPtr->align = ALIGN_BOTTOM;
449
    } else if (strcmp(value, "center") == 0) {
450
        embPtr->align = ALIGN_CENTER;
451
    } else if (strcmp(value, "top") == 0) {
452
        embPtr->align = ALIGN_TOP;
453
    } else {
454
        Tcl_AppendResult(interp, "bad alignment \"", value,
455
                "\": must be baseline, bottom, center, or top",
456
                (char *) NULL);
457
        return TCL_ERROR;
458
    }
459
    return TCL_OK;
460
}
461
 
462
/*
463
 *--------------------------------------------------------------
464
 *
465
 * AlignPrintProc --
466
 *
467
 *      This procedure is invoked by the Tk configuration code
468
 *      to produce a printable string for the "-align" configuration
469
 *      option for embedded windows.
470
 *
471
 * Results:
472
 *      The return value is a string describing the embedded
473
 *      window's current alignment.
474
 *
475
 * Side effects:
476
 *      None.
477
 *
478
 *--------------------------------------------------------------
479
 */
480
 
481
        /* ARGSUSED */
482
static char *
483
AlignPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
484
    ClientData clientData;              /* Ignored. */
485
    Tk_Window tkwin;                    /* Window for text widget. */
486
    char *widgRec;                      /* Pointer to TkTextEmbWindow
487
                                         * structure. */
488
    int offset;                         /* Ignored. */
489
    Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with
490
                                         * information about how to reclaim
491
                                         * storage for return string. */
492
{
493
    switch (((TkTextEmbWindow *) widgRec)->align) {
494
        case ALIGN_BASELINE:
495
            return "baseline";
496
        case ALIGN_BOTTOM:
497
            return "bottom";
498
        case ALIGN_CENTER:
499
            return "center";
500
        case ALIGN_TOP:
501
            return "top";
502
        default:
503
            return "??";
504
    }
505
}
506
 
507
/*
508
 *--------------------------------------------------------------
509
 *
510
 * EmbWinStructureProc --
511
 *
512
 *      This procedure is invoked by the Tk event loop whenever
513
 *      StructureNotify events occur for a window that's embedded
514
 *      in a text widget.  This procedure's only purpose is to
515
 *      clean up when windows are deleted.
516
 *
517
 * Results:
518
 *      None.
519
 *
520
 * Side effects:
521
 *      The window is disassociated from the window segment, and
522
 *      the portion of the text is redisplayed.
523
 *
524
 *--------------------------------------------------------------
525
 */
526
 
527
static void
528
EmbWinStructureProc(clientData, eventPtr)
529
    ClientData clientData;      /* Pointer to record describing window item. */
530
    XEvent *eventPtr;           /* Describes what just happened. */
531
{
532
    register TkTextSegment *ewPtr = (TkTextSegment *) clientData;
533
    TkTextIndex index;
534
 
535
    if (eventPtr->type != DestroyNotify) {
536
        return;
537
    }
538
 
539
    Tcl_DeleteHashEntry(Tcl_FindHashEntry(&ewPtr->body.ew.textPtr->windowTable,
540
            Tk_PathName(ewPtr->body.ew.tkwin)));
541
    ewPtr->body.ew.tkwin = NULL;
542
    index.tree = ewPtr->body.ew.textPtr->tree;
543
    index.linePtr = ewPtr->body.ew.linePtr;
544
    index.charIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr);
545
    TkTextChanged(ewPtr->body.ew.textPtr, &index, &index);
546
}
547
 
548
/*
549
 *--------------------------------------------------------------
550
 *
551
 * EmbWinRequestProc --
552
 *
553
 *      This procedure is invoked whenever a window that's associated
554
 *      with a window canvas item changes its requested dimensions.
555
 *
556
 * Results:
557
 *      None.
558
 *
559
 * Side effects:
560
 *      The size and location on the screen of the window may change,
561
 *      depending on the options specified for the window item.
562
 *
563
 *--------------------------------------------------------------
564
 */
565
 
566
        /* ARGSUSED */
567
static void
568
EmbWinRequestProc(clientData, tkwin)
569
    ClientData clientData;              /* Pointer to record for window item. */
570
    Tk_Window tkwin;                    /* Window that changed its desired
571
                                         * size. */
572
{
573
    TkTextSegment *ewPtr = (TkTextSegment *) clientData;
574
    TkTextIndex index;
575
 
576
    index.tree = ewPtr->body.ew.textPtr->tree;
577
    index.linePtr = ewPtr->body.ew.linePtr;
578
    index.charIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr);
579
    TkTextChanged(ewPtr->body.ew.textPtr, &index, &index);
580
}
581
 
582
/*
583
 *--------------------------------------------------------------
584
 *
585
 * EmbWinLostSlaveProc --
586
 *
587
 *      This procedure is invoked by the Tk geometry manager when
588
 *      a slave window managed by a text widget is claimed away
589
 *      by another geometry manager.
590
 *
591
 * Results:
592
 *      None.
593
 *
594
 * Side effects:
595
 *      The window is disassociated from the window segment, and
596
 *      the portion of the text is redisplayed.
597
 *
598
 *--------------------------------------------------------------
599
 */
600
 
601
static void
602
EmbWinLostSlaveProc(clientData, tkwin)
603
    ClientData clientData;      /* Pointer to record describing window item. */
604
    Tk_Window tkwin;            /* Window that was claimed away by another
605
                                 * geometry manager. */
606
{
607
    register TkTextSegment *ewPtr = (TkTextSegment *) clientData;
608
    TkTextIndex index;
609
 
610
    Tk_DeleteEventHandler(ewPtr->body.ew.tkwin, StructureNotifyMask,
611
            EmbWinStructureProc, (ClientData) ewPtr);
612
    Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr);
613
    if (ewPtr->body.ew.textPtr->tkwin != Tk_Parent(tkwin)) {
614
        Tk_UnmaintainGeometry(tkwin, ewPtr->body.ew.textPtr->tkwin);
615
    } else {
616
        Tk_UnmapWindow(tkwin);
617
    }
618
    Tcl_DeleteHashEntry(Tcl_FindHashEntry(&ewPtr->body.ew.textPtr->windowTable,
619
            Tk_PathName(ewPtr->body.ew.tkwin)));
620
    ewPtr->body.ew.tkwin = NULL;
621
    index.tree = ewPtr->body.ew.textPtr->tree;
622
    index.linePtr = ewPtr->body.ew.linePtr;
623
    index.charIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr);
624
    TkTextChanged(ewPtr->body.ew.textPtr, &index, &index);
625
}
626
 
627
/*
628
 *--------------------------------------------------------------
629
 *
630
 * EmbWinDeleteProc --
631
 *
632
 *      This procedure is invoked by the text B-tree code whenever
633
 *      an embedded window lies in a range of characters being deleted.
634
 *
635
 * Results:
636
 *      Returns 0 to indicate that the deletion has been accepted.
637
 *
638
 * Side effects:
639
 *      The embedded window is deleted, if it exists, and any resources
640
 *      associated with it are released.
641
 *
642
 *--------------------------------------------------------------
643
 */
644
 
645
        /* ARGSUSED */
646
static int
647
EmbWinDeleteProc(ewPtr, linePtr, treeGone)
648
    TkTextSegment *ewPtr;               /* Segment being deleted. */
649
    TkTextLine *linePtr;                /* Line containing segment. */
650
    int treeGone;                       /* Non-zero means the entire tree is
651
                                         * being deleted, so everything must
652
                                         * get cleaned up. */
653
{
654
    Tcl_HashEntry *hPtr;
655
 
656
    if (ewPtr->body.ew.tkwin != NULL) {
657
        hPtr = Tcl_FindHashEntry(&ewPtr->body.ew.textPtr->windowTable,
658
                Tk_PathName(ewPtr->body.ew.tkwin));
659
        if (hPtr != NULL) {
660
            /*
661
             * (It's possible for there to be no hash table entry for this
662
             * window, if an error occurred while creating the window segment
663
             * but before the window got added to the table)
664
             */
665
 
666
            Tcl_DeleteHashEntry(hPtr);
667
        }
668
 
669
        /*
670
         * Delete the event handler for the window before destroying
671
         * the window, so that EmbWinStructureProc doesn't get called
672
         * (we'll already do everything that it would have done, and
673
         * it will just get confused).
674
         */
675
 
676
        Tk_DeleteEventHandler(ewPtr->body.ew.tkwin, StructureNotifyMask,
677
                EmbWinStructureProc, (ClientData) ewPtr);
678
        Tk_DestroyWindow(ewPtr->body.ew.tkwin);
679
    }
680
    Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr);
681
    Tk_FreeOptions(configSpecs, (char *) &ewPtr->body.ew,
682
            ewPtr->body.ew.textPtr->display, 0);
683
    ckfree((char *) ewPtr);
684
    return 0;
685
}
686
 
687
/*
688
 *--------------------------------------------------------------
689
 *
690
 * EmbWinCleanupProc --
691
 *
692
 *      This procedure is invoked by the B-tree code whenever a
693
 *      segment containing an embedded window is moved from one
694
 *      line to another.
695
 *
696
 * Results:
697
 *      None.
698
 *
699
 * Side effects:
700
 *      The linePtr field of the segment gets updated.
701
 *
702
 *--------------------------------------------------------------
703
 */
704
 
705
static TkTextSegment *
706
EmbWinCleanupProc(ewPtr, linePtr)
707
    TkTextSegment *ewPtr;               /* Mark segment that's being moved. */
708
    TkTextLine *linePtr;                /* Line that now contains segment. */
709
{
710
    ewPtr->body.ew.linePtr = linePtr;
711
    return ewPtr;
712
}
713
 
714
/*
715
 *--------------------------------------------------------------
716
 *
717
 * EmbWinLayoutProc --
718
 *
719
 *      This procedure is the "layoutProc" for embedded window
720
 *      segments.
721
 *
722
 * Results:
723
 *      1 is returned to indicate that the segment should be
724
 *      displayed.  The chunkPtr structure is filled in.
725
 *
726
 * Side effects:
727
 *      None, except for filling in chunkPtr.
728
 *
729
 *--------------------------------------------------------------
730
 */
731
 
732
        /*ARGSUSED*/
733
static int
734
EmbWinLayoutProc(textPtr, indexPtr, ewPtr, offset, maxX, maxChars,
735
        noCharsYet, wrapMode, chunkPtr)
736
    TkText *textPtr;            /* Text widget being layed out. */
737
    TkTextIndex *indexPtr;      /* Identifies first character in chunk. */
738
    TkTextSegment *ewPtr;       /* Segment corresponding to indexPtr. */
739
    int offset;                 /* Offset within segPtr corresponding to
740
                                 * indexPtr (always 0). */
741
    int maxX;                   /* Chunk must not occupy pixels at this
742
                                 * position or higher. */
743
    int maxChars;               /* Chunk must not include more than this
744
                                 * many characters. */
745
    int noCharsYet;             /* Non-zero means no characters have been
746
                                 * assigned to this line yet. */
747
    Tk_Uid wrapMode;            /* Wrap mode to use for line: tkTextCharUid,
748
                                 * tkTextNoneUid, or tkTextWordUid. */
749
    register TkTextDispChunk *chunkPtr;
750
                                /* Structure to fill in with information
751
                                 * about this chunk.  The x field has already
752
                                 * been set by the caller. */
753
{
754
    int width, height;
755
 
756
    if (offset != 0) {
757
        panic("Non-zero offset in EmbWinLayoutProc");
758
    }
759
 
760
    if ((ewPtr->body.ew.tkwin == NULL) && (ewPtr->body.ew.create != NULL)) {
761
        int code, new;
762
        Tcl_DString name;
763
        Tk_Window ancestor;
764
        Tcl_HashEntry *hPtr;
765
 
766
        /*
767
         * The window doesn't currently exist.  Create it by evaluating
768
         * the creation script.  The script must return the window's
769
         * path name:  look up that name to get back to the window
770
         * token.  Then register ourselves as the geometry manager for
771
         * the window.
772
         */
773
 
774
        code = Tcl_GlobalEval(textPtr->interp, ewPtr->body.ew.create);
775
        if (code != TCL_OK) {
776
            createError:
777
            Tcl_BackgroundError(textPtr->interp);
778
            goto gotWindow;
779
        }
780
        Tcl_DStringInit(&name);
781
        Tcl_DStringAppend(&name, textPtr->interp->result, -1);
782
        Tcl_ResetResult(textPtr->interp);
783
        ewPtr->body.ew.tkwin = Tk_NameToWindow(textPtr->interp,
784
                Tcl_DStringValue(&name), textPtr->tkwin);
785
        if (ewPtr->body.ew.tkwin == NULL) {
786
            goto createError;
787
        }
788
        for (ancestor = textPtr->tkwin; ;
789
                ancestor = Tk_Parent(ancestor)) {
790
            if (ancestor == Tk_Parent(ewPtr->body.ew.tkwin)) {
791
                break;
792
            }
793
            if (Tk_IsTopLevel(ancestor)) {
794
                badMaster:
795
                Tcl_AppendResult(textPtr->interp, "can't embed ",
796
                        Tk_PathName(ewPtr->body.ew.tkwin), " relative to ",
797
                        Tk_PathName(textPtr->tkwin), (char *) NULL);
798
                Tcl_BackgroundError(textPtr->interp);
799
                ewPtr->body.ew.tkwin = NULL;
800
                goto gotWindow;
801
            }
802
        }
803
        if (Tk_IsTopLevel(ewPtr->body.ew.tkwin)
804
                || (textPtr->tkwin == ewPtr->body.ew.tkwin)) {
805
            goto badMaster;
806
        }
807
        Tk_ManageGeometry(ewPtr->body.ew.tkwin, &textGeomType,
808
                (ClientData) ewPtr);
809
        Tk_CreateEventHandler(ewPtr->body.ew.tkwin, StructureNotifyMask,
810
                EmbWinStructureProc, (ClientData) ewPtr);
811
 
812
        /*
813
         * Special trick!  Must enter into the hash table *after*
814
         * calling Tk_ManageGeometry:  if the window was already managed
815
         * elsewhere in this text, the Tk_ManageGeometry call will cause
816
         * the entry to be removed, which could potentially lose the new
817
         * entry.
818
         */
819
 
820
        hPtr = Tcl_CreateHashEntry(&textPtr->windowTable,
821
                Tk_PathName(ewPtr->body.ew.tkwin), &new);
822
        Tcl_SetHashValue(hPtr, ewPtr);
823
    }
824
 
825
    /*
826
     * See if there's room for this window on this line.
827
     */
828
 
829
    gotWindow:
830
    if (ewPtr->body.ew.tkwin == NULL) {
831
        width = 0;
832
        height = 0;
833
    } else {
834
        width = Tk_ReqWidth(ewPtr->body.ew.tkwin) + 2*ewPtr->body.ew.padX;
835
        height = Tk_ReqHeight(ewPtr->body.ew.tkwin) + 2*ewPtr->body.ew.padY;
836
    }
837
    if ((width > (maxX - chunkPtr->x))
838
            && !noCharsYet && (textPtr->wrapMode != tkTextNoneUid)) {
839
        return 0;
840
    }
841
 
842
    /*
843
     * Fill in the chunk structure.
844
     */
845
 
846
    chunkPtr->displayProc = EmbWinDisplayProc;
847
    chunkPtr->undisplayProc = EmbWinUndisplayProc;
848
    chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL;
849
    chunkPtr->bboxProc = EmbWinBboxProc;
850
    chunkPtr->numChars = 1;
851
    if (ewPtr->body.ew.align == ALIGN_BASELINE) {
852
        chunkPtr->minAscent = height - ewPtr->body.ew.padY;
853
        chunkPtr->minDescent = ewPtr->body.ew.padY;
854
        chunkPtr->minHeight = 0;
855
    } else {
856
        chunkPtr->minAscent = 0;
857
        chunkPtr->minDescent = 0;
858
        chunkPtr->minHeight = height;
859
    }
860
    chunkPtr->width = width;
861
    chunkPtr->breakIndex = -1;
862
    chunkPtr->breakIndex = 1;
863
    chunkPtr->clientData = (ClientData) ewPtr;
864
    ewPtr->body.ew.chunkCount += 1;
865
    return 1;
866
}
867
 
868
/*
869
 *--------------------------------------------------------------
870
 *
871
 * EmbWinCheckProc --
872
 *
873
 *      This procedure is invoked by the B-tree code to perform
874
 *      consistency checks on embedded windows.
875
 *
876
 * Results:
877
 *      None.
878
 *
879
 * Side effects:
880
 *      The procedure panics if it detects anything wrong with
881
 *      the embedded window.
882
 *
883
 *--------------------------------------------------------------
884
 */
885
 
886
static void
887
EmbWinCheckProc(ewPtr, linePtr)
888
    TkTextSegment *ewPtr;               /* Segment to check. */
889
    TkTextLine *linePtr;                /* Line containing segment. */
890
{
891
    if (ewPtr->nextPtr == NULL) {
892
        panic("EmbWinCheckProc: embedded window is last segment in line");
893
    }
894
    if (ewPtr->size != 1) {
895
        panic("EmbWinCheckProc: embedded window has size %d", ewPtr->size);
896
    }
897
}
898
 
899
/*
900
 *--------------------------------------------------------------
901
 *
902
 * EmbWinDisplayProc --
903
 *
904
 *      This procedure is invoked by the text displaying code
905
 *      when it is time to actually draw an embedded window
906
 *      chunk on the screen.
907
 *
908
 * Results:
909
 *      None.
910
 *
911
 * Side effects:
912
 *      The embedded window gets moved to the correct location
913
 *      and mapped onto the screen.
914
 *
915
 *--------------------------------------------------------------
916
 */
917
 
918
static void
919
EmbWinDisplayProc(chunkPtr, x, y, lineHeight, baseline, display, dst, screenY)
920
    TkTextDispChunk *chunkPtr;          /* Chunk that is to be drawn. */
921
    int x;                              /* X-position in dst at which to
922
                                         * draw this chunk (differs from
923
                                         * the x-position in the chunk because
924
                                         * of scrolling). */
925
    int y;                              /* Top of rectangular bounding box
926
                                         * for line: tells where to draw this
927
                                         * chunk in dst (x-position is in
928
                                         * the chunk itself). */
929
    int lineHeight;                     /* Total height of line. */
930
    int baseline;                       /* Offset of baseline from y. */
931
    Display *display;                   /* Display to use for drawing. */
932
    Drawable dst;                       /* Pixmap or window in which to draw */
933
    int screenY;                        /* Y-coordinate in text window that
934
                                         * corresponds to y. */
935
{
936
    TkTextSegment *ewPtr = (TkTextSegment *) chunkPtr->clientData;
937
    int lineX, windowX, windowY, width, height;
938
    Tk_Window tkwin;
939
 
940
    tkwin = ewPtr->body.ew.tkwin;
941
    if (tkwin == NULL) {
942
        return;
943
    }
944
    if ((x + chunkPtr->width) <= 0) {
945
        /*
946
         * The window is off-screen;  just unmap it.
947
         */
948
 
949
        if (ewPtr->body.ew.textPtr->tkwin != Tk_Parent(tkwin)) {
950
            Tk_UnmaintainGeometry(tkwin, ewPtr->body.ew.textPtr->tkwin);
951
        } else {
952
            Tk_UnmapWindow(tkwin);
953
        }
954
        return;
955
    }
956
 
957
    /*
958
     * Compute the window's location and size in the text widget, taking
959
     * into account the align and stretch values for the window.
960
     */
961
 
962
    EmbWinBboxProc(chunkPtr, 0, screenY, lineHeight, baseline, &lineX,
963
            &windowY, &width, &height);
964
    windowX = lineX - chunkPtr->x + x;
965
 
966
    if (ewPtr->body.ew.textPtr->tkwin == Tk_Parent(tkwin)) {
967
        if ((windowX != Tk_X(tkwin)) || (windowY != Tk_Y(tkwin))
968
                || (Tk_ReqWidth(tkwin) != Tk_Width(tkwin))
969
                || (height != Tk_Height(tkwin))) {
970
            Tk_MoveResizeWindow(tkwin, windowX, windowY, width, height);
971
        }
972
        Tk_MapWindow(tkwin);
973
    } else {
974
        Tk_MaintainGeometry(tkwin, ewPtr->body.ew.textPtr->tkwin,
975
                windowX, windowY, width, height);
976
    }
977
 
978
    /*
979
     * Mark the window as displayed so that it won't get unmapped.
980
     */
981
 
982
    ewPtr->body.ew.displayed = 1;
983
}
984
 
985
/*
986
 *--------------------------------------------------------------
987
 *
988
 * EmbWinUndisplayProc --
989
 *
990
 *      This procedure is called when the chunk for an embedded
991
 *      window is no longer going to be displayed.  It arranges
992
 *      for the window associated with the chunk to be unmapped.
993
 *
994
 * Results:
995
 *      None.
996
 *
997
 * Side effects:
998
 *      The window is scheduled for unmapping.
999
 *
1000
 *--------------------------------------------------------------
1001
 */
1002
 
1003
static void
1004
EmbWinUndisplayProc(textPtr, chunkPtr)
1005
    TkText *textPtr;                    /* Overall information about text
1006
                                         * widget. */
1007
    TkTextDispChunk *chunkPtr;          /* Chunk that is about to be freed. */
1008
{
1009
    TkTextSegment *ewPtr = (TkTextSegment *) chunkPtr->clientData;
1010
 
1011
    ewPtr->body.ew.chunkCount--;
1012
    if (ewPtr->body.ew.chunkCount == 0) {
1013
        /*
1014
         * Don't unmap the window immediately, since there's a good chance
1015
         * that it will immediately be redisplayed, perhaps even in the
1016
         * same place.  Instead, schedule the window to be unmapped later;
1017
         * the call to EmbWinDelayedUnmap will be cancelled in the likely
1018
         * event that the unmap becomes unnecessary.
1019
         */
1020
 
1021
        ewPtr->body.ew.displayed = 0;
1022
        Tcl_DoWhenIdle(EmbWinDelayedUnmap, (ClientData) ewPtr);
1023
    }
1024
}
1025
 
1026
/*
1027
 *--------------------------------------------------------------
1028
 *
1029
 * EmbWinBboxProc --
1030
 *
1031
 *      This procedure is called to compute the bounding box of
1032
 *      the area occupied by an embedded window.
1033
 *
1034
 * Results:
1035
 *      There is no return value.  *xPtr and *yPtr are filled in
1036
 *      with the coordinates of the upper left corner of the
1037
 *      window, and *widthPtr and *heightPtr are filled in with
1038
 *      the dimensions of the window in pixels.  Note:  not all
1039
 *      of the returned bbox is necessarily visible on the screen
1040
 *      (the rightmost part might be off-screen to the right,
1041
 *      and the bottommost part might be off-screen to the bottom).
1042
 *
1043
 * Side effects:
1044
 *      None.
1045
 *
1046
 *--------------------------------------------------------------
1047
 */
1048
 
1049
static void
1050
EmbWinBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr,
1051
        widthPtr, heightPtr)
1052
    TkTextDispChunk *chunkPtr;          /* Chunk containing desired char. */
1053
    int index;                          /* Index of desired character within
1054
                                         * the chunk. */
1055
    int y;                              /* Topmost pixel in area allocated
1056
                                         * for this line. */
1057
    int lineHeight;                     /* Total height of line. */
1058
    int baseline;                       /* Location of line's baseline, in
1059
                                         * pixels measured down from y. */
1060
    int *xPtr, *yPtr;                   /* Gets filled in with coords of
1061
                                         * character's upper-left pixel. */
1062
    int *widthPtr;                      /* Gets filled in with width of
1063
                                         * character, in pixels. */
1064
    int *heightPtr;                     /* Gets filled in with height of
1065
                                         * character, in pixels. */
1066
{
1067
    TkTextSegment *ewPtr = (TkTextSegment *) chunkPtr->clientData;
1068
    Tk_Window tkwin;
1069
 
1070
    tkwin = ewPtr->body.ew.tkwin;
1071
    if (tkwin != NULL) {
1072
        *widthPtr = Tk_ReqWidth(tkwin);
1073
        *heightPtr = Tk_ReqHeight(tkwin);
1074
    } else {
1075
        *widthPtr = 0;
1076
        *heightPtr = 0;
1077
    }
1078
    *xPtr = chunkPtr->x + ewPtr->body.ew.padX;
1079
    if (ewPtr->body.ew.stretch) {
1080
        if (ewPtr->body.ew.align == ALIGN_BASELINE) {
1081
            *heightPtr = baseline - ewPtr->body.ew.padY;
1082
        } else {
1083
            *heightPtr = lineHeight - 2*ewPtr->body.ew.padY;
1084
        }
1085
    }
1086
    switch (ewPtr->body.ew.align) {
1087
        case ALIGN_BOTTOM:
1088
            *yPtr = y + (lineHeight - *heightPtr - ewPtr->body.ew.padY);
1089
            break;
1090
        case ALIGN_CENTER:
1091
            *yPtr = y + (lineHeight - *heightPtr)/2;
1092
            break;
1093
        case ALIGN_TOP:
1094
            *yPtr = y + ewPtr->body.ew.padY;
1095
            break;
1096
        case ALIGN_BASELINE:
1097
            *yPtr = y + (baseline - *heightPtr);
1098
            break;
1099
    }
1100
}
1101
 
1102
/*
1103
 *--------------------------------------------------------------
1104
 *
1105
 * EmbWinDelayedUnmap --
1106
 *
1107
 *      This procedure is an idle handler that does the actual
1108
 *      work of unmapping an embedded window.  See the comment
1109
 *      in EmbWinUndisplayProc for details.
1110
 *
1111
 * Results:
1112
 *      None.
1113
 *
1114
 * Side effects:
1115
 *      The window gets unmapped, unless its chunk reference count
1116
 *      has become non-zero again.
1117
 *
1118
 *--------------------------------------------------------------
1119
 */
1120
 
1121
static void
1122
EmbWinDelayedUnmap(clientData)
1123
    ClientData clientData;              /* Token for the window to
1124
                                         * be unmapped. */
1125
{
1126
    TkTextSegment *ewPtr = (TkTextSegment *) clientData;
1127
 
1128
    if (!ewPtr->body.ew.displayed && (ewPtr->body.ew.tkwin != NULL)) {
1129
        if (ewPtr->body.ew.textPtr->tkwin != Tk_Parent(ewPtr->body.ew.tkwin)) {
1130
            Tk_UnmaintainGeometry(ewPtr->body.ew.tkwin,
1131
                    ewPtr->body.ew.textPtr->tkwin);
1132
        } else {
1133
            Tk_UnmapWindow(ewPtr->body.ew.tkwin);
1134
        }
1135
    }
1136
}
1137
 
1138
/*
1139
 *--------------------------------------------------------------
1140
 *
1141
 * TkTextWindowIndex --
1142
 *
1143
 *      Given the name of an embedded window within a text widget,
1144
 *      returns an index corresponding to the window's position
1145
 *      in the text.
1146
 *
1147
 * Results:
1148
 *      The return value is 1 if there is an embedded window by
1149
 *      the given name in the text widget, 0 otherwise.  If the
1150
 *      window exists, *indexPtr is filled in with its index.
1151
 *
1152
 * Side effects:
1153
 *      None.
1154
 *
1155
 *--------------------------------------------------------------
1156
 */
1157
 
1158
int
1159
TkTextWindowIndex(textPtr, name, indexPtr)
1160
    TkText *textPtr;            /* Text widget containing window. */
1161
    char *name;                 /* Name of window. */
1162
    TkTextIndex *indexPtr;      /* Index information gets stored here. */
1163
{
1164
    Tcl_HashEntry *hPtr;
1165
    TkTextSegment *ewPtr;
1166
 
1167
    hPtr = Tcl_FindHashEntry(&textPtr->windowTable, name);
1168
    if (hPtr == NULL) {
1169
        return 0;
1170
    }
1171
    ewPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
1172
    indexPtr->tree = textPtr->tree;
1173
    indexPtr->linePtr = ewPtr->body.ew.linePtr;
1174
    indexPtr->charIndex = TkTextSegToOffset(ewPtr, indexPtr->linePtr);
1175
    return 1;
1176
}

powered by: WebSVN 2.1.0

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