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