2 * Copyright 2004, Joe English.
5 * TtkBlinkCursor(corePtr), usually called in a widget's Init hook,
6 * arranges to periodically toggle the corePtr->flags CURSOR_ON bit
7 * on and off (and schedule a redisplay) whenever the widget has focus.
9 * Note: Widgets may have additional logic to decide whether
10 * to display the cursor or not (e.g., readonly or disabled states);
11 * TtkBlinkCursor() does not account for this.
14 * Add script-level access to configure application-wide blink rate.
19 #include "ttkWidget.h"
21 #define DEF_CURSOR_ON_TIME 600 /* milliseconds */
22 #define DEF_CURSOR_OFF_TIME 300 /* milliseconds */
24 /* Interp-specific data for tracking cursors:
28 WidgetCore *owner; /* Widget that currently has cursor */
29 Tcl_TimerToken timer; /* Blink timer */
30 int onTime; /* #milliseconds to blink cursor on */
31 int offTime; /* #milliseconds to blink cursor off */
34 /* CursorManagerDeleteProc --
35 * InterpDeleteProc for cursor manager.
37 static void CursorManagerDeleteProc(ClientData clientData, Tcl_Interp *interp)
39 CursorManager *cm = (CursorManager*)clientData;
41 Tcl_DeleteTimerHandler(cm->timer);
46 /* GetCursorManager --
47 * Look up and create if necessary the interp's cursor manager.
49 static CursorManager *GetCursorManager(Tcl_Interp *interp)
51 static const char *cm_key = "ttk::CursorManager";
52 CursorManager *cm = Tcl_GetAssocData(interp, cm_key,0);
55 cm = ckalloc(sizeof(*cm));
58 cm->onTime = DEF_CURSOR_ON_TIME;
59 cm->offTime = DEF_CURSOR_OFF_TIME;
60 Tcl_SetAssocData(interp, cm_key, CursorManagerDeleteProc, cm);
66 * Timer handler to blink the insert cursor on and off.
69 CursorBlinkProc(ClientData clientData)
71 CursorManager *cm = (CursorManager*)clientData;
74 if (cm->owner->flags & CURSOR_ON) {
75 cm->owner->flags &= ~CURSOR_ON;
76 blinkTime = cm->offTime;
78 cm->owner->flags |= CURSOR_ON;
79 blinkTime = cm->onTime;
81 cm->timer = Tcl_CreateTimerHandler(blinkTime, CursorBlinkProc, clientData);
82 TtkRedisplayWidget(cm->owner);
86 * Turn cursor off, disable blink timer.
88 static void LoseCursor(CursorManager *cm, WidgetCore *corePtr)
90 if (corePtr->flags & CURSOR_ON) {
91 corePtr->flags &= ~CURSOR_ON;
92 TtkRedisplayWidget(corePtr);
94 if (cm->owner == corePtr) {
98 Tcl_DeleteTimerHandler(cm->timer);
104 * Claim ownership of the insert cursor and blink on.
106 static void ClaimCursor(CursorManager *cm, WidgetCore *corePtr)
108 if (cm->owner == corePtr)
111 LoseCursor(cm, cm->owner);
113 corePtr->flags |= CURSOR_ON;
114 TtkRedisplayWidget(corePtr);
117 cm->timer = Tcl_CreateTimerHandler(cm->onTime, CursorBlinkProc, cm);
122 * Event handler for FocusIn and FocusOut events;
123 * claim/lose ownership of the insert cursor when the widget
124 * acquires/loses keyboard focus.
127 #define CursorEventMask (FocusChangeMask|StructureNotifyMask)
128 #define RealFocusEvent(d) \
129 (d == NotifyInferior || d == NotifyAncestor || d == NotifyNonlinear)
132 CursorEventProc(ClientData clientData, XEvent *eventPtr)
134 WidgetCore *corePtr = (WidgetCore *)clientData;
135 CursorManager *cm = GetCursorManager(corePtr->interp);
137 switch (eventPtr->type) {
139 if (cm->owner == corePtr)
140 LoseCursor(cm, corePtr);
141 Tk_DeleteEventHandler(
142 corePtr->tkwin, CursorEventMask, CursorEventProc, clientData);
145 if (RealFocusEvent(eventPtr->xfocus.detail))
146 ClaimCursor(cm, corePtr);
149 if (RealFocusEvent(eventPtr->xfocus.detail))
150 LoseCursor(cm, corePtr);
156 * TtkBlinkCursor (main routine) --
157 * Arrange to blink the cursor on and off whenever the
160 void TtkBlinkCursor(WidgetCore *corePtr)
162 Tk_CreateEventHandler(
163 corePtr->tkwin, CursorEventMask, CursorEventProc, corePtr);