]>
Commit | Line | Data |
---|---|---|
6a5fa4e0 MG |
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->cursorFont = None; | |
364 | dispPtr->grabWinPtr = NULL; | |
365 | dispPtr->ungrabWinPtr = NULL; | |
366 | dispPtr->buttonWinPtr = NULL; | |
367 | dispPtr->pointerWinPtr = NULL; | |
368 | dispPtr->serverWinPtr = NULL; | |
369 | dispPtr->grabFlags = 0; | |
370 | dispPtr->focusPtr = NULL; | |
371 | tkDisplayList = dispPtr; | |
372 | Tk_CreateFileHandler(ConnectionNumber(display), | |
373 | TK_READABLE, (void (*)()) NULL, | |
374 | (ClientData) display); | |
375 | break; | |
376 | } | |
377 | if ((strncmp(dispPtr->name, screenName, length) == 0) | |
378 | && (dispPtr->name[length] == '\0')) { | |
379 | break; | |
380 | } | |
381 | } | |
382 | if (screenId >= ScreenCount(dispPtr->display)) { | |
383 | sprintf(interp->result, "bad screen number \"%d\"", screenId); | |
384 | return (TkDisplay *) NULL; | |
385 | } | |
386 | *screenPtr = screenId; | |
387 | return dispPtr; | |
388 | } | |
389 | \f | |
390 | /* | |
391 | *-------------------------------------------------------------- | |
392 | * | |
393 | * NewWindow -- | |
394 | * | |
395 | * This procedure creates and initializes a TkWindow structure. | |
396 | * | |
397 | * Results: | |
398 | * The return value is a pointer to the new window. | |
399 | * | |
400 | * Side effects: | |
401 | * A new window structure is allocated and all its fields are | |
402 | * initialized. | |
403 | * | |
404 | *-------------------------------------------------------------- | |
405 | */ | |
406 | ||
407 | static TkWindow * | |
408 | NewWindow(dispPtr, screenNum) | |
409 | TkDisplay *dispPtr; /* Display associated with new window. */ | |
410 | int screenNum; /* Index of screen for new window. */ | |
411 | { | |
412 | register TkWindow *winPtr; | |
413 | ||
414 | winPtr = (TkWindow *) ckalloc(sizeof(TkWindow)); | |
415 | winPtr->display = dispPtr->display; | |
416 | winPtr->dispPtr = dispPtr; | |
417 | winPtr->screenNum = screenNum; | |
418 | winPtr->window = None; | |
419 | winPtr->childList = NULL; | |
420 | winPtr->parentPtr = NULL; | |
421 | winPtr->nextPtr = NULL; | |
422 | winPtr->mainPtr = NULL; | |
423 | winPtr->pathName = NULL; | |
424 | winPtr->nameUid = NULL; | |
425 | winPtr->classUid = NULL; | |
426 | winPtr->changes = defChanges; | |
427 | winPtr->dirtyChanges = CWX|CWY|CWWidth|CWHeight|CWBorderWidth; | |
428 | winPtr->atts = defAtts; | |
429 | winPtr->dirtyAtts = CWEventMask; | |
430 | winPtr->flags = 0; | |
431 | winPtr->handlerList = NULL; | |
432 | winPtr->focusProc = NULL; | |
433 | winPtr->focusData = NULL; | |
434 | winPtr->optionLevel = -1; | |
435 | winPtr->selHandlerList = NULL; | |
436 | winPtr->selClearProc = NULL; | |
437 | winPtr->selClearData = NULL; | |
438 | winPtr->geomProc = NULL; | |
439 | winPtr->geomData = NULL; | |
440 | winPtr->reqWidth = winPtr->reqHeight = 0; | |
441 | winPtr->internalBorderWidth = 0; | |
442 | winPtr->wmInfoPtr = NULL; | |
443 | return winPtr; | |
444 | } | |
445 | \f | |
446 | /* | |
447 | *---------------------------------------------------------------------- | |
448 | * | |
449 | * NameWindow -- | |
450 | * | |
451 | * This procedure is invoked to give a window a name and insert | |
452 | * the window into the hierarchy associated with a particular | |
453 | * application. | |
454 | * | |
455 | * Results: | |
456 | * A standard Tcl return value. | |
457 | * | |
458 | * Side effects: | |
459 | * See above. | |
460 | * | |
461 | *---------------------------------------------------------------------- | |
462 | */ | |
463 | ||
464 | static int | |
465 | NameWindow(interp, winPtr, parentPtr, name) | |
466 | Tcl_Interp *interp; /* Interpreter to use for error reporting. */ | |
467 | register TkWindow *winPtr; /* Window that is to be named and inserted. */ | |
468 | TkWindow *parentPtr; /* Pointer to logical parent for winPtr | |
469 | * (used for naming, options, etc.). */ | |
470 | char *name; /* Name for winPtr; must be unique among | |
471 | * parentPtr's children. */ | |
472 | { | |
473 | #define FIXED_SIZE 200 | |
474 | char staticSpace[FIXED_SIZE]; | |
475 | char *pathName; | |
476 | int new; | |
477 | Tcl_HashEntry *hPtr; | |
478 | int length1, length2; | |
479 | ||
480 | /* | |
481 | * Setup all the stuff except name right away, then do the name stuff | |
482 | * last. This is so that if the name stuff fails, everything else | |
483 | * will be properly initialized (needed to destroy the window cleanly | |
484 | * after the naming failure). | |
485 | */ | |
486 | winPtr->parentPtr = parentPtr; | |
487 | winPtr->nextPtr = parentPtr->childList; | |
488 | parentPtr->childList = winPtr; | |
489 | winPtr->mainPtr = parentPtr->mainPtr; | |
490 | winPtr->nameUid = Tk_GetUid(name); | |
491 | ||
492 | /* | |
493 | * To permit names of arbitrary length, must be prepared to malloc | |
494 | * a buffer to hold the new path name. To run fast in the common | |
495 | * case where names are short, use a fixed-size buffer on the | |
496 | * stack. | |
497 | */ | |
498 | ||
499 | length1 = strlen(parentPtr->pathName); | |
500 | length2 = strlen(name); | |
501 | if ((length1+length2+2) <= FIXED_SIZE) { | |
502 | pathName = staticSpace; | |
503 | } else { | |
504 | pathName = (char *) ckalloc((unsigned) (length1+length2+2)); | |
505 | } | |
506 | if (length1 == 1) { | |
507 | pathName[0] = '.'; | |
508 | strcpy(pathName+1, name); | |
509 | } else { | |
510 | strcpy(pathName, parentPtr->pathName); | |
511 | pathName[length1] = '.'; | |
512 | strcpy(pathName+length1+1, name); | |
513 | } | |
514 | hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new); | |
515 | if (pathName != staticSpace) { | |
516 | ckfree(pathName); | |
517 | } | |
518 | if (!new) { | |
519 | Tcl_AppendResult(interp, "window name \"", name, | |
520 | "\" already exists in parent", (char *) NULL); | |
521 | return TCL_ERROR; | |
522 | } | |
523 | Tcl_SetHashValue(hPtr, winPtr); | |
524 | winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr); | |
525 | return TCL_OK; | |
526 | } | |
527 | \f | |
528 | /* | |
529 | *---------------------------------------------------------------------- | |
530 | * | |
531 | * Tk_CreateMainWindow -- | |
532 | * | |
533 | * Make a new main window. A main window is a special kind of | |
534 | * top-level window used as the outermost window in an | |
535 | * application. | |
536 | * | |
537 | * Results: | |
538 | * The return value is a token for the new window, or NULL if | |
539 | * an error prevented the new window from being created. If | |
540 | * NULL is returned, an error message will be left in | |
541 | * interp->result. | |
542 | * | |
543 | * Side effects: | |
544 | * A new window structure is allocated locally; "interp" is | |
545 | * associated with the window and registered for "send" commands | |
546 | * under "baseName". BaseName may be extended with an instance | |
547 | * number in the form "#2" if necessary to make it globally | |
548 | * unique. Tk-related commands are bound into interp. An X | |
549 | * window is NOT initially created, but will be created the | |
550 | * first time the window is mapped. | |
551 | * | |
552 | *---------------------------------------------------------------------- | |
553 | */ | |
554 | ||
555 | Tk_Window | |
556 | Tk_CreateMainWindow(interp, screenName, baseName) | |
557 | Tcl_Interp *interp; /* Interpreter to use for error reporting. */ | |
558 | char *screenName; /* Name of screen on which to create | |
559 | * window. Empty or NULL string means | |
560 | * use DISPLAY environment variable. */ | |
561 | char *baseName; /* Base name for application; usually of the | |
562 | * form "prog instance". */ | |
563 | { | |
564 | Tk_Window tkwin; | |
565 | int result, dummy; | |
566 | Tcl_HashEntry *hPtr; | |
567 | register TkMainInfo *mainPtr; | |
568 | register TkWindow *winPtr; | |
569 | register TkCmd *cmdPtr; | |
570 | ||
571 | /* | |
572 | * Create the basic TkWindow structure. | |
573 | */ | |
574 | ||
575 | tkwin = CreateTopLevelWindow(interp, (Tk_Window) NULL, baseName, | |
576 | screenName); | |
577 | if (tkwin == NULL) { | |
578 | return NULL; | |
579 | } | |
580 | ||
581 | /* | |
582 | * Create the TkMainInfo structure for this application, and set | |
583 | * up name-related information for the new window. | |
584 | */ | |
585 | ||
586 | winPtr = (TkWindow *) tkwin; | |
587 | mainPtr = (TkMainInfo *) ckalloc(sizeof(TkMainInfo)); | |
588 | mainPtr->winPtr = winPtr; | |
589 | mainPtr->interp = interp; | |
590 | Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS); | |
591 | mainPtr->bindingTable = Tk_CreateBindingTable(interp); | |
592 | /* XXX: FOCUS */ | |
593 | /* mainPtr->focusPtr = NULL; */ | |
594 | mainPtr->optionRootPtr = NULL; | |
595 | winPtr->mainPtr = mainPtr; | |
596 | hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy); | |
597 | Tcl_SetHashValue(hPtr, winPtr); | |
598 | winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr); | |
599 | ||
600 | /* | |
601 | * Register the interpreter for "send" purposes. If baseName isn't | |
602 | * already unique, find a unique suffix to add to it to make it | |
603 | * unique. Change the window's name to contain the suffix. | |
604 | */ | |
605 | ||
606 | result = Tk_RegisterInterp(interp, baseName, tkwin); | |
607 | if (result == TCL_OK) { | |
608 | winPtr->nameUid = Tk_GetUid(baseName); | |
609 | } else { | |
610 | char newName[110]; | |
611 | int i; | |
612 | ||
613 | for (i = 2; ; i++) { | |
614 | sprintf(newName, "%.100s #%d", baseName, i); | |
615 | Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); | |
616 | result = Tk_RegisterInterp(interp, newName, tkwin); | |
617 | if (result == TCL_OK) { | |
618 | break; | |
619 | } | |
620 | if (i >= 100) { | |
621 | Tcl_SetResult(interp, | |
622 | "couldn't generate unique name to register application", | |
623 | TCL_STATIC); | |
624 | Tk_DestroyWindow(tkwin); | |
625 | } | |
626 | } | |
627 | winPtr->nameUid = Tk_GetUid(newName); | |
628 | } | |
629 | ||
630 | /* | |
631 | * Bind in Tk's commands. | |
632 | */ | |
633 | ||
634 | for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) { | |
635 | Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc, | |
636 | (ClientData) tkwin, (void (*)()) NULL); | |
637 | } | |
638 | ||
639 | /* | |
640 | * Set variables for the intepreter. | |
641 | */ | |
642 | ||
643 | Tcl_SetVar(interp, "tk_library", TK_Library, TCL_GLOBAL_ONLY); | |
644 | Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY); | |
645 | Tcl_SetVar(interp, "tkVersion", TK_VERSION, TCL_GLOBAL_ONLY); | |
646 | ||
647 | tk_NumMainWindows++; | |
648 | return tkwin; | |
649 | } | |
650 | \f | |
651 | /* | |
652 | *-------------------------------------------------------------- | |
653 | * | |
654 | * Tk_CreateWindow -- | |
655 | * | |
656 | * Create a new internal or top-level window as a child of an | |
657 | * existing window. | |
658 | * | |
659 | * Results: | |
660 | * The return value is a token for the new window. This | |
661 | * is not the same as X's token for the window. If an error | |
662 | * occurred in creating the window (e.g. no such display or | |
663 | * screen), then an error message is left in interp->result and | |
664 | * NULL is returned. | |
665 | * | |
666 | * Side effects: | |
667 | * A new window structure is allocated locally. An X | |
668 | * window is not initially created, but will be created | |
669 | * the first time the window is mapped. | |
670 | * | |
671 | *-------------------------------------------------------------- | |
672 | */ | |
673 | ||
674 | Tk_Window | |
675 | Tk_CreateWindow(interp, parent, name, screenName) | |
676 | Tcl_Interp *interp; /* Interpreter to use for error reporting. | |
677 | * Interp->result is assumed to be | |
678 | * initialized by the caller. */ | |
679 | Tk_Window parent; /* Token for parent of new window. */ | |
680 | char *name; /* Name for new window. Must be unique | |
681 | * among parent's children. */ | |
682 | char *screenName; /* If NULL, new window will be internal on | |
683 | * same screen as its parent. If non-NULL, | |
684 | * gives name of screen on which to create | |
685 | * new window; window will be a top-level | |
686 | * window. */ | |
687 | { | |
688 | TkWindow *parentPtr = (TkWindow *) parent; | |
689 | TkWindow *winPtr; | |
690 | ||
691 | if (screenName == NULL) { | |
692 | winPtr = NewWindow(parentPtr->dispPtr, parentPtr->screenNum); | |
693 | if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) { | |
694 | Tk_DestroyWindow((Tk_Window) winPtr); | |
695 | return NULL; | |
696 | } else { | |
697 | return (Tk_Window) winPtr; | |
698 | } | |
699 | } else { | |
700 | /* | |
701 | * This is a fix for dvx XOpenDisplay... display name conformalization | |
702 | * bugs... | |
703 | */ | |
704 | char dsp[256]; | |
705 | int len; | |
706 | ||
707 | strcpy(dsp, screenName); | |
708 | len = strlen(dsp); | |
709 | if (len && (dsp[len -1] == '.')) | |
710 | dsp[len -1] = '\0'; | |
711 | ||
712 | return CreateTopLevelWindow(interp, parent, name, dsp); | |
713 | } | |
714 | } | |
715 | \f | |
716 | /* | |
717 | *---------------------------------------------------------------------- | |
718 | * | |
719 | * Tk_CreateWindowFromPath -- | |
720 | * | |
721 | * This procedure is similar to Tk_CreateInternalWindow except | |
722 | * that it uses a path name to create the window, rather than | |
723 | * a parent and a child name. | |
724 | * | |
725 | * Results: | |
726 | * The return value is a token for the new window. This | |
727 | * is not the same as X's token for the window. If an error | |
728 | * occurred in creating the window (e.g. no such display or | |
729 | * screen), then an error message is left in interp->result and | |
730 | * NULL is returned. | |
731 | * | |
732 | * Side effects: | |
733 | * A new window structure is allocated locally. An X | |
734 | * window is not initially created, but will be created | |
735 | * the first time the window is mapped. | |
736 | * | |
737 | *---------------------------------------------------------------------- | |
738 | */ | |
739 | ||
740 | Tk_Window | |
741 | Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName) | |
742 | Tcl_Interp *interp; /* Interpreter to use for error reporting. | |
743 | * Interp->result is assumed to be | |
744 | * initialized by the caller. */ | |
745 | Tk_Window tkwin; /* Token for any window in application | |
746 | * that is to contain new window. */ | |
747 | char *pathName; /* Path name for new window within the | |
748 | * application of tkwin. The parent of | |
749 | * this window must already exist, but | |
750 | * the window itself must not exist. */ | |
751 | char *screenName; /* If NULL, new window will be on same | |
752 | * screen as its parent. If non-NULL, | |
753 | * gives name of screen on which to create | |
754 | * new window; window will be a top-level | |
755 | * window. */ | |
756 | { | |
757 | #define FIXED_SPACE 5 | |
758 | char fixedSpace[FIXED_SPACE+1]; | |
759 | char *p; | |
760 | Tk_Window parent; | |
761 | int numChars; | |
762 | ||
763 | /* | |
764 | * Strip the parent's name out of pathName (it's everything up | |
765 | * to the last dot). There are two tricky parts: (a) must | |
766 | * copy the parent's name somewhere else to avoid modifying | |
767 | * the pathName string (for large names, space for the copy | |
768 | * will have to be malloc'ed); (b) must special-case the | |
769 | * situation where the parent is ".". | |
770 | */ | |
771 | ||
772 | p = strrchr(pathName, '.'); | |
773 | if (p == NULL) { | |
774 | Tcl_AppendResult(interp, "bad window path name \"", pathName, | |
775 | "\"", (char *) NULL); | |
776 | return NULL; | |
777 | } | |
778 | numChars = p-pathName; | |
779 | if (numChars > FIXED_SPACE) { | |
780 | p = (char *) ckalloc((unsigned) (numChars+1)); | |
781 | } else { | |
782 | p = fixedSpace; | |
783 | } | |
784 | if (numChars == 0) { | |
785 | *p = '.'; | |
786 | p[1] = '\0'; | |
787 | } else { | |
788 | strncpy(p, pathName, numChars); | |
789 | p[numChars] = '\0'; | |
790 | } | |
791 | ||
792 | /* | |
793 | * Find the parent window. | |
794 | */ | |
795 | ||
796 | parent = Tk_NameToWindow(interp, p, tkwin); | |
797 | if (p != fixedSpace) { | |
798 | ckfree(p); | |
799 | } | |
800 | if (parent == NULL) { | |
801 | return NULL; | |
802 | } | |
803 | ||
804 | /* | |
805 | * Create the window. | |
806 | */ | |
807 | ||
808 | if (screenName == NULL) { | |
809 | TkWindow *parentPtr = (TkWindow *) parent; | |
810 | TkWindow *winPtr; | |
811 | ||
812 | winPtr = NewWindow(parentPtr->dispPtr, parentPtr->screenNum); | |
813 | if (NameWindow(interp, winPtr, parentPtr, pathName+numChars+1) | |
814 | != TCL_OK) { | |
815 | Tk_DestroyWindow((Tk_Window) winPtr); | |
816 | return NULL; | |
817 | } else { | |
818 | return (Tk_Window) winPtr; | |
819 | } | |
820 | } else { | |
821 | return CreateTopLevelWindow(interp, parent, pathName+numChars+1, | |
822 | screenName); | |
823 | } | |
824 | } | |
825 | \f | |
826 | /* | |
827 | *-------------------------------------------------------------- | |
828 | * | |
829 | * Tk_DestroyWindow -- | |
830 | * | |
831 | * Destroy an existing window. After this call, the caller | |
832 | * should never again use the token. | |
833 | * | |
834 | * Results: | |
835 | * None. | |
836 | * | |
837 | * Side effects: | |
838 | * The window is deleted, along with all of its children. | |
839 | * Relevant callback procedures are invoked. | |
840 | * | |
841 | *-------------------------------------------------------------- | |
842 | */ | |
843 | ||
844 | void | |
845 | Tk_DestroyWindow(tkwin) | |
846 | Tk_Window tkwin; /* Window to destroy. */ | |
847 | { | |
848 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
849 | XEvent event; | |
850 | ||
851 | /* | |
852 | * Recursively destroy children. The TK_RECURSIVE_DESTROY | |
853 | * flags means that the child's window needn't be explicitly | |
854 | * destroyed (the destroy of the parent already did it), nor | |
855 | * does it need to be removed from its parent's child list, | |
856 | * since the parent is being destroyed too. | |
857 | */ | |
858 | ||
859 | while (winPtr->childList != NULL) { | |
860 | winPtr->childList->flags |= TK_RECURSIVE_DESTROY; | |
861 | Tk_DestroyWindow((Tk_Window) winPtr->childList); | |
862 | } | |
863 | ||
864 | /* | |
865 | * Generate a DestroyNotify event. In order for the DestroyNotify | |
866 | * event to be processed correctly, need to make sure the window | |
867 | * exists. This is a bit of a kludge, and may be unnecessarily | |
868 | * expensive, but without it no event handlers will get called for | |
869 | * windows that don't exist yet. | |
870 | */ | |
871 | ||
872 | if (winPtr->window == None) { | |
873 | Tk_MakeWindowExist(tkwin); | |
874 | } | |
875 | winPtr->flags |= TK_ALREADY_DEAD; | |
876 | event.type = DestroyNotify; | |
877 | event.xdestroywindow.serial = | |
878 | LastKnownRequestProcessed(winPtr->display); | |
879 | event.xdestroywindow.send_event = False; | |
880 | event.xdestroywindow.display = winPtr->display; | |
881 | event.xdestroywindow.event = winPtr->window; | |
882 | event.xdestroywindow.window = winPtr->window; | |
883 | Tk_HandleEvent(&event); | |
884 | ||
885 | /* | |
886 | * Cleanup the data structures associated with this window. | |
887 | * No need to destroy windows during recursive destroys, since | |
888 | * that will happen automatically when the parent window is | |
889 | * destroyed (not true for top-level windows: must destroy | |
890 | * them explicitly). | |
891 | */ | |
892 | ||
893 | if (winPtr->window != None) { | |
894 | if (!(winPtr->flags & TK_RECURSIVE_DESTROY) | |
895 | || (winPtr->flags & TK_TOP_LEVEL)) { | |
896 | XDestroyWindow(winPtr->display, winPtr->window); | |
897 | } | |
898 | XDeleteContext(winPtr->display, winPtr->window, tkWindowContext); | |
899 | winPtr->window = None; | |
900 | } | |
901 | if (winPtr->parentPtr != NULL) { | |
902 | if (winPtr->parentPtr->childList == winPtr) { | |
903 | winPtr->parentPtr->childList = winPtr->nextPtr; | |
904 | } else { | |
905 | register TkWindow *winPtr2; | |
906 | ||
907 | for (winPtr2 = winPtr->parentPtr->childList; ; | |
908 | winPtr2 = winPtr2->nextPtr) { | |
909 | if (winPtr2 == NULL) { | |
910 | panic("Tk_DestroyWindow couldn't find child in parent (deleted twice?)"); | |
911 | break; | |
912 | } | |
913 | if (winPtr2->nextPtr == winPtr) { | |
914 | winPtr2->nextPtr = winPtr->nextPtr; | |
915 | break; | |
916 | } | |
917 | } | |
918 | } | |
919 | } | |
920 | TkEventDeadWindow(winPtr); | |
921 | TkOptionDeadWindow(winPtr); | |
922 | TkSelDeadWindow(winPtr); | |
923 | if (winPtr->flags & TK_TOP_LEVEL) { | |
924 | TkWmDeadWindow(winPtr); | |
925 | } | |
926 | TkGrabDeadWindow(winPtr); | |
927 | if (winPtr->mainPtr != NULL) { | |
928 | Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable, | |
929 | (ClientData) winPtr->pathName); | |
930 | if (winPtr->pathName != NULL) { | |
931 | Tcl_DeleteHashEntry(Tcl_FindHashEntry(&winPtr->mainPtr->nameTable, | |
932 | winPtr->pathName)); | |
933 | } | |
934 | if (winPtr->mainPtr->winPtr == winPtr) { | |
935 | register TkCmd *cmdPtr; | |
936 | ||
937 | /* | |
938 | * Deleting a main window. Delete the TkMainInfo structure too | |
939 | * and replace all of Tk's commands with dummy commands that | |
940 | * return errors. Also delete the "send" command to unregister | |
941 | * the interpreter. | |
942 | */ | |
943 | ||
944 | for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) { | |
945 | Tcl_CreateCommand(winPtr->mainPtr->interp, cmdPtr->name, | |
946 | TkDeadAppCmd, (ClientData) NULL, (void (*)()) NULL); | |
947 | } | |
948 | Tcl_CreateCommand(winPtr->mainPtr->interp, "send", | |
949 | TkDeadAppCmd, (ClientData) NULL, (void (*)()) NULL); | |
950 | Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable); | |
951 | Tk_DeleteBindingTable(winPtr->mainPtr->bindingTable); | |
952 | ckfree((char *) winPtr->mainPtr); | |
953 | tk_NumMainWindows--; | |
954 | } | |
955 | } | |
956 | ckfree((char *) winPtr); | |
957 | } | |
958 | \f | |
959 | /* | |
960 | *-------------------------------------------------------------- | |
961 | * | |
962 | * Tk_MapWindow -- | |
963 | * | |
964 | * Map a window within its parent. This may require the | |
965 | * window and/or its parents to actually be created. | |
966 | * | |
967 | * Results: | |
968 | * None. | |
969 | * | |
970 | * Side effects: | |
971 | * The given window will be mapped. Windows may also | |
972 | * be created. | |
973 | * | |
974 | *-------------------------------------------------------------- | |
975 | */ | |
976 | ||
977 | void | |
978 | Tk_MapWindow(tkwin) | |
979 | Tk_Window tkwin; /* Token for window to map. */ | |
980 | { | |
981 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
982 | ||
983 | if (winPtr->flags & TK_MAPPED) { | |
984 | return; | |
985 | } | |
986 | if (winPtr->window == None) { | |
987 | Tk_MakeWindowExist(tkwin); | |
988 | } | |
989 | if (winPtr->flags & TK_TOP_LEVEL) { | |
990 | if (!TkWmMapWindow(winPtr)) { | |
991 | return; | |
992 | } | |
993 | } else { | |
994 | /* | |
995 | * Don't set the mapped flag for top-level windows: TkWmMapWindow | |
996 | * does it if appropriate (e.g. if the window is going to be non- | |
997 | * iconic). | |
998 | */ | |
999 | ||
1000 | winPtr->flags |= TK_MAPPED; | |
1001 | } | |
1002 | XMapWindow(winPtr->display, winPtr->window); | |
1003 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1004 | XEvent event; | |
1005 | ||
1006 | event.type = MapNotify; | |
1007 | event.xmap.serial = LastKnownRequestProcessed(winPtr->display); | |
1008 | event.xmap.send_event = False; | |
1009 | event.xmap.display = winPtr->display; | |
1010 | event.xmap.event = winPtr->window; | |
1011 | event.xmap.window = winPtr->window; | |
1012 | event.xmap.override_redirect = winPtr->atts.override_redirect; | |
1013 | Tk_HandleEvent(&event); | |
1014 | } | |
1015 | } | |
1016 | \f | |
1017 | /* | |
1018 | *-------------------------------------------------------------- | |
1019 | * | |
1020 | * Tk_MakeWindowExist -- | |
1021 | * | |
1022 | * Ensure that a particular window actually exists. This | |
1023 | * procedure shouldn't normally need to be invoked from | |
1024 | * outside the Tk package, but may be needed if someone | |
1025 | * wants to manipulate a window before mapping it. | |
1026 | * | |
1027 | * Results: | |
1028 | * None. | |
1029 | * | |
1030 | * Side effects: | |
1031 | * When the procedure returns, the X window associated with | |
1032 | * tkwin is guaranteed to exist. This may require the | |
1033 | * window's ancestors to be created also. | |
1034 | * | |
1035 | *-------------------------------------------------------------- | |
1036 | */ | |
1037 | ||
1038 | void | |
1039 | Tk_MakeWindowExist(tkwin) | |
1040 | Tk_Window tkwin; /* Token for window. */ | |
1041 | { | |
1042 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1043 | Window parent; | |
1044 | ||
1045 | if (winPtr->window != None) { | |
1046 | return; | |
1047 | } | |
1048 | ||
1049 | if (winPtr->flags & TK_TOP_LEVEL) { | |
1050 | /* | |
1051 | * workaround by dhopkins for OLPC Micropolis gtk.Socket integration. | |
1052 | */ | |
1053 | ||
1054 | if (tk_RootWindow) { | |
1055 | parent = | |
1056 | tk_RootWindow; | |
1057 | } else { | |
1058 | parent = | |
1059 | XRootWindow(winPtr->display, winPtr->screenNum); | |
1060 | } | |
1061 | ||
1062 | } else { | |
1063 | if (winPtr->parentPtr->window == None) { | |
1064 | Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr); | |
1065 | } | |
1066 | parent = winPtr->parentPtr->window; | |
1067 | } | |
1068 | ||
1069 | /* workaround to support non-default colormaps */ | |
1070 | #if 0 | |
1071 | winPtr->window = XCreateWindow(winPtr->display, parent, | |
1072 | winPtr->changes.x, winPtr->changes.y, | |
1073 | winPtr->changes.width, winPtr->changes.height, | |
1074 | winPtr->changes.border_width, CopyFromParent, | |
1075 | InputOutput, CopyFromParent, winPtr->dirtyAtts, | |
1076 | &winPtr->atts); | |
1077 | #else | |
1078 | { Screen *scr = ScreenOfDisplay(winPtr->display, winPtr->screenNum); | |
1079 | ||
1080 | winPtr->dirtyAtts |= CWColormap | CWBorderPixmap; | |
1081 | winPtr->atts.colormap = Tk_DefaultColormap(scr); | |
1082 | winPtr->atts.border_pixmap = Tk_DefaultPixmap(scr); | |
1083 | ||
1084 | winPtr->window = XCreateWindow(winPtr->display, parent, | |
1085 | winPtr->changes.x, winPtr->changes.y, | |
1086 | winPtr->changes.width, winPtr->changes.height, | |
1087 | winPtr->changes.border_width, | |
1088 | Tk_DefaultDepth(scr), | |
1089 | InputOutput, | |
1090 | Tk_DefaultVisual(scr), | |
1091 | winPtr->dirtyAtts, &winPtr->atts); | |
1092 | } | |
1093 | #endif | |
1094 | ||
1095 | XSaveContext(winPtr->display, winPtr->window, tkWindowContext, | |
1096 | (void *) winPtr); | |
1097 | winPtr->dirtyAtts = 0; | |
1098 | winPtr->dirtyChanges &= ~(CWX|CWY|CWWidth|CWHeight|CWBorderWidth); | |
1099 | if (winPtr->dirtyChanges != 0) { | |
1100 | XConfigureWindow(winPtr->display, winPtr->window, | |
1101 | winPtr->dirtyChanges, &winPtr->changes); | |
1102 | winPtr->dirtyChanges = 0; | |
1103 | } | |
1104 | ||
1105 | /* | |
1106 | * Issue a ConfigureNotify event if there were deferred configuration | |
1107 | * changes. | |
1108 | */ | |
1109 | ||
1110 | if (winPtr->flags & TK_NEED_CONFIG_NOTIFY) { | |
1111 | winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY; | |
1112 | DoConfigureNotify(winPtr); | |
1113 | } | |
1114 | } | |
1115 | \f | |
1116 | /* | |
1117 | *-------------------------------------------------------------- | |
1118 | * | |
1119 | * Tk_UnmapWindow, etc. -- | |
1120 | * | |
1121 | * There are several procedures under here, each of which | |
1122 | * mirrors an existing X procedure. In addition to performing | |
1123 | * the functions of the corresponding procedure, each | |
1124 | * procedure also updates the local window structure and | |
1125 | * synthesizes an X event (if the window's structure is being | |
1126 | * managed internally). | |
1127 | * | |
1128 | * Results: | |
1129 | * See the manual entries. | |
1130 | * | |
1131 | * Side effects: | |
1132 | * See the manual entries. | |
1133 | * | |
1134 | *-------------------------------------------------------------- | |
1135 | */ | |
1136 | ||
1137 | void | |
1138 | Tk_UnmapWindow(tkwin) | |
1139 | Tk_Window tkwin; /* Token for window to unmap. */ | |
1140 | { | |
1141 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1142 | ||
1143 | if (!(winPtr->flags & TK_MAPPED)) { | |
1144 | return; | |
1145 | } | |
1146 | winPtr->flags &= ~TK_MAPPED; | |
1147 | XUnmapWindow(winPtr->display, winPtr->window); | |
1148 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1149 | XEvent event; | |
1150 | ||
1151 | event.type = UnmapNotify; | |
1152 | event.xunmap.serial = LastKnownRequestProcessed(winPtr->display); | |
1153 | event.xunmap.send_event = False; | |
1154 | event.xunmap.display = winPtr->display; | |
1155 | event.xunmap.event = winPtr->window; | |
1156 | event.xunmap.window = winPtr->window; | |
1157 | event.xunmap.from_configure = False; | |
1158 | Tk_HandleEvent(&event); | |
1159 | } | |
1160 | } | |
1161 | ||
1162 | void | |
1163 | Tk_ConfigureWindow(tkwin, valueMask, valuePtr) | |
1164 | Tk_Window tkwin; /* Window to re-configure. */ | |
1165 | unsigned int valueMask; /* Mask indicating which parts of | |
1166 | * *valuePtr are to be used. */ | |
1167 | XWindowChanges *valuePtr; /* New values. */ | |
1168 | { | |
1169 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1170 | ||
1171 | if ((winPtr->window == None) || !(winPtr->flags & TK_TOP_LEVEL)) { | |
1172 | if (valueMask & CWX) { | |
1173 | winPtr->changes.x = valuePtr->x; | |
1174 | } | |
1175 | if (valueMask & CWY) { | |
1176 | winPtr->changes.y = valuePtr->y; | |
1177 | } | |
1178 | if (valueMask & CWWidth) { | |
1179 | winPtr->changes.width = valuePtr->width; | |
1180 | } | |
1181 | if (valueMask & CWHeight) { | |
1182 | winPtr->changes.height = valuePtr->height; | |
1183 | } | |
1184 | if (valueMask & CWBorderWidth) { | |
1185 | winPtr->changes.border_width = valuePtr->border_width; | |
1186 | } | |
1187 | if (valueMask & CWSibling) { | |
1188 | winPtr->changes.sibling = valuePtr->sibling; | |
1189 | } | |
1190 | if (valueMask & CWStackMode) { | |
1191 | winPtr->changes.stack_mode = valuePtr->stack_mode; | |
1192 | } | |
1193 | } | |
1194 | ||
1195 | if (winPtr->window != None) { | |
1196 | XConfigureWindow(winPtr->display, winPtr->window, | |
1197 | valueMask, valuePtr); | |
1198 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1199 | DoConfigureNotify(winPtr); | |
1200 | } | |
1201 | } else { | |
1202 | winPtr->dirtyChanges |= valueMask; | |
1203 | winPtr->flags |= TK_NEED_CONFIG_NOTIFY; | |
1204 | } | |
1205 | } | |
1206 | ||
1207 | void | |
1208 | Tk_MoveWindow(tkwin, x, y) | |
1209 | Tk_Window tkwin; /* Window to move. */ | |
1210 | int x, y; /* New location for window (within | |
1211 | * parent). */ | |
1212 | { | |
1213 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1214 | ||
1215 | if (winPtr->window != None) { | |
1216 | XMoveWindow(winPtr->display, winPtr->window, x, y); | |
1217 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1218 | winPtr->changes.x = x; | |
1219 | winPtr->changes.y = y; | |
1220 | DoConfigureNotify(winPtr); | |
1221 | } | |
1222 | } else { | |
1223 | winPtr->changes.x = x; | |
1224 | winPtr->changes.y = y; | |
1225 | winPtr->dirtyChanges |= CWX|CWY; | |
1226 | winPtr->flags |= TK_NEED_CONFIG_NOTIFY; | |
1227 | } | |
1228 | } | |
1229 | ||
1230 | void | |
1231 | Tk_ResizeWindow(tkwin, width, height) | |
1232 | Tk_Window tkwin; /* Window to resize. */ | |
1233 | unsigned int width, height; /* New dimensions for window. */ | |
1234 | { | |
1235 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1236 | ||
1237 | if (winPtr->window != None) { | |
1238 | XResizeWindow(winPtr->display, winPtr->window, width, height); | |
1239 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1240 | winPtr->changes.width = width; | |
1241 | winPtr->changes.height = height; | |
1242 | DoConfigureNotify(winPtr); | |
1243 | } | |
1244 | } else { | |
1245 | winPtr->changes.width = width; | |
1246 | winPtr->changes.height = height; | |
1247 | winPtr->dirtyChanges |= CWWidth|CWHeight; | |
1248 | winPtr->flags |= TK_NEED_CONFIG_NOTIFY; | |
1249 | } | |
1250 | } | |
1251 | ||
1252 | void | |
1253 | Tk_MoveResizeWindow(tkwin, x, y, width, height) | |
1254 | Tk_Window tkwin; /* Window to move and resize. */ | |
1255 | int x, y; /* New location for window (within | |
1256 | * parent). */ | |
1257 | unsigned int width, height; /* New dimensions for window. */ | |
1258 | { | |
1259 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1260 | ||
1261 | if (winPtr->window != None) { | |
1262 | XMoveResizeWindow(winPtr->display, winPtr->window, | |
1263 | x, y, width, height); | |
1264 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1265 | winPtr->changes.x = x; | |
1266 | winPtr->changes.y = y; | |
1267 | winPtr->changes.width = width; | |
1268 | winPtr->changes.height = height; | |
1269 | DoConfigureNotify(winPtr); | |
1270 | } | |
1271 | } else { | |
1272 | winPtr->changes.x = x; | |
1273 | winPtr->changes.y = y; | |
1274 | winPtr->changes.width = width; | |
1275 | winPtr->changes.height = height; | |
1276 | winPtr->dirtyChanges |= CWX|CWY|CWWidth|CWHeight; | |
1277 | winPtr->flags |= TK_NEED_CONFIG_NOTIFY; | |
1278 | } | |
1279 | } | |
1280 | ||
1281 | void | |
1282 | Tk_SetWindowBorderWidth(tkwin, width) | |
1283 | Tk_Window tkwin; /* Window to modify. */ | |
1284 | int width; /* New border width for window. */ | |
1285 | { | |
1286 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1287 | ||
1288 | winPtr->changes.border_width = width; | |
1289 | if (winPtr->window != None) { | |
1290 | XSetWindowBorderWidth(winPtr->display, winPtr->window, width); | |
1291 | if (!(winPtr->flags & TK_TOP_LEVEL)) { | |
1292 | DoConfigureNotify(winPtr); | |
1293 | } | |
1294 | } else { | |
1295 | winPtr->dirtyChanges |= CWBorderWidth; | |
1296 | winPtr->flags |= TK_NEED_CONFIG_NOTIFY; | |
1297 | } | |
1298 | } | |
1299 | ||
1300 | void | |
1301 | Tk_ChangeWindowAttributes(tkwin, valueMask, attsPtr) | |
1302 | Tk_Window tkwin; /* Window to manipulate. */ | |
1303 | unsigned long valueMask; /* OR'ed combination of bits, | |
1304 | * indicating which fields of | |
1305 | * *attsPtr are to be used. */ | |
1306 | register XSetWindowAttributes *attsPtr; | |
1307 | /* New values for some attributes. */ | |
1308 | { | |
1309 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1310 | ||
1311 | if (valueMask & CWBackPixmap) { | |
1312 | winPtr->atts.background_pixmap = attsPtr->background_pixmap; | |
1313 | } | |
1314 | if (valueMask & CWBackPixel) { | |
1315 | winPtr->atts.background_pixel = attsPtr->background_pixel; | |
1316 | } | |
1317 | if (valueMask & CWBorderPixmap) { | |
1318 | winPtr->atts.border_pixmap = attsPtr->border_pixmap; | |
1319 | } | |
1320 | if (valueMask & CWBorderPixel) { | |
1321 | winPtr->atts.border_pixel = attsPtr->border_pixel; | |
1322 | } | |
1323 | if (valueMask & CWBitGravity) { | |
1324 | winPtr->atts.bit_gravity = attsPtr->bit_gravity; | |
1325 | } | |
1326 | if (valueMask & CWWinGravity) { | |
1327 | winPtr->atts.win_gravity = attsPtr->win_gravity; | |
1328 | } | |
1329 | if (valueMask & CWBackingStore) { | |
1330 | winPtr->atts.backing_store = attsPtr->backing_store; | |
1331 | } | |
1332 | if (valueMask & CWBackingPlanes) { | |
1333 | winPtr->atts.backing_planes = attsPtr->backing_planes; | |
1334 | } | |
1335 | if (valueMask & CWBackingPixel) { | |
1336 | winPtr->atts.backing_pixel = attsPtr->backing_pixel; | |
1337 | } | |
1338 | if (valueMask & CWOverrideRedirect) { | |
1339 | winPtr->atts.override_redirect = attsPtr->override_redirect; | |
1340 | } | |
1341 | if (valueMask & CWSaveUnder) { | |
1342 | winPtr->atts.save_under = attsPtr->save_under; | |
1343 | } | |
1344 | if (valueMask & CWEventMask) { | |
1345 | winPtr->atts.event_mask = attsPtr->event_mask; | |
1346 | } | |
1347 | if (valueMask & CWDontPropagate) { | |
1348 | winPtr->atts.do_not_propagate_mask | |
1349 | = attsPtr->do_not_propagate_mask; | |
1350 | } | |
1351 | if (valueMask & CWColormap) { | |
1352 | winPtr->atts.colormap = attsPtr->colormap; | |
1353 | } | |
1354 | if (valueMask & CWCursor) { | |
1355 | winPtr->atts.cursor = attsPtr->cursor; | |
1356 | } | |
1357 | ||
1358 | if (winPtr->window != None) { | |
1359 | XChangeWindowAttributes(winPtr->display, winPtr->window, | |
1360 | valueMask, attsPtr); | |
1361 | } else { | |
1362 | winPtr->dirtyAtts |= valueMask; | |
1363 | } | |
1364 | } | |
1365 | ||
1366 | void | |
1367 | Tk_SetWindowBackground(tkwin, pixel) | |
1368 | Tk_Window tkwin; /* Window to manipulate. */ | |
1369 | unsigned long pixel; /* Pixel value to use for | |
1370 | * window's background. */ | |
1371 | { | |
1372 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1373 | ||
1374 | winPtr->atts.background_pixel = pixel; | |
1375 | ||
1376 | if (winPtr->window != None) { | |
1377 | XSetWindowBackground(winPtr->display, winPtr->window, pixel); | |
1378 | } else { | |
1379 | winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBackPixmap) | |
1380 | | CWBackPixel; | |
1381 | } | |
1382 | } | |
1383 | ||
1384 | void | |
1385 | Tk_SetWindowBackgroundPixmap(tkwin, pixmap) | |
1386 | Tk_Window tkwin; /* Window to manipulate. */ | |
1387 | Pixmap pixmap; /* Pixmap to use for window's | |
1388 | * background. */ | |
1389 | { | |
1390 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1391 | ||
1392 | winPtr->atts.background_pixmap = pixmap; | |
1393 | ||
1394 | if (winPtr->window != None) { | |
1395 | XSetWindowBackgroundPixmap(winPtr->display, | |
1396 | winPtr->window, pixmap); | |
1397 | } else { | |
1398 | winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBackPixel) | |
1399 | | CWBackPixmap; | |
1400 | } | |
1401 | } | |
1402 | ||
1403 | void | |
1404 | Tk_SetWindowBorder(tkwin, pixel) | |
1405 | Tk_Window tkwin; /* Window to manipulate. */ | |
1406 | unsigned long pixel; /* Pixel value to use for | |
1407 | * window's border. */ | |
1408 | { | |
1409 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1410 | ||
1411 | winPtr->atts.border_pixel = pixel; | |
1412 | ||
1413 | if (winPtr->window != None) { | |
1414 | XSetWindowBorder(winPtr->display, winPtr->window, pixel); | |
1415 | } else { | |
1416 | winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBorderPixmap) | |
1417 | | CWBorderPixel; | |
1418 | } | |
1419 | } | |
1420 | ||
1421 | void | |
1422 | Tk_SetWindowBorderPixmap(tkwin, pixmap) | |
1423 | Tk_Window tkwin; /* Window to manipulate. */ | |
1424 | Pixmap pixmap; /* Pixmap to use for window's | |
1425 | * border. */ | |
1426 | { | |
1427 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1428 | ||
1429 | winPtr->atts.border_pixmap = pixmap; | |
1430 | ||
1431 | if (winPtr->window != None) { | |
1432 | XSetWindowBorderPixmap(winPtr->display, | |
1433 | winPtr->window, pixmap); | |
1434 | } else { | |
1435 | winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBorderPixel) | |
1436 | | CWBorderPixmap; | |
1437 | } | |
1438 | } | |
1439 | ||
1440 | void | |
1441 | Tk_DefineCursor(tkwin, cursor) | |
1442 | Tk_Window tkwin; /* Window to manipulate. */ | |
1443 | Cursor cursor; /* Cursor to use for window (may be None). */ | |
1444 | { | |
1445 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1446 | ||
1447 | winPtr->atts.cursor = cursor; | |
1448 | ||
1449 | if (winPtr->window != None) { | |
1450 | XDefineCursor(winPtr->display, winPtr->window, cursor); | |
1451 | } else { | |
1452 | winPtr->dirtyAtts = winPtr->dirtyAtts | CWCursor; | |
1453 | } | |
1454 | } | |
1455 | ||
1456 | void | |
1457 | Tk_UndefineCursor(tkwin) | |
1458 | Tk_Window tkwin; /* Window to manipulate. */ | |
1459 | { | |
1460 | Tk_DefineCursor(tkwin, None); | |
1461 | } | |
1462 | \f | |
1463 | /* | |
1464 | *---------------------------------------------------------------------- | |
1465 | * | |
1466 | * DoConfigureNotify -- | |
1467 | * | |
1468 | * Generate a ConfigureNotify event describing the current | |
1469 | * configuration of a window. | |
1470 | * | |
1471 | * Results: | |
1472 | * None. | |
1473 | * | |
1474 | * Side effects: | |
1475 | * An event is generated and processed by Tk_HandleEvent. | |
1476 | * | |
1477 | *---------------------------------------------------------------------- | |
1478 | */ | |
1479 | ||
1480 | static void | |
1481 | DoConfigureNotify(winPtr) | |
1482 | register TkWindow *winPtr; /* Window whose configuration | |
1483 | * was just changed. */ | |
1484 | { | |
1485 | XEvent event; | |
1486 | ||
1487 | event.type = ConfigureNotify; | |
1488 | event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display); | |
1489 | event.xconfigure.send_event = False; | |
1490 | event.xconfigure.display = winPtr->display; | |
1491 | event.xconfigure.event = winPtr->window; | |
1492 | event.xconfigure.window = winPtr->window; | |
1493 | event.xconfigure.x = winPtr->changes.x; | |
1494 | event.xconfigure.y = winPtr->changes.y; | |
1495 | event.xconfigure.width = winPtr->changes.width; | |
1496 | event.xconfigure.height = winPtr->changes.height; | |
1497 | event.xconfigure.border_width = winPtr->changes.border_width; | |
1498 | if (winPtr->changes.stack_mode == Above) { | |
1499 | event.xconfigure.above = winPtr->changes.sibling; | |
1500 | } else { | |
1501 | event.xconfigure.above = None; | |
1502 | } | |
1503 | event.xconfigure.override_redirect = winPtr->atts.override_redirect; | |
1504 | Tk_HandleEvent(&event); | |
1505 | } | |
1506 | \f | |
1507 | /* | |
1508 | *---------------------------------------------------------------------- | |
1509 | * | |
1510 | * Tk_SetClass -- | |
1511 | * | |
1512 | * This procedure is used to give a window a class. | |
1513 | * | |
1514 | * Results: | |
1515 | * None. | |
1516 | * | |
1517 | * Side effects: | |
1518 | * A new class is stored for tkwin, replacing any existing | |
1519 | * class for it. | |
1520 | * | |
1521 | *---------------------------------------------------------------------- | |
1522 | */ | |
1523 | ||
1524 | void | |
1525 | Tk_SetClass(tkwin, className) | |
1526 | Tk_Window tkwin; /* Token for window to assign class. */ | |
1527 | char *className; /* New class for tkwin. */ | |
1528 | { | |
1529 | register TkWindow *winPtr = (TkWindow *) tkwin; | |
1530 | ||
1531 | winPtr->classUid = Tk_GetUid(className); | |
1532 | if (winPtr->flags & TK_TOP_LEVEL) { | |
1533 | TkWmSetClass(winPtr); | |
1534 | } | |
1535 | } | |
1536 | \f | |
1537 | /* | |
1538 | *---------------------------------------------------------------------- | |
1539 | * | |
1540 | * Tk_NameToWindow -- | |
1541 | * | |
1542 | * Given a string name for a window, this procedure | |
1543 | * returns the token for the window, if there exists a | |
1544 | * window corresponding to the given name. | |
1545 | * | |
1546 | * Results: | |
1547 | * The return result is either a token for the window corresponding | |
1548 | * to "name", or else NULL to indicate that there is no such | |
1549 | * window. In this case, an error message is left in interp->result. | |
1550 | * | |
1551 | * Side effects: | |
1552 | * None. | |
1553 | * | |
1554 | *---------------------------------------------------------------------- | |
1555 | */ | |
1556 | ||
1557 | Tk_Window | |
1558 | Tk_NameToWindow(interp, pathName, tkwin) | |
1559 | Tcl_Interp *interp; /* Where to report errors. */ | |
1560 | char *pathName; /* Path name of window. */ | |
1561 | Tk_Window tkwin; /* Token for window: name is assumed to | |
1562 | * belong to the same main window as tkwin. */ | |
1563 | { | |
1564 | Tcl_HashEntry *hPtr; | |
1565 | ||
1566 | hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable, | |
1567 | pathName); | |
1568 | if (hPtr == NULL) { | |
1569 | Tcl_AppendResult(interp, "bad window path name \"", | |
1570 | pathName, "\"", (char *) NULL); | |
1571 | return NULL; | |
1572 | } | |
1573 | return (Tk_Window) Tcl_GetHashValue(hPtr); | |
1574 | } | |
1575 | \f | |
1576 | /* | |
1577 | *---------------------------------------------------------------------- | |
1578 | * | |
1579 | * Tk_DisplayName -- | |
1580 | * | |
1581 | * Return the textual name of a window's display. | |
1582 | * | |
1583 | * Results: | |
1584 | * The return value is the string name of the display associated | |
1585 | * with tkwin. | |
1586 | * | |
1587 | * Side effects: | |
1588 | * None. | |
1589 | * | |
1590 | *---------------------------------------------------------------------- | |
1591 | */ | |
1592 | ||
1593 | char * | |
1594 | Tk_DisplayName(tkwin) | |
1595 | Tk_Window tkwin; /* Window whose display name is desired. */ | |
1596 | { | |
1597 | return ((TkWindow *) tkwin)->dispPtr->name; | |
1598 | } |