4 * This file provides basic window-manipulation procedures.
6 * Copyright (c) 1995-2001 Christian Werner.
8 * See the file "license.terms" for information on usage and redistribution
9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
23 CkMainInfo *ckMainInfo = NULL;
28 * Curses input event handling information.
38 static InputInfo inputInfo = {
45 static void InputSetup _ANSI_ARGS_((InputInfo *inputInfo));
46 static void InputExit _ANSI_ARGS_((ClientData clientData));
47 static void InputThread _ANSI_ARGS_((void *arg));
48 static LRESULT CALLBACK InputHandler _ANSI_ARGS_((HWND hwnd, UINT message,
51 static void InputHandler2 _ANSI_ARGS_((ClientData clientData));
55 * The variables below hold several uid's that are used in many places
59 Ck_Uid ckDisabledUid = NULL;
60 Ck_Uid ckActiveUid = NULL;
61 Ck_Uid ckNormalUid = NULL;
64 * The following structure defines all of the commands supported by
65 * the toolkit, and the C procedures that execute them.
68 typedef int (CkCmdProc) _ANSI_ARGS_((ClientData clientData,
70 int argc, char **argv));
73 char *name; /* Name of command. */
74 CkCmdProc *cmdProc; /* Command procedure. */
79 * Commands that are part of the intrinsics:
82 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
83 {"after", Tk_AfterCmd},
87 {"bindtags", Ck_BindtagsCmd},
88 {"curses", Ck_CursesCmd},
89 {"destroy", Ck_DestroyCmd},
91 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
92 {"fileevent", Tk_FileeventCmd},
94 {"focus", Ck_FocusCmd},
96 {"lower", Ck_LowerCmd},
97 {"option", Ck_OptionCmd},
99 {"place", Ck_PlaceCmd},
100 {"raise", Ck_RaiseCmd},
101 {"recorder", Ck_RecorderCmd},
102 {"tkwait", Ck_TkwaitCmd},
103 {"update", Ck_UpdateCmd},
104 {"winfo", Ck_WinfoCmd},
107 * Widget-creation commands.
110 {"button", Ck_ButtonCmd},
111 {"checkbutton", Ck_ButtonCmd},
112 {"entry", Ck_EntryCmd},
113 {"frame", Ck_FrameCmd},
114 {"label", Ck_ButtonCmd},
115 {"listbox", Ck_ListboxCmd},
116 {"menu", Ck_MenuCmd},
117 {"menubutton", Ck_MenubuttonCmd},
118 {"message", Ck_MessageCmd},
119 {"radiobutton", Ck_ButtonCmd},
120 {"scrollbar", Ck_ScrollbarCmd},
121 {"text", Ck_TextCmd},
122 {"toplevel", Ck_FrameCmd},
123 {"tree", Ck_TreeCmd},
125 {(char *) NULL, (CkCmdProc *) NULL}
129 * Static procedures of this module.
132 static void UnlinkWindow _ANSI_ARGS_((CkWindow *winPtr));
133 static void UnlinkToplevel _ANSI_ARGS_((CkWindow *winPtr));
134 static void ChangeToplevelFocus _ANSI_ARGS_((CkWindow *winPtr));
135 static void DoRefresh _ANSI_ARGS_((ClientData clientData));
136 static void RefreshToplevels _ANSI_ARGS_((CkWindow *winPtr));
137 static void RefreshThem _ANSI_ARGS_((CkWindow *winPtr));
138 static void UpdateHWCursor _ANSI_ARGS_((CkMainInfo *mainPtr));
139 static CkWindow *GetWindowXY _ANSI_ARGS_((CkWindow *winPtr, int *xPtr,
141 static int DeadAppCmd _ANSI_ARGS_((ClientData clientData,
142 Tcl_Interp *interp, int argc, char **argv));
143 static int ExecCmd _ANSI_ARGS_((ClientData clientData,
144 Tcl_Interp *interp, int argc, char **argv));
145 static int PutsCmd _ANSI_ARGS_((ClientData clientData,
146 Tcl_Interp *interp, int argc, char **argv));
147 static int CloseCmd _ANSI_ARGS_((ClientData clientData,
148 Tcl_Interp *interp, int argc, char **argv));
149 static int FlushCmd _ANSI_ARGS_((ClientData clientData,
150 Tcl_Interp *interp, int argc, char **argv));
151 static int ReadCmd _ANSI_ARGS_((ClientData clientData,
152 Tcl_Interp *interp, int argc, char **argv));
153 static int GetsCmd _ANSI_ARGS_((ClientData clientData,
154 Tcl_Interp *interp, int argc, char **argv));
157 * Some plain Tcl commands are handled specially.
160 CkCmd redirCommands[] = {
169 {(char *) NULL, (CkCmdProc *) NULL}
173 * The following structure is used as ClientData for redirected
174 * plain Tcl commands.
183 *--------------------------------------------------------------
187 * This procedure creates and initializes a CkWindow structure.
190 * The return value is a pointer to the new window.
193 * A new window structure is allocated and all its fields are
196 *--------------------------------------------------------------
205 winPtr = (CkWindow *) ckalloc(sizeof (CkWindow));
206 winPtr->window = NULL;
207 winPtr->childList = NULL;
208 winPtr->lastChildPtr = NULL;
209 winPtr->parentPtr = NULL;
210 winPtr->nextPtr = NULL;
211 winPtr->topLevPtr = NULL;
212 winPtr->mainPtr = NULL;
213 winPtr->pathName = NULL;
214 winPtr->nameUid = NULL;
215 winPtr->classUid = NULL;
216 winPtr->handlerList = NULL;
217 winPtr->tagPtr = NULL;
219 winPtr->focusPtr = NULL;
220 winPtr->geomMgrPtr = NULL;
221 winPtr->geomData = NULL;
222 winPtr->optionLevel = -1;
223 winPtr->reqWidth = winPtr->reqHeight = 1;
224 winPtr->x = winPtr->y = 0;
225 winPtr->width = winPtr->height = 1;
226 winPtr->fg = COLOR_WHITE;
227 winPtr->bg = COLOR_BLACK;
228 winPtr->attr = A_NORMAL;
235 *----------------------------------------------------------------------
239 * This procedure is invoked to give a window a name and insert
240 * the window into the hierarchy associated with a particular
244 * A standard Tcl return value.
249 *----------------------------------------------------------------------
253 NameWindow(interp, winPtr, parentPtr, name)
254 Tcl_Interp *interp; /* Interpreter to use for error reporting. */
255 CkWindow *winPtr; /* Window that is to be named and inserted. */
256 CkWindow *parentPtr; /* Pointer to logical parent for winPtr
257 * (used for naming, options, etc.). */
258 char *name; /* Name for winPtr; must be unique among
259 * parentPtr's children. */
261 #define FIXED_SIZE 200
262 char staticSpace[FIXED_SIZE];
266 int length1, length2;
269 * Setup all the stuff except name right away, then do the name stuff
270 * last. This is so that if the name stuff fails, everything else
271 * will be properly initialized (needed to destroy the window cleanly
272 * after the naming failure).
274 winPtr->parentPtr = parentPtr;
275 winPtr->nextPtr = NULL;
276 if (parentPtr->childList == NULL) {
277 parentPtr->lastChildPtr = winPtr;
278 parentPtr->childList = winPtr;
280 parentPtr->lastChildPtr->nextPtr = winPtr;
281 parentPtr->lastChildPtr = winPtr;
283 winPtr->mainPtr = parentPtr->mainPtr;
284 winPtr->nameUid = Ck_GetUid(name);
287 * Don't permit names that start with an upper-case letter: this
288 * will just cause confusion with class names in the option database.
291 if (isupper((unsigned char) name[0])) {
292 Tcl_AppendResult(interp,
293 "window name starts with an upper-case letter: \"",
294 name, "\"", (char *) NULL);
299 * To permit names of arbitrary length, must be prepared to malloc
300 * a buffer to hold the new path name. To run fast in the common
301 * case where names are short, use a fixed-size buffer on the
305 length1 = strlen(parentPtr->pathName);
306 length2 = strlen(name);
307 if ((length1+length2+2) <= FIXED_SIZE) {
308 pathName = staticSpace;
310 pathName = (char *) ckalloc((unsigned) (length1+length2+2));
314 strcpy(pathName+1, name);
316 strcpy(pathName, parentPtr->pathName);
317 pathName[length1] = '.';
318 strcpy(pathName+length1+1, name);
320 hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new);
321 if (pathName != staticSpace) {
325 Tcl_AppendResult(interp, "window name \"", name,
326 "\" already exists in parent", (char *) NULL);
329 Tcl_SetHashValue(hPtr, winPtr);
330 winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr);
331 Tcl_CreateHashEntry(&parentPtr->mainPtr->winTable, (char *) winPtr, &new);
336 *----------------------------------------------------------------------
340 * Returns the main window for an application.
343 * If interp is associated with the main window, the main
344 * window is returned. Otherwise NULL is returned and an
345 * error message is left in interp->result.
350 *----------------------------------------------------------------------
354 Ck_MainWindow(interp)
355 Tcl_Interp *interp; /* Interpreter that embodies application,
356 * also used for error reporting. */
358 if (ckMainInfo == NULL || ckMainInfo->interp != interp) {
360 interp->result = "no main window for application.";
363 return ckMainInfo->winPtr;
367 *----------------------------------------------------------------------
369 * Ck_CreateMainWindow --
371 * Make the main window.
374 * The return value is a token for the new window, or NULL if
375 * an error prevented the new window from being created. If
376 * NULL is returned, an error message will be left in
380 * A new window structure is allocated locally.
382 *----------------------------------------------------------------------
386 Ck_CreateMainWindow(interp, className)
387 Tcl_Interp *interp; /* Interpreter to use for error reporting. */
388 char *className; /* Class name of the new main window. */
396 #ifdef HAVE_SIGACTION
397 struct sigaction oldsig, newsig;
399 Ck_SignalProc sigproc;
402 #ifdef NCURSES_MOUSE_VERSION
409 * For now, only one main window may exists for the application.
411 if (ckMainInfo != NULL)
415 * Create the basic CkWindow structure.
418 winPtr = NewWindow(NULL);
421 * Create the CkMainInfo structure for this application, and set
422 * up name-related information for the new window.
425 mainPtr = (CkMainInfo *) ckalloc(sizeof(CkMainInfo));
426 mainPtr->winPtr = winPtr;
427 mainPtr->interp = interp;
428 Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS);
429 Tcl_InitHashTable(&mainPtr->winTable, TCL_ONE_WORD_KEYS);
430 mainPtr->topLevPtr = NULL;
431 mainPtr->focusPtr = winPtr;
432 mainPtr->bindingTable = Ck_CreateBindingTable(interp);
433 mainPtr->optionRootPtr = NULL;
434 mainPtr->refreshCount = 0;
435 mainPtr->refreshDelay = 0;
436 mainPtr->lastRefresh = 0;
437 mainPtr->refreshTimer = NULL;
439 ckMainInfo = mainPtr;
440 winPtr->mainPtr = mainPtr;
441 winPtr->nameUid = Ck_GetUid(".");
442 winPtr->classUid = Ck_GetUid("Main"); /* ??? */
443 winPtr->flags |= CK_TOPLEVEL;
444 hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, (char *) winPtr->nameUid,
446 Tcl_SetHashValue(hPtr, winPtr);
447 winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr);
448 Tcl_CreateHashEntry(&mainPtr->winTable, (char *) winPtr, &dummy);
450 ckNormalUid = Ck_GetUid("normal");
451 ckDisabledUid = Ck_GetUid("disabled");
452 ckActiveUid = Ck_GetUid("active");
457 char enc[32], *envcp = getenv("CK_USE_ENCODING");
458 unsigned int cp = GetConsoleCP();
460 if (envcp && strncmp(envcp, "cp", 2) == 0) {
461 cp = atoi(envcp + 2);
465 if (GetConsoleOutputCP() != cp) {
466 SetConsoleOutputCP(cp);
468 sprintf(enc, "cp%d", cp);
469 mainPtr->isoEncoding = Tcl_GetEncoding(NULL, enc);
473 * Use default system encoding as suggested by
474 * Anton Kovalenko <a_kovalenko@mtu-net.ru>.
475 * May be overriden by environment variable.
477 mainPtr->isoEncoding = Tcl_GetEncoding(NULL, getenv("CK_USE_ENCODING"));
478 if (mainPtr->isoEncoding == NULL) {
479 mainPtr->isoEncoding = Tcl_GetEncoding(NULL, NULL);
482 if (mainPtr->isoEncoding == NULL) {
483 panic("standard encoding not found");
485 Tcl_DStringInit(&mainPtr->isoBuffer);
488 /* Curses related initialization */
491 /* This is essential for ncurses-1.9.4 */
492 #ifdef HAVE_SIGACTION
493 newsig.sa_handler = SIG_IGN;
494 sigfillset(&newsig.sa_mask);
496 sigaction(SIGTSTP, &newsig, &oldsig);
498 sigproc = (Ck_SignalProc) signal(SIGTSTP, SIG_IGN);
501 if (initscr() == (WINDOW *) ERR) {
502 ckfree((char *) winPtr);
506 /* This is essential for ncurses-1.9.4 */
507 #ifdef HAVE_SIGACTION
508 sigaction(SIGTSTP, &oldsig, NULL);
510 signal(SIGTSTP, sigproc);
516 scrollok(stdscr, FALSE);
517 keypad(stdscr, TRUE);
518 nodelay(stdscr, TRUE);
521 mainPtr->maxWidth = COLS;
522 mainPtr->maxHeight = LINES;
523 winPtr->width = mainPtr->maxWidth;
524 winPtr->height = mainPtr->maxHeight;
525 winPtr->window = newwin(winPtr->height, winPtr->width, 0, 0);
528 mainPtr->flags |= CK_HAS_COLOR;
530 #ifdef NCURSES_MOUSE_VERSION
532 mousemask(BUTTON1_PRESSED | BUTTON1_RELEASED |
533 BUTTON2_PRESSED | BUTTON2_RELEASED |
534 BUTTON3_PRESSED | BUTTON3_RELEASED, NULL);
535 mainPtr->flags |= (getmouse(&mEvent) != ERR) ? CK_HAS_MOUSE : 0;
536 #endif /* NCURSES_MOUSE_VERSION */
538 #if defined(__WIN32__) || defined(__DJGPP__)
539 mouse_set(BUTTON1_PRESSED | BUTTON1_RELEASED |
540 BUTTON2_PRESSED | BUTTON2_RELEASED |
541 BUTTON3_PRESSED | BUTTON3_RELEASED);
542 mainPtr->flags |= CK_HAS_MOUSE;
545 term = getenv("TERM");
546 isxterm = strncmp(term, "xterm", 5) == 0 ||
547 strncmp(term, "rxvt", 4) == 0 ||
548 strncmp(term, "kterm", 5) == 0 ||
549 strncmp(term, "color_xterm", 11) == 0 ||
550 (term[0] != '\0' && strncmp(term + 1, "xterm", 5) == 0);
551 if (!(mainPtr->flags & CK_HAS_MOUSE) && isxterm) {
552 mainPtr->flags |= CK_HAS_MOUSE | CK_MOUSE_XTERM;
554 fputs("\033[?1000h", stdout);
557 #endif /* __WIN32__ */
561 * Some ncurses aren't compiled with GPM support built in,
562 * therefore by setting the following environment variable
563 * usage of GPM can be turned on.
565 if (!isxterm && (mainPtr->flags & CK_HAS_MOUSE)) {
566 char *forcegpm = getenv("CK_USE_GPM");
568 if (forcegpm && strchr("YyTt123456789", forcegpm[0])) {
569 mainPtr->flags &= ~CK_HAS_MOUSE;
572 if (!isxterm && !(mainPtr->flags & CK_HAS_MOUSE)) {
575 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
576 EXTERN int CkHandleGPMInput _ANSI_ARGS_((ClientData clientData,
577 int mask, int flags));
579 EXTERN void CkHandleGPMInput _ANSI_ARGS_((ClientData clientData,
583 conn.eventMask = GPM_DOWN | GPM_UP | GPM_MOVE;
584 conn.defaultMask = 0;
587 fd = Gpm_Open(&conn, 0);
589 mainPtr->flags |= CK_HAS_MOUSE;
590 #if (TCL_MAJOR_VERSION >= 8)
591 mainPtr->mouseData = (ClientData) fd;
592 Tcl_CreateFileHandler(fd, TCL_READABLE,
593 CkHandleGPMInput, (ClientData) mainPtr);
595 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
596 mainPtr->mouseData = (ClientData) fd;
597 Tk_CreateFileHandler2(fd, CkHandleGPMInput, (ClientData) mainPtr);
599 mainPtr->mouseData = (ClientData)
600 Tcl_GetFile((ClientData) fd, TCL_UNIX_FD);
601 Tcl_CreateFileHandler((Tcl_File) mainPtr->mouseData, TCL_READABLE,
602 CkHandleGPMInput, (ClientData) mainPtr);
607 #endif /* HAVE_GPM */
610 /* PDCurses specific !!! */
611 inputInfo.mainPtr = mainPtr;
612 inputInfo.stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
614 SetConsoleMode(inputInfo.stdinHandle,
615 ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
616 InputSetup(&inputInfo);
618 #if (TCL_MAJOR_VERSION >= 8)
619 Tcl_CreateFileHandler(0,
620 TCL_READABLE, CkHandleInput, (ClientData) mainPtr);
622 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
623 Tk_CreateFileHandler2(0, CkHandleInput, (ClientData) mainPtr);
625 Tcl_CreateFileHandler(Tcl_GetFile((ClientData) 0, TCL_UNIX_FD),
626 TCL_READABLE, CkHandleInput, (ClientData) mainPtr);
631 idlok(winPtr->window, TRUE);
632 scrollok(winPtr->window, FALSE);
633 keypad(winPtr->window, TRUE);
634 nodelay(winPtr->window, TRUE);
635 meta(winPtr->window, TRUE);
637 while (getch() != ERR) {
638 /* empty loop body. */
640 winPtr->flags |= CK_MAPPED;
641 Ck_SetWindowAttr(winPtr, winPtr->fg, winPtr->bg, winPtr->attr);
642 Ck_ClearToBot(winPtr, 0, 0);
643 Ck_EventuallyRefresh(winPtr);
646 * Bind in Ck's commands.
649 for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
650 Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc,
651 (ClientData) winPtr, (Tcl_CmdDeleteProc *) NULL);
655 * Redirect some critical Tcl commands to our own procedures
657 for (cmdPtr = redirCommands; cmdPtr->name != NULL; cmdPtr++) {
658 RedirInfo *redirInfo;
659 #if (TCL_MAJOR_VERSION >= 8)
661 extern int TclRenameCommand _ANSI_ARGS_((Tcl_Interp *interp,
662 char *oldName, char *newName));
664 redirInfo = (RedirInfo *) ckalloc(sizeof (RedirInfo));
665 redirInfo->mainPtr = mainPtr;
666 Tcl_GetCommandInfo(interp, cmdPtr->name, &redirInfo->cmdInfo);
667 #if (TCL_MAJOR_VERSION >= 8)
668 Tcl_DStringInit(&cmdName);
669 Tcl_DStringAppend(&cmdName, "____", -1);
670 Tcl_DStringAppend(&cmdName, cmdPtr->name, -1);
671 TclRenameCommand(interp, cmdPtr->name, Tcl_DStringValue(&cmdName));
672 Tcl_DStringFree(&cmdName);
674 Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc,
675 (ClientData) redirInfo, (Tcl_CmdDeleteProc *) free);
679 * Set variables for the intepreter.
682 #if (TCL_MAJOR_VERSION < 8)
683 if (Tcl_GetVar(interp, "ck_library", TCL_GLOBAL_ONLY) == NULL) {
685 * A library directory hasn't already been set, so figure out
689 char *libDir = getenv("CK_LIBRARY");
691 if (libDir == NULL) {
694 Tcl_SetVar(interp, "ck_library", libDir, TCL_GLOBAL_ONLY);
697 Tcl_SetVar(interp, "ck_version", CK_VERSION, TCL_GLOBAL_ONLY);
700 * Make main window into a frame widget.
703 Ck_SetClass(winPtr, className);
704 CkInitFrame(interp, winPtr, 0, NULL);
705 mainPtr->topLevPtr = winPtr;
706 winPtr->focusPtr = winPtr;
711 *----------------------------------------------------------------------
715 * This procedure is invoked to add Ck to an interpreter. It
716 * incorporates all of Ck's commands into the interpreter and
717 * creates the main window for a new Ck application.
720 * Returns a standard Tcl completion code and sets interp->result
721 * if there is an error.
724 * Depends on what's in the ck.tcl script.
726 *----------------------------------------------------------------------
731 Tcl_Interp *interp; /* Interpreter to initialize. */
733 CkWindow *mainWindow;
734 char *p, *name, *class;
736 static char initCmd[] =
737 #if (TCL_MAJOR_VERSION >= 8)
739 global ck_library ck_version\n\
741 tcl_findLibrary ck $ck_version 0 ck.tcl CK_LIBRARY ck_library\n\
746 global ck_library ck_version env\n\
749 if [info exists env(CK_LIBRARY)] {\n\
750 lappend dirs $env(CK_LIBRARY)\n\
752 lappend dirs $ck_library\n\
753 lappend dirs [file dirname [info library]]/lib/ck$ck_version\n\
754 catch {lappend dirs [file dirname [file dirname \\\n\
755 [info nameofexecutable]]]/lib/ck$ck_version}\n\
756 set lib ck$ck_version\n\
757 lappend dirs [file dirname [file dirname [pwd]]]/$lib/library\n\
758 lappend dirs [file dirname [file dirname [info library]]]/$lib/library\n\
759 lappend dirs [file dirname [pwd]]/library\n\
762 if ![catch {uplevel #0 source $i/ck.tcl}] {\n\
766 set msg \"Can't find a usable ck.tcl in the following directories: \n\"\n\
767 append msg \" $dirs\n\"\n\
768 append msg \"This probably means that Ck wasn't installed properly.\n\"\n\
774 p = Tcl_GetVar(interp, "argv0", TCL_GLOBAL_ONLY);
775 if (p == NULL || *p == '\0')
777 name = strrchr(p, '/');
782 class = (char *) ckalloc((unsigned) (strlen(name) + 1));
784 class[0] = toupper((unsigned char) class[0]);
785 mainWindow = Ck_CreateMainWindow(interp, class);
788 #if !((TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4))
789 if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL)
791 code = Tcl_PkgProvide(interp, "Ck", CK_VERSION);
795 return Tcl_Eval(interp, initCmd);
799 *--------------------------------------------------------------
803 * Create a new window as a child of an existing window.
806 * The return value is the pointer to the new window.
807 * If an error occurred in creating the window, then an
808 * error message is left in interp->result and NULL is
812 * A new window structure is allocated locally. A curses
813 * window is not initially created, but will be created
814 * the first time the window is mapped.
816 *--------------------------------------------------------------
820 Ck_CreateWindow(interp, parentPtr, name, toplevel)
821 Tcl_Interp *interp; /* Interpreter to use for error reporting.
822 * Interp->result is assumed to be
823 * initialized by the caller. */
824 CkWindow *parentPtr; /* Parent of new window. */
825 char *name; /* Name for new window. Must be unique
826 * among parent's children. */
827 int toplevel; /* If true, create toplevel window. */
831 winPtr = NewWindow(parentPtr);
832 if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) {
833 Ck_DestroyWindow(winPtr);
839 winPtr->flags |= CK_TOPLEVEL;
840 winPtr->focusPtr = winPtr;
841 if (winPtr->mainPtr->topLevPtr == NULL) {
842 winPtr->topLevPtr = winPtr->mainPtr->topLevPtr;
843 winPtr->mainPtr->topLevPtr = winPtr;
845 for (wPtr = winPtr->mainPtr->topLevPtr; wPtr->topLevPtr != NULL;
846 wPtr = wPtr->topLevPtr) {
847 /* Empty loop body. */
849 winPtr->topLevPtr = wPtr->topLevPtr;
850 wPtr->topLevPtr = winPtr;
857 *----------------------------------------------------------------------
859 * Ck_CreateWindowFromPath --
861 * This procedure is similar to Ck_CreateWindow except that
862 * it uses a path name to create the window, rather than a
863 * parent and a child name.
866 * The return value is the pointer to the new window.
867 * If an error occurred in creating the window, then an
868 * error message is left in interp->result and NULL is
872 * A new window structure is allocated locally. A curses
873 * window is not initially created, but will be created
874 * the first time the window is mapped.
876 *----------------------------------------------------------------------
880 Ck_CreateWindowFromPath(interp, anywin, pathName, toplevel)
881 Tcl_Interp *interp; /* Interpreter to use for error reporting.
882 * Interp->result is assumed to be
883 * initialized by the caller. */
884 CkWindow *anywin; /* Pointer to any window in application
885 * that is to contain new window. */
886 char *pathName; /* Path name for new window within the
887 * application of anywin. The parent of
888 * this window must already exist, but
889 * the window itself must not exist. */
890 int toplevel; /* If true, create toplevel window. */
892 #define FIXED_SPACE 5
893 char fixedSpace[FIXED_SPACE+1];
895 CkWindow *parentPtr, *winPtr;
899 * Strip the parent's name out of pathName (it's everything up
900 * to the last dot). There are two tricky parts: (a) must
901 * copy the parent's name somewhere else to avoid modifying
902 * the pathName string (for large names, space for the copy
903 * will have to be malloc'ed); (b) must special-case the
904 * situation where the parent is ".".
907 p = strrchr(pathName, '.');
909 Tcl_AppendResult(interp, "bad window path name \"", pathName,
910 "\"", (char *) NULL);
913 numChars = p - pathName;
914 if (numChars > FIXED_SPACE) {
915 p = (char *) ckalloc((unsigned) (numChars+1));
923 strncpy(p, pathName, numChars);
928 * Find the parent window.
931 parentPtr = Ck_NameToWindow(interp, p, anywin);
932 if (p != fixedSpace) {
935 if (parentPtr == NULL)
942 winPtr = NewWindow(parentPtr);
943 if (NameWindow(interp, winPtr, parentPtr, pathName + numChars + 1)
945 Ck_DestroyWindow(winPtr);
951 winPtr->flags |= CK_TOPLEVEL;
952 winPtr->focusPtr = winPtr;
953 if (winPtr->mainPtr->topLevPtr == NULL) {
954 winPtr->topLevPtr = winPtr->mainPtr->topLevPtr;
955 winPtr->mainPtr->topLevPtr = winPtr;
957 for (wPtr = winPtr->mainPtr->topLevPtr; wPtr->topLevPtr != NULL;
958 wPtr = wPtr->topLevPtr) {
959 /* Empty loop body. */
961 winPtr->topLevPtr = wPtr->topLevPtr;
962 wPtr->topLevPtr = winPtr;
969 *--------------------------------------------------------------
971 * Ck_DestroyWindow --
973 * Destroy an existing window. After this call, the caller
974 * should never again use the pointer.
980 * The window is deleted, along with all of its children.
981 * Relevant callback procedures are invoked.
983 *--------------------------------------------------------------
987 Ck_DestroyWindow(winPtr)
988 CkWindow *winPtr; /* Window to destroy. */
992 #ifdef NCURSES_MOUSE_VERSION
996 if (winPtr->flags & CK_ALREADY_DEAD)
998 winPtr->flags |= CK_ALREADY_DEAD;
1001 * Recursively destroy children. The CK_RECURSIVE_DESTROY
1002 * flags means that the child's window needn't be explicitly
1003 * destroyed (the destroy of the parent already did it), nor
1004 * does it need to be removed from its parent's child list,
1005 * since the parent is being destroyed too.
1008 while (winPtr->childList != NULL) {
1009 winPtr->childList->flags |= CK_RECURSIVE_DESTROY;
1010 Ck_DestroyWindow(winPtr->childList);
1012 if (winPtr->mainPtr->focusPtr == winPtr) {
1013 event.type = CK_EV_FOCUSOUT;
1014 event.winPtr = winPtr;
1015 Ck_HandleEvent(winPtr->mainPtr, (CkEvent *) &event);
1017 if (winPtr->window != NULL) {
1018 delwin(winPtr->window);
1019 winPtr->window = NULL;
1021 CkOptionDeadWindow(winPtr);
1022 event.type = CK_EV_DESTROY;
1023 event.winPtr = winPtr;
1024 Ck_HandleEvent(winPtr->mainPtr, (CkEvent *) &event);
1025 if (winPtr->tagPtr != NULL) {
1026 CkFreeBindingTags(winPtr);
1028 UnlinkWindow(winPtr);
1029 CkEventDeadWindow(winPtr);
1030 hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->winTable, (char *) winPtr);
1032 Tcl_DeleteHashEntry(hPtr);
1033 if (winPtr->pathName != NULL) {
1034 CkMainInfo *mainPtr = winPtr->mainPtr;
1036 Ck_DeleteAllBindings(mainPtr->bindingTable,
1037 (ClientData) winPtr->pathName);
1038 Tcl_DeleteHashEntry(Tcl_FindHashEntry(&mainPtr->nameTable,
1040 if (mainPtr->winPtr == winPtr) {
1043 for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++)
1044 if (cmdPtr->cmdProc != Ck_ExitCmd)
1045 Tcl_CreateCommand(mainPtr->interp, cmdPtr->name,
1046 DeadAppCmd, (ClientData) NULL,
1047 (Tcl_CmdDeleteProc *) NULL);
1048 Tcl_DeleteHashTable(&mainPtr->nameTable);
1049 Ck_DeleteBindingTable(mainPtr->bindingTable);
1051 #ifdef NCURSES_MOUSE_VERSION
1053 mainPtr->flags &= (getmouse(&mEvent) != ERR) ? ~CK_HAS_MOUSE : ~0;
1054 #endif /* NCURSES_MOUSE_VERSION */
1056 if (mainPtr->flags & CK_HAS_MOUSE) {
1057 #if defined(__WIN32__) || defined(__DJGPP__)
1060 if (mainPtr->flags & CK_MOUSE_XTERM) {
1062 fputs("\033[?1000l", stdout);
1066 #if (TCL_MAJOR_VERSION >= 8)
1067 Tcl_DeleteFileHandler((int) mainPtr->mouseData);
1069 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
1070 Tk_DeleteFileHandler((int) mainPtr->mouseData);
1072 Tcl_DeleteFileHandler((Tcl_File) mainPtr->mouseData);
1081 if (mainPtr->flags & CK_NOCLR_ON_EXIT) {
1082 wattrset(stdscr, A_NORMAL);
1089 Tcl_DStringFree(&mainPtr->isoBuffer);
1090 Tcl_FreeEncoding(mainPtr->isoEncoding);
1092 ckfree((char *) mainPtr);
1097 if (winPtr->flags & CK_TOPLEVEL) {
1098 UnlinkToplevel(winPtr);
1099 ChangeToplevelFocus(winPtr->mainPtr->topLevPtr);
1100 } else if (winPtr->mainPtr->focusPtr == winPtr) {
1101 winPtr->mainPtr->focusPtr = winPtr->parentPtr;
1102 if (winPtr->mainPtr->focusPtr != NULL &&
1103 (winPtr->mainPtr->focusPtr->flags & CK_MAPPED)) {
1104 event.type = CK_EV_FOCUSIN;
1105 event.winPtr = winPtr->mainPtr->focusPtr;
1106 Ck_HandleEvent(winPtr->mainPtr, (CkEvent *) &event);
1111 for (topPtr = winPtr; topPtr != NULL && !(topPtr->flags & CK_TOPLEVEL);
1112 topPtr = topPtr->parentPtr) {
1113 /* Empty loop body. */
1115 if (topPtr->focusPtr == winPtr)
1116 topPtr->focusPtr = winPtr->parentPtr;
1118 Ck_EventuallyRefresh(winPtr);
1120 ckfree((char *) winPtr);
1124 *--------------------------------------------------------------
1128 * Map a window within its parent. This may require the
1129 * window and/or its parents to actually be created.
1135 * The given window will be mapped. Windows may also
1138 *--------------------------------------------------------------
1142 Ck_MapWindow(winPtr)
1143 CkWindow *winPtr; /* Pointer to window to map. */
1145 if (winPtr == NULL || (winPtr->flags & CK_MAPPED))
1147 if (!(winPtr->parentPtr->flags & CK_MAPPED))
1149 if (winPtr->window == NULL)
1150 Ck_MakeWindowExist(winPtr);
1154 *--------------------------------------------------------------
1156 * Ck_MakeWindowExist --
1158 * Ensure that a particular window actually exists.
1164 * When the procedure returns, the curses window associated
1165 * with winPtr is guaranteed to exist. This may require the
1166 * window's ancestors to be created also.
1168 *--------------------------------------------------------------
1172 Ck_MakeWindowExist(winPtr)
1173 CkWindow *winPtr; /* Pointer to window. */
1176 CkMainInfo *mainPtr;
1177 CkWindow *parentPtr;
1178 CkWindowEvent event;
1180 if (winPtr == NULL || winPtr->window != NULL)
1183 mainPtr = winPtr->mainPtr;
1184 if (winPtr->parentPtr->window == NULL)
1185 Ck_MakeWindowExist(winPtr->parentPtr);
1187 if (winPtr->x >= mainPtr->maxWidth)
1188 winPtr->x = mainPtr->maxWidth - 1;
1191 if (winPtr->y >= mainPtr->maxHeight)
1192 winPtr->y = mainPtr->maxHeight - 1;
1199 if (!(winPtr->flags & CK_TOPLEVEL)) {
1200 parentPtr = winPtr->parentPtr;
1203 else if (x >= parentPtr->width)
1204 x = winPtr->x = parentPtr->width - 1;
1207 else if (y >= parentPtr->height)
1208 y = winPtr->y = parentPtr->height - 1;
1209 if (x + winPtr->width >= parentPtr->width)
1210 winPtr->width = parentPtr->width - x;
1211 if (y + winPtr->height >= parentPtr->height)
1212 winPtr->height = parentPtr->height - y;
1214 while ((parentPtr = parentPtr->parentPtr) != NULL) {
1217 if (parentPtr->flags & CK_TOPLEVEL)
1221 if (winPtr->width <= 0)
1223 if (winPtr->height <= 0)
1226 winPtr->window = newwin(winPtr->height, winPtr->width, y, x);
1227 idlok(winPtr->window, TRUE);
1228 scrollok(winPtr->window, FALSE);
1229 keypad(winPtr->window, TRUE);
1230 nodelay(winPtr->window, TRUE);
1231 meta(winPtr->window, TRUE);
1232 winPtr->flags |= CK_MAPPED;
1233 Ck_ClearToBot(winPtr, 0, 0);
1234 Ck_SetWindowAttr(winPtr, winPtr->fg, winPtr->bg, winPtr->attr);
1235 Ck_EventuallyRefresh(winPtr);
1237 event.type = CK_EV_MAP;
1238 event.winPtr = winPtr;
1239 Ck_HandleEvent(mainPtr, (CkEvent *) &event);
1240 event.type = CK_EV_EXPOSE;
1241 event.winPtr = winPtr;
1242 Ck_HandleEvent(mainPtr, (CkEvent *) &event);
1243 if (winPtr == mainPtr->focusPtr) {
1244 event.type = CK_EV_FOCUSIN;
1245 event.winPtr = winPtr;
1246 Ck_HandleEvent(mainPtr, (CkEvent *) &event);
1251 *--------------------------------------------------------------
1255 * Move given window and its children.
1263 *--------------------------------------------------------------
1267 Ck_MoveWindow(winPtr, x, y)
1268 CkWindow *winPtr; /* Window to move. */
1269 int x, y; /* New location for window (within
1272 CkWindow *childPtr, *parentPtr;
1280 if (winPtr->window == NULL)
1285 if (!(winPtr->flags & CK_TOPLEVEL)) {
1287 while ((parentPtr = parentPtr->parentPtr) != NULL) {
1288 newx += parentPtr->x;
1289 newy += parentPtr->y;
1290 if (parentPtr->flags & CK_TOPLEVEL)
1294 if (newx + winPtr->width >= winPtr->mainPtr->maxWidth) {
1295 winPtr->x -= newx - (winPtr->mainPtr->maxWidth - winPtr->width);
1296 newx = winPtr->mainPtr->maxWidth - winPtr->width;
1298 if (newy + winPtr->height >= winPtr->mainPtr->maxHeight) {
1299 winPtr->y -= newy - (winPtr->mainPtr->maxHeight - winPtr->height);
1300 newy = winPtr->mainPtr->maxHeight - winPtr->height;
1311 mvwin(winPtr->window, newy, newx);
1313 for (childPtr = winPtr->childList;
1314 childPtr != NULL; childPtr = childPtr->nextPtr)
1315 if (!(childPtr->flags & CK_TOPLEVEL))
1316 Ck_MoveWindow(childPtr, childPtr->x, childPtr->y);
1317 Ck_EventuallyRefresh(winPtr);
1321 *--------------------------------------------------------------
1323 * Ck_ResizeWindow --
1325 * Resize given window and eventually its children.
1333 *--------------------------------------------------------------
1337 Ck_ResizeWindow(winPtr, width, height)
1338 CkWindow *winPtr; /* Window to resize. */
1339 int width, height; /* New dimensions for window. */
1341 CkWindow *childPtr, *parentPtr;
1342 CkWindow *mainWin = winPtr->mainPtr->winPtr;
1343 CkWindowEvent event;
1345 int x, y, evMap = 0, doResize = 0;
1347 if (winPtr == NULL || winPtr == mainWin)
1351 * Special case: if both width/height set to -12345, adjust
1352 * within parent window !
1355 parentPtr = winPtr->parentPtr;
1356 if (!(width == -12345 && height == -12345)) {
1357 winPtr->width = width;
1358 winPtr->height = height;
1362 if (!(winPtr->flags & CK_TOPLEVEL)) {
1363 if (winPtr->x + winPtr->width >= parentPtr->width) {
1364 winPtr->width = parentPtr->width - winPtr->x;
1367 if (winPtr->y + winPtr->height >= parentPtr->height) {
1368 winPtr->height = parentPtr->height - winPtr->y;
1375 if (winPtr->window == NULL)
1381 while ((parentPtr = parentPtr->parentPtr) != NULL) {
1384 if (parentPtr->flags & CK_TOPLEVEL)
1392 if (winPtr->width <= 0)
1394 if (winPtr->height <= 0)
1397 if (x + winPtr->width > winPtr->mainPtr->maxWidth)
1398 winPtr->width = winPtr->mainPtr->maxWidth - x;
1399 if (y + winPtr->height > winPtr->mainPtr->maxHeight)
1400 winPtr->height = winPtr->mainPtr->maxHeight - y;
1402 new = newwin(winPtr->height, winPtr->width, y, x);
1403 if (winPtr->window == NULL) {
1404 winPtr->flags |= CK_MAPPED;
1407 delwin(winPtr->window);
1409 winPtr->window = new;
1410 idlok(winPtr->window, TRUE);
1411 scrollok(winPtr->window, FALSE);
1412 keypad(winPtr->window, TRUE);
1413 nodelay(winPtr->window, TRUE);
1414 meta(winPtr->window, TRUE);
1415 Ck_SetWindowAttr(winPtr, winPtr->fg, winPtr->bg, winPtr->attr);
1416 Ck_ClearToBot(winPtr, 0, 0);
1418 for (childPtr = winPtr->childList;
1419 childPtr != NULL; childPtr = childPtr->nextPtr) {
1420 if (childPtr->flags & CK_TOPLEVEL)
1422 Ck_ResizeWindow(childPtr, -12345, -12345);
1424 Ck_EventuallyRefresh(winPtr);
1426 event.type = CK_EV_MAP;
1427 event.winPtr = winPtr;
1428 Ck_HandleEvent(mainWin->mainPtr, (CkEvent *) &event);
1429 event.type = CK_EV_EXPOSE;
1430 event.winPtr = winPtr;
1431 Ck_HandleEvent(mainWin->mainPtr, (CkEvent *) &event);
1435 *--------------------------------------------------------------
1437 * Ck_UnmapWindow, etc. --
1439 * There are several procedures under here, each of which
1440 * mirrors an existing X procedure. In addition to performing
1441 * the functions of the corresponding procedure, each
1442 * procedure also updates the local window structure and
1443 * synthesizes an X event (if the window's structure is being
1444 * managed internally).
1447 * See the manual entries.
1450 * See the manual entries.
1452 *--------------------------------------------------------------
1456 Ck_UnmapWindow(winPtr)
1457 CkWindow *winPtr; /* Pointer to window to unmap. */
1460 CkMainInfo *mainPtr = winPtr->mainPtr;
1461 CkWindowEvent event;
1463 for (childPtr = winPtr->childList;
1464 childPtr != NULL; childPtr = childPtr->nextPtr) {
1465 if (childPtr->flags & CK_TOPLEVEL)
1467 Ck_UnmapWindow(childPtr);
1469 if (!(winPtr->flags & CK_MAPPED))
1471 winPtr->flags &= ~CK_MAPPED;
1472 delwin(winPtr->window);
1473 winPtr->window = NULL;
1474 Ck_EventuallyRefresh(winPtr);
1476 if (mainPtr->focusPtr == winPtr) {
1477 CkWindow *parentPtr;
1479 parentPtr = winPtr->parentPtr;
1480 while (parentPtr != NULL && !(parentPtr->flags & CK_TOPLEVEL))
1481 parentPtr = parentPtr->parentPtr;
1482 mainPtr->focusPtr = parentPtr;
1483 event.type = CK_EV_FOCUSOUT;
1484 event.winPtr = winPtr;
1485 Ck_HandleEvent(mainPtr, (CkEvent *) &event);
1487 event.type = CK_EV_UNMAP;
1488 event.winPtr = winPtr;
1489 Ck_HandleEvent(mainPtr, (CkEvent *) &event);
1493 Ck_SetWindowAttr(winPtr, fg, bg, attr)
1494 CkWindow *winPtr; /* Window to manipulate. */
1495 int fg, bg; /* Foreground/background colors. */
1496 int attr; /* Video attributes. */
1500 winPtr->attr = attr;
1501 if (winPtr->window != NULL) {
1502 if ((winPtr->mainPtr->flags & (CK_HAS_COLOR | CK_REVERSE_KLUDGE)) ==
1503 (CK_HAS_COLOR | CK_REVERSE_KLUDGE)) {
1504 if (attr & A_REVERSE) {
1513 wattrset(winPtr->window, attr | Ck_GetPair(winPtr, fg, bg));
1518 Ck_GetRootGeometry(winPtr, xPtr, yPtr, widthPtr, heightPtr)
1520 int *xPtr, *yPtr, *widthPtr, *heightPtr;
1524 if (widthPtr != NULL)
1525 *widthPtr = winPtr->width;
1526 if (heightPtr != NULL)
1527 *heightPtr = winPtr->height;
1533 if (winPtr->flags & CK_TOPLEVEL)
1535 winPtr = winPtr->parentPtr;
1536 } while (winPtr != NULL);
1544 *----------------------------------------------------------------------
1546 * Ck_NameToWindow --
1548 * Given a string name for a window, this procedure
1549 * returns the pointer to the window, if there exists a
1550 * window corresponding to the given name.
1553 * The return result is either the pointer to the window corresponding
1554 * to "name", or else NULL to indicate that there is no such
1555 * window. In this case, an error message is left in interp->result.
1560 *----------------------------------------------------------------------
1564 Ck_NameToWindow(interp, pathName, winPtr)
1565 Tcl_Interp *interp; /* Where to report errors. */
1566 char *pathName; /* Path name of window. */
1567 CkWindow *winPtr; /* Pointer to window: name is assumed to
1568 * belong to the same main window as winPtr. */
1570 Tcl_HashEntry *hPtr;
1572 hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->nameTable, pathName);
1574 Tcl_AppendResult(interp, "bad window path name \"",
1575 pathName, "\"", (char *) NULL);
1578 return (CkWindow *) Tcl_GetHashValue(hPtr);
1582 *----------------------------------------------------------------------
1586 * This procedure is used to give a window a class.
1592 * A new class is stored for winPtr, replacing any existing
1595 *----------------------------------------------------------------------
1599 Ck_SetClass(winPtr, className)
1600 CkWindow *winPtr; /* Window to assign class. */
1601 char *className; /* New class for window. */
1603 winPtr->classUid = Ck_GetUid(className);
1604 CkOptionClassChanged(winPtr);
1608 *----------------------------------------------------------------------
1612 * This procedure removes a window from the childList of its
1619 * The window is unlinked from its childList.
1621 *----------------------------------------------------------------------
1625 UnlinkWindow(winPtr)
1626 CkWindow *winPtr; /* Child window to be unlinked. */
1630 if (winPtr->parentPtr == NULL)
1632 prevPtr = winPtr->parentPtr->childList;
1633 if (prevPtr == winPtr) {
1634 winPtr->parentPtr->childList = winPtr->nextPtr;
1635 if (winPtr->nextPtr == NULL)
1636 winPtr->parentPtr->lastChildPtr = NULL;
1638 while (prevPtr->nextPtr != winPtr) {
1639 prevPtr = prevPtr->nextPtr;
1640 if (prevPtr == NULL)
1641 panic("UnlinkWindow couldn't find child in parent");
1643 prevPtr->nextPtr = winPtr->nextPtr;
1644 if (winPtr->nextPtr == NULL)
1645 winPtr->parentPtr->lastChildPtr = prevPtr;
1650 *----------------------------------------------------------------------
1654 * This procedure removes a window from the toplevel list.
1660 * The window is unlinked from the toplevel list.
1662 *----------------------------------------------------------------------
1666 UnlinkToplevel(winPtr)
1671 prevPtr = winPtr->mainPtr->topLevPtr;
1672 if (prevPtr == winPtr) {
1673 winPtr->mainPtr->topLevPtr = winPtr->topLevPtr;
1675 while (prevPtr->topLevPtr != winPtr) {
1676 prevPtr = prevPtr->topLevPtr;
1677 if (prevPtr == NULL)
1678 panic("UnlinkToplevel couldn't find toplevel");
1680 prevPtr->topLevPtr = winPtr->topLevPtr;
1685 *----------------------------------------------------------------------
1687 * Ck_RestackWindow --
1689 * Change a window's position in the stacking order.
1692 * TCL_OK is normally returned. If other is not a descendant
1693 * of winPtr's parent then TCL_ERROR is returned and winPtr is
1697 * WinPtr is repositioned in the stacking order.
1699 *----------------------------------------------------------------------
1703 Ck_RestackWindow(winPtr, aboveBelow, otherPtr)
1704 CkWindow *winPtr; /* Pointer to window whose position in
1705 * the stacking order is to change. */
1706 int aboveBelow; /* Indicates new position of winPtr relative
1707 * to other; must be Above or Below. */
1708 CkWindow *otherPtr; /* WinPtr will be moved to a position that
1709 * puts it just above or below this window.
1710 * If NULL then winPtr goes above or below
1711 * all windows in the same parent. */
1715 if (winPtr->flags & CK_TOPLEVEL) {
1716 if (otherPtr != NULL) {
1717 while (otherPtr != NULL && !(otherPtr->flags & CK_TOPLEVEL))
1718 otherPtr = otherPtr->parentPtr;
1720 if (otherPtr == winPtr)
1723 UnlinkToplevel(winPtr);
1724 if (aboveBelow == CK_ABOVE) {
1725 if (otherPtr == NULL) {
1726 winPtr->topLevPtr = winPtr->mainPtr->topLevPtr;
1727 winPtr->mainPtr->topLevPtr = winPtr;
1729 CkWindow *thisPtr = winPtr->mainPtr->topLevPtr;
1732 while (thisPtr != NULL && thisPtr != otherPtr) {
1734 thisPtr = thisPtr->topLevPtr;
1736 if (prevPtr == NULL) {
1737 winPtr->topLevPtr = winPtr->mainPtr->topLevPtr;
1738 winPtr->mainPtr->topLevPtr = winPtr;
1740 winPtr->topLevPtr = prevPtr->topLevPtr;
1741 prevPtr->topLevPtr = winPtr;
1745 CkWindow *thisPtr = winPtr->mainPtr->topLevPtr;
1748 while (thisPtr != NULL && thisPtr != otherPtr) {
1750 thisPtr = thisPtr->topLevPtr;
1752 if (thisPtr == NULL) {
1753 winPtr->topLevPtr = prevPtr->topLevPtr;
1754 prevPtr->topLevPtr = winPtr;
1756 winPtr->topLevPtr = thisPtr->topLevPtr;
1757 thisPtr->topLevPtr = winPtr;
1760 ChangeToplevelFocus(winPtr->mainPtr->topLevPtr);
1765 * Find an ancestor of otherPtr that is a sibling of winPtr.
1768 if (otherPtr == NULL) {
1769 if (aboveBelow == CK_BELOW)
1770 otherPtr = winPtr->parentPtr->lastChildPtr;
1772 otherPtr = winPtr->parentPtr->childList;
1774 while (winPtr->parentPtr != otherPtr->parentPtr) {
1775 otherPtr = otherPtr->parentPtr;
1776 if (otherPtr == NULL)
1780 if (otherPtr == winPtr)
1784 * Reposition winPtr in the stacking order.
1787 UnlinkWindow(winPtr);
1788 if (aboveBelow == CK_BELOW) {
1789 winPtr->nextPtr = otherPtr->nextPtr;
1790 if (winPtr->nextPtr == NULL)
1791 winPtr->parentPtr->lastChildPtr = winPtr;
1792 otherPtr->nextPtr = winPtr;
1794 prevPtr = winPtr->parentPtr->childList;
1795 if (prevPtr == otherPtr)
1796 winPtr->parentPtr->childList = winPtr;
1798 while (prevPtr->nextPtr != otherPtr)
1799 prevPtr = prevPtr->nextPtr;
1800 prevPtr->nextPtr = winPtr;
1802 winPtr->nextPtr = otherPtr;
1806 Ck_EventuallyRefresh(winPtr);
1811 *----------------------------------------------------------------------
1815 * This procedure is invoked to change the focus window for a
1816 * given display in a given application.
1822 * Event handlers may be invoked to process the change of
1825 *----------------------------------------------------------------------
1830 CkWindow *winPtr; /* Window that is to be the new focus. */
1832 CkMainInfo *mainPtr = winPtr->mainPtr;
1834 CkWindow *oldTop = NULL, *newTop, *oldFocus;
1836 if (winPtr == mainPtr->focusPtr)
1839 oldFocus = mainPtr->focusPtr;
1840 if (oldFocus != NULL) {
1841 for (oldTop = oldFocus; oldTop != NULL &&
1842 !(oldTop->flags & CK_TOPLEVEL); oldTop = oldTop->parentPtr) {
1843 /* Empty loop body. */
1845 event.win.type = CK_EV_FOCUSOUT;
1846 event.win.winPtr = oldFocus;
1847 Ck_HandleEvent(mainPtr, &event);
1849 mainPtr->focusPtr = winPtr;
1850 for (newTop = winPtr; newTop != NULL &&
1851 !(newTop->flags & CK_TOPLEVEL); newTop = newTop->parentPtr) {
1852 /* Empty loop body. */
1854 if (oldTop != newTop) {
1856 oldTop->focusPtr = oldFocus;
1857 Ck_RestackWindow(newTop, CK_ABOVE, NULL);
1858 Ck_EventuallyRefresh(mainPtr->winPtr);
1860 if (winPtr->flags & CK_MAPPED) {
1861 event.win.type = CK_EV_FOCUSIN;
1862 event.win.winPtr = winPtr;
1863 Ck_HandleEvent(mainPtr, &event);
1864 Ck_EventuallyRefresh(mainPtr->winPtr);
1869 *----------------------------------------------------------------------
1871 * ChangeToplevelFocus --
1873 *----------------------------------------------------------------------
1877 ChangeToplevelFocus(winPtr)
1880 CkWindow *winTop, *oldTop;
1881 CkMainInfo *mainPtr;
1886 mainPtr = winPtr->mainPtr;
1887 for (winTop = winPtr; winTop != NULL && !(winTop->flags & CK_TOPLEVEL);
1888 winTop = winTop->parentPtr) {
1889 /* Empty loop body. */
1891 for (oldTop = mainPtr->focusPtr; oldTop != NULL &&
1892 !(oldTop->flags & CK_TOPLEVEL); oldTop = oldTop->parentPtr) {
1893 /* Empty loop body. */
1895 if (winTop != oldTop) {
1898 if (oldTop != NULL) {
1899 oldTop->focusPtr = mainPtr->focusPtr;
1900 event.win.type = CK_EV_FOCUSOUT;
1901 event.win.winPtr = mainPtr->focusPtr;
1902 Ck_HandleEvent(mainPtr, &event);
1904 mainPtr->focusPtr = winTop->focusPtr;
1905 event.win.type = CK_EV_FOCUSIN;
1906 event.win.winPtr = mainPtr->focusPtr;
1907 Ck_HandleEvent(mainPtr, &event);
1912 *----------------------------------------------------------------------
1914 * Ck_EventuallyRefresh --
1916 * Dispatch refresh of entire screen.
1921 *----------------------------------------------------------------------
1925 Ck_EventuallyRefresh(winPtr)
1928 if (++winPtr->mainPtr->refreshCount == 1)
1929 Tcl_DoWhenIdle(DoRefresh, (ClientData) winPtr->mainPtr);
1933 *----------------------------------------------------------------------
1937 * Refresh all curses windows. If the terminal is connected via
1938 * a network connection (ie terminal server) the curses typeahead
1939 * mechanism is not sufficient for delaying screen updates due to
1941 * Therefore the refreshDelay may be used in order to limit updates
1942 * to happen not more often than 1000/refreshDelay times per second.
1947 *----------------------------------------------------------------------
1951 DoRefresh(clientData)
1952 ClientData clientData;
1954 CkMainInfo *mainPtr = (CkMainInfo *) clientData;
1956 if (mainPtr->flags & CK_REFRESH_TIMER) {
1957 Tk_DeleteTimerHandler(mainPtr->refreshTimer);
1958 mainPtr->flags &= ~CK_REFRESH_TIMER;
1960 if (--mainPtr->refreshCount > 0) {
1961 Tk_DoWhenIdle2(DoRefresh, clientData);
1964 mainPtr->refreshCount = 0;
1965 if (mainPtr->refreshDelay > 0) {
1966 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
1970 gettimeofday(&tv, (struct timezone *) NULL);
1971 t0 = (tv.tv_sec + 0.000001 * tv.tv_usec) * 1000;
1975 extern void TclpGetTime _ANSI_ARGS_((Tcl_Time *timePtr));
1978 t0 = (tv.sec + 0.000001 * tv.usec) * 1000;
1980 if (t0 - mainPtr->lastRefresh < mainPtr->refreshDelay) {
1981 mainPtr->refreshTimer = Tk_CreateTimerHandler(
1982 mainPtr->refreshDelay - (int) (t0 - mainPtr->lastRefresh),
1983 DoRefresh, clientData);
1984 mainPtr->flags |= CK_REFRESH_TIMER;
1987 mainPtr->lastRefresh = t0;
1990 RefreshToplevels(mainPtr->topLevPtr);
1991 UpdateHWCursor(ckMainInfo);
1996 *----------------------------------------------------------------------
1998 * RefreshToplevels --
2000 * Recursively refresh all toplevel windows starting at winPtr.
2005 *----------------------------------------------------------------------
2009 RefreshToplevels(winPtr)
2012 if (winPtr->topLevPtr != NULL)
2013 RefreshToplevels(winPtr->topLevPtr);
2014 if (winPtr->window != NULL) {
2015 touchwin(winPtr->window);
2016 wnoutrefresh(winPtr->window);
2017 if (winPtr->childList != NULL)
2018 RefreshThem(winPtr->childList);
2023 *----------------------------------------------------------------------
2027 * Recursively refresh all curses windows starting at winPtr.
2032 *----------------------------------------------------------------------
2039 if (winPtr->nextPtr != NULL)
2040 RefreshThem(winPtr->nextPtr);
2041 if (winPtr->flags & CK_TOPLEVEL)
2043 if (winPtr->window != NULL) {
2044 touchwin(winPtr->window);
2045 wnoutrefresh(winPtr->window);
2047 if (winPtr->childList != NULL)
2048 RefreshThem(winPtr->childList);
2052 *----------------------------------------------------------------------
2056 * Make hardware cursor (in)visible for given window using curses.
2061 *----------------------------------------------------------------------
2065 UpdateHWCursor(mainPtr)
2066 CkMainInfo *mainPtr;
2069 CkWindow *wPtr, *stopAtWin, *winPtr = mainPtr->focusPtr;
2071 if (winPtr == NULL || winPtr->window == NULL ||
2072 (winPtr->flags & (CK_SHOW_CURSOR | CK_ALREADY_DEAD)) == 0) {
2075 if (mainPtr->focusPtr != NULL && mainPtr->focusPtr->window != NULL)
2076 wnoutrefresh(mainPtr->focusPtr->window);
2081 * Get position of HW cursor in winPtr coordinates.
2084 getyx(winPtr->window, y, x);
2087 while (winPtr != NULL) {
2088 for (wPtr = winPtr->childList;
2089 wPtr != NULL && wPtr != stopAtWin; wPtr = wPtr->nextPtr) {
2090 if ((wPtr->flags & CK_TOPLEVEL) || wPtr->window == NULL)
2092 if (x >= wPtr->x && x < wPtr->x + wPtr->width &&
2093 y >= wPtr->y && y < wPtr->y + wPtr->height)
2099 if (winPtr->parentPtr == NULL)
2101 winPtr = winPtr->parentPtr;
2102 if (winPtr->flags & CK_TOPLEVEL)
2105 for (wPtr = mainPtr->topLevPtr; wPtr != NULL && wPtr != winPtr;
2106 wPtr = wPtr->topLevPtr)
2107 if (x >= wPtr->x && x < wPtr->x + wPtr->width &&
2108 y >= wPtr->y && y < wPtr->y + wPtr->height)
2111 wnoutrefresh(mainPtr->focusPtr->window);
2115 *----------------------------------------------------------------------
2119 * Given X, Y coordinates, return topmost window.
2124 *----------------------------------------------------------------------
2128 GetWindowXY(winPtr, xPtr, yPtr)
2135 x = *xPtr - winPtr->x; y = *yPtr - winPtr->y;
2136 for (wPtr = winPtr->childList; wPtr != NULL; wPtr = wPtr->nextPtr) {
2137 if (!(wPtr->flags & CK_MAPPED) || (wPtr->flags & CK_TOPLEVEL))
2139 if (x >= wPtr->x && x < wPtr->x + wPtr->width &&
2140 y >= wPtr->y && y < wPtr->y + wPtr->height) {
2141 wPtr = GetWindowXY(wPtr, &x, &y);
2153 *----------------------------------------------------------------------
2157 * Given X, Y coordinates, return topmost window.
2158 * If mode is zero, consider all toplevels, otherwise consider
2159 * only topmost toplevel in search.
2162 * Window pointer or NULL. *xPtr, *yPtr are adjusted to window
2163 * coordinate system if possible.
2165 *----------------------------------------------------------------------
2169 Ck_GetWindowXY(mainPtr, xPtr, yPtr, mode)
2170 CkMainInfo *mainPtr;
2171 int *xPtr, *yPtr, mode;
2176 x0 = *xPtr; y0 = *yPtr;
2177 wPtr = mainPtr->topLevPtr;
2180 if (wPtr->flags & CK_MAPPED) {
2181 if (x >= wPtr->x && x < wPtr->x + wPtr->width &&
2182 y >= wPtr->y && y < wPtr->y + wPtr->height) {
2183 wPtr = GetWindowXY(wPtr, &x, &y);
2195 wPtr = wPtr->topLevPtr;
2203 *----------------------------------------------------------------------
2207 * Make hardware cursor (in)visible for given window.
2212 *----------------------------------------------------------------------
2216 Ck_SetHWCursor(winPtr, newState)
2220 int oldState = winPtr->flags & CK_SHOW_CURSOR;
2222 if (newState == oldState)
2226 winPtr->flags |= CK_SHOW_CURSOR;
2228 winPtr->flags &= ~CK_SHOW_CURSOR;
2229 if (winPtr == winPtr->mainPtr->focusPtr)
2230 UpdateHWCursor(winPtr->mainPtr);
2234 *----------------------------------------------------------------------
2238 * Clear window starting from given position, til end of line.
2243 *----------------------------------------------------------------------
2247 Ck_ClearToEol(winPtr, x, y)
2251 WINDOW *window = winPtr->window;
2256 if (x == -1 && y == -1)
2257 getyx(window, y, x);
2259 wmove(window, y, x);
2260 for (; x < winPtr->width; x++)
2261 waddch(window, ' ');
2265 *----------------------------------------------------------------------
2269 * Clear window starting from given position, til end of screen.
2274 *----------------------------------------------------------------------
2278 Ck_ClearToBot(winPtr, x, y)
2282 WINDOW *window = winPtr->window;
2287 wmove(window, y, x);
2288 for (; x < winPtr->width; x++)
2289 waddch(window, ' ');
2290 for (++y; y < winPtr->height; y++) {
2291 wmove(window, y, 0);
2292 for (x = 0; x < winPtr->width; x++)
2293 waddch(window, ' ');
2298 *----------------------------------------------------------------------
2302 * Report error since toolkit gone.
2307 *----------------------------------------------------------------------
2311 DeadAppCmd(clientData, interp, argc, argv)
2312 ClientData clientData;
2317 interp->result = "toolkit uninstalled";
2322 *----------------------------------------------------------------------
2326 * Own version of "exec" Tcl command which supports the -endwin
2330 * See documentation for "exec".
2332 *----------------------------------------------------------------------
2336 ExecCmd(clientData, interp, argc, argv)
2337 ClientData clientData;
2342 RedirInfo *redirInfo = (RedirInfo *) clientData;
2343 Tcl_CmdInfo *cmdInfo = &redirInfo->cmdInfo;
2344 int result, endWin = 0;
2347 #ifdef HAVE_SIGACTION
2348 struct sigaction oldsig, newsig;
2350 Ck_SignalProc sigproc;
2354 if (argc > 1 && strcmp(argv[1], "-endwin") == 0) {
2356 savedargv1 = argv[1];
2361 #ifdef HAVE_SIGACTION
2362 newsig.sa_handler = SIG_IGN;
2363 sigfillset(&newsig.sa_mask);
2364 newsig.sa_flags = 0;
2365 sigaction(SIGINT, &newsig, &oldsig);
2367 sigproc = signal(SIGINT, SIG_IGN);
2371 result = (*cmdInfo->proc)(cmdInfo->clientData, interp,
2372 argc - endWin, argv + endWin);
2375 #ifdef HAVE_SIGACTION
2376 sigaction(SIGINT, &oldsig, NULL);
2378 signal(SIGINT, sigproc);
2382 argv[1] = savedargv1;
2383 Ck_EventuallyRefresh(redirInfo->mainPtr->winPtr);
2389 *----------------------------------------------------------------------
2393 * Redirect "puts" Tcl command from "stdout" to "stderr" in the
2394 * hope that it will not destroy our screen.
2397 * See documentation of "puts" command.
2399 *----------------------------------------------------------------------
2403 PutsCmd(clientData, interp, argc, argv)
2404 ClientData clientData;
2409 RedirInfo *redirInfo = (RedirInfo *) clientData;
2410 Tcl_CmdInfo *cmdInfo = &redirInfo->cmdInfo;
2414 newArgv[0] = argv[0];
2415 if (argc > 1 && strcmp(argv[1], "-nonewline") == 0) {
2416 newArgv[1] = argv[1];
2419 if (argc == index + 2) {
2420 newArgv[index + 2] = argv[index + 1];
2422 newArgv[index + 1] = "stderr";
2423 return (*cmdInfo->proc)(cmdInfo->clientData, interp,
2424 index + 3, newArgv);
2425 } else if (argc == index + 3 &&
2426 (strcmp(argv[index + 1], "stdout") == 0 ||
2427 strcmp(argv[index + 1], "file1") == 0)) {
2428 newArgv[index + 2] = argv[index + 2];
2431 return (*cmdInfo->proc)(cmdInfo->clientData, interp, argc, argv);
2435 *----------------------------------------------------------------------
2439 * Report error when attempt is made to close stdin or stdout.
2442 * See documentation of "close" command.
2444 *----------------------------------------------------------------------
2448 CloseCmd(clientData, interp, argc, argv)
2449 ClientData clientData;
2454 RedirInfo *redirInfo = (RedirInfo *) clientData;
2455 Tcl_CmdInfo *cmdInfo = &redirInfo->cmdInfo;
2458 (strcmp(argv[1], "stdin") == 0 ||
2459 strcmp(argv[1], "file0") == 0 ||
2460 strcmp(argv[1], "stdout") == 0 ||
2461 strcmp(argv[1], "file1") == 0)) {
2462 Tcl_AppendResult(interp, "may not close fileId \"",
2463 argv[1], "\" while in toolkit", (char *) NULL);
2466 return (*cmdInfo->proc)(cmdInfo->clientData, interp, argc, argv);
2470 *----------------------------------------------------------------------
2474 * Report error when attempt is made to flush stdin or stdout.
2477 * See documentation of "flush" command.
2479 *----------------------------------------------------------------------
2483 FlushCmd(clientData, interp, argc, argv)
2484 ClientData clientData;
2489 RedirInfo *redirInfo = (RedirInfo *) clientData;
2490 Tcl_CmdInfo *cmdInfo = &redirInfo->cmdInfo;
2493 (strcmp(argv[1], "stdin") == 0 ||
2494 strcmp(argv[1], "file0") == 0 ||
2495 strcmp(argv[1], "stdout") == 0 ||
2496 strcmp(argv[1], "file1") == 0)) {
2497 Tcl_AppendResult(interp, "may not flush fileId \"",
2498 argv[1], "\" while in toolkit", (char *) NULL);
2501 return (*cmdInfo->proc)(cmdInfo->clientData, interp, argc, argv);
2505 *----------------------------------------------------------------------
2509 * Report error when attempt is made to read from stdin.
2512 * See documentation of "read" command.
2514 *----------------------------------------------------------------------
2518 ReadCmd(clientData, interp, argc, argv)
2519 ClientData clientData;
2524 RedirInfo *redirInfo = (RedirInfo *) clientData;
2525 Tcl_CmdInfo *cmdInfo = &redirInfo->cmdInfo;
2528 (strcmp(argv[1], "stdin") == 0 ||
2529 strcmp(argv[1], "file0") == 0)) ||
2531 (strcmp(argv[2], "stdin") == 0 ||
2532 strcmp(argv[2], "file0") == 0))) {
2533 Tcl_AppendResult(interp, "may not read from fileId \"",
2534 argv[1], "\" while in toolkit", (char *) NULL);
2537 return (*cmdInfo->proc)(cmdInfo->clientData, interp, argc, argv);
2541 *----------------------------------------------------------------------
2545 * Report error when attempt is made to read from stdin.
2548 * See documentation of "gets" command.
2550 *----------------------------------------------------------------------
2554 GetsCmd(clientData, interp, argc, argv)
2555 ClientData clientData;
2560 RedirInfo *redirInfo = (RedirInfo *) clientData;
2561 Tcl_CmdInfo *cmdInfo = &redirInfo->cmdInfo;
2564 (strcmp(argv[1], "stdin") == 0 ||
2565 strcmp(argv[1], "file0") == 0)) {
2566 Tcl_AppendResult(interp, "may not gets from fileId \"",
2567 argv[1], "\" while in toolkit", (char *) NULL);
2570 return (*cmdInfo->proc)(cmdInfo->clientData, interp, argc, argv);
2576 *----------------------------------------------------------------------
2578 * WIN32 specific curses input event handling.
2580 *----------------------------------------------------------------------
2584 InputSetup(inputInfo)
2585 InputInfo *inputInfo;
2591 * Create the async notification window with a new class.
2594 class.cbClsExtra = 0;
2595 class.cbWndExtra = 0;
2596 class.hInstance = GetModuleHandle(NULL);
2597 class.hbrBackground = NULL;
2598 class.lpszMenuName = NULL;
2599 class.lpszClassName = "CursesInput";
2600 class.lpfnWndProc = InputHandler;
2602 class.hCursor = NULL;
2603 if (RegisterClass(&class)) {
2605 CreateWindow("CursesInput", "CursesInput", WS_TILED, 0, 0,
2606 0, 0, NULL, NULL, class.hInstance, NULL);
2608 if (inputInfo->hwnd == NULL) {
2609 panic("cannot create curses input window");
2611 SetWindowLong(inputInfo->hwnd, GWL_USERDATA, (LONG) inputInfo);
2612 inputInfo->thread = CreateThread(NULL, 4096,
2613 (LPTHREAD_START_ROUTINE) InputThread,
2614 (void *) inputInfo, 0, &id);
2615 Tcl_CreateExitHandler(InputExit, (ClientData) inputInfo);
2619 InputExit(clientData)
2620 ClientData clientData;
2622 InputInfo *inputInfo = (InputInfo *) clientData;
2624 if (inputInfo->hwnd != NULL) {
2625 HWND hwnd = inputInfo->hwnd;
2627 inputInfo->hwnd = NULL;
2628 DestroyWindow(hwnd);
2630 if (inputInfo->thread != INVALID_HANDLE_VALUE) {
2631 WaitForSingleObject(inputInfo->thread, 1000);
2639 InputInfo *inputInfo = (InputInfo *) arg;
2643 while (inputInfo->hwnd != NULL) {
2645 PeekConsoleInput(inputInfo->stdinHandle, &ip, 1, &nRead);
2647 PostMessage(inputInfo->hwnd, WM_USER + 42, 0, 0);
2651 inputInfo->thread = INVALID_HANDLE_VALUE;
2655 static LRESULT CALLBACK
2656 InputHandler(hwnd, message, wParam, lParam)
2662 InputInfo *inputInfo = (InputInfo *) GetWindowLong(hwnd, GWL_USERDATA);
2664 if (message != WM_USER + 42) {
2665 return DefWindowProc(hwnd, message, wParam, lParam);
2667 Tk_DoWhenIdle(InputHandler2, (ClientData) inputInfo);
2672 InputHandler2(clientData)
2673 ClientData clientData;
2675 InputInfo *inputInfo = (InputInfo *) clientData;
2680 CkHandleInput((ClientData) inputInfo->mainPtr, TCL_READABLE);
2682 PeekConsoleInput(inputInfo->stdinHandle, &ip, 1, &nRead);
2683 } while (nRead != 0);