]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * tkWindow.c -- | |
3 | * | |
4 | * This file provides basic window-manipulation procedures, | |
5 | * which are equivalent to procedures in Xlib (and even | |
6 | * invoke them) but also maintain the local Tk_Window | |
7 | * structure. | |
8 | * | |
9 | * Copyright 1989-1992 Regents of the University of California. | |
10 | * Permission to use, copy, modify, and distribute this | |
11 | * software and its documentation for any purpose and without | |
12 | * fee is hereby granted, provided that the above copyright | |
13 | * notice appear in all copies. The University of California | |
14 | * makes no representations about the suitability of this | |
15 | * software for any purpose. It is provided "as is" without | |
16 | * express or implied warranty. | |
17 | */ | |
18 | ||
19 | #ifndef lint | |
20 | static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkWindow.c,v 1.92 92/08/21 11:42:44 ouster Exp $ SPRITE (Berkeley)"; | |
21 | #endif | |
22 | ||
23 | #include "tkconfig.h" | |
24 | #include "tkint.h" | |
25 | ||
26 | /* | |
27 | * Global absolute file name: | |
28 | */ | |
29 | char *TK_Library = TK_LIBRARY; | |
30 | ||
31 | /* | |
32 | * Count of open displays. | |
33 | */ | |
34 | int tk_Displays; | |
35 | ||
36 | /* | |
37 | * Count of number of main windows currently open in this process. | |
38 | */ | |
39 | ||
40 | int tk_NumMainWindows; | |
41 | ||
42 | /* | |
43 | * Added by dhopkins for OLPC Micropolis gtk.Socket integration. | |
44 | */ | |
45 | ||
46 | Window tk_RootWindow = 0; | |
47 | ||
48 | /* | |
49 | * List of all displays currently in use. | |
50 | */ | |
51 | ||
52 | TkDisplay *tkDisplayList = NULL; | |
53 | ||
54 | /* | |
55 | * Have statics in this module been initialized? | |
56 | */ | |
57 | ||
58 | static initialized = 0; | |
59 | ||
60 | /* | |
61 | * Context information used to map from X window id's to | |
62 | * TkWindow structures (during event handling, for example): | |
63 | */ | |
64 | ||
65 | XContext tkWindowContext; | |
66 | ||
67 | /* | |
68 | * The variables below hold several uid's that are used in many places | |
69 | * in the toolkit. | |
70 | */ | |
71 | ||
72 | Tk_Uid tkDisabledUid = NULL; | |
73 | Tk_Uid tkActiveUid = NULL; | |
74 | Tk_Uid tkNormalUid = NULL; | |
75 | ||
76 | /* | |
77 | * Default values for "changes" and "atts" fields of TkWindows. Note | |
78 | * that Tk always requests all events for all windows, except StructureNotify | |
79 | * events on internal windows: these events are generated internally. | |
80 | */ | |
81 | ||
82 | static XWindowChanges defChanges = { | |
83 | 0, 0, 1, 1, 0, 0, Above | |
84 | }; | |
85 | #define ALL_EVENTS_MASK \ | |
86 | KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \ | |
87 | EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \ | |
88 | VisibilityChangeMask|SubstructureNotifyMask| \ | |
89 | FocusChangeMask|PropertyChangeMask|ColormapChangeMask | |
90 | static XSetWindowAttributes defAtts= { | |
91 | None, /* background_pixmap */ | |
92 | 0, /* background_pixel */ | |
93 | CopyFromParent, /* border_pixmap */ | |
94 | 0, /* border_pixel */ | |
95 | ForgetGravity, /* bit_gravity */ | |
96 | NorthWestGravity, /* win_gravity */ | |
97 | NotUseful, /* backing_store */ | |
98 | ~0, /* backing_planes */ | |
99 | 0, /* backing_pixel */ | |
100 | False, /* save_under */ | |
101 | ALL_EVENTS_MASK, /* event_mask */ | |
102 | 0, /* do_not_propagate_mask */ | |
103 | False, /* override_redirect */ | |
104 | CopyFromParent, /* colormap */ | |
105 | None /* cursor */ | |
106 | }; | |
107 | ||
108 | /* | |
109 | * The following structure defines all of the commands supported by | |
110 | * Tk, and the C procedures that execute them. | |
111 | */ | |
112 | ||
113 | typedef struct { | |
114 | char *name; /* Name of command. */ | |
115 | int (*cmdProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, | |
116 | int argc, char **argv)); | |
117 | /* Command procedure. */ | |
118 | } TkCmd; | |
119 | ||
120 | TkCmd commands[] = { | |
121 | /* | |
122 | * Commands that are part of the intrinsics: | |
123 | */ | |
124 | ||
125 | {"after", Tk_AfterCmd}, | |
126 | {"bind", Tk_BindCmd}, | |
127 | {"destroy", Tk_DestroyCmd}, | |
128 | {"focus", Tk_FocusCmd}, | |
129 | {"grab", Tk_GrabCmd}, | |
130 | {"option", Tk_OptionCmd}, | |
131 | {"pack", Tk_PackCmd}, | |
132 | {"place", Tk_PlaceCmd}, | |
133 | {"selection", Tk_SelectionCmd}, | |
134 | {"tkwait", Tk_TkwaitCmd}, | |
135 | {"update", Tk_UpdateCmd}, | |
136 | {"winfo", Tk_WinfoCmd}, | |
137 | {"wm", Tk_WmCmd}, | |
138 | {"accept", Tcp_AcceptCmd}, | |
139 | {"shutdown", Tcp_ShutdownCmd}, | |
140 | {"connect", Tcp_ConnectCmd}, | |
141 | {"filehandler", Tcp_FileHandlerCmd}, | |
142 | ||
143 | /* | |
144 | * Widget-creation commands. | |
145 | */ | |
146 | {"button", Tk_ButtonCmd}, | |
147 | {"canvas", Tk_CanvasCmd}, | |
148 | {"checkbutton", Tk_ButtonCmd}, | |
149 | {"entry", Tk_EntryCmd}, | |
150 | {"frame", Tk_FrameCmd}, | |
151 | {"label", Tk_ButtonCmd}, | |
152 | {"listbox", Tk_ListboxCmd}, | |
153 | {"menu", Tk_MenuCmd}, | |
154 | {"menubutton", Tk_MenubuttonCmd}, | |
155 | {"message", Tk_MessageCmd}, | |
156 | {"radiobutton", Tk_ButtonCmd}, | |
157 | {"scale", Tk_ScaleCmd}, | |
158 | {"scrollbar", Tk_ScrollbarCmd}, | |
159 | {"text", Tk_TextCmd}, | |
160 | {"toplevel", Tk_FrameCmd}, | |
161 | {(char *) NULL, (int (*)()) NULL} | |
162 | }; | |
163 | ||
164 | /* | |
165 | * Forward declarations to procedures defined later in this file: | |
166 | */ | |
167 | ||
168 | static Tk_Window CreateTopLevelWindow _ANSI_ARGS_((Tcl_Interp *interp, | |
169 | Tk_Window parent, char *name, char *screenName)); | |
170 | static void DoConfigureNotify _ANSI_ARGS_((TkWindow *winPtr)); | |
171 | static TkDisplay * GetScreen _ANSI_ARGS_((Tcl_Interp *interp, | |
172 | char *screenName, int *screenPtr)); | |
173 | static int NameWindow _ANSI_ARGS_((Tcl_Interp *interp, | |
174 | TkWindow *winPtr, TkWindow *parentPtr, | |
175 | char *name)); | |
176 | static TkWindow * NewWindow _ANSI_ARGS_((TkDisplay *dispPtr, | |
177 | int screenNum)); | |
178 | \f | |
179 | /* | |
180 | *---------------------------------------------------------------------- | |
181 | * | |
182 | * CreateTopLevelWindow -- | |
183 | * | |
184 | * Make a new window that will be at top-level (its parent will | |
185 | * be the root window of a screen). | |
186 | * | |
187 | * Results: | |
188 | * The return value is a token for the new window, or NULL if | |
189 | * an error prevented the new window from being created. If | |
190 | * NULL is returned, an error message will be left in | |
191 | * interp->result. | |
192 | * | |
193 | * Side effects: | |
194 | * A new window structure is allocated locally. An X | |
195 | * window is NOT initially created, but will be created | |
196 | * the first time the window is mapped. | |
197 | * | |
198 | *---------------------------------------------------------------------- | |
199 | */ | |
200 | ||
201 | static Tk_Window | |
202 | CreateTopLevelWindow(interp, parent, name, screenName) | |
203 | Tcl_Interp *interp; /* Interpreter to use for error reporting. */ | |
204 | Tk_Window parent; /* Token for logical parent of new window | |
205 | * (used for naming, options, etc.). May | |
206 | * be NULL. */ | |
207 | char *name; /* Name for new window; if parent is | |
208 | * non-NULL, must be unique among parent's | |
209 | * children. */ | |
210 | char *screenName; /* Name of screen on which to create | |
211 | * window. NULL means use DISPLAY environment | |
212 | * variable to determine. Empty string means | |
213 | * use parent's screen, or DISPLAY if no | |
214 | * parent. */ | |
215 | { | |
216 | register TkWindow *winPtr; | |
217 | register TkDisplay *dispPtr; | |
218 | int screenId; | |
219 | ||
220 | if (!initialized) { | |
221 | initialized = 1; | |
222 | tkWindowContext = XUniqueContext(); | |
223 | tkActiveUid = Tk_GetUid("active"); | |
224 | tkDisabledUid = Tk_GetUid("disabled"); | |
225 | tkNormalUid = Tk_GetUid("normal"); | |
226 | } | |
227 | ||
228 | if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) { | |
229 | dispPtr = ((TkWindow *) parent)->dispPtr; | |
230 | screenId = Tk_ScreenNumber(parent); | |
231 | } else { | |
232 | dispPtr = GetScreen(interp, screenName, &screenId); | |
233 | if (dispPtr == NULL) { | |
234 | return (Tk_Window) NULL; | |
235 | } | |
236 | } | |
237 | ||
238 | winPtr = NewWindow(dispPtr, screenId); | |
239 | ||
240 | /* | |
241 | * Internal windows don't normally ask for StructureNotify events, | |
242 | * since we can generate them internally. However, for top-level | |
243 | * windows we need to as for the events because the window could | |
244 | * be manipulated externally. | |
245 | */ | |
246 | ||
247 | winPtr->atts.event_mask |= StructureNotifyMask; | |
248 | ||
249 | /* | |
250 | * (Need to set the TK_TOP_LEVEL flag immediately here; otherwise | |
251 | * Tk_DestroyWindow will core dump if it is called before the flag | |
252 | * has been set.) | |
253 | */ | |
254 | ||
255 | winPtr->flags |= TK_TOP_LEVEL; | |
256 | if (parent != NULL) { | |
257 | if (NameWindow(interp, winPtr, (TkWindow *) parent, name) != TCL_OK) { | |
258 | Tk_DestroyWindow((Tk_Window) winPtr); | |
259 | return (Tk_Window) NULL; | |
260 | } | |
261 | } | |
262 | TkWmNewWindow(winPtr); | |
263 | return (Tk_Window) winPtr; | |
264 | } | |
265 | \f | |
266 | /* | |
267 | *---------------------------------------------------------------------- | |
268 | * | |
269 | * GetScreen -- | |
270 | * | |
271 | * Given a string name for a display-plus-screen, find the | |
272 | * TkDisplay structure for the display and return the screen | |
273 | * number too. | |
274 | * | |
275 | * Results: | |
276 | * The return value is a pointer to information about the display, | |
277 | * or NULL if the display couldn't be opened. In this case, an | |
278 | * error message is left in interp->result. The location at | |
279 | * *screenPtr is overwritten with the screen number parsed from | |
280 | * screenName. | |
281 | * | |
282 | * Side effects: | |
283 | * A new connection is opened to the display if there is no | |
284 | * connection already. A new TkDisplay data structure is also | |
285 | * setup, if necessary. | |
286 | * | |
287 | *---------------------------------------------------------------------- | |
288 | */ | |
289 | ||
290 | static TkDisplay * | |
291 | GetScreen(interp, screenName, screenPtr) | |
292 | Tcl_Interp *interp; /* Place to leave error message. */ | |
293 | char *screenName; /* Name for screen. NULL or empty means | |
294 | * use DISPLAY envariable. */ | |
295 | int *screenPtr; /* Where to store screen number. */ | |
296 | { | |
297 | register TkDisplay *dispPtr; | |
298 | char *p; | |
299 | int length, screenId; | |
300 | ||
301 | /* | |
302 | * Separate the screen number from the rest of the display | |
303 | * name. ScreenName is assumed to have the syntax | |
304 | * <display>.<screen> with the dot and the screen being | |
305 | * optional. | |
306 | */ | |
307 | ||
308 | if ((screenName == NULL) || (screenName[0] == '\0')) { | |
309 | screenName = getenv("DISPLAY"); | |
310 | if (screenName == NULL) { | |
311 | interp->result = | |
312 | "no display name and no $DISPLAY environment variable"; | |
313 | return (TkDisplay *) NULL; | |
314 | } | |
315 | } | |
316 | length = strlen(screenName); | |
317 | screenId = 0; | |
318 | p = screenName+length-1; | |
319 | while (isdigit(*p) && (p != screenName)) { | |
320 | p--; | |
321 | } | |
322 | if ((*p == '.') && (p[1] != '\0')) { | |
323 | length = p - screenName; | |
324 | screenId = strtoul(p+1, (char **) NULL, 10); | |
325 | } | |
326 | ||
327 | /* | |
328 | * See if we already have a connection to this display. If not, | |
329 | * then open a new connection. | |
330 | */ | |
331 | ||
332 | for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) { | |
333 | if (dispPtr == NULL) { | |
334 | Display *display = NULL; | |
335 | ||
336 | display = XOpenDisplay(screenName); | |
337 | ||
338 | if (display == NULL) { | |
339 | Tcl_AppendResult(interp, "couldn't connect to display \"", | |
340 | screenName, "\"", (char *) NULL); | |
341 | return (TkDisplay *) NULL; | |
342 | } | |
343 | if (getenv("XSYNCHRONIZE") != NULL) { | |
344 | XSynchronize(display, 1); | |
345 | } | |
346 | tk_Displays++; | |
347 | dispPtr = (TkDisplay *) ckalloc(sizeof(TkDisplay)); | |
348 | dispPtr->display = display; | |
349 | dispPtr->nextPtr = tkDisplayList; | |
350 | dispPtr->name = (char *) ckalloc((unsigned) (length+1)); | |
351 | dispPtr->lastEventTime = CurrentTime; | |
352 | strncpy(dispPtr->name, screenName, length); | |
353 | dispPtr->mouseMainPtr = NULL; | |
354 | dispPtr->name[length] = '\0'; | |
355 | dispPtr->symsPerCode = 0; | |
356 | dispPtr->errorPtr = NULL; | |
357 | dispPtr->deleteCount = 0; | |
358 | dispPtr->commWindow = NULL; | |
359 | dispPtr->selectionOwner = NULL; | |
360 | dispPtr->selectionSerial = 0; | |
361 | dispPtr->multipleAtom = None; | |
362 | dispPtr->atomInit = 0; | |
363 | dispPtr->modeModMask = 0; | |
364 | dispPtr->metaModMask = 0; | |
365 | dispPtr->altModMask = 0; | |
366 | dispPtr->cursorFont = None; | |
367 | dispPtr->grabWinPtr = NULL; | |
368 | dispPtr->ungrabWinPtr = NULL; | |
369 | dispPtr->buttonWinPtr = NULL; | |
370 | dispPtr->pointerWinPtr = NULL; | |
371 | dispPtr->serverWinPtr = NULL; | |
372 | dispPtr->grabFlags = 0; | |
373 | dispPtr->focusPtr = NULL; | |
374 | tkDisplayList = dispPtr; | |
375 | Tk_CreateFileHandler(ConnectionNumber(display), | |
376 | TK_READABLE, (void (*)()) NULL, | |
377 | (ClientData) display); | |
378 | break; | |
379 | } | |
380 | if ((strncmp(dispPtr->name, screenName, length) == 0) | |
381 | && (dispPtr->name[length] == '\0')) { | |
382 | break; | |
383 | } | |
384 | } | |
385 | if (screenId >= ScreenCount(dispPtr->display)) { | |
386 | sprintf(interp->result, "bad screen number \"%d\"", screenId); | |
387 | return (TkDisplay *) NULL; | |
388 | } | |
389 | *screenPtr = screenId; | |
390 | return dispPtr; | |
391 | } | |
392 | \f | |
393 | /* | |
394 | *-------------------------------------------------------------- | |
395 | * | |
396 | * NewWindow -- | |
397 | * | |
398 | * This procedure creates and initializes a TkWindow structure. | |
399 | * | |
400 | * Results: | |
401 | * The return value is a pointer to the new window. | |
402 | * | |
403 | * Side effects: | |
404 | * A new window structure is allocated and all its fields are | |
405 | * initialized. | |
406 | * | |
407 | *-------------------------------------------------------------- | |
408 | */ | |
409 | ||
410 | static TkWindow * | |
411 | NewWindow(dispPtr, screenNum) | |
412 | TkDisplay *dispPtr; /* Display associated with new window. */ | |
413 | int screenNum; /* Index of screen for new window. */ | |
414 | { | |
415 | register TkWindow *winPtr; | |
416 | ||
417 | winPtr = (TkWindow *) ckalloc(sizeof(TkWindow)); | |
418 | winPtr->display = dispPtr->display; | |
419 | winPtr->dispPtr = dispPtr; | |
420 | winPtr->screenNum = screenNum; | |
421 | winPtr->window = None; | |
422 | winPtr->childList = NULL; | |
423 | winPtr->parentPtr = NULL; | |
424 | winPtr->nextPtr = NULL; | |
425 | winPtr->mainPtr = NULL; | |
426 | winPtr->pathName = NULL; | |
427 | winPtr->nameUid = NULL; | |
428 | winPtr->classUid = NULL; | |
429 | winPtr->changes = defChanges; | |
430 | winPtr->dirtyChanges = CWX|CWY|CWWidth|CWHeight|CWBorderWidth; | |
431 | winPtr->atts = defAtts; | |
432 | winPtr->dirtyAtts = CWEventMask; | |
433 | winPtr->flags = 0; | |
434 | winPtr->handlerList = NULL; | |
435 | winPtr->focusProc = NULL; | |
436 | winPtr->focusData = NULL; | |
437 | winPtr->optionLevel = -1; | |
438 | winPtr->selHandlerList = NULL; | |
439 | winPtr->selClearProc = NULL; | |
440 | winPtr->selClearData = NULL; | |
441 | winPtr->geomProc = NULL; | |
442 | winPtr->geomData = NULL; | |
443 | winPtr->reqWidth = winPtr->reqHeight = 0; | |
444 | winPtr->internalBorderWidth = 0; | |
445 | winPtr->wmInfoPtr = NULL; | |
446 | return winPtr; | |
447 | } | |
448 | \f | |
449 | /* | |
450 | *---------------------------------------------------------------------- | |
451 | * | |
452 | * NameWindow -- | |
453 | * | |
454 | * This procedure is invoked to give a window a name and insert | |
455 | * the window into the hierarchy associated with a particular | |
456 | * application. | |
457 | * | |
458 | * Results: | |
459 | * A standard Tcl return value. | |
460 | * | |
461 | * Side effects: | |
462 | * See above. | |
463 | * | |
464 | *---------------------------------------------------------------------- | |
465 | */ | |
466 | ||
467 | static int | |
468 | NameWindow(interp, winPtr, parentPtr, name) | |
469 | Tcl_Interp *interp; /* Interpreter to use for error reporting. */ | |
470 | register TkWindow *winPtr; /* Window that is to be named and inserted. */ | |
471 | TkWindow *parentPtr; /* Pointer to logical parent for winPtr | |
472 | * (used for naming, options, etc.). */ | |
473 | char *name; /* Name for winPtr; must be unique among | |
474 | * parentPtr's children. */ | |
475 | { | |
476 | #define FIXED_SIZE 200 | |
477 | char staticSpace[FIXED_SIZE]; | |
478 | char *pathName; | |
479 | int new; | |
480 | Tcl_HashEntry *hPtr; | |
481 | int length1, length2; | |
482 | ||
483 | /* | |
484 | * Setup all the stuff except name right away, then do the name stuff | |
485 | * last. This is so that if the name stuff fails, everything else | |
486 | * will be properly initialized (needed to destroy the window cleanly | |
487 | * after the naming failure). | |
488 | */ | |
489 | winPtr->parentPtr = parentPtr; | |
490 | winPtr->nextPtr = parentPtr->childList; | |
491 | parentPtr->childList = winPtr; | |
492 | winPtr->mainPtr = parentPtr->mainPtr; | |
493 | winPtr->nameUid = Tk_GetUid(name); | |
494 | ||
495 | /* | |
496 | * To permit names of arbitrary length, must be prepared to malloc | |
497 | * a buffer to hold the new path name. To run fast in the common | |
498 | * case where names are short, use a fixed-size buffer on the | |
499 | * stack. | |
500 | */ | |
501 | ||
502 | length1 = strlen(parentPtr->pathName); | |
503 | length2 = strlen(name); | |
504 | if ((length1+length2+2) <= FIXED_SIZE) { | |
505 | pathName = staticSpace; | |
506 | } else { | |
507 | pathName = (char *) ckalloc((unsigned) (length1+length2+2)); | |
508 | } | |
509 | if (length1 == 1) { | |
510 | pathName[0] = '.'; | |
511 | strcpy(pathName+1, name); | |
512 | } else { | |
513 | strcpy(pathName, parentPtr->pathName); | |
514 | pathName[length1] = '.'; | |
515 | strcpy(pathName+length1+1, name); | |
516 | } | |
517 | hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new); | |
518 | if (pathName != staticSpace) { | |
519 | ckfree(pathName); | |
520 | } | |
521 | if (!new) { | |
522 | Tcl_AppendResult(interp, "window name \"", name, | |
523 | "\" already exists in parent", (char *) NULL); | |
524 | return TCL_ERROR; | |
525 | } | |
526 | Tcl_SetHashValue(hPtr, winPtr); | |
527 | winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr); | |
528 | return TCL_OK; | |
529 | } | |
530 | \f | |
531 | /* | |
532 | *---------------------------------------------------------------------- | |
533 | * | |
534 | * Tk_CreateMainWindow -- | |
535 | * | |
536 | * Make a new main window. A main window is a special kind of | |
537 | * top-level window used as the outermost window in an | |
538 | * application. | |
539 | * | |
540 | * Results: | |
541 | * The return value is a token for the new window, or NULL if | |
542 | * an error prevented the new window from being created. If | |
543 | * NULL is returned, an error message will be left in | |
544 | * interp->result. | |
545 | * | |
546 | * Side effects: | |
547 | * A new window structure is allocated locally; "interp" is | |
548 | * associated with the window and registered for "send" commands | |
549 | * under "baseName". BaseName may be extended with an instance | |
550 | * number in the form "#2" if necessary to make it globally | |
551 | * unique. Tk-related commands are bound into interp. An X | |
552 | * window is NOT initially created, but will be created the | |
553 | * first time the window is mapped. | |
554 | * | |
555 | *---------------------------------------------------------------------- | |
556 | */ | |
557 | ||
558 | Tk_Window | |
559 | Tk_CreateMainWindow(interp, screenName, baseName) | |
560 | Tcl_Interp *interp; /* Interpreter to use for error reporting. */ | |
561 | char *screenName; /* Name of screen on which to create | |
562 | * window. Empty or NULL string means | |
563 | * use DISPLAY environment variable. */ | |
564 | char *baseName; /* Base name for application; usually of the | |
565 | * form "prog instance". */ | |
566 | { | |
567 | Tk_Window tkwin; | |
568 | int result, dummy; | |
569 | Tcl_HashEntry *hPtr; | |
570 | register TkMainInfo *mainPtr; | |
571 | register TkWindow *winPtr; | |
572 | register TkCmd *cmdPtr; | |
573 | ||
574 | /* | |
575 | * Create the basic TkWindow structure. | |
576 | */ | |
577 | ||
578 | tkwin = CreateTopLevelWindow(interp, (Tk_Window) NULL, baseName, | |
579 | screenName); | |
580 | if (tkwin == NULL) { | |
581 | return NULL; | |
582 | } | |
583 | ||
584 | /* | |
585 | * Create the TkMainInfo structure for this application, and set | |
586 | * up name-related information for the new window. | |
587 | */ | |
588 | ||
589 | winPtr = (TkWindow *) tkwin; | |
590 | mainPtr = (TkMainInfo *) ckalloc(sizeof(TkMainInfo)); | |
591 | mainPtr->winPtr = winPtr; | |
592 | mainPtr->interp = interp; | |
593 | Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS); | |
594 | mainPtr->bindingTable = Tk_CreateBindingTable(interp); | |
595 | /* XXX: FOCUS */ | |
596 | /* mainPtr->focusPtr = NULL; */ | |
597 | mainPtr->optionRootPtr = NULL; | |
598 | winPtr->mainPtr = mainPtr; | |
599 | hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy); | |
600 | Tcl_SetHashValue(hPtr, winPtr); | |
601 | winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr); | |
602 | ||
603 | /* | |
604 | * Register the interpreter for "send" purposes. If baseName isn't | |
605 | * already unique, find a unique suffix to add to it to make it | |
606 | * unique. Change the window's name to contain the suffix. | |
607 | */ | |
608 | ||
609 | result = Tk_RegisterInterp(interp, baseName, tkwin); | |
610 | if (result == TCL_OK) { | |
611 | winPtr->nameUid = Tk_GetUid(baseName); | |
612 | } else { | |
613 | char newName[110]; | |
614 | int i; | |
615 | ||
616 | for (i = 2; ; i++) { | |
617 | sprintf(newName, "%.100s #%d", baseName, i); | |
618 | Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); | |
619 | result = Tk_RegisterInterp(interp, newName, tkwin); | |
620 | if (result == TCL_OK) { | |
621 | break; | |
622 | } | |
623 | if (i >= 100) { | |
624 | Tcl_SetResult(interp, | |
625 | "couldn't generate unique name to register application", | |
626 | TCL_STATIC); | |
627 | Tk_DestroyWindow(tkwin); | |
628 | } | |
629 | } | |
630 | winPtr->nameUid = Tk_GetUid(newName); | |
631 | } | |
632 | ||
633 | /* | |
634 | * Bind in Tk's commands. | |
635 | */ | |
636 | ||
637 | for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) { | |
638 | Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc, | |
639 | (ClientData) tkwin, (void (*)()) NULL); | |
640 | } | |
641 | ||
642 | /* | |
643 | * Set variables for the intepreter. | |
644 | */ | |
645 | ||
646 | Tcl_SetVar(interp, "tk_library", TK_Library, TCL_GLOBAL_ONLY); | |
647 | Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY); | |
648 | Tcl_SetVar(interp, "tkVersion", TK_VERSION, TCL_GLOBAL_ONLY); | |
649 | ||
650 | tk_NumMainWindows++; | |
651 | return tkwin; | |
652 | } | |
653 | \f | |
654 | /* | |
655 | *-------------------------------------------------------------- | |
656 | * | |
657 | * Tk_CreateWindow -- | |
658 | * | |
659 | * Create a new internal or top-level window as a child of an | |
660 | * existing window. | |
661 | * | |
662 | * Results: | |
663 | * The return value is a token for the new window. This | |
664 | * is not the same as X's token for the window. If an error | |
665 | * occurred in creating the window (e.g. no such display or | |
666 | * screen), then an error message is left in interp->result and | |
667 | * NULL is returned. | |
668 | * | |
669 | * Side effects: | |
670 | * A new window structure is allocated locally. An X | |
671 | * window is not initially created, but will be created | |
672 | * the first time the window is mapped. | |
673 | * | |
674 | *-------------------------------------------------------------- | |
675 | */ | |
676 | ||
677 | Tk_Window | |
678 | Tk_CreateWindow(interp, parent, name, screenName) | |
679 | Tcl_Interp *interp; /* Interpreter to use for error reporting. | |
680 | * Interp->result is assumed to be | |
681 | * initialized by the caller. */ | |
682 | Tk_Window parent; /* Token for parent of new window. */ | |
683 | char *name; /* Name for new window. Must be unique | |
684 | * among parent's children. */ | |
685 | char *screenName; /* If NULL, new window will be internal on | |
686 | * same screen as its parent. If non-NULL, | |
687 | * gives name of screen on which to create | |
688 | * new window; window will be a top-level | |
689 | * window. */ | |
690 | { | |
691 | TkWindow *parentPtr = (TkWindow *) parent; | |
692 | TkWindow *winPtr; | |
693 | ||
694 | if (screenName == NULL) { | |
695 | winPtr = NewWindow(parentPtr->dispPtr, parentPtr->screenNum); | |
696 | if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) { | |
697 | Tk_DestroyWindow((Tk_Window) winPtr); | |
698 | return NULL; | |
699 | } else { | |
700 | return (Tk_Window) winPtr; | |
701 | } | |
702 | } else { | |
703 | /* | |
704 | * This is a fix for dvx XOpenDisplay... display name conformalization | |
705 | * bugs... | |
706 | */ | |
707 | char dsp[256]; | |
708 | int len; | |
709 | ||
710 | strcpy(dsp, screenName); | |
711 | len = strlen(dsp); | |
712 | if (len && (dsp[len -1] == '.')) | |
713 | dsp[len -1] = '\0'; | |
714 | ||
715 | return CreateTopLevelWindow(interp, parent, name, dsp); | |
716 | } | |
717 | } | |
718 | \f | |
719 | /* | |
720 | *---------------------------------------------------------------------- | |
721 | * | |
722 | * Tk_CreateWindowFromPath -- | |
723 | * | |
724 | * This procedure is similar to Tk_CreateInternalWindow except | |
725 | * that it uses a path name to create the window, rather than | |
726 | * a parent and a child name. | |
727 | * | |
728 | * Results: | |
729 | * The return value is a token for the new window. This | |
730 | * is not the same as X's token for the window. If an error | |
731 | * occurred in creating the window (e.g. no such display or | |
732 | * screen), then an error message is left in interp->result and | |
733 | * NULL is returned. | |
734 | * | |
735 | * Side effects: | |
736 | * A new window structure is allocated locally. An X | |
737 | * window is not initially created, but will be created | |
738 | * the first time the window is mapped. | |
739 | * | |
740 | *---------------------------------------------------------------------- | |
741 | */ | |
742 | ||
743 | Tk_Window | |
744 | Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName) | |
745 | Tcl_Interp *interp; /* Interpreter to use for error reporting. | |
746 | * Interp->result is assumed to be | |
747 | * initialized by the caller. */ | |
748 | Tk_Window tkwin; /* Token for any window in application | |
749 | * that is to contain new window. */ | |
750 | char *pathName; /* Path name for new window within the | |
751 | * application of tkwin. The parent of | |
752 | * this window must already exist, but | |
753 | * the window itself must not exist. */ | |
754 | char *screenName; /* If NULL, new window will be on same | |
755 | * screen as its parent. If non-NULL, | |
756 | * gives name of screen on which to create | |
757 | * new window; window will be a top-level | |
758 | * window. */ | |
759 | { | |
760 | #define FIXED_SPACE 5 | |
761 | char fixedSpace[FIXED_SPACE+1]; | |
762 | char *p; | |
763 | Tk_Window parent; | |
764 | int numChars; | |
765 | ||
766 | /* | |
767 | * Strip the parent's name out of pathName (it's everything up | |
768 | * to the last dot). There are two tricky parts: (a) must | |
769 | * copy the parent's name somewhere else to avoid modifying | |
770 | * the pathName string (for large names, space for the copy | |
771 | * will have to be malloc'ed); (b) must special-case the | |
772 | * situation where the parent is ".". | |
773 | */ | |
774 | ||
775 | p = strrchr(pathName, '.'); | |
776 | if (p == NULL) { | |
777 | Tcl_AppendResult(interp, "bad window path name \"", pathName, | |
778 | "\"", (char *) NULL); | |
779 | return NULL; | |
780 | } | |
781 | numChars = p-pathName; | |
782 | if (numChars > FIXED_SPACE) { | |
783 | p = (char *) ckalloc((unsigned) (numChars+1)); | |
784 | } else { | |
785 | p = fixedSpace; | |
786 | } | |
787 | if (numChars == 0) { | |
788 | *p = '.'; | |
789 | p[1] = '\0'; | |
790 | } else { | |
791 | strncpy(p, pathName, numChars); | |
792 | p[numChars] = '\0'; | |
793 | } | |
794 | ||
795 | /* | |
796 | * Find the parent window. | |
797 | */ | |
798 | ||
799 | parent = Tk_NameToWindow(interp, p, tkwin); | |
800 | if (p != fixedSpace) { | |
801 | ckfree(p); | |
802 | } | |
803 | if (parent == NULL) { | |
804 | return NULL; | |
805 | } | |
806 | ||
807 | /* | |
808 | * Create the window. | |
809 | */ | |
810 | ||
811 | if (screenName == NULL) { | |
812 | TkWindow *parentPtr = (TkWindow *) parent; | |
813 | TkWindow *winPtr; | |
814 | ||
815 | winPtr = NewWindow(parentPtr->dispPtr, parentPtr->screenNum); | |
816 | if (NameWindow(interp, winPtr, parentPtr, pathName+numChars+1) | |
817 | != TCL_OK) { | |
818 | Tk_DestroyWindow((Tk_Window) winPtr); | |
819 | return NULL; | |
820 | } else { | |
821 | return (Tk_Window) winPtr; | |
822 | } | |
823 | } else { | |
824 | return CreateTopLevelWindow(interp, parent, pathName+numChars+1, | |
825 | screenName); | |
826 | } | |
827 | } | |
828 | \f | |
829 | /* | |
830 | *-------------------------------------------------------------- | |
831 | * | |
832 | * Tk_DestroyWindow -- | |
833 | * | |
834 | * Destroy an existing window. After this call, the caller | |
835 | * should never again use the token. | |
836 | * | |
837 | * Results: | |
838 | * None. | |
839 | * | |
840 | * Side effects: | |
841 | * The window is deleted, along with all of its children. | |
842 | * Relevant callback procedures are invoked. | |
843 | * | |
844 | *-------------------------------------------------------------- | |
845 | */ | |
846 | ||
847 | void | |
848 | Tk_DestroyWindow(tkwin) | |
849 | Tk_Window tkwin; /* Window to destroy. */ | |
850 | { | |
851 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
852 | XEvent event; | |
853 | ||
854 | /* | |
855 | * Recursively destroy children. The TK_RECURSIVE_DESTROY | |
856 | * flags means that the child's window needn't be explicitly | |
857 | * destroyed (the destroy of the parent already did it), nor | |
858 | * does it need to be removed from its parent's child list, | |
859 | * since the parent is being destroyed too. | |
860 | */ | |
861 | ||
862 | while (winPtr->childList != NULL) { | |
863 | winPtr->childList->flags |= TK_RECURSIVE_DESTROY; | |
864 | Tk_DestroyWindow((Tk_Window) winPtr->childList); | |
865 | } | |
866 | ||
867 | /* | |
868 | * Generate a DestroyNotify event. In order for the DestroyNotify | |
869 | * event to be processed correctly, need to make sure the window | |
870 | * exists. This is a bit of a kludge, and may be unnecessarily | |
871 | * expensive, but without it no event handlers will get called for | |
872 | * windows that don't exist yet. | |
873 | */ | |
874 | ||
875 | if (winPtr->window == None) { | |
876 | Tk_MakeWindowExist(tkwin); | |
877 | } | |
878 | winPtr->flags |= TK_ALREADY_DEAD; | |
879 | event.type = DestroyNotify; | |
880 | event.xdestroywindow.serial = | |
881 | LastKnownRequestProcessed(winPtr->display); | |
882 | event.xdestroywindow.send_event = False; | |
883 | event.xdestroywindow.display = winPtr->display; | |
884 | event.xdestroywindow.event = winPtr->window; | |
885 | event.xdestroywindow.window = winPtr->window; | |
886 | Tk_HandleEvent(&event); | |
887 | ||
888 | /* | |
889 | * Cleanup the data structures associated with this window. | |
890 | * No need to destroy windows during recursive destroys, since | |
891 | * that will happen automatically when the parent window is | |
892 | * destroyed (not true for top-level windows: must destroy | |
893 | * them explicitly). | |
894 | */ | |
895 | ||
896 | if (winPtr->window != None) { | |
897 | if (!(winPtr->flags & TK_RECURSIVE_DESTROY) | |
898 | || (winPtr->flags & TK_TOP_LEVEL)) { | |
899 | XDestroyWindow(winPtr->display, winPtr->window); | |
900 | } | |
901 | XDeleteContext(winPtr->display, winPtr->window, tkWindowContext); | |
902 | winPtr->window = None; | |
903 | } | |
904 | if (winPtr->parentPtr != NULL) { | |
905 | if (winPtr->parentPtr->childList == winPtr) { | |
906 | winPtr->parentPtr->childList = winPtr->nextPtr; | |
907 | } else { | |
908 | register TkWindow *winPtr2; | |
909 | ||
910 | for (winPtr2 = winPtr->parentPtr->childList; ; | |
911 | winPtr2 = winPtr2->nextPtr) { | |
912 | if (winPtr2 == NULL) { | |
913 | panic("Tk_DestroyWindow couldn't find child in parent (deleted twice?)"); | |
914 | break; | |
915 | } | |
916 | if (winPtr2->nextPtr == winPtr) { | |
917 | winPtr2->nextPtr = winPtr->nextPtr; | |
918 | break; | |
919 | } | |
920 | } | |
921 | } | |
922 | } | |
923 | TkEventDeadWindow(winPtr); | |
924 | TkOptionDeadWindow(winPtr); | |
925 | TkSelDeadWindow(winPtr); | |
926 | if (winPtr->flags & TK_TOP_LEVEL) { | |
927 | TkWmDeadWindow(winPtr); | |
928 | } | |
929 | TkGrabDeadWindow(winPtr); | |
930 | if (winPtr->mainPtr != NULL) { | |
931 | Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable, | |
932 | (ClientData) winPtr->pathName); | |
933 | if (winPtr->pathName != NULL) { | |
934 | Tcl_DeleteHashEntry(Tcl_FindHashEntry(&winPtr->mainPtr->nameTable, | |
935 | winPtr->pathName)); | |
936 | } | |
937 | if (winPtr->mainPtr->winPtr == winPtr) { | |
938 | register TkCmd *cmdPtr; | |
939 | ||
940 | /* | |
941 | * Deleting a main window. Delete the TkMainInfo structure too | |
942 | * and replace all of Tk's commands with dummy commands that | |
943 | * return errors. Also delete the "send" command to unregister | |
944 | * the interpreter. | |
945 | */ | |
946 | ||
947 | for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) { | |
948 | Tcl_CreateCommand(winPtr->mainPtr->interp, cmdPtr->name, | |
949 | TkDeadAppCmd, (ClientData) NULL, (void (*)()) NULL); | |
950 | } | |
951 | Tcl_CreateCommand(winPtr->mainPtr->interp, "send", | |
952 | TkDeadAppCmd, (ClientData) NULL, (void (*)()) NULL); | |
953 | Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable); | |
954 | Tk_DeleteBindingTable(winPtr->mainPtr->bindingTable); | |
955 | ckfree((char *) winPtr->mainPtr); | |
956 | tk_NumMainWindows--; | |
957 | } | |
958 | } | |
959 | ckfree((char *) winPtr); | |
960 | } | |
961 | \f | |
962 | /* | |
963 | *-------------------------------------------------------------- | |
964 | * | |
965 | * Tk_MapWindow -- | |
966 | * | |
967 | * Map a window within its parent. This may require the | |
968 | * window and/or its parents to actually be created. | |
969 | * | |
970 | * Results: | |
971 | * None. | |
972 | * | |
973 | * Side effects: | |
974 | * The given window will be mapped. Windows may also | |
975 | * be created. | |
976 | * | |
977 | *-------------------------------------------------------------- | |
978 | */ | |
979 | ||
980 | void | |
981 | Tk_MapWindow(tkwin) | |
982 | Tk_Window tkwin; /* Token for window to map. */ | |
983 | { | |
984 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
985 | ||
986 | if (winPtr->flags & TK_MAPPED) { | |
987 | return; | |
988 | } | |
989 | if (winPtr->window == None) { | |
990 | Tk_MakeWindowExist(tkwin); | |
991 | } | |
992 | if (winPtr->flags & TK_TOP_LEVEL) { | |
993 | if (!TkWmMapWindow(winPtr)) { | |
994 | return; | |
995 | } | |
996 | } else { | |
997 | /* | |
998 | * Don't set the mapped flag for top-level windows: TkWmMapWindow | |
999 | * does it if appropriate (e.g. if the window is going to be non- | |
1000 | * iconic). | |
1001 | */ | |
1002 | ||
1003 | winPtr->flags |= TK_MAPPED; | |
1004 | } | |
1005 | XMapWindow(winPtr->display, winPtr->window); | |
1006 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1007 | XEvent event; | |
1008 | ||
1009 | event.type = MapNotify; | |
1010 | event.xmap.serial = LastKnownRequestProcessed(winPtr->display); | |
1011 | event.xmap.send_event = False; | |
1012 | event.xmap.display = winPtr->display; | |
1013 | event.xmap.event = winPtr->window; | |
1014 | event.xmap.window = winPtr->window; | |
1015 | event.xmap.override_redirect = winPtr->atts.override_redirect; | |
1016 | Tk_HandleEvent(&event); | |
1017 | } | |
1018 | } | |
1019 | \f | |
1020 | /* | |
1021 | *-------------------------------------------------------------- | |
1022 | * | |
1023 | * Tk_MakeWindowExist -- | |
1024 | * | |
1025 | * Ensure that a particular window actually exists. This | |
1026 | * procedure shouldn't normally need to be invoked from | |
1027 | * outside the Tk package, but may be needed if someone | |
1028 | * wants to manipulate a window before mapping it. | |
1029 | * | |
1030 | * Results: | |
1031 | * None. | |
1032 | * | |
1033 | * Side effects: | |
1034 | * When the procedure returns, the X window associated with | |
1035 | * tkwin is guaranteed to exist. This may require the | |
1036 | * window's ancestors to be created also. | |
1037 | * | |
1038 | *-------------------------------------------------------------- | |
1039 | */ | |
1040 | ||
1041 | void | |
1042 | Tk_MakeWindowExist(tkwin) | |
1043 | Tk_Window tkwin; /* Token for window. */ | |
1044 | { | |
1045 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1046 | Window parent; | |
1047 | ||
1048 | if (winPtr->window != None) { | |
1049 | return; | |
1050 | } | |
1051 | ||
1052 | if (winPtr->flags & TK_TOP_LEVEL) { | |
1053 | /* | |
1054 | * workaround by dhopkins for OLPC Micropolis gtk.Socket integration. | |
1055 | */ | |
1056 | ||
1057 | if (tk_RootWindow) { | |
1058 | parent = | |
1059 | tk_RootWindow; | |
1060 | } else { | |
1061 | parent = | |
1062 | XRootWindow(winPtr->display, winPtr->screenNum); | |
1063 | } | |
1064 | ||
1065 | } else { | |
1066 | if (winPtr->parentPtr->window == None) { | |
1067 | Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr); | |
1068 | } | |
1069 | parent = winPtr->parentPtr->window; | |
1070 | } | |
1071 | ||
1072 | /* workaround to support non-default colormaps */ | |
1073 | #if 0 | |
1074 | winPtr->window = XCreateWindow(winPtr->display, parent, | |
1075 | winPtr->changes.x, winPtr->changes.y, | |
1076 | winPtr->changes.width, winPtr->changes.height, | |
1077 | winPtr->changes.border_width, CopyFromParent, | |
1078 | InputOutput, CopyFromParent, winPtr->dirtyAtts, | |
1079 | &winPtr->atts); | |
1080 | #else | |
1081 | { Screen *scr = ScreenOfDisplay(winPtr->display, winPtr->screenNum); | |
1082 | ||
1083 | winPtr->dirtyAtts |= CWColormap | CWBorderPixmap; | |
1084 | winPtr->atts.colormap = Tk_DefaultColormap(scr); | |
1085 | winPtr->atts.border_pixmap = Tk_DefaultPixmap(scr); | |
1086 | ||
1087 | winPtr->window = XCreateWindow(winPtr->display, parent, | |
1088 | winPtr->changes.x, winPtr->changes.y, | |
1089 | winPtr->changes.width, winPtr->changes.height, | |
1090 | winPtr->changes.border_width, | |
1091 | Tk_DefaultDepth(scr), | |
1092 | InputOutput, | |
1093 | Tk_DefaultVisual(scr), | |
1094 | winPtr->dirtyAtts, &winPtr->atts); | |
1095 | } | |
1096 | #endif | |
1097 | ||
1098 | XSaveContext(winPtr->display, winPtr->window, tkWindowContext, | |
1099 | (void *) winPtr); | |
1100 | winPtr->dirtyAtts = 0; | |
1101 | winPtr->dirtyChanges &= ~(CWX|CWY|CWWidth|CWHeight|CWBorderWidth); | |
1102 | if (winPtr->dirtyChanges != 0) { | |
1103 | XConfigureWindow(winPtr->display, winPtr->window, | |
1104 | winPtr->dirtyChanges, &winPtr->changes); | |
1105 | winPtr->dirtyChanges = 0; | |
1106 | } | |
1107 | ||
1108 | /* | |
1109 | * Issue a ConfigureNotify event if there were deferred configuration | |
1110 | * changes. | |
1111 | */ | |
1112 | ||
1113 | if (winPtr->flags & TK_NEED_CONFIG_NOTIFY) { | |
1114 | winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY; | |
1115 | DoConfigureNotify(winPtr); | |
1116 | } | |
1117 | } | |
1118 | \f | |
1119 | /* | |
1120 | *-------------------------------------------------------------- | |
1121 | * | |
1122 | * Tk_UnmapWindow, etc. -- | |
1123 | * | |
1124 | * There are several procedures under here, each of which | |
1125 | * mirrors an existing X procedure. In addition to performing | |
1126 | * the functions of the corresponding procedure, each | |
1127 | * procedure also updates the local window structure and | |
1128 | * synthesizes an X event (if the window's structure is being | |
1129 | * managed internally). | |
1130 | * | |
1131 | * Results: | |
1132 | * See the manual entries. | |
1133 | * | |
1134 | * Side effects: | |
1135 | * See the manual entries. | |
1136 | * | |
1137 | *-------------------------------------------------------------- | |
1138 | */ | |
1139 | ||
1140 | void | |
1141 | Tk_UnmapWindow(tkwin) | |
1142 | Tk_Window tkwin; /* Token for window to unmap. */ | |
1143 | { | |
1144 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1145 | ||
1146 | if (!(winPtr->flags & TK_MAPPED)) { | |
1147 | return; | |
1148 | } | |
1149 | winPtr->flags &= ~TK_MAPPED; | |
1150 | XUnmapWindow(winPtr->display, winPtr->window); | |
1151 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1152 | XEvent event; | |
1153 | ||
1154 | event.type = UnmapNotify; | |
1155 | event.xunmap.serial = LastKnownRequestProcessed(winPtr->display); | |
1156 | event.xunmap.send_event = False; | |
1157 | event.xunmap.display = winPtr->display; | |
1158 | event.xunmap.event = winPtr->window; | |
1159 | event.xunmap.window = winPtr->window; | |
1160 | event.xunmap.from_configure = False; | |
1161 | Tk_HandleEvent(&event); | |
1162 | } | |
1163 | } | |
1164 | ||
1165 | void | |
1166 | Tk_ConfigureWindow(tkwin, valueMask, valuePtr) | |
1167 | Tk_Window tkwin; /* Window to re-configure. */ | |
1168 | unsigned int valueMask; /* Mask indicating which parts of | |
1169 | * *valuePtr are to be used. */ | |
1170 | XWindowChanges *valuePtr; /* New values. */ | |
1171 | { | |
1172 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1173 | ||
1174 | if ((winPtr->window == None) || !(winPtr->flags & TK_TOP_LEVEL)) { | |
1175 | if (valueMask & CWX) { | |
1176 | winPtr->changes.x = valuePtr->x; | |
1177 | } | |
1178 | if (valueMask & CWY) { | |
1179 | winPtr->changes.y = valuePtr->y; | |
1180 | } | |
1181 | if (valueMask & CWWidth) { | |
1182 | winPtr->changes.width = valuePtr->width; | |
1183 | } | |
1184 | if (valueMask & CWHeight) { | |
1185 | winPtr->changes.height = valuePtr->height; | |
1186 | } | |
1187 | if (valueMask & CWBorderWidth) { | |
1188 | winPtr->changes.border_width = valuePtr->border_width; | |
1189 | } | |
1190 | if (valueMask & CWSibling) { | |
1191 | winPtr->changes.sibling = valuePtr->sibling; | |
1192 | } | |
1193 | if (valueMask & CWStackMode) { | |
1194 | winPtr->changes.stack_mode = valuePtr->stack_mode; | |
1195 | } | |
1196 | } | |
1197 | ||
1198 | if (winPtr->window != None) { | |
1199 | XConfigureWindow(winPtr->display, winPtr->window, | |
1200 | valueMask, valuePtr); | |
1201 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1202 | DoConfigureNotify(winPtr); | |
1203 | } | |
1204 | } else { | |
1205 | winPtr->dirtyChanges |= valueMask; | |
1206 | winPtr->flags |= TK_NEED_CONFIG_NOTIFY; | |
1207 | } | |
1208 | } | |
1209 | ||
1210 | void | |
1211 | Tk_MoveWindow(tkwin, x, y) | |
1212 | Tk_Window tkwin; /* Window to move. */ | |
1213 | int x, y; /* New location for window (within | |
1214 | * parent). */ | |
1215 | { | |
1216 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1217 | ||
1218 | if (winPtr->window != None) { | |
1219 | XMoveWindow(winPtr->display, winPtr->window, x, y); | |
1220 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1221 | winPtr->changes.x = x; | |
1222 | winPtr->changes.y = y; | |
1223 | DoConfigureNotify(winPtr); | |
1224 | } | |
1225 | } else { | |
1226 | winPtr->changes.x = x; | |
1227 | winPtr->changes.y = y; | |
1228 | winPtr->dirtyChanges |= CWX|CWY; | |
1229 | winPtr->flags |= TK_NEED_CONFIG_NOTIFY; | |
1230 | } | |
1231 | } | |
1232 | ||
1233 | void | |
1234 | Tk_ResizeWindow(tkwin, width, height) | |
1235 | Tk_Window tkwin; /* Window to resize. */ | |
1236 | unsigned int width, height; /* New dimensions for window. */ | |
1237 | { | |
1238 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1239 | ||
1240 | if (winPtr->window != None) { | |
1241 | XResizeWindow(winPtr->display, winPtr->window, width, height); | |
1242 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1243 | winPtr->changes.width = width; | |
1244 | winPtr->changes.height = height; | |
1245 | DoConfigureNotify(winPtr); | |
1246 | } | |
1247 | } else { | |
1248 | winPtr->changes.width = width; | |
1249 | winPtr->changes.height = height; | |
1250 | winPtr->dirtyChanges |= CWWidth|CWHeight; | |
1251 | winPtr->flags |= TK_NEED_CONFIG_NOTIFY; | |
1252 | } | |
1253 | } | |
1254 | ||
1255 | void | |
1256 | Tk_MoveResizeWindow(tkwin, x, y, width, height) | |
1257 | Tk_Window tkwin; /* Window to move and resize. */ | |
1258 | int x, y; /* New location for window (within | |
1259 | * parent). */ | |
1260 | unsigned int width, height; /* New dimensions for window. */ | |
1261 | { | |
1262 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1263 | ||
1264 | if (winPtr->window != None) { | |
1265 | XMoveResizeWindow(winPtr->display, winPtr->window, | |
1266 | x, y, width, height); | |
1267 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1268 | winPtr->changes.x = x; | |
1269 | winPtr->changes.y = y; | |
1270 | winPtr->changes.width = width; | |
1271 | winPtr->changes.height = height; | |
1272 | DoConfigureNotify(winPtr); | |
1273 | } | |
1274 | } else { | |
1275 | winPtr->changes.x = x; | |
1276 | winPtr->changes.y = y; | |
1277 | winPtr->changes.width = width; | |
1278 | winPtr->changes.height = height; | |
1279 | winPtr->dirtyChanges |= CWX|CWY|CWWidth|CWHeight; | |
1280 | winPtr->flags |= TK_NEED_CONFIG_NOTIFY; | |
1281 | } | |
1282 | } | |
1283 | ||
1284 | void | |
1285 | Tk_SetWindowBorderWidth(tkwin, width) | |
1286 | Tk_Window tkwin; /* Window to modify. */ | |
1287 | int width; /* New border width for window. */ | |
1288 | { | |
1289 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1290 | ||
1291 | winPtr->changes.border_width = width; | |
1292 | if (winPtr->window != None) { | |
1293 | XSetWindowBorderWidth(winPtr->display, winPtr->window, width); | |
1294 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1295 | DoConfigureNotify(winPtr); | |
1296 | } | |
1297 | } else { | |
1298 | winPtr->dirtyChanges |= CWBorderWidth; | |
1299 | winPtr->flags |= TK_NEED_CONFIG_NOTIFY; | |
1300 | } | |
1301 | } | |
1302 | ||
1303 | void | |
1304 | Tk_ChangeWindowAttributes(tkwin, valueMask, attsPtr) | |
1305 | Tk_Window tkwin; /* Window to manipulate. */ | |
1306 | unsigned long valueMask; /* OR'ed combination of bits, | |
1307 | * indicating which fields of | |
1308 | * *attsPtr are to be used. */ | |
1309 | register XSetWindowAttributes *attsPtr; | |
1310 | /* New values for some attributes. */ | |
1311 | { | |
1312 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1313 | ||
1314 | if (valueMask & CWBackPixmap) { | |
1315 | winPtr->atts.background_pixmap = attsPtr->background_pixmap; | |
1316 | } | |
1317 | if (valueMask & CWBackPixel) { | |
1318 | winPtr->atts.background_pixel = attsPtr->background_pixel; | |
1319 | } | |
1320 | if (valueMask & CWBorderPixmap) { | |
1321 | winPtr->atts.border_pixmap = attsPtr->border_pixmap; | |
1322 | } | |
1323 | if (valueMask & CWBorderPixel) { | |
1324 | winPtr->atts.border_pixel = attsPtr->border_pixel; | |
1325 | } | |
1326 | if (valueMask & CWBitGravity) { | |
1327 | winPtr->atts.bit_gravity = attsPtr->bit_gravity; | |
1328 | } | |
1329 | if (valueMask & CWWinGravity) { | |
1330 | winPtr->atts.win_gravity = attsPtr->win_gravity; | |
1331 | } | |
1332 | if (valueMask & CWBackingStore) { | |
1333 | winPtr->atts.backing_store = attsPtr->backing_store; | |
1334 | } | |
1335 | if (valueMask & CWBackingPlanes) { | |
1336 | winPtr->atts.backing_planes = attsPtr->backing_planes; | |
1337 | } | |
1338 | if (valueMask & CWBackingPixel) { | |
1339 | winPtr->atts.backing_pixel = attsPtr->backing_pixel; | |
1340 | } | |
1341 | if (valueMask & CWOverrideRedirect) { | |
1342 | winPtr->atts.override_redirect = attsPtr->override_redirect; | |
1343 | } | |
1344 | if (valueMask & CWSaveUnder) { | |
1345 | winPtr->atts.save_under = attsPtr->save_under; | |
1346 | } | |
1347 | if (valueMask & CWEventMask) { | |
1348 | winPtr->atts.event_mask = attsPtr->event_mask; | |
1349 | } | |
1350 | if (valueMask & CWDontPropagate) { | |
1351 | winPtr->atts.do_not_propagate_mask | |
1352 | = attsPtr->do_not_propagate_mask; | |
1353 | } | |
1354 | if (valueMask & CWColormap) { | |
1355 | winPtr->atts.colormap = attsPtr->colormap; | |
1356 | } | |
1357 | if (valueMask & CWCursor) { | |
1358 | winPtr->atts.cursor = attsPtr->cursor; | |
1359 | } | |
1360 | ||
1361 | if (winPtr->window != None) { | |
1362 | XChangeWindowAttributes(winPtr->display, winPtr->window, | |
1363 | valueMask, attsPtr); | |
1364 | } else { | |
1365 | winPtr->dirtyAtts |= valueMask; | |
1366 | } | |
1367 | } | |
1368 | ||
1369 | void | |
1370 | Tk_SetWindowBackground(tkwin, pixel) | |
1371 | Tk_Window tkwin; /* Window to manipulate. */ | |
1372 | unsigned long pixel; /* Pixel value to use for | |
1373 | * window's background. */ | |
1374 | { | |
1375 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1376 | ||
1377 | winPtr->atts.background_pixel = pixel; | |
1378 | ||
1379 | if (winPtr->window != None) { | |
1380 | XSetWindowBackground(winPtr->display, winPtr->window, pixel); | |
1381 | } else { | |
1382 | winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBackPixmap) | |
1383 | | CWBackPixel; | |
1384 | } | |
1385 | } | |
1386 | ||
1387 | void | |
1388 | Tk_SetWindowBackgroundPixmap(tkwin, pixmap) | |
1389 | Tk_Window tkwin; /* Window to manipulate. */ | |
1390 | Pixmap pixmap; /* Pixmap to use for window's | |
1391 | * background. */ | |
1392 | { | |
1393 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1394 | ||
1395 | winPtr->atts.background_pixmap = pixmap; | |
1396 | ||
1397 | if (winPtr->window != None) { | |
1398 | XSetWindowBackgroundPixmap(winPtr->display, | |
1399 | winPtr->window, pixmap); | |
1400 | } else { | |
1401 | winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBackPixel) | |
1402 | | CWBackPixmap; | |
1403 | } | |
1404 | } | |
1405 | ||
1406 | void | |
1407 | Tk_SetWindowBorder(tkwin, pixel) | |
1408 | Tk_Window tkwin; /* Window to manipulate. */ | |
1409 | unsigned long pixel; /* Pixel value to use for | |
1410 | * window's border. */ | |
1411 | { | |
1412 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1413 | ||
1414 | winPtr->atts.border_pixel = pixel; | |
1415 | ||
1416 | if (winPtr->window != None) { | |
1417 | XSetWindowBorder(winPtr->display, winPtr->window, pixel); | |
1418 | } else { | |
1419 | winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBorderPixmap) | |
1420 | | CWBorderPixel; | |
1421 | } | |
1422 | } | |
1423 | ||
1424 | void | |
1425 | Tk_SetWindowBorderPixmap(tkwin, pixmap) | |
1426 | Tk_Window tkwin; /* Window to manipulate. */ | |
1427 | Pixmap pixmap; /* Pixmap to use for window's | |
1428 | * border. */ | |
1429 | { | |
1430 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1431 | ||
1432 | winPtr->atts.border_pixmap = pixmap; | |
1433 | ||
1434 | if (winPtr->window != None) { | |
1435 | XSetWindowBorderPixmap(winPtr->display, | |
1436 | winPtr->window, pixmap); | |
1437 | } else { | |
1438 | winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBorderPixel) | |
1439 | | CWBorderPixmap; | |
1440 | } | |
1441 | } | |
1442 | ||
1443 | void | |
1444 | Tk_DefineCursor(tkwin, cursor) | |
1445 | Tk_Window tkwin; /* Window to manipulate. */ | |
1446 | Cursor cursor; /* Cursor to use for window (may be None). */ | |
1447 | { | |
1448 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1449 | ||
1450 | winPtr->atts.cursor = cursor; | |
1451 | ||
1452 | if (winPtr->window != None) { | |
1453 | XDefineCursor(winPtr->display, winPtr->window, cursor); | |
1454 | } else { | |
1455 | winPtr->dirtyAtts = winPtr->dirtyAtts | CWCursor; | |
1456 | } | |
1457 | } | |
1458 | ||
1459 | void | |
1460 | Tk_UndefineCursor(tkwin) | |
1461 | Tk_Window tkwin; /* Window to manipulate. */ | |
1462 | { | |
1463 | Tk_DefineCursor(tkwin, None); | |
1464 | } | |
1465 | \f | |
1466 | /* | |
1467 | *---------------------------------------------------------------------- | |
1468 | * | |
1469 | * DoConfigureNotify -- | |
1470 | * | |
1471 | * Generate a ConfigureNotify event describing the current | |
1472 | * configuration of a window. | |
1473 | * | |
1474 | * Results: | |
1475 | * None. | |
1476 | * | |
1477 | * Side effects: | |
1478 | * An event is generated and processed by Tk_HandleEvent. | |
1479 | * | |
1480 | *---------------------------------------------------------------------- | |
1481 | */ | |
1482 | ||
1483 | static void | |
1484 | DoConfigureNotify(winPtr) | |
1485 | register TkWindow *winPtr; /* Window whose configuration | |
1486 | * was just changed. */ | |
1487 | { | |
1488 | XEvent event; | |
1489 | ||
1490 | event.type = ConfigureNotify; | |
1491 | event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display); | |
1492 | event.xconfigure.send_event = False; | |
1493 | event.xconfigure.display = winPtr->display; | |
1494 | event.xconfigure.event = winPtr->window; | |
1495 | event.xconfigure.window = winPtr->window; | |
1496 | event.xconfigure.x = winPtr->changes.x; | |
1497 | event.xconfigure.y = winPtr->changes.y; | |
1498 | event.xconfigure.width = winPtr->changes.width; | |
1499 | event.xconfigure.height = winPtr->changes.height; | |
1500 | event.xconfigure.border_width = winPtr->changes.border_width; | |
1501 | if (winPtr->changes.stack_mode == Above) { | |
1502 | event.xconfigure.above = winPtr->changes.sibling; | |
1503 | } else { | |
1504 | event.xconfigure.above = None; | |
1505 | } | |
1506 | event.xconfigure.override_redirect = winPtr->atts.override_redirect; | |
1507 | Tk_HandleEvent(&event); | |
1508 | } | |
1509 | \f | |
1510 | /* | |
1511 | *---------------------------------------------------------------------- | |
1512 | * | |
1513 | * Tk_SetClass -- | |
1514 | * | |
1515 | * This procedure is used to give a window a class. | |
1516 | * | |
1517 | * Results: | |
1518 | * None. | |
1519 | * | |
1520 | * Side effects: | |
1521 | * A new class is stored for tkwin, replacing any existing | |
1522 | * class for it. | |
1523 | * | |
1524 | *---------------------------------------------------------------------- | |
1525 | */ | |
1526 | ||
1527 | void | |
1528 | Tk_SetClass(tkwin, className) | |
1529 | Tk_Window tkwin; /* Token for window to assign class. */ | |
1530 | char *className; /* New class for tkwin. */ | |
1531 | { | |
1532 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1533 | ||
1534 | winPtr->classUid = Tk_GetUid(className); | |
1535 | if (winPtr->flags & TK_TOP_LEVEL) { | |
1536 | TkWmSetClass(winPtr); | |
1537 | } | |
1538 | } | |
1539 | \f | |
1540 | /* | |
1541 | *---------------------------------------------------------------------- | |
1542 | * | |
1543 | * Tk_NameToWindow -- | |
1544 | * | |
1545 | * Given a string name for a window, this procedure | |
1546 | * returns the token for the window, if there exists a | |
1547 | * window corresponding to the given name. | |
1548 | * | |
1549 | * Results: | |
1550 | * The return result is either a token for the window corresponding | |
1551 | * to "name", or else NULL to indicate that there is no such | |
1552 | * window. In this case, an error message is left in interp->result. | |
1553 | * | |
1554 | * Side effects: | |
1555 | * None. | |
1556 | * | |
1557 | *---------------------------------------------------------------------- | |
1558 | */ | |
1559 | ||
1560 | Tk_Window | |
1561 | Tk_NameToWindow(interp, pathName, tkwin) | |
1562 | Tcl_Interp *interp; /* Where to report errors. */ | |
1563 | char *pathName; /* Path name of window. */ | |
1564 | Tk_Window tkwin; /* Token for window: name is assumed to | |
1565 | * belong to the same main window as tkwin. */ | |
1566 | { | |
1567 | Tcl_HashEntry *hPtr; | |
1568 | ||
1569 | hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable, | |
1570 | pathName); | |
1571 | if (hPtr == NULL) { | |
1572 | Tcl_AppendResult(interp, "bad window path name \"", | |
1573 | pathName, "\"", (char *) NULL); | |
1574 | return NULL; | |
1575 | } | |
1576 | return (Tk_Window) Tcl_GetHashValue(hPtr); | |
1577 | } | |
1578 | \f | |
1579 | /* | |
1580 | *---------------------------------------------------------------------- | |
1581 | * | |
1582 | * Tk_DisplayName -- | |
1583 | * | |
1584 | * Return the textual name of a window's display. | |
1585 | * | |
1586 | * Results: | |
1587 | * The return value is the string name of the display associated | |
1588 | * with tkwin. | |
1589 | * | |
1590 | * Side effects: | |
1591 | * None. | |
1592 | * | |
1593 | *---------------------------------------------------------------------- | |
1594 | */ | |
1595 | ||
1596 | char * | |
1597 | Tk_DisplayName(tkwin) | |
1598 | Tk_Window tkwin; /* Window whose display name is desired. */ | |
1599 | { | |
1600 | return ((TkWindow *) tkwin)->dispPtr->name; | |
1601 | } |