]> cvs.zerfleddert.de Git - micropolis/blob - src/tk/tkmsg.c
Fixes for compilation with gcc 15
[micropolis] / src / tk / tkmsg.c
1 /*
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 1990 Regents of the University of California.
9 * Permission to use, copy, modify, and distribute this
10 * software and its documentation for any purpose and without
11 * fee is hereby granted, provided that the above copyright
12 * notice appear in all copies. The University of California
13 * makes no representations about the suitability of this
14 * software for any purpose. It is provided "as is" without
15 * express or implied warranty.
16 */
17
18 #ifndef lint
19 static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkMessage.c,v 1.36 92/06/08 11:06:05 ouster Exp $ SPRITE (Berkeley)";
20 #endif
21
22 #include "tkconfig.h"
23 #include "default.h"
24 #include "tkint.h"
25
26 /*
27 * A data structure of the following type is kept for each message
28 * widget managed by this file:
29 */
30
31 typedef struct {
32 Tk_Window tkwin; /* Window that embodies the message. NULL
33 * means that the window has been destroyed
34 * but the data structures haven't yet been
35 * cleaned up.*/
36 Tcl_Interp *interp; /* Interpreter associated with message. */
37 Tk_Uid string; /* String displayed in message. */
38 int numChars; /* Number of characters in string, not
39 * including terminating NULL character. */
40 char *textVarName; /* Name of variable (malloc'ed) or NULL.
41 * If non-NULL, message displays the contents
42 * of this variable. */
43
44 /*
45 * Information used when displaying widget:
46 */
47
48 Tk_3DBorder border; /* Structure used to draw 3-D border and
49 * background. NULL means a border hasn't
50 * been created yet. */
51 int borderWidth; /* Width of border. */
52 int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
53 XFontStruct *fontPtr; /* Information about text font, or NULL. */
54 XColor *fgColorPtr; /* Foreground color in normal mode. */
55 GC textGC; /* GC for drawing text in normal mode. */
56 int padX, padY; /* User-requested extra space around text. */
57 Tk_Anchor anchor; /* Where to position text within window region
58 * if window is larger or smaller than
59 * needed. */
60 int width; /* User-requested width, in pixels. 0 means
61 * compute width using aspect ratio below. */
62 int aspect; /* Desired aspect ratio for window
63 * (100*width/height). */
64 int lineLength; /* Length of each line, in pixels. Computed
65 * from width and/or aspect. */
66 int msgHeight; /* Total number of pixels in vertical direction
67 * needed to display message. */
68 Tk_Justify justify; /* Justification for text. */
69
70 /*
71 * Miscellaneous information:
72 */
73
74 Cursor cursor; /* Current cursor for window, or None. */
75 int flags; /* Various flags; see below for
76 * definitions. */
77 } Message;
78
79 /*
80 * Flag bits for messages:
81 *
82 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler
83 * has already been queued to redraw
84 * this window.
85 * CLEAR_NEEDED; Need to clear the window when redrawing.
86 */
87
88 #define REDRAW_PENDING 1
89 #define CLEAR_NEEDED 2
90
91 /*
92 * Information used for argv parsing.
93 */
94
95
96 static Tk_ConfigSpec configSpecs[] = {
97 {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
98 DEF_MESSAGE_ANCHOR, Tk_Offset(Message, anchor), 0},
99 {TK_CONFIG_INT, "-aspect", "aspect", "Aspect",
100 DEF_MESSAGE_ASPECT, Tk_Offset(Message, aspect), 0},
101 {TK_CONFIG_BORDER, "-background", "background", "Background",
102 DEF_MESSAGE_BG_COLOR, Tk_Offset(Message, border),
103 TK_CONFIG_COLOR_ONLY},
104 {TK_CONFIG_BORDER, "-background", "background", "Background",
105 DEF_MESSAGE_BG_MONO, Tk_Offset(Message, border),
106 TK_CONFIG_MONO_ONLY},
107 {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
108 (char *) NULL, 0, 0},
109 {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
110 (char *) NULL, 0, 0},
111 {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
112 DEF_MESSAGE_BORDER_WIDTH, Tk_Offset(Message, borderWidth), 0},
113 {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
114 DEF_MESSAGE_CURSOR, Tk_Offset(Message, cursor), TK_CONFIG_NULL_OK},
115 {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
116 (char *) NULL, 0, 0},
117 {TK_CONFIG_FONT, "-font", "font", "Font",
118 DEF_MESSAGE_FONT, Tk_Offset(Message, fontPtr), 0},
119 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
120 DEF_MESSAGE_FG, Tk_Offset(Message, fgColorPtr), 0},
121 {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
122 DEF_MESSAGE_JUSTIFY, Tk_Offset(Message, justify), 0},
123 {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
124 DEF_MESSAGE_PADX, Tk_Offset(Message, padX), 0},
125 {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
126 DEF_MESSAGE_PADY, Tk_Offset(Message, padY), 0},
127 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
128 DEF_MESSAGE_RELIEF, Tk_Offset(Message, relief), 0},
129 {TK_CONFIG_STRING, "-text", "text", "Text",
130 DEF_MESSAGE_TEXT, Tk_Offset(Message, string), 0},
131 {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable",
132 DEF_MESSAGE_TEXT_VARIABLE, Tk_Offset(Message, textVarName),
133 TK_CONFIG_NULL_OK},
134 {TK_CONFIG_PIXELS, "-width", "width", "Width",
135 DEF_MESSAGE_WIDTH, Tk_Offset(Message, width), 0},
136 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
137 (char *) NULL, 0, 0}
138 };
139
140 /*
141 * Forward declarations for procedures defined later in this file:
142 */
143
144 static void MessageEventProc _ANSI_ARGS_((ClientData clientData,
145 XEvent *eventPtr));
146 static char * MessageTextVarProc _ANSI_ARGS_((ClientData clientData,
147 Tcl_Interp *interp, char *name1, char *name2,
148 int flags));
149 static int MessageWidgetCmd _ANSI_ARGS_((ClientData clientData,
150 Tcl_Interp *interp, int argc, char **argv));
151 static void ComputeMessageGeometry _ANSI_ARGS_((Message *msgPtr));
152 static int ConfigureMessage _ANSI_ARGS_((Tcl_Interp *interp,
153 Message *msgPtr, int argc, char **argv,
154 int flags));
155 static void DestroyMessage _ANSI_ARGS_((ClientData clientData));
156 static void DisplayMessage _ANSI_ARGS_((ClientData clientData));
157 \f
158 /*
159 *--------------------------------------------------------------
160 *
161 * Tk_MessageCmd --
162 *
163 * This procedure is invoked to process the "message" Tcl
164 * command. See the user documentation for details on what
165 * it does.
166 *
167 * Results:
168 * A standard Tcl result.
169 *
170 * Side effects:
171 * See the user documentation.
172 *
173 *--------------------------------------------------------------
174 */
175
176 int
177 Tk_MessageCmd (
178 ClientData clientData, /* Main window associated with
179 * interpreter. */
180 Tcl_Interp *interp, /* Current interpreter. */
181 int argc, /* Number of arguments. */
182 char **argv /* Argument strings. */
183 )
184 {
185 register Message *msgPtr;
186 Tk_Window new;
187 Tk_Window tkwin = (Tk_Window) clientData;
188
189 if (argc < 2) {
190 Tcl_AppendResult(interp, "wrong # args: should be \"",
191 argv[0], " pathName ?options?\"", (char *) NULL);
192 return TCL_ERROR;
193 }
194
195 new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
196 if (new == NULL) {
197 return TCL_ERROR;
198 }
199
200 msgPtr = (Message *) ckalloc(sizeof(Message));
201 msgPtr->tkwin = new;
202 msgPtr->interp = interp;
203 msgPtr->string = NULL;
204 msgPtr->textVarName = NULL;
205 msgPtr->border = NULL;
206 msgPtr->borderWidth = 0;
207 msgPtr->relief = TK_RELIEF_FLAT;
208 msgPtr->fontPtr = NULL;
209 msgPtr->fgColorPtr = NULL;
210 msgPtr->textGC = NULL;
211 msgPtr->padX = 0;
212 msgPtr->padY = 0;
213 msgPtr->width = 0;
214 msgPtr->aspect = 150;
215 msgPtr->justify = TK_JUSTIFY_LEFT;
216 msgPtr->cursor = None;
217 msgPtr->flags = 0;
218
219 Tk_SetClass(msgPtr->tkwin, "Message");
220 Tk_CreateEventHandler(msgPtr->tkwin, ExposureMask|StructureNotifyMask,
221 MessageEventProc, (ClientData) msgPtr);
222 Tcl_CreateCommand(interp, Tk_PathName(msgPtr->tkwin), MessageWidgetCmd,
223 (ClientData) msgPtr, (void (*)(int *)) NULL);
224 if (ConfigureMessage(interp, msgPtr, argc-2, argv+2, 0) != TCL_OK) {
225 goto error;
226 }
227
228 interp->result = Tk_PathName(msgPtr->tkwin);
229 return TCL_OK;
230
231 error:
232 Tk_DestroyWindow(msgPtr->tkwin);
233 return TCL_ERROR;
234 }
235 \f
236 /*
237 *--------------------------------------------------------------
238 *
239 * MessageWidgetCmd --
240 *
241 * This procedure is invoked to process the Tcl command
242 * that corresponds to a widget managed by this module.
243 * See the user documentation for details on what it does.
244 *
245 * Results:
246 * A standard Tcl result.
247 *
248 * Side effects:
249 * See the user documentation.
250 *
251 *--------------------------------------------------------------
252 */
253
254 static int
255 MessageWidgetCmd (
256 ClientData clientData, /* Information about message widget. */
257 Tcl_Interp *interp, /* Current interpreter. */
258 int argc, /* Number of arguments. */
259 char **argv /* Argument strings. */
260 )
261 {
262 register Message *msgPtr = (Message *) clientData;
263 int length;
264 char c;
265
266 if (argc < 2) {
267 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
268 " option ?arg arg ...?\"", (char *) NULL);
269 return TCL_ERROR;
270 }
271 c = argv[1][0];
272 length = strlen(argv[1]);
273 if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
274 if (argc == 2) {
275 return Tk_ConfigureInfo(interp, msgPtr->tkwin, configSpecs,
276 (char *) msgPtr, (char *) NULL, 0);
277 } else if (argc == 3) {
278 return Tk_ConfigureInfo(interp, msgPtr->tkwin, configSpecs,
279 (char *) msgPtr, argv[2], 0);
280 } else {
281 return ConfigureMessage(interp, msgPtr, argc-2, argv+2,
282 TK_CONFIG_ARGV_ONLY);
283 }
284 } else {
285 Tcl_AppendResult(interp, "bad option \"", argv[1],
286 "\": must be configure", (char *) NULL);
287 return TCL_ERROR;
288 }
289 }
290 \f
291 /*
292 *----------------------------------------------------------------------
293 *
294 * DestroyMessage --
295 *
296 * This procedure is invoked by Tk_EventuallyFree or Tk_Release
297 * to clean up the internal structure of a message at a safe time
298 * (when no-one is using it anymore).
299 *
300 * Results:
301 * None.
302 *
303 * Side effects:
304 * Everything associated with the message is freed up.
305 *
306 *----------------------------------------------------------------------
307 */
308
309 static void
310 DestroyMessage (
311 ClientData clientData /* Info about message widget. */
312 )
313 {
314 register Message *msgPtr = (Message *) clientData;
315
316 if (msgPtr->string != NULL) {
317 ckfree(msgPtr->string);
318 }
319 if (msgPtr->textVarName != NULL) {
320 Tcl_UntraceVar(msgPtr->interp, msgPtr->textVarName,
321 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
322 MessageTextVarProc, (ClientData) msgPtr);
323 ckfree(msgPtr->textVarName);
324 }
325 if (msgPtr->border != NULL) {
326 Tk_Free3DBorder(msgPtr->border);
327 }
328 if (msgPtr->fontPtr != NULL) {
329 Tk_FreeFontStruct(msgPtr->fontPtr);
330 }
331 if (msgPtr->fgColorPtr != NULL) {
332 Tk_FreeColor(msgPtr->fgColorPtr);
333 }
334 if (msgPtr->textGC != None) {
335 Tk_FreeGC(msgPtr->textGC);
336 }
337 if (msgPtr->cursor != None) {
338 Tk_FreeCursor(msgPtr->cursor);
339 }
340 ckfree((char *) msgPtr);
341 }
342 \f
343 /*
344 *----------------------------------------------------------------------
345 *
346 * ConfigureMessage --
347 *
348 * This procedure is called to process an argv/argc list, plus
349 * the Tk option database, in order to configure (or
350 * reconfigure) a message widget.
351 *
352 * Results:
353 * The return value is a standard Tcl result. If TCL_ERROR is
354 * returned, then interp->result contains an error message.
355 *
356 * Side effects:
357 * Configuration information, such as text string, colors, font,
358 * etc. get set for msgPtr; old resources get freed, if there
359 * were any.
360 *
361 *----------------------------------------------------------------------
362 */
363
364 static int
365 ConfigureMessage (
366 Tcl_Interp *interp, /* Used for error reporting. */
367 register Message *msgPtr, /* Information about widget; may or may
368 * not already have values for some fields. */
369 int argc, /* Number of valid entries in argv. */
370 char **argv, /* Arguments. */
371 int flags /* Flags to pass to Tk_ConfigureWidget. */
372 )
373 {
374 XGCValues gcValues;
375 GC newGC;
376
377 /*
378 * Eliminate any existing trace on a variable monitored by the message.
379 */
380
381 if (msgPtr->textVarName != NULL) {
382 Tcl_UntraceVar(interp, msgPtr->textVarName,
383 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
384 MessageTextVarProc, (ClientData) msgPtr);
385 }
386
387 if (Tk_ConfigureWidget(interp, msgPtr->tkwin, configSpecs,
388 argc, argv, (char *) msgPtr, flags) != TCL_OK) {
389 return TCL_ERROR;
390 }
391
392 /*
393 * If the message is to display the value of a variable, then set up
394 * a trace on the variable's value, create the variable if it doesn't
395 * exist, and fetch its current value.
396 */
397
398 if (msgPtr->textVarName != NULL) {
399 char *value;
400
401 value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY);
402 if (value == NULL) {
403 Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string,
404 TCL_GLOBAL_ONLY);
405 } else {
406 if (msgPtr->string != NULL) {
407 ckfree(msgPtr->string);
408 }
409 msgPtr->string = ckalloc((unsigned) (strlen(value) + 1));
410 strcpy(msgPtr->string, value);
411 }
412 Tcl_TraceVar(interp, msgPtr->textVarName,
413 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
414 MessageTextVarProc, (ClientData) msgPtr);
415 }
416
417 /*
418 * A few other options need special processing, such as setting
419 * the background from a 3-D border or handling special defaults
420 * that couldn't be specified to Tk_ConfigureWidget.
421 */
422
423 msgPtr->numChars = strlen(msgPtr->string);
424
425 Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border);
426
427 gcValues.font = msgPtr->fontPtr->fid;
428 gcValues.foreground = msgPtr->fgColorPtr->pixel;
429 newGC = Tk_GetGC(msgPtr->tkwin, GCForeground|GCFont,
430 &gcValues);
431 if (msgPtr->textGC != None) {
432 Tk_FreeGC(msgPtr->textGC);
433 }
434 msgPtr->textGC = newGC;
435
436 if (msgPtr->padX == -1) {
437 msgPtr->padX = msgPtr->fontPtr->ascent/2;
438 }
439
440 if (msgPtr->padY == -1) {
441 msgPtr->padY = msgPtr->fontPtr->ascent/4;
442 }
443
444 if (msgPtr->justify == TK_JUSTIFY_FILL) {
445 interp->result = "can't use \"fill\" justify style in messages";
446 return TCL_ERROR;
447 }
448
449 /*
450 * Recompute the desired geometry for the window, and arrange for
451 * the window to be redisplayed.
452 */
453
454 ComputeMessageGeometry(msgPtr);
455 if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin)
456 && !(msgPtr->flags & REDRAW_PENDING)) {
457 Tk_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
458 msgPtr->flags |= REDRAW_PENDING|CLEAR_NEEDED;
459 }
460
461 return TCL_OK;
462 }
463 \f
464 /*
465 *--------------------------------------------------------------
466 *
467 * ComputeMessageGeometry --
468 *
469 * Compute the desired geometry for a message window,
470 * taking into account the desired aspect ratio for the
471 * window.
472 *
473 * Results:
474 * None.
475 *
476 * Side effects:
477 * Tk_GeometryRequest is called to inform the geometry
478 * manager of the desired geometry for this window.
479 *
480 *--------------------------------------------------------------
481 */
482
483 static void
484 ComputeMessageGeometry (
485 register Message *msgPtr /* Information about window. */
486 )
487 {
488 char *p;
489 int width, inc, height, numLines;
490 int thisWidth, maxWidth;
491 int aspect, lowerBound, upperBound;
492
493 /*
494 * Compute acceptable bounds for the final aspect ratio.
495 */
496 aspect = msgPtr->aspect/10;
497 if (aspect < 5) {
498 aspect = 5;
499 }
500 lowerBound = msgPtr->aspect - aspect;
501 upperBound = msgPtr->aspect + aspect;
502
503 /*
504 * Do the computation in multiple passes: start off with
505 * a very wide window, and compute its height. Then change
506 * the width and try again. Reduce the size of the change
507 * and iterate until dimensions are found that approximate
508 * the desired aspect ratio. Or, if the user gave an explicit
509 * width then just use that.
510 */
511
512 if (msgPtr->width > 0) {
513 width = msgPtr->width;
514 inc = 0;
515 } else {
516 width = WidthOfScreen(Tk_Screen(msgPtr->tkwin))/2;
517 inc = width/2;
518 }
519 for ( ; ; inc /= 2) {
520 maxWidth = 0;
521 for (numLines = 1, p = msgPtr->string; ; numLines++) {
522 if (*p == '\n') {
523 p++;
524 continue;
525 }
526 p += TkMeasureChars(msgPtr->fontPtr, p,
527 msgPtr->numChars - (p - msgPtr->string), 0, width,
528 TK_WHOLE_WORDS|TK_AT_LEAST_ONE, &thisWidth);
529 if (thisWidth > maxWidth) {
530 maxWidth = thisWidth;
531 }
532 if (*p == 0) {
533 break;
534 }
535
536 /*
537 * Skip spaces and tabs at the beginning of a line, unless
538 * they follow a user-requested newline.
539 */
540
541 while (isspace(*p)) {
542 if (*p == '\n') {
543 p++;
544 break;
545 }
546 p++;
547 }
548 }
549
550 height = numLines * (msgPtr->fontPtr->ascent
551 + msgPtr->fontPtr->descent) + 2*msgPtr->borderWidth
552 + 2*msgPtr->padY;
553 if (inc <= 2) {
554 break;
555 }
556 aspect = (100*(maxWidth + 2*msgPtr->borderWidth
557 + 2*msgPtr->padX))/height;
558 if (aspect < lowerBound) {
559 width += inc;
560 } else if (aspect > upperBound) {
561 width -= inc;
562 } else {
563 break;
564 }
565 }
566 msgPtr->lineLength = maxWidth;
567 msgPtr->msgHeight = numLines * (msgPtr->fontPtr->ascent
568 + msgPtr->fontPtr->descent);
569 Tk_GeometryRequest(msgPtr->tkwin,
570 maxWidth + 2*msgPtr->borderWidth + 2*msgPtr->padX, height);
571 Tk_SetInternalBorder(msgPtr->tkwin, msgPtr->borderWidth);
572 }
573 \f
574 /*
575 *--------------------------------------------------------------
576 *
577 * DisplayMessage --
578 *
579 * This procedure redraws the contents of a message window.
580 *
581 * Results:
582 * None.
583 *
584 * Side effects:
585 * Information appears on the screen.
586 *
587 *--------------------------------------------------------------
588 */
589
590 static void
591 DisplayMessage (
592 ClientData clientData /* Information about window. */
593 )
594 {
595 register Message *msgPtr = (Message *) clientData;
596 register Tk_Window tkwin = msgPtr->tkwin;
597 char *p;
598 int x, y, lineLength, numChars, charsLeft;
599
600 msgPtr->flags &= ~REDRAW_PENDING;
601 if ((msgPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
602 return;
603 }
604 if (msgPtr->flags & CLEAR_NEEDED) {
605 XClearWindow(Tk_Display(tkwin), Tk_WindowId(tkwin));
606 msgPtr->flags &= ~CLEAR_NEEDED;
607 }
608
609 /*
610 * Compute starting y-location for message based on message size
611 * and anchor option.
612 */
613
614 switch (msgPtr->anchor) {
615 case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE:
616 y = msgPtr->borderWidth + msgPtr->padY;
617 break;
618 case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E:
619 y = (Tk_Height(tkwin) - msgPtr->msgHeight)/2;
620 break;
621 default:
622 y = Tk_Height(tkwin) - msgPtr->borderWidth - msgPtr->padY
623 - msgPtr->msgHeight;
624 break;
625 }
626 y += msgPtr->fontPtr->ascent;
627
628 /*
629 * Work through the string to display one line at a time.
630 * Display each line in three steps. First compute the
631 * line's width, then figure out where to display the
632 * line to justify it properly, then display the line.
633 */
634
635 for (p = msgPtr->string, charsLeft = msgPtr->numChars; *p != 0;
636 y += msgPtr->fontPtr->ascent + msgPtr->fontPtr->descent) {
637 if (*p == '\n') {
638 p++;
639 charsLeft--;
640 continue;
641 }
642 numChars = TkMeasureChars(msgPtr->fontPtr, p, charsLeft, 0,
643 msgPtr->lineLength, TK_WHOLE_WORDS|TK_AT_LEAST_ONE,
644 &lineLength);
645 switch (msgPtr->anchor) {
646 case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW:
647 x = msgPtr->borderWidth + msgPtr->padX;
648 break;
649 case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S:
650 x = (Tk_Width(tkwin) - msgPtr->lineLength)/2;
651 break;
652 default:
653 x = Tk_Width(tkwin) - msgPtr->borderWidth - msgPtr->padX
654 - msgPtr->lineLength;
655 break;
656 }
657 if (msgPtr->justify == TK_JUSTIFY_CENTER) {
658 x += (msgPtr->lineLength - lineLength)/2;
659 } else if (msgPtr->justify == TK_JUSTIFY_RIGHT) {
660 x += msgPtr->lineLength - lineLength;
661 }
662 TkDisplayChars(Tk_Display(tkwin), Tk_WindowId(tkwin),
663 msgPtr->textGC, msgPtr->fontPtr, p, numChars, x, y, 0);
664 p += numChars;
665 charsLeft -= numChars;
666
667 /*
668 * Skip blanks at the beginning of a line, unless they follow
669 * a user-requested newline.
670 */
671
672 while (isspace(*p)) {
673 charsLeft--;
674 if (*p == '\n') {
675 p++;
676 break;
677 }
678 p++;
679 }
680 }
681
682 if (msgPtr->relief != TK_RELIEF_FLAT) {
683 Tk_Draw3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin),
684 msgPtr->border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin),
685 msgPtr->borderWidth, msgPtr->relief);
686 }
687 }
688 \f
689 /*
690 *--------------------------------------------------------------
691 *
692 * MessageEventProc --
693 *
694 * This procedure is invoked by the Tk dispatcher for various
695 * events on messages.
696 *
697 * Results:
698 * None.
699 *
700 * Side effects:
701 * When the window gets deleted, internal structures get
702 * cleaned up. When it gets exposed, it is redisplayed.
703 *
704 *--------------------------------------------------------------
705 */
706
707 static void
708 MessageEventProc (
709 ClientData clientData, /* Information about window. */
710 XEvent *eventPtr /* Information about event. */
711 )
712 {
713 Message *msgPtr = (Message *) clientData;
714
715 if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
716 if ((msgPtr->tkwin != NULL) && !(msgPtr->flags & REDRAW_PENDING)) {
717 Tk_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
718 msgPtr->flags |= REDRAW_PENDING;
719 }
720 } else if (eventPtr->type == DestroyNotify) {
721 Tcl_DeleteCommand(msgPtr->interp, Tk_PathName(msgPtr->tkwin));
722 msgPtr->tkwin = NULL;
723 if (msgPtr->flags & REDRAW_PENDING) {
724 Tk_CancelIdleCall(DisplayMessage, (ClientData) msgPtr);
725 }
726 Tk_EventuallyFree((ClientData) msgPtr, DestroyMessage);
727 }
728 }
729 \f
730 /*
731 *--------------------------------------------------------------
732 *
733 * MessageTextVarProc --
734 *
735 * This procedure is invoked when someone changes the variable
736 * whose contents are to be displayed in a message.
737 *
738 * Results:
739 * NULL is always returned.
740 *
741 * Side effects:
742 * The text displayed in the message will change to match the
743 * variable.
744 *
745 *--------------------------------------------------------------
746 */
747
748 /* ARGSUSED */
749 static char *
750 MessageTextVarProc (
751 ClientData clientData, /* Information about message. */
752 Tcl_Interp *interp, /* Interpreter containing variable. */
753 char *name1, /* Name of variable. */
754 char *name2, /* Second part of variable name. */
755 int flags /* Information about what happened. */
756 )
757 {
758 register Message *msgPtr = (Message *) clientData;
759 char *value;
760
761 /*
762 * If the variable is unset, then immediately recreate it unless
763 * the whole interpreter is going away.
764 */
765
766 if (flags & TCL_TRACE_UNSETS) {
767 if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
768 Tcl_SetVar2(interp, name1, name2, msgPtr->string,
769 flags & TCL_GLOBAL_ONLY);
770 Tcl_TraceVar2(interp, name1, name2,
771 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
772 MessageTextVarProc, clientData);
773 }
774 return (char *) NULL;
775 }
776
777 value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
778 if (value == NULL) {
779 value = "";
780 }
781 if (msgPtr->string != NULL) {
782 ckfree(msgPtr->string);
783 }
784 msgPtr->numChars = strlen(value);
785 msgPtr->string = ckalloc((unsigned) (msgPtr->numChars + 1));
786 strcpy(msgPtr->string, value);
787 ComputeMessageGeometry(msgPtr);
788
789 msgPtr->flags |= CLEAR_NEEDED;
790 if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin)
791 && !(msgPtr->flags & REDRAW_PENDING)) {
792 Tk_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
793 msgPtr->flags |= REDRAW_PENDING;
794 }
795 return (char *) NULL;
796 }
Impressum, Datenschutz