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

Subversion Repositories or1k

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

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

Line No. Rev Author Line
1 578 markom
/*
2
 * tkMessage.c --
3
 *
4
 *      This module implements a message widgets for the Tk
5
 *      toolkit.  A message widget displays a multi-line string
6
 *      in a window according to a particular aspect ratio.
7
 *
8
 * Copyright (c) 1990-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: tkMessage.c,v 1.1.1.1 2002-01-16 10:25:52 markom Exp $
15
 */
16
 
17
#include "tkPort.h"
18
#include "default.h"
19
#include "tkInt.h"
20
 
21
/*
22
 * A data structure of the following type is kept for each message
23
 * widget managed by this file:
24
 */
25
 
26
typedef struct {
27
    Tk_Window tkwin;            /* Window that embodies the message.  NULL
28
                                 * means that the window has been destroyed
29
                                 * but the data structures haven't yet been
30
                                 * cleaned up.*/
31
    Display *display;           /* Display containing widget.  Used, among
32
                                 * other things, so that resources can be
33
                                 * freed even after tkwin has gone away. */
34
    Tcl_Interp *interp;         /* Interpreter associated with message. */
35
    Tcl_Command widgetCmd;      /* Token for message's widget command. */
36
 
37
    /*
38
     * Information used when displaying widget:
39
     */
40
 
41
    char *string;               /* String displayed in message. */
42
    int numChars;               /* Number of characters in string, not
43
                                 * including terminating NULL character. */
44
    char *textVarName;          /* Name of variable (malloc'ed) or NULL.
45
                                 * If non-NULL, message displays the contents
46
                                 * of this variable. */
47
    Tk_3DBorder border;         /* Structure used to draw 3-D border and
48
                                 * background.  NULL means a border hasn't
49
                                 * been created yet. */
50
    int borderWidth;            /* Width of border. */
51
    int relief;                 /* 3-D effect: TK_RELIEF_RAISED, etc. */
52
    int highlightWidth;         /* Width in pixels of highlight to draw
53
                                 * around widget when it has the focus.
54
                                 * <= 0 means don't draw a highlight. */
55
    XColor *highlightBgColorPtr;
56
                                /* Color for drawing traversal highlight
57
                                 * area when highlight is off. */
58
    XColor *highlightColorPtr;  /* Color for drawing traversal highlight. */
59
    Tk_Font tkfont;             /* Information about text font, or NULL. */
60
    XColor *fgColorPtr;         /* Foreground color in normal mode. */
61
    int padX, padY;             /* User-requested extra space around text. */
62
    int width;                  /* User-requested width, in pixels.  0 means
63
                                 * compute width using aspect ratio below. */
64
    int aspect;                 /* Desired aspect ratio for window
65
                                 * (100*width/height). */
66
    int msgWidth;               /* Width in pixels needed to display
67
                                 * message. */
68
    int msgHeight;              /* Height in pixels needed to display
69
                                 * message. */
70
    Tk_Anchor anchor;           /* Where to position text within window region
71
                                 * if window is larger or smaller than
72
                                 * needed. */
73
    Tk_Justify justify;         /* Justification for text. */
74
 
75
    GC textGC;                  /* GC for drawing text in normal mode. */
76
    Tk_TextLayout textLayout;   /* Saved layout information. */
77
 
78
    /*
79
     * Miscellaneous information:
80
     */
81
 
82
    Tk_Cursor cursor;           /* Current cursor for window, or None. */
83
    char *takeFocus;            /* Value of -takefocus option;  not used in
84
                                 * the C code, but used by keyboard traversal
85
                                 * scripts.  Malloc'ed, but may be NULL. */
86
    int flags;                  /* Various flags;  see below for
87
                                 * definitions. */
88
} Message;
89
 
90
/*
91
 * Flag bits for messages:
92
 *
93
 * REDRAW_PENDING:              Non-zero means a DoWhenIdle handler
94
 *                              has already been queued to redraw
95
 *                              this window.
96
 * GOT_FOCUS:                   Non-zero means this button currently
97
 *                              has the input focus.
98
 */
99
 
100
#define REDRAW_PENDING          1
101
#define GOT_FOCUS               4
102
 
103
/*
104
 * Information used for argv parsing.
105
 */
106
 
107
static Tk_ConfigSpec configSpecs[] = {
108
    {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
109
        DEF_MESSAGE_ANCHOR, Tk_Offset(Message, anchor), 0},
110
    {TK_CONFIG_INT, "-aspect", "aspect", "Aspect",
111
        DEF_MESSAGE_ASPECT, Tk_Offset(Message, aspect), 0},
112
    {TK_CONFIG_BORDER, "-background", "background", "Background",
113
        DEF_MESSAGE_BG_COLOR, Tk_Offset(Message, border),
114
        TK_CONFIG_COLOR_ONLY},
115
    {TK_CONFIG_BORDER, "-background", "background", "Background",
116
        DEF_MESSAGE_BG_MONO, Tk_Offset(Message, border),
117
        TK_CONFIG_MONO_ONLY},
118
    {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
119
        (char *) NULL, 0, 0},
120
    {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
121
        (char *) NULL, 0, 0},
122
    {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
123
        DEF_MESSAGE_BORDER_WIDTH, Tk_Offset(Message, borderWidth), 0},
124
    {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
125
        DEF_MESSAGE_CURSOR, Tk_Offset(Message, cursor), TK_CONFIG_NULL_OK},
126
    {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
127
        (char *) NULL, 0, 0},
128
    {TK_CONFIG_FONT, "-font", "font", "Font",
129
        DEF_MESSAGE_FONT, Tk_Offset(Message, tkfont), 0},
130
    {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
131
        DEF_MESSAGE_FG, Tk_Offset(Message, fgColorPtr), 0},
132
    {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
133
        "HighlightBackground", DEF_MESSAGE_HIGHLIGHT_BG,
134
        Tk_Offset(Message, highlightBgColorPtr), 0},
135
    {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
136
        DEF_MESSAGE_HIGHLIGHT, Tk_Offset(Message, highlightColorPtr), 0},
137
    {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
138
        "HighlightThickness",
139
        DEF_MESSAGE_HIGHLIGHT_WIDTH, Tk_Offset(Message, highlightWidth), 0},
140
    {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
141
        DEF_MESSAGE_JUSTIFY, Tk_Offset(Message, justify), 0},
142
    {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
143
        DEF_MESSAGE_PADX, Tk_Offset(Message, padX), 0},
144
    {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
145
        DEF_MESSAGE_PADY, Tk_Offset(Message, padY), 0},
146
    {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
147
        DEF_MESSAGE_RELIEF, Tk_Offset(Message, relief), 0},
148
    {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
149
        DEF_MESSAGE_TAKE_FOCUS, Tk_Offset(Message, takeFocus),
150
        TK_CONFIG_NULL_OK},
151
    {TK_CONFIG_STRING, "-text", "text", "Text",
152
        DEF_MESSAGE_TEXT, Tk_Offset(Message, string), 0},
153
    {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable",
154
        DEF_MESSAGE_TEXT_VARIABLE, Tk_Offset(Message, textVarName),
155
        TK_CONFIG_NULL_OK},
156
    {TK_CONFIG_PIXELS, "-width", "width", "Width",
157
        DEF_MESSAGE_WIDTH, Tk_Offset(Message, width), 0},
158
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
159
        (char *) NULL, 0, 0}
160
};
161
 
162
/*
163
 * Forward declarations for procedures defined later in this file:
164
 */
165
 
166
static void             MessageCmdDeletedProc _ANSI_ARGS_((
167
                            ClientData clientData));
168
static void             MessageEventProc _ANSI_ARGS_((ClientData clientData,
169
                            XEvent *eventPtr));
170
static char *           MessageTextVarProc _ANSI_ARGS_((ClientData clientData,
171
                            Tcl_Interp *interp, char *name1, char *name2,
172
                            int flags));
173
static int              MessageWidgetCmd _ANSI_ARGS_((ClientData clientData,
174
                            Tcl_Interp *interp, int argc, char **argv));
175
static void             MessageWorldChanged _ANSI_ARGS_((
176
                            ClientData instanceData));
177
static void             ComputeMessageGeometry _ANSI_ARGS_((Message *msgPtr));
178
static int              ConfigureMessage _ANSI_ARGS_((Tcl_Interp *interp,
179
                            Message *msgPtr, int argc, char **argv,
180
                            int flags));
181
static void             DestroyMessage _ANSI_ARGS_((char *memPtr));
182
static void             DisplayMessage _ANSI_ARGS_((ClientData clientData));
183
 
184
/*
185
 * The structure below defines message class behavior by means of procedures
186
 * that can be invoked from generic window code.
187
 */
188
 
189
static TkClassProcs messageClass = {
190
    NULL,                       /* createProc. */
191
    MessageWorldChanged,        /* geometryProc. */
192
    NULL                        /* modalProc. */
193
};
194
 
195
 
196
/*
197
 *--------------------------------------------------------------
198
 *
199
 * Tk_MessageCmd --
200
 *
201
 *      This procedure is invoked to process the "message" Tcl
202
 *      command.  See the user documentation for details on what
203
 *      it does.
204
 *
205
 * Results:
206
 *      A standard Tcl result.
207
 *
208
 * Side effects:
209
 *      See the user documentation.
210
 *
211
 *--------------------------------------------------------------
212
 */
213
 
214
int
215
Tk_MessageCmd(clientData, interp, argc, argv)
216
    ClientData clientData;      /* Main window associated with
217
                                 * interpreter. */
218
    Tcl_Interp *interp;         /* Current interpreter. */
219
    int argc;                   /* Number of arguments. */
220
    char **argv;                /* Argument strings. */
221
{
222
    register Message *msgPtr;
223
    Tk_Window new;
224
    Tk_Window tkwin = (Tk_Window) clientData;
225
 
226
    if (argc < 2) {
227
        Tcl_AppendResult(interp, "wrong # args: should be \"",
228
                argv[0], " pathName ?options?\"", (char *) NULL);
229
        return TCL_ERROR;
230
    }
231
 
232
    new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
233
    if (new == NULL) {
234
        return TCL_ERROR;
235
    }
236
 
237
    msgPtr = (Message *) ckalloc(sizeof(Message));
238
    msgPtr->tkwin = new;
239
    msgPtr->display = Tk_Display(new);
240
    msgPtr->interp = interp;
241
    msgPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(msgPtr->tkwin),
242
            MessageWidgetCmd, (ClientData) msgPtr, MessageCmdDeletedProc);
243
    msgPtr->textLayout = NULL;
244
    msgPtr->string = NULL;
245
    msgPtr->numChars = 0;
246
    msgPtr->textVarName = NULL;
247
    msgPtr->border = NULL;
248
    msgPtr->borderWidth = 0;
249
    msgPtr->relief = TK_RELIEF_FLAT;
250
    msgPtr->highlightWidth = 0;
251
    msgPtr->highlightBgColorPtr = NULL;
252
    msgPtr->highlightColorPtr = NULL;
253
    msgPtr->tkfont = NULL;
254
    msgPtr->fgColorPtr = NULL;
255
    msgPtr->textGC = None;
256
    msgPtr->padX = 0;
257
    msgPtr->padY = 0;
258
    msgPtr->anchor = TK_ANCHOR_CENTER;
259
    msgPtr->width = 0;
260
    msgPtr->aspect = 150;
261
    msgPtr->msgWidth = 0;
262
    msgPtr->msgHeight = 0;
263
    msgPtr->justify = TK_JUSTIFY_LEFT;
264
    msgPtr->cursor = None;
265
    msgPtr->takeFocus = NULL;
266
    msgPtr->flags = 0;
267
 
268
    Tk_SetClass(msgPtr->tkwin, "Message");
269
    TkSetClassProcs(msgPtr->tkwin, &messageClass, (ClientData) msgPtr);
270
    Tk_CreateEventHandler(msgPtr->tkwin,
271
            ExposureMask|StructureNotifyMask|FocusChangeMask,
272
            MessageEventProc, (ClientData) msgPtr);
273
    if (ConfigureMessage(interp, msgPtr, argc-2, argv+2, 0) != TCL_OK) {
274
        goto error;
275
    }
276
 
277
    interp->result = Tk_PathName(msgPtr->tkwin);
278
    return TCL_OK;
279
 
280
    error:
281
    Tk_DestroyWindow(msgPtr->tkwin);
282
    return TCL_ERROR;
283
}
284
 
285
/*
286
 *--------------------------------------------------------------
287
 *
288
 * MessageWidgetCmd --
289
 *
290
 *      This procedure is invoked to process the Tcl command
291
 *      that corresponds to a widget managed by this module.
292
 *      See the user documentation for details on what it does.
293
 *
294
 * Results:
295
 *      A standard Tcl result.
296
 *
297
 * Side effects:
298
 *      See the user documentation.
299
 *
300
 *--------------------------------------------------------------
301
 */
302
 
303
static int
304
MessageWidgetCmd(clientData, interp, argc, argv)
305
    ClientData clientData;      /* Information about message widget. */
306
    Tcl_Interp *interp;         /* Current interpreter. */
307
    int argc;                   /* Number of arguments. */
308
    char **argv;                /* Argument strings. */
309
{
310
    register Message *msgPtr = (Message *) clientData;
311
    size_t length;
312
    int c;
313
 
314
    if (argc < 2) {
315
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
316
                " option ?arg arg ...?\"", (char *) NULL);
317
        return TCL_ERROR;
318
    }
319
    c = argv[1][0];
320
    length = strlen(argv[1]);
321
    if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
322
            && (length >= 2)) {
323
        if (argc != 3) {
324
            Tcl_AppendResult(interp, "wrong # args: should be \"",
325
                    argv[0], " cget option\"",
326
                    (char *) NULL);
327
            return TCL_ERROR;
328
        }
329
        return Tk_ConfigureValue(interp, msgPtr->tkwin, configSpecs,
330
                (char *) msgPtr, argv[2], 0);
331
    } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
332
            && (length  >= 2)) {
333
        if (argc == 2) {
334
            return Tk_ConfigureInfo(interp, msgPtr->tkwin, configSpecs,
335
                    (char *) msgPtr, (char *) NULL, 0);
336
        } else if (argc == 3) {
337
            return Tk_ConfigureInfo(interp, msgPtr->tkwin, configSpecs,
338
                    (char *) msgPtr, argv[2], 0);
339
        } else {
340
            return ConfigureMessage(interp, msgPtr, argc-2, argv+2,
341
                    TK_CONFIG_ARGV_ONLY);
342
        }
343
    } else {
344
        Tcl_AppendResult(interp, "bad option \"", argv[1],
345
                "\": must be cget or configure", (char *) NULL);
346
        return TCL_ERROR;
347
    }
348
}
349
 
350
/*
351
 *----------------------------------------------------------------------
352
 *
353
 * DestroyMessage --
354
 *
355
 *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
356
 *      to clean up the internal structure of a message at a safe time
357
 *      (when no-one is using it anymore).
358
 *
359
 * Results:
360
 *      None.
361
 *
362
 * Side effects:
363
 *      Everything associated with the message is freed up.
364
 *
365
 *----------------------------------------------------------------------
366
 */
367
 
368
static void
369
DestroyMessage(memPtr)
370
    char *memPtr;               /* Info about message widget. */
371
{
372
    register Message *msgPtr = (Message *) memPtr;
373
 
374
    /*
375
     * Free up all the stuff that requires special handling, then
376
     * let Tk_FreeOptions handle all the standard option-related
377
     * stuff.
378
     */
379
 
380
    Tk_FreeTextLayout(msgPtr->textLayout);
381
    if (msgPtr->textVarName != NULL) {
382
        Tcl_UntraceVar(msgPtr->interp, msgPtr->textVarName,
383
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
384
                MessageTextVarProc, (ClientData) msgPtr);
385
    }
386
    if (msgPtr->textGC != None) {
387
        Tk_FreeGC(msgPtr->display, msgPtr->textGC);
388
    }
389
    Tk_FreeOptions(configSpecs, (char *) msgPtr, msgPtr->display, 0);
390
    ckfree((char *) msgPtr);
391
}
392
 
393
/*
394
 *----------------------------------------------------------------------
395
 *
396
 * ConfigureMessage --
397
 *
398
 *      This procedure is called to process an argv/argc list, plus
399
 *      the Tk option database, in order to configure (or
400
 *      reconfigure) a message widget.
401
 *
402
 * Results:
403
 *      The return value is a standard Tcl result.  If TCL_ERROR is
404
 *      returned, then interp->result contains an error message.
405
 *
406
 * Side effects:
407
 *      Configuration information, such as text string, colors, font,
408
 *      etc. get set for msgPtr;  old resources get freed, if there
409
 *      were any.
410
 *
411
 *----------------------------------------------------------------------
412
 */
413
 
414
static int
415
ConfigureMessage(interp, msgPtr, argc, argv, flags)
416
    Tcl_Interp *interp;         /* Used for error reporting. */
417
    register Message *msgPtr;   /* Information about widget;  may or may
418
                                 * not already have values for some fields. */
419
    int argc;                   /* Number of valid entries in argv. */
420
    char **argv;                /* Arguments. */
421
    int flags;                  /* Flags to pass to Tk_ConfigureWidget. */
422
{
423
    /*
424
     * Eliminate any existing trace on a variable monitored by the message.
425
     */
426
 
427
    if (msgPtr->textVarName != NULL) {
428
        Tcl_UntraceVar(interp, msgPtr->textVarName,
429
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
430
                MessageTextVarProc, (ClientData) msgPtr);
431
    }
432
 
433
    if (Tk_ConfigureWidget(interp, msgPtr->tkwin, configSpecs,
434
            argc, argv, (char *) msgPtr, flags) != TCL_OK) {
435
        return TCL_ERROR;
436
    }
437
 
438
    /*
439
     * If the message is to display the value of a variable, then set up
440
     * a trace on the variable's value, create the variable if it doesn't
441
     * exist, and fetch its current value.
442
     */
443
 
444
    if (msgPtr->textVarName != NULL) {
445
        char *value;
446
 
447
        value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY);
448
        if (value == NULL) {
449
            Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string,
450
                    TCL_GLOBAL_ONLY);
451
        } else {
452
            if (msgPtr->string != NULL) {
453
                ckfree(msgPtr->string);
454
            }
455
            msgPtr->string = strcpy(ckalloc(strlen(value) + 1), value);
456
        }
457
        Tcl_TraceVar(interp, msgPtr->textVarName,
458
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
459
                MessageTextVarProc, (ClientData) msgPtr);
460
    }
461
 
462
    /*
463
     * A few other options need special processing, such as setting
464
     * the background from a 3-D border or handling special defaults
465
     * that couldn't be specified to Tk_ConfigureWidget.
466
     */
467
 
468
    msgPtr->numChars = strlen(msgPtr->string);
469
 
470
    Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border);
471
 
472
    if (msgPtr->highlightWidth < 0) {
473
        msgPtr->highlightWidth = 0;
474
    }
475
 
476
    MessageWorldChanged((ClientData) msgPtr);
477
    return TCL_OK;
478
}
479
 
480
/*
481
 *---------------------------------------------------------------------------
482
 *
483
 * MessageWorldChanged --
484
 *
485
 *      This procedure is called when the world has changed in some
486
 *      way and the widget needs to recompute all its graphics contexts
487
 *      and determine its new geometry.
488
 *
489
 * Results:
490
 *      None.
491
 *
492
 * Side effects:
493
 *      Message will be relayed out and redisplayed.
494
 *
495
 *---------------------------------------------------------------------------
496
 */
497
 
498
static void
499
MessageWorldChanged(instanceData)
500
    ClientData instanceData;    /* Information about widget. */
501
{
502
    XGCValues gcValues;
503
    GC gc;
504
    Tk_FontMetrics fm;
505
    Message *msgPtr;
506
 
507
    msgPtr = (Message *) instanceData;
508
 
509
    gcValues.font = Tk_FontId(msgPtr->tkfont);
510
    gcValues.foreground = msgPtr->fgColorPtr->pixel;
511
    gc = Tk_GetGCColor(msgPtr->tkwin, GCForeground | GCFont, &gcValues,
512
                       msgPtr->fgColorPtr, NULL);
513
    if (msgPtr->textGC != None) {
514
        Tk_FreeGC(msgPtr->display, msgPtr->textGC);
515
    }
516
    msgPtr->textGC = gc;
517
 
518
    Tk_GetFontMetrics(msgPtr->tkfont, &fm);
519
    if (msgPtr->padX < 0) {
520
        msgPtr->padX = fm.ascent / 2;
521
    }
522
    if (msgPtr->padY == -1) {
523
        msgPtr->padY = fm.ascent / 4;
524
    }
525
 
526
    /*
527
     * Recompute the desired geometry for the window, and arrange for
528
     * the window to be redisplayed.
529
     */
530
 
531
    ComputeMessageGeometry(msgPtr);
532
    if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin)
533
            && !(msgPtr->flags & REDRAW_PENDING)) {
534
        Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
535
        msgPtr->flags |= REDRAW_PENDING;
536
    }
537
}
538
 
539
/*
540
 *--------------------------------------------------------------
541
 *
542
 * ComputeMessageGeometry --
543
 *
544
 *      Compute the desired geometry for a message window,
545
 *      taking into account the desired aspect ratio for the
546
 *      window.
547
 *
548
 * Results:
549
 *      None.
550
 *
551
 * Side effects:
552
 *      Tk_GeometryRequest is called to inform the geometry
553
 *      manager of the desired geometry for this window.
554
 *
555
 *--------------------------------------------------------------
556
 */
557
 
558
static void
559
ComputeMessageGeometry(msgPtr)
560
    register Message *msgPtr;   /* Information about window. */
561
{
562
    int width, inc, height;
563
    int thisWidth, thisHeight, maxWidth;
564
    int aspect, lowerBound, upperBound, inset;
565
 
566
    Tk_FreeTextLayout(msgPtr->textLayout);
567
 
568
    inset = msgPtr->borderWidth + msgPtr->highlightWidth;
569
 
570
    /*
571
     * Compute acceptable bounds for the final aspect ratio.
572
     */
573
 
574
    aspect = msgPtr->aspect/10;
575
    if (aspect < 5) {
576
        aspect = 5;
577
    }
578
    lowerBound = msgPtr->aspect - aspect;
579
    upperBound = msgPtr->aspect + aspect;
580
 
581
    /*
582
     * Do the computation in multiple passes:  start off with
583
     * a very wide window, and compute its height.  Then change
584
     * the width and try again.  Reduce the size of the change
585
     * and iterate until dimensions are found that approximate
586
     * the desired aspect ratio.  Or, if the user gave an explicit
587
     * width then just use that.
588
     */
589
 
590
    if (msgPtr->width > 0) {
591
        width = msgPtr->width;
592
        inc = 0;
593
    } else {
594
        width = WidthOfScreen(Tk_Screen(msgPtr->tkwin))/2;
595
        inc = width/2;
596
    }
597
 
598
    for ( ; ; inc /= 2) {
599
        msgPtr->textLayout = Tk_ComputeTextLayout(msgPtr->tkfont,
600
                msgPtr->string, msgPtr->numChars, width, msgPtr->justify,
601
                0, &thisWidth, &thisHeight);
602
        maxWidth = thisWidth + 2 * (inset + msgPtr->padX);
603
        height = thisHeight + 2 * (inset + msgPtr->padY);
604
 
605
        if (inc <= 2) {
606
            break;
607
        }
608
        aspect = (100 * maxWidth) / height;
609
 
610
        if (aspect < lowerBound) {
611
            width += inc;
612
        } else if (aspect > upperBound) {
613
            width -= inc;
614
        } else {
615
            break;
616
        }
617
        Tk_FreeTextLayout(msgPtr->textLayout);
618
    }
619
    msgPtr->msgWidth = thisWidth;
620
    msgPtr->msgHeight = thisHeight;
621
    Tk_GeometryRequest(msgPtr->tkwin, maxWidth, height);
622
    Tk_SetInternalBorder(msgPtr->tkwin, inset);
623
}
624
 
625
/*
626
 *--------------------------------------------------------------
627
 *
628
 * DisplayMessage --
629
 *
630
 *      This procedure redraws the contents of a message window.
631
 *
632
 * Results:
633
 *      None.
634
 *
635
 * Side effects:
636
 *      Information appears on the screen.
637
 *
638
 *--------------------------------------------------------------
639
 */
640
 
641
static void
642
DisplayMessage(clientData)
643
    ClientData clientData;      /* Information about window. */
644
{
645
    register Message *msgPtr = (Message *) clientData;
646
    register Tk_Window tkwin = msgPtr->tkwin;
647
    int x, y;
648
 
649
    msgPtr->flags &= ~REDRAW_PENDING;
650
    if ((msgPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
651
        return;
652
    }
653
    Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border, 0, 0,
654
            Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
655
 
656
    /*
657
     * Compute starting y-location for message based on message size
658
     * and anchor option.
659
     */
660
 
661
    TkComputeAnchor(msgPtr->anchor, tkwin, msgPtr->padX, msgPtr->padY,
662
            msgPtr->msgWidth, msgPtr->msgHeight, &x, &y);
663
    Tk_DrawTextLayout(Tk_Display(tkwin), Tk_WindowId(tkwin), msgPtr->textGC,
664
            msgPtr->textLayout, x, y, 0, -1);
665
 
666
    if (msgPtr->relief != TK_RELIEF_FLAT) {
667
        Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border,
668
                msgPtr->highlightWidth, msgPtr->highlightWidth,
669
                Tk_Width(tkwin) - 2*msgPtr->highlightWidth,
670
                Tk_Height(tkwin) - 2*msgPtr->highlightWidth,
671
                msgPtr->borderWidth, msgPtr->relief);
672
    }
673
    if (msgPtr->highlightWidth != 0) {
674
        GC gc;
675
 
676
        if (msgPtr->flags & GOT_FOCUS) {
677
            gc = Tk_GCForColor(msgPtr->highlightColorPtr, Tk_WindowId(tkwin));
678
        } else {
679
            gc = Tk_GCForColor(msgPtr->highlightBgColorPtr, Tk_WindowId(tkwin));
680
        }
681
        Tk_DrawFocusHighlight(tkwin, gc, msgPtr->highlightWidth,
682
                Tk_WindowId(tkwin));
683
    }
684
}
685
 
686
/*
687
 *--------------------------------------------------------------
688
 *
689
 * MessageEventProc --
690
 *
691
 *      This procedure is invoked by the Tk dispatcher for various
692
 *      events on messages.
693
 *
694
 * Results:
695
 *      None.
696
 *
697
 * Side effects:
698
 *      When the window gets deleted, internal structures get
699
 *      cleaned up.  When it gets exposed, it is redisplayed.
700
 *
701
 *--------------------------------------------------------------
702
 */
703
 
704
static void
705
MessageEventProc(clientData, eventPtr)
706
    ClientData clientData;      /* Information about window. */
707
    XEvent *eventPtr;           /* Information about event. */
708
{
709
    Message *msgPtr = (Message *) clientData;
710
 
711
    if (((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0))
712
            || (eventPtr->type == ConfigureNotify)) {
713
        goto redraw;
714
    } else if (eventPtr->type == DestroyNotify) {
715
        if (msgPtr->tkwin != NULL) {
716
            msgPtr->tkwin = NULL;
717
            Tcl_DeleteCommandFromToken(msgPtr->interp, msgPtr->widgetCmd);
718
        }
719
        if (msgPtr->flags & REDRAW_PENDING) {
720
            Tcl_CancelIdleCall(DisplayMessage, (ClientData) msgPtr);
721
        }
722
        Tcl_EventuallyFree((ClientData) msgPtr, DestroyMessage);
723
    } else if (eventPtr->type == FocusIn) {
724
        if (eventPtr->xfocus.detail != NotifyInferior) {
725
            msgPtr->flags |= GOT_FOCUS;
726
            if (msgPtr->highlightWidth > 0) {
727
                goto redraw;
728
            }
729
        }
730
    } else if (eventPtr->type == FocusOut) {
731
        if (eventPtr->xfocus.detail != NotifyInferior) {
732
            msgPtr->flags &= ~GOT_FOCUS;
733
            if (msgPtr->highlightWidth > 0) {
734
                goto redraw;
735
            }
736
        }
737
    }
738
    return;
739
 
740
    redraw:
741
    if ((msgPtr->tkwin != NULL) && !(msgPtr->flags & REDRAW_PENDING)) {
742
        Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
743
        msgPtr->flags |= REDRAW_PENDING;
744
    }
745
}
746
 
747
/*
748
 *----------------------------------------------------------------------
749
 *
750
 * MessageCmdDeletedProc --
751
 *
752
 *      This procedure is invoked when a widget command is deleted.  If
753
 *      the widget isn't already in the process of being destroyed,
754
 *      this command destroys it.
755
 *
756
 * Results:
757
 *      None.
758
 *
759
 * Side effects:
760
 *      The widget is destroyed.
761
 *
762
 *----------------------------------------------------------------------
763
 */
764
 
765
static void
766
MessageCmdDeletedProc(clientData)
767
    ClientData clientData;      /* Pointer to widget record for widget. */
768
{
769
    Message *msgPtr = (Message *) clientData;
770
    Tk_Window tkwin = msgPtr->tkwin;
771
 
772
    /*
773
     * This procedure could be invoked either because the window was
774
     * destroyed and the command was then deleted (in which case tkwin
775
     * is NULL) or because the command was deleted, and then this procedure
776
     * destroys the widget.
777
     */
778
 
779
    if (tkwin != NULL) {
780
        msgPtr->tkwin = NULL;
781
        Tk_DestroyWindow(tkwin);
782
    }
783
}
784
 
785
/*
786
 *--------------------------------------------------------------
787
 *
788
 * MessageTextVarProc --
789
 *
790
 *      This procedure is invoked when someone changes the variable
791
 *      whose contents are to be displayed in a message.
792
 *
793
 * Results:
794
 *      NULL is always returned.
795
 *
796
 * Side effects:
797
 *      The text displayed in the message will change to match the
798
 *      variable.
799
 *
800
 *--------------------------------------------------------------
801
 */
802
 
803
        /* ARGSUSED */
804
static char *
805
MessageTextVarProc(clientData, interp, name1, name2, flags)
806
    ClientData clientData;      /* Information about message. */
807
    Tcl_Interp *interp;         /* Interpreter containing variable. */
808
    char *name1;                /* Name of variable. */
809
    char *name2;                /* Second part of variable name. */
810
    int flags;                  /* Information about what happened. */
811
{
812
    register Message *msgPtr = (Message *) clientData;
813
    char *value;
814
 
815
    /*
816
     * If the variable is unset, then immediately recreate it unless
817
     * the whole interpreter is going away.
818
     */
819
 
820
    if (flags & TCL_TRACE_UNSETS) {
821
        if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
822
            Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string,
823
                    TCL_GLOBAL_ONLY);
824
            Tcl_TraceVar(interp, msgPtr->textVarName,
825
                    TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
826
                    MessageTextVarProc, clientData);
827
        }
828
        return (char *) NULL;
829
    }
830
 
831
    value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY);
832
    if (value == NULL) {
833
        value = "";
834
    }
835
    if (msgPtr->string != NULL) {
836
        ckfree(msgPtr->string);
837
    }
838
    msgPtr->numChars = strlen(value);
839
    msgPtr->string = (char *) ckalloc((unsigned) (msgPtr->numChars + 1));
840
    strcpy(msgPtr->string, value);
841
    ComputeMessageGeometry(msgPtr);
842
 
843
    if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin)
844
            && !(msgPtr->flags & REDRAW_PENDING)) {
845
        Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
846
        msgPtr->flags |= REDRAW_PENDING;
847
    }
848
    return (char *) NULL;
849
}

powered by: WebSVN 2.1.0

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