/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkmessage.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkmessage.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25