4 * This file provides basic event-managing facilities,
5 * whereby procedure callbacks may be attached to
8 * Copyright (c) 1990-1994 The Regents of the University of California.
9 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
10 * Copyright (c) 1995-1999 Christian Werner
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
24 * There's a potential problem if a handler is deleted while it's
25 * current (i.e. its procedure is executing), since Ck_HandleEvent
26 * will need to read the handler's "nextPtr" field when the procedure
27 * returns. To handle this problem, structures of the type below
28 * indicate the next handler to be processed for any (recursively
29 * nested) dispatches in progress. The nextHandler fields get
30 * updated if the handlers pointed to are deleted. Ck_HandleEvent
31 * also needs to know if the entire window gets deleted; the winPtr
32 * field is set to zero if that particular window gets deleted.
35 typedef struct InProgress {
36 CkEvent *eventPtr; /* Event currently being handled. */
37 CkWindow *winPtr; /* Window for event. Gets set to NULL if
38 * window is deleted while event is being
40 CkEventHandler *nextHandler; /* Next handler in search. */
41 struct InProgress *nextPtr; /* Next higher nested search. */
44 static InProgress *pendingPtr = NULL;
45 /* Topmost search in progress, or
49 * For each call to Ck_CreateGenericHandler, an instance of the following
50 * structure will be created. All of the active handlers are linked into a
54 typedef struct GenericHandler {
55 Ck_GenericProc *proc; /* Procedure to dispatch on all events. */
56 ClientData clientData; /* Client data to pass to procedure. */
57 int deleteFlag; /* Flag to set when this handler is deleted. */
58 struct GenericHandler *nextPtr;
59 /* Next handler in list of all generic
60 * handlers, or NULL for end of list. */
63 static GenericHandler *genericList = NULL;
64 /* First handler in the list, or NULL. */
65 static GenericHandler *lastGenericPtr = NULL;
66 /* Last handler in list. */
69 * There's a potential problem if Ck_HandleEvent is entered recursively.
70 * A handler cannot be deleted physically until we have returned from
71 * calling it. Otherwise, we're looking at unallocated memory in advancing to
72 * its `next' entry. We deal with the problem by using the `delete flag' and
73 * deleting handlers only when it's known that there's no handler active.
75 * The following variable has a non-zero value when a handler is active.
78 static int genericHandlersActive = 0;
81 * For barcode readers an instance of the following structure is linked
82 * to mainInfo. The supported DATA LOGIC barcode readers are connected
83 * between PC keyboard and PC keyboard controller and generate a data
84 * packet surrounded by start and end characters. If the start character
85 * is received a timer is started and the following keystrokes are
86 * collected into the buffer until the end character is received or the
90 #define DEFAULT_BARCODE_TIMEOUT 1000
92 typedef struct barcodeData {
93 Tk_TimerToken timer;/* Barcode packet timer. */
94 int pkttime; /* Timeout value. */
95 int startChar; /* Start of barcode packet character. */
96 int endChar; /* End of barcode packet character. */
97 int delivered; /* BarCode event has been delivered. */
98 int index; /* Current index into buffer. */
100 char buffer[256]; /* Here the barcode packet is assembled. */
102 char buffer[128]; /* Here the barcode packet is assembled. */
107 * Timeout procedure for reading barcode packet:
110 static void BarcodeTimeout _ANSI_ARGS_((ClientData clientData));
113 *--------------------------------------------------------------
115 * Ck_CreateEventHandler --
117 * Arrange for a given procedure to be invoked whenever
118 * events from a given class occur in a given window.
124 * From now on, whenever an event of the type given by
125 * mask occurs for token and is processed by Ck_HandleEvent,
126 * proc will be called. See the manual entry for details
127 * of the calling sequence and return value for proc.
129 *--------------------------------------------------------------
133 Ck_CreateEventHandler(winPtr, mask, proc, clientData)
134 CkWindow *winPtr; /* Window in which to create handler. */
135 long mask; /* Events for which proc should be called. */
136 Ck_EventProc *proc; /* Procedure to call for each
138 ClientData clientData; /* Arbitrary data to pass to proc. */
140 CkEventHandler *handlerPtr;
144 * Skim through the list of existing handlers to see if there's
145 * already a handler declared with the same callback and clientData
146 * (if so, just change the mask). If no existing handler matches,
147 * then create a new handler.
151 if (winPtr->handlerList == NULL) {
152 handlerPtr = (CkEventHandler *) ckalloc(sizeof (CkEventHandler));
153 winPtr->handlerList = handlerPtr;
156 for (handlerPtr = winPtr->handlerList; ;
157 handlerPtr = handlerPtr->nextPtr) {
158 if ((handlerPtr->proc == proc)
159 && (handlerPtr->clientData == clientData)) {
160 handlerPtr->mask = mask;
163 if (handlerPtr->nextPtr == NULL) {
170 * Create a new handler if no matching old handler was found.
174 handlerPtr->nextPtr = (CkEventHandler *) ckalloc(
175 sizeof (CkEventHandler));
176 handlerPtr = handlerPtr->nextPtr;
178 handlerPtr->mask = mask;
179 handlerPtr->proc = proc;
180 handlerPtr->clientData = clientData;
181 handlerPtr->nextPtr = NULL;
186 *--------------------------------------------------------------
188 * Ck_DeleteEventHandler --
190 * Delete a previously-created handler.
196 * If there existed a handler as described by the
197 * parameters, the handler is deleted so that proc
198 * will not be invoked again.
200 *--------------------------------------------------------------
204 Ck_DeleteEventHandler(winPtr, mask, proc, clientData)
205 CkWindow *winPtr; /* Same as corresponding arguments passed */
206 long mask; /* previously to Ck_CreateEventHandler. */
208 ClientData clientData;
210 CkEventHandler *handlerPtr;
212 CkEventHandler *prevPtr;
215 * Find the event handler to be deleted, or return
216 * immediately if it doesn't exist.
219 for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ;
220 prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) {
221 if (handlerPtr == NULL) {
224 if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc)
225 && (handlerPtr->clientData == clientData)) {
231 * If Ck_HandleEvent is about to process this handler, tell it to
232 * process the next one instead.
235 for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
236 if (ipPtr->nextHandler == handlerPtr) {
237 ipPtr->nextHandler = handlerPtr->nextPtr;
242 * Free resources associated with the handler.
245 if (prevPtr == NULL) {
246 winPtr->handlerList = handlerPtr->nextPtr;
248 prevPtr->nextPtr = handlerPtr->nextPtr;
250 ckfree((char *) handlerPtr);
253 /*--------------------------------------------------------------
255 * Ck_CreateGenericHandler --
257 * Register a procedure to be called on each event, regardless
258 * of window. Generic handlers are useful for capturing
259 * events that aren't associated with windows, or events for windows
266 * From now on, whenever an event is given to Ck_HandleEvent,
267 * invoke proc, giving it clientData and the event as arguments.
269 *--------------------------------------------------------------
273 Ck_CreateGenericHandler(proc, clientData)
274 Ck_GenericProc *proc; /* Procedure to call on every event. */
275 ClientData clientData; /* One-word value to pass to proc. */
277 GenericHandler *handlerPtr;
279 handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler));
281 handlerPtr->proc = proc;
282 handlerPtr->clientData = clientData;
283 handlerPtr->deleteFlag = 0;
284 handlerPtr->nextPtr = NULL;
285 if (genericList == NULL) {
286 genericList = handlerPtr;
288 lastGenericPtr->nextPtr = handlerPtr;
290 lastGenericPtr = handlerPtr;
294 *--------------------------------------------------------------
296 * Ck_DeleteGenericHandler --
298 * Delete a previously-created generic handler.
304 * If there existed a handler as described by the parameters,
305 * that handler is logically deleted so that proc will not be
306 * invoked again. The physical deletion happens in the event
307 * loop in Ck_HandleEvent.
309 *--------------------------------------------------------------
313 Ck_DeleteGenericHandler(proc, clientData)
314 Ck_GenericProc *proc;
315 ClientData clientData;
317 GenericHandler * handler;
319 for (handler = genericList; handler; handler = handler->nextPtr) {
320 if ((handler->proc == proc) && (handler->clientData == clientData)) {
321 handler->deleteFlag = 1;
327 *--------------------------------------------------------------
331 * Given an event, invoke all the handlers that have
332 * been registered for the event.
338 * Depends on the handlers.
340 *--------------------------------------------------------------
344 Ck_HandleEvent(mainPtr, eventPtr)
346 CkEvent *eventPtr; /* Event to dispatch. */
348 CkEventHandler *handlerPtr;
349 GenericHandler *genericPtr;
350 GenericHandler *genPrevPtr;
355 * Invoke all the generic event handlers (those that are
356 * invoked for all events). If a generic event handler reports that
357 * an event is fully processed, go no further.
360 for (genPrevPtr = NULL, genericPtr = genericList; genericPtr != NULL; ) {
361 if (genericPtr->deleteFlag) {
362 if (!genericHandlersActive) {
363 GenericHandler *tmpPtr;
366 * This handler needs to be deleted and there are no
367 * calls pending through the handler, so now is a safe
371 tmpPtr = genericPtr->nextPtr;
372 if (genPrevPtr == NULL) {
373 genericList = tmpPtr;
375 genPrevPtr->nextPtr = tmpPtr;
377 if (tmpPtr == NULL) {
378 lastGenericPtr = genPrevPtr;
380 (void) ckfree((char *) genericPtr);
387 genericHandlersActive++;
388 done = (*genericPtr->proc)(genericPtr->clientData, eventPtr);
389 genericHandlersActive--;
394 genPrevPtr = genericPtr;
395 genericPtr = genPrevPtr->nextPtr;
398 if (Tcl_FindHashEntry(&mainPtr->winTable, (char *) eventPtr->any.winPtr)
401 * There isn't a CkWindow structure for this window.
405 winPtr = eventPtr->any.winPtr;
406 ip.eventPtr = eventPtr;
408 ip.nextHandler = NULL;
409 ip.nextPtr = pendingPtr;
411 for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) {
412 if ((handlerPtr->mask & eventPtr->type) != 0) {
413 ip.nextHandler = handlerPtr->nextPtr;
414 (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr);
415 handlerPtr = ip.nextHandler;
417 handlerPtr = handlerPtr->nextPtr;
422 * Pass the event to the "bind" command mechanism.
425 CkBindEventProc(winPtr, eventPtr);
427 pendingPtr = ip.nextPtr;
431 *--------------------------------------------------------------
433 * CkEventDeadWindow --
435 * This procedure is invoked when it is determined that
436 * a window is dead. It cleans up event-related information
443 * Various things get cleaned up and recycled.
445 *--------------------------------------------------------------
449 CkEventDeadWindow(winPtr)
450 CkWindow *winPtr; /* Information about the window
451 * that is being deleted. */
453 CkEventHandler *handlerPtr;
457 * While deleting all the handlers, be careful to check for
458 * Ck_HandleEvent being about to process one of the deleted
459 * handlers. If it is, tell it to quit (all of the handlers
460 * are being deleted).
463 while (winPtr->handlerList != NULL) {
464 handlerPtr = winPtr->handlerList;
465 winPtr->handlerList = handlerPtr->nextPtr;
466 for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
467 if (ipPtr->nextHandler == handlerPtr) {
468 ipPtr->nextHandler = NULL;
470 if (ipPtr->winPtr == winPtr) {
471 ipPtr->winPtr = NULL;
474 ckfree((char *) handlerPtr);
479 *--------------------------------------------------------------
483 * Process keyboard events from curses.
486 * The return value is TK_FILE_HANDLED if the procedure
487 * actually found an event to process. If no event was found
488 * then TK_READABLE is returned.
491 * The handling of the event could cause additional
494 *--------------------------------------------------------------
497 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
499 CkHandleInput(clientData, mask, flags)
500 ClientData clientData; /* Pointer to main info. */
501 int mask; /* OR-ed combination of the bits TK_READABLE,
502 * TK_WRITABLE, and TK_EXCEPTION, indicating
503 * current state of file. */
504 int flags; /* Flag bits passed to Tk_DoOneEvent;
505 * contains bits such as TK_DONT_WAIT,
506 * TK_X_EVENTS, Tk_FILE_EVENTS, etc. */
509 CkMainInfo *mainPtr = (CkMainInfo *) clientData;
511 static int buttonpressed = 0;
512 static int errCount = 0;
514 if (!(flags & TK_FILE_EVENTS))
517 if (!(mask & TK_READABLE))
522 if (++errCount > 100) {
523 Tcl_Eval(mainPtr->interp, "exit 99");
524 exit(99); /* just in case */
531 * Barcode reader handling.
534 if (mainPtr->flags & CK_HAS_BARCODE) {
535 BarcodeData *bd = (BarcodeData *) mainPtr->barcodeData;
538 * Here, special handling for nested event loops:
539 * If BarCode event has been delivered already, we must
540 * reset the buffer index in order to get normal Key events.
542 if (bd->delivered && bd->index >= 0) {
547 if (bd->index >= 0 || code == bd->startChar) {
548 if (code == bd->startChar) {
549 Tk_DeleteTimerHandler(bd->timer);
550 bd->timer = Tk_CreateTimerHandler(bd->pkttime, BarcodeTimeout,
551 (ClientData) mainPtr);
553 } else if (code == bd->endChar) {
554 Tk_DeleteTimerHandler(bd->timer);
555 bd->timer = (Tk_TimerToken) NULL;
557 event.key.type = CK_EV_BARCODE;
558 event.key.winPtr = mainPtr->focusPtr;
559 event.key.keycode = 0;
560 Ck_HandleEvent(mainPtr, &event);
562 * Careful, event handler could turn barcode off.
563 * Only reset buffer index if BarCode event delivered
566 bd = (BarcodeData *) mainPtr->barcodeData;
567 if (bd != NULL && bd->delivered) {
571 return TK_FILE_HANDLED;
573 /* Leave space for one NUL byte. */
574 if (bd->index < sizeof (bd->buffer) - 1)
575 bd->buffer[bd->index] = code;
582 #ifdef NCURSES_MOUSE_VERSION
584 * ncurses-1.9.8a has builtin mouse support for at least xterm.
587 if (code == KEY_MOUSE) {
591 if (mainPtr->flags & CK_MOUSE_XTERM) {
595 if (getmouse(&mEvent) == ERR)
596 return TK_FILE_HANDLED;
598 for (i = 1; i <= 3; i++) {
599 if (BUTTON_PRESS(mEvent.bstate, i)) {
600 event.mouse.type = CK_EV_MOUSE_DOWN;
602 } else if (BUTTON_RELEASE(mEvent.bstate, i)) {
603 event.mouse.type = CK_EV_MOUSE_UP;
605 event.mouse.button = i;
606 event.mouse.x = mEvent.x;
607 event.mouse.y = mEvent.y;
608 event.mouse.winPtr = Ck_GetWindowXY(mainPtr, &event.mouse.x,
610 Ck_HandleEvent(mainPtr, &event);
611 return TK_FILE_HANDLED;
617 #if defined(__WIN32__) || defined(DJGPP)
618 if ((mainPtr->flags & CK_HAS_MOUSE) && code == KEY_MOUSE) {
622 for (i = 0; i < 3; i++) {
623 if (Mouse_status.button[i] == BUTTON_PRESSED) {
624 event.mouse.type = CK_EV_MOUSE_DOWN;
626 } else if (Mouse_status.button[i] == BUTTON_RELEASED) {
627 event.mouse.type = CK_EV_MOUSE_UP;
629 event.mouse.button = i + 1;
630 event.mouse.x = Mouse_status.x;
631 event.mouse.y = Mouse_status.y;
632 event.mouse.winPtr = Ck_GetWindowXY(mainPtr, &event.mouse.x,
634 Ck_HandleEvent(mainPtr, &event);
635 return TK_FILE_HANDLED;
642 * Xterm mouse report handling: Although GPM has an xterm module
643 * this is separately done here, since I want to be as independent
644 * as possible from GPM.
645 * It is assumed that the entire mouse report comes in one piece
646 * ie without any delay between the 6 relevant characters.
647 * Only a single button down/up event is generated.
650 #if !defined(__WIN32__)&& !defined(DJGPP)
651 if ((mainPtr->flags & CK_MOUSE_XTERM) && (code == 0x1b || code == 0x9b)) {
679 event.mouse.button = ((code2 - 0x20) & 0x03) + 1;
685 event.mouse.x = event.mouse.rootx = code2 - 0x20 - 1;
691 event.mouse.y = event.mouse.rooty = code2 - 0x20 - 1;
692 if (event.mouse.button > 3) {
693 event.mouse.button = buttonpressed;
695 event.mouse.type = CK_EV_MOUSE_UP;
697 } else if (buttonpressed == 0) {
698 buttonpressed = event.mouse.button;
699 event.mouse.type = CK_EV_MOUSE_DOWN;
701 event.mouse.winPtr = Ck_GetWindowXY(mainPtr, &event.mouse.x,
703 Ck_HandleEvent(mainPtr, &event);
704 return TK_FILE_HANDLED;
711 event.key.type = CK_EV_KEYPRESS;
712 event.key.winPtr = mainPtr->focusPtr;
713 event.key.keycode = code;
714 if (event.key.keycode < 0)
715 event.key.keycode &= 0xff;
716 Ck_HandleEvent(mainPtr, &event);
717 return TK_FILE_HANDLED;
721 CkHandleInput(clientData, mask)
722 ClientData clientData; /* Pointer to main info. */
723 int mask; /* OR-ed combination of the bits TK_READABLE,
724 * TK_WRITABLE, and TK_EXCEPTION, indicating
725 * current state of file. */
728 CkMainInfo *mainPtr = (CkMainInfo *) clientData;
730 static int buttonpressed = 0;
731 static int errCount = 0;
733 if (!(mask & TCL_READABLE))
738 if (++errCount > 100) {
739 Tcl_Eval(mainPtr->interp, "exit 99");
740 #if (TCL_MAJOR_VERSION >= 8)
741 Tcl_Exit(99); /* just in case */
743 exit(99); /* just in case */
751 * Barcode reader handling.
754 if (mainPtr->flags & CK_HAS_BARCODE) {
755 BarcodeData *bd = (BarcodeData *) mainPtr->barcodeData;
758 * Here, special handling for nested event loops:
759 * If BarCode event has been delivered already, we must
760 * reset the buffer index in order to get normal Key events.
762 if (bd->delivered && bd->index >= 0) {
767 if (bd->index >= 0 || code == bd->startChar) {
768 if (code == bd->startChar) {
769 Tk_DeleteTimerHandler(bd->timer);
770 bd->timer = Tk_CreateTimerHandler(bd->pkttime, BarcodeTimeout,
771 (ClientData) mainPtr);
773 } else if (code == bd->endChar) {
774 Tk_DeleteTimerHandler(bd->timer);
775 bd->timer = (Tk_TimerToken) NULL;
777 event.key.type = CK_EV_BARCODE;
778 event.key.winPtr = mainPtr->focusPtr;
779 event.key.keycode = 0;
780 Ck_HandleEvent(mainPtr, &event);
782 * Careful, event handler could turn barcode off.
783 * Only reset buffer index if BarCode event delivered
786 bd = (BarcodeData *) mainPtr->barcodeData;
787 if (bd != NULL && bd->delivered) {
793 /* Leave space for one NUL byte. */
794 if (bd->index < sizeof (bd->buffer) - 1) {
800 Tcl_ExternalToUtf(NULL, mainPtr->isoEncoding,
801 &c, 1, 0, NULL, utfb, sizeof (utfb),
803 if (bd->index + numc < sizeof (bd->buffer) - 1) {
804 for (i = 0; i < numc; i++)
805 bd->buffer[bd->index + i] = utfb[i];
807 bd->buffer[bd->index] = '\0';
808 bd->index += numc - 1;
810 bd->buffer[bd->index] = code;
819 #ifdef NCURSES_MOUSE_VERSION
821 * ncurses-1.9.8a has builtin mouse support for at least xterm.
824 if (code == KEY_MOUSE) {
828 if (mainPtr->flags & CK_MOUSE_XTERM) {
832 if (getmouse(&mEvent) == ERR)
835 for (i = 1; i <= 3; i++) {
836 if (BUTTON_PRESS(mEvent.bstate, i)) {
837 event.mouse.type = CK_EV_MOUSE_DOWN;
839 } else if (BUTTON_RELEASE(mEvent.bstate, i)) {
840 event.mouse.type = CK_EV_MOUSE_UP;
842 event.mouse.button = i;
843 event.mouse.rootx = mEvent.x;
844 event.mouse.rooty = mEvent.y;
845 event.mouse.x = mEvent.x;
846 event.mouse.y = mEvent.y;
847 event.mouse.winPtr = Ck_GetWindowXY(mainPtr, &event.mouse.x,
849 Ck_HandleEvent(mainPtr, &event);
856 #if defined(__WIN32__) || defined(DJGPP)
857 if ((mainPtr->flags & CK_HAS_MOUSE) && code == KEY_MOUSE) {
861 for (i = 0; i < 3; i++) {
862 if (Mouse_status.button[i] == BUTTON_PRESSED) {
863 event.mouse.type = CK_EV_MOUSE_DOWN;
865 } else if (Mouse_status.button[i] == BUTTON_RELEASED) {
866 event.mouse.type = CK_EV_MOUSE_UP;
868 event.mouse.button = i + 1;
869 event.mouse.x = Mouse_status.x;
870 event.mouse.y = Mouse_status.y;
871 event.mouse.winPtr = Ck_GetWindowXY(mainPtr, &event.mouse.x,
873 Ck_HandleEvent(mainPtr, &event);
881 * Xterm mouse report handling: Although GPM has an xterm module
882 * this is separately done here, since I want to be as independent
883 * as possible from GPM.
884 * It is assumed that the entire mouse report comes in one piece
885 * ie without any delay between the 6 relevant characters.
886 * Only a single button down/up event is generated.
889 #if !defined(__WIN32__) && !defined(DJGPP)
890 if ((mainPtr->flags & CK_MOUSE_XTERM) && (code == 0x1b || code == 0x9b)) {
918 event.mouse.button = ((code2 - 0x20) & 0x03) + 1;
924 event.mouse.x = event.mouse.rootx = code2 - 0x20 - 1;
930 event.mouse.y = event.mouse.rooty = code2 - 0x20 - 1;
931 if (event.mouse.button > 3) {
932 event.mouse.button = buttonpressed;
934 event.mouse.type = CK_EV_MOUSE_UP;
936 } else if (buttonpressed == 0) {
937 buttonpressed = event.mouse.button;
938 event.mouse.type = CK_EV_MOUSE_DOWN;
940 event.mouse.winPtr = Ck_GetWindowXY(mainPtr, &event.mouse.x,
942 Ck_HandleEvent(mainPtr, &event);
950 event.key.type = CK_EV_KEYPRESS;
951 event.key.winPtr = mainPtr->focusPtr;
952 event.key.keycode = code;
953 if (event.key.keycode < 0)
954 event.key.keycode &= 0xff;
955 Ck_HandleEvent(mainPtr, &event);
958 #endif /* TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION <= 4 */
962 *--------------------------------------------------------------
964 * CkHandleGPMInput --
966 * Process mouse events from GPM.
969 * The return value is TK_FILE_HANDLED if the procedure
970 * actually found an event to process. If no event was found
971 * then TK_READABLE is returned.
974 * The handling of the event could cause additional
977 *--------------------------------------------------------------
980 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
982 CkHandleGPMInput(clientData, mask, flags)
983 ClientData clientData; /* Pointer to main info. */
984 int mask; /* OR-ed combination of the bits TK_READABLE,
985 * TK_WRITABLE, and TK_EXCEPTION, indicating
986 * current state of file. */
987 int flags; /* Flag bits passed to Tk_DoOneEvent;
988 * contains bits such as TK_DONT_WAIT,
989 * TK_X_EVENTS, Tk_FILE_EVENTS, etc. */
993 CkMainInfo *mainPtr = (CkMainInfo *) clientData;
996 if (!(flags & TK_FILE_EVENTS))
999 if (!(mask & TK_READABLE))
1002 ret = Gpm_GetEvent(&gpmEvent);
1005 * GPM connection is closed; delete this file handler.
1008 Tk_DeleteFileHandler((int) mainPtr->mouseData);
1009 mainPtr->mouseData = (ClientData) -1;
1011 } else if (ret == -1)
1014 GPM_DRAWPOINTER(&gpmEvent);
1015 type = gpmEvent.type & (GPM_DOWN | GPM_UP);
1016 if (type == GPM_DOWN || type == GPM_UP) {
1017 event.mouse.type = type == GPM_DOWN ? CK_EV_MOUSE_DOWN :
1019 if (gpmEvent.buttons & GPM_B_LEFT)
1020 event.mouse.button = 1;
1021 else if (gpmEvent.buttons & GPM_B_MIDDLE)
1022 event.mouse.button = 2;
1023 else if (gpmEvent.buttons & GPM_B_RIGHT)
1024 event.mouse.button = 3;
1025 event.mouse.x = event.mouse.rootx = gpmEvent.x - 1;
1026 event.mouse.y = event.mouse.rooty = gpmEvent.y - 1;
1027 event.mouse.winPtr = Ck_GetWindowXY(mainPtr, &event.mouse.x,
1029 Ck_HandleEvent(mainPtr, &event);
1030 return TK_FILE_HANDLED;
1036 CkHandleGPMInput(clientData, mask)
1037 ClientData clientData; /* Pointer to main info. */
1038 int mask; /* OR-ed combination of the bits TK_READABLE,
1039 * TK_WRITABLE, and TK_EXCEPTION, indicating
1040 * current state of file. */
1044 CkMainInfo *mainPtr = (CkMainInfo *) clientData;
1047 if (!(mask & TCL_READABLE))
1050 ret = Gpm_GetEvent(&gpmEvent);
1053 * GPM connection is closed; delete this file handler.
1055 #if (TCL_MAJOR_VERSION == 7)
1056 Tcl_DeleteFileHandler((Tcl_File) mainPtr->mouseData);
1058 Tcl_DeleteFileHandler((int) mainPtr->mouseData);
1060 mainPtr->mouseData = (ClientData) 0;
1062 } else if (ret == -1)
1065 GPM_DRAWPOINTER(&gpmEvent);
1066 type = gpmEvent.type & (GPM_DOWN | GPM_UP);
1067 if (type == GPM_DOWN || type == GPM_UP) {
1068 event.mouse.type = type == GPM_DOWN ? CK_EV_MOUSE_DOWN :
1070 if (gpmEvent.buttons & GPM_B_LEFT)
1071 event.mouse.button = 1;
1072 else if (gpmEvent.buttons & GPM_B_MIDDLE)
1073 event.mouse.button = 2;
1074 else if (gpmEvent.buttons & GPM_B_RIGHT)
1075 event.mouse.button = 3;
1076 event.mouse.x = event.mouse.rootx = gpmEvent.x - 1;
1077 event.mouse.y = event.mouse.rooty = gpmEvent.y - 1;
1078 event.mouse.winPtr = Ck_GetWindowXY(mainPtr, &event.mouse.x,
1080 Ck_HandleEvent(mainPtr, &event);
1083 #endif /* TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION <= 4 */
1084 #endif /* HAVE_GPM */
1087 *--------------------------------------------------------------
1091 * Call Ck_DoOneEvent over and over again in an infinite
1092 * loop as long as there exist any main windows.
1098 * Arbitrary; depends on handlers for events.
1100 *--------------------------------------------------------------
1106 extern CkMainInfo *ckMainInfo;
1108 while (ckMainInfo != NULL) {
1114 *--------------------------------------------------------------
1118 * Handle timeout while reading barcode packet.
1120 *--------------------------------------------------------------
1124 BarcodeTimeout(clientData)
1125 ClientData clientData;
1127 CkMainInfo *mainPtr = (CkMainInfo *) clientData;
1128 BarcodeData *bd = (BarcodeData *) mainPtr->barcodeData;
1132 bd->timer = (Tk_TimerToken) NULL;
1137 *--------------------------------------------------------------
1139 * CkGetBarcodeData --
1141 * Return data collected in barcode packet buffer.
1143 *--------------------------------------------------------------
1147 CkGetBarcodeData(mainPtr)
1148 CkMainInfo *mainPtr;
1150 BarcodeData *bd = (BarcodeData *) mainPtr->barcodeData;
1152 if (bd == NULL || bd->index < 0)
1154 if (bd->index >= sizeof (bd->buffer) - 1)
1155 bd->buffer[sizeof (bd->buffer) - 1] = '\0';
1157 bd->buffer[bd->index] = '\0';
1162 *--------------------------------------------------------------
1166 * Minor command handler to deal with barcode reader.
1167 * Called by "curses" Tcl command.
1170 * TCL_OK or TCL_ERROR.
1173 *--------------------------------------------------------------
1177 CkBarcodeCmd(clientData, interp, argc, argv)
1178 ClientData clientData; /* Main window associated with
1180 Tcl_Interp *interp; /* Current interpreter. */
1181 int argc; /* Number of arguments. */
1182 char **argv; /* Argument strings. */
1184 CkMainInfo *mainPtr = ((CkWindow *) (clientData))->mainPtr;
1185 BarcodeData *bd = (BarcodeData *) mainPtr->barcodeData;
1188 if (mainPtr->flags & CK_HAS_BARCODE) {
1191 sprintf(buffer, "%d %d %d", bd->startChar, bd->endChar,
1193 Tcl_AppendResult(interp, buffer, (char *) NULL);
1196 } else if (argc == 3) {
1197 if (strcmp(argv[2], "off") != 0)
1199 if (mainPtr->flags & CK_HAS_BARCODE) {
1200 Tk_DeleteTimerHandler(bd->timer);
1201 mainPtr->flags &= ~CK_HAS_BARCODE;
1202 mainPtr->barcodeData = NULL;
1203 ckfree((char *) bd);
1206 } else if (argc == 4 || argc == 5) {
1207 int start, end, pkttime;
1209 if (Tcl_GetInt(interp, argv[2], &start) != TCL_OK ||
1210 Tcl_GetInt(interp, argv[3], &end) != TCL_OK)
1212 if (argc > 4 && Tcl_GetInt(interp, argv[4], &pkttime) != TCL_OK)
1214 if (!(mainPtr->flags & CK_HAS_BARCODE)) {
1215 bd = (BarcodeData *) ckalloc(sizeof (BarcodeData));
1216 mainPtr->flags |= CK_HAS_BARCODE;
1217 mainPtr->barcodeData = (ClientData) bd;
1218 bd->pkttime = DEFAULT_BARCODE_TIMEOUT;
1219 bd->timer = (Tk_TimerToken) NULL;
1223 if (argc > 4 && pkttime > 50)
1224 bd->pkttime = pkttime;
1225 bd->startChar = start;
1230 Tcl_AppendResult(interp, "bad or wrong # args: should be \"", argv[0],
1231 " barcode ?off?\" or \"",
1232 argv[0], " barcode startChar endChar ?timeout?\"", (char *) NULL);