diff options
Diffstat (limited to 'generic/ttk/ttkBlink.c')
-rw-r--r-- | generic/ttk/ttkBlink.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/generic/ttk/ttkBlink.c b/generic/ttk/ttkBlink.c new file mode 100644 index 0000000..7e46fac --- /dev/null +++ b/generic/ttk/ttkBlink.c @@ -0,0 +1,166 @@ +/* + * Copyright 2004, Joe English. + * + * Usage: + * TtkBlinkCursor(corePtr), usually called in a widget's Init hook, + * arranges to periodically toggle the corePtr->flags CURSOR_ON bit + * on and off (and schedule a redisplay) whenever the widget has focus. + * + * Note: Widgets may have additional logic to decide whether + * to display the cursor or not (e.g., readonly or disabled states); + * TtkBlinkCursor() does not account for this. + * + * TODO: + * Add script-level access to configure application-wide blink rate. + */ + +#include <tk.h> +#include "ttkTheme.h" +#include "ttkWidget.h" + +#define DEF_CURSOR_ON_TIME 600 /* milliseconds */ +#define DEF_CURSOR_OFF_TIME 300 /* milliseconds */ + +/* Interp-specific data for tracking cursors: + */ +typedef struct +{ + WidgetCore *owner; /* Widget that currently has cursor */ + Tcl_TimerToken timer; /* Blink timer */ + int onTime; /* #milliseconds to blink cursor on */ + int offTime; /* #milliseconds to blink cursor off */ +} CursorManager; + +/* CursorManagerDeleteProc -- + * InterpDeleteProc for cursor manager. + */ +static void CursorManagerDeleteProc(ClientData clientData, Tcl_Interp *interp) +{ + CursorManager *cm = (CursorManager*)clientData; + if (cm->timer) { + Tcl_DeleteTimerHandler(cm->timer); + } + ckfree(clientData); +} + +/* GetCursorManager -- + * Look up and create if necessary the interp's cursor manager. + */ +static CursorManager *GetCursorManager(Tcl_Interp *interp) +{ + static const char *cm_key = "ttk::CursorManager"; + CursorManager *cm = (CursorManager *) Tcl_GetAssocData(interp, cm_key,0); + + if (!cm) { + cm = (CursorManager*)ckalloc(sizeof(*cm)); + cm->timer = 0; + cm->owner = 0; + cm->onTime = DEF_CURSOR_ON_TIME; + cm->offTime = DEF_CURSOR_OFF_TIME; + Tcl_SetAssocData(interp,cm_key,CursorManagerDeleteProc,(ClientData)cm); + } + return cm; +} + +/* CursorBlinkProc -- + * Timer handler to blink the insert cursor on and off. + */ +static void +CursorBlinkProc(ClientData clientData) +{ + CursorManager *cm = (CursorManager*)clientData; + int blinkTime; + + if (cm->owner->flags & CURSOR_ON) { + cm->owner->flags &= ~CURSOR_ON; + blinkTime = cm->offTime; + } else { + cm->owner->flags |= CURSOR_ON; + blinkTime = cm->onTime; + } + cm->timer = Tcl_CreateTimerHandler(blinkTime, CursorBlinkProc, clientData); + TtkRedisplayWidget(cm->owner); +} + +/* LoseCursor -- + * Turn cursor off, disable blink timer. + */ +static void LoseCursor(CursorManager *cm, WidgetCore *corePtr) +{ + if (corePtr->flags & CURSOR_ON) { + corePtr->flags &= ~CURSOR_ON; + TtkRedisplayWidget(corePtr); + } + if (cm->owner == corePtr) { + cm->owner = NULL; + } + if (cm->timer) { + Tcl_DeleteTimerHandler(cm->timer); + cm->timer = 0; + } +} + +/* ClaimCursor -- + * Claim ownership of the insert cursor and blink on. + */ +static void ClaimCursor(CursorManager *cm, WidgetCore *corePtr) +{ + if (cm->owner == corePtr) + return; + if (cm->owner) + LoseCursor(cm, cm->owner); + + corePtr->flags |= CURSOR_ON; + TtkRedisplayWidget(corePtr); + + cm->owner = corePtr; + cm->timer = Tcl_CreateTimerHandler(cm->onTime, CursorBlinkProc, cm); +} + +/* + * CursorEventProc -- + * Event handler for FocusIn and FocusOut events; + * claim/lose ownership of the insert cursor when the widget + * acquires/loses keyboard focus. + */ + +#define CursorEventMask (FocusChangeMask|StructureNotifyMask) +#define RealFocusEvent(d) \ + (d == NotifyInferior || d == NotifyAncestor || d == NotifyNonlinear) + +static void +CursorEventProc(ClientData clientData, XEvent *eventPtr) +{ + WidgetCore *corePtr = (WidgetCore *)clientData; + CursorManager *cm = GetCursorManager(corePtr->interp); + + switch (eventPtr->type) { + case DestroyNotify: + if (cm->owner == corePtr) + LoseCursor(cm, corePtr); + Tk_DeleteEventHandler( + corePtr->tkwin, CursorEventMask, CursorEventProc, clientData); + break; + case FocusIn: + if (RealFocusEvent(eventPtr->xfocus.detail)) + ClaimCursor(cm, corePtr); + break; + case FocusOut: + if (RealFocusEvent(eventPtr->xfocus.detail)) + LoseCursor(cm, corePtr); + break; + } +} + +/* + * TtkBlinkCursor (main routine) -- + * Arrange to blink the cursor on and off whenever the + * widget has focus. + */ +void TtkBlinkCursor(WidgetCore *corePtr) +{ + Tk_CreateEventHandler( + corePtr->tkwin, CursorEventMask, CursorEventProc, corePtr); +} + +/*EOF*/ |