summaryrefslogtreecommitdiffstats
path: root/win/tclWinNotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinNotify.c')
-rw-r--r--win/tclWinNotify.c259
1 files changed, 134 insertions, 125 deletions
diff --git a/win/tclWinNotify.c b/win/tclWinNotify.c
index d0d2560..aed7a33 100644
--- a/win/tclWinNotify.c
+++ b/win/tclWinNotify.c
@@ -43,9 +43,6 @@ typedef struct ThreadSpecificData {
static Tcl_ThreadDataKey dataKey;
-extern TclStubs tclStubs;
-extern Tcl_NotifierProcs tclOriginalNotifier;
-
/*
* The following static indicates the number of threads that have initialized
* notifiers. It controls the lifetime of the TclNotifier window class.
@@ -54,6 +51,7 @@ extern Tcl_NotifierProcs tclOriginalNotifier;
*/
static int notifierCount = 0;
+static const TCHAR classname[] = TEXT("TclNotifier");
TCL_DECLARE_MUTEX(notifierMutex)
/*
@@ -82,6 +80,9 @@ static LRESULT CALLBACK NotifierProc(HWND hwnd, UINT message,
ClientData
Tcl_InitNotifier(void)
{
+ if (tclNotifierHooks.initNotifierProc) {
+ return tclNotifierHooks.initNotifierProc();
+ } else {
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
WNDCLASS class;
@@ -98,12 +99,12 @@ Tcl_InitNotifier(void)
class.hInstance = TclWinGetTclInstance();
class.hbrBackground = NULL;
class.lpszMenuName = NULL;
- class.lpszClassName = "TclNotifier";
+ class.lpszClassName = classname;
class.lpfnWndProc = NotifierProc;
class.hIcon = NULL;
class.hCursor = NULL;
- if (!RegisterClassA(&class)) {
+ if (!RegisterClass(&class)) {
Tcl_Panic("Unable to register TclNotifier window class");
}
}
@@ -120,7 +121,8 @@ Tcl_InitNotifier(void)
tsdPtr->event = CreateEvent(NULL, FALSE /* !manual */,
FALSE /* !signaled */, NULL);
- return (ClientData) tsdPtr;
+ return tsdPtr;
+ }
}
/*
@@ -144,46 +146,51 @@ void
Tcl_FinalizeNotifier(
ClientData clientData) /* Pointer to notifier data. */
{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
+ if (tclNotifierHooks.finalizeNotifierProc) {
+ tclNotifierHooks.finalizeNotifierProc(clientData);
+ return;
+ } else {
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
- /*
- * Only finalize the notifier if a notifier was installed in the current
- * thread; there is a route in which this is not guaranteed to be true
- * (when tclWin32Dll.c:DllMain() is called with the flag
- * DLL_PROCESS_DETACH by the OS, which could be doing so from a thread
- * that's never previously been involved with Tcl, e.g. the task manager)
- * so this check is important.
- *
- * Fixes Bug #217982 reported by Hugh Vu and Gene Leache.
- */
+ /*
+ * Only finalize the notifier if a notifier was installed in the
+ * current thread; there is a route in which this is not guaranteed to
+ * be true (when tclWin32Dll.c:DllMain() is called with the flag
+ * DLL_PROCESS_DETACH by the OS, which could be doing so from a thread
+ * that's never previously been involved with Tcl, e.g. the task
+ * manager) so this check is important.
+ *
+ * Fixes Bug #217982 reported by Hugh Vu and Gene Leache.
+ */
- if (tsdPtr == NULL) {
- return;
- }
+ if (tsdPtr == NULL) {
+ return;
+ }
- DeleteCriticalSection(&tsdPtr->crit);
- CloseHandle(tsdPtr->event);
+ DeleteCriticalSection(&tsdPtr->crit);
+ CloseHandle(tsdPtr->event);
- /*
- * Clean up the timer and messaging window for this thread.
- */
+ /*
+ * Clean up the timer and messaging window for this thread.
+ */
- if (tsdPtr->hwnd) {
- KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
- DestroyWindow(tsdPtr->hwnd);
- }
+ if (tsdPtr->hwnd) {
+ KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
+ DestroyWindow(tsdPtr->hwnd);
+ }
- /*
- * If this is the last thread to use the notifier, unregister the notifier
- * window class.
- */
+ /*
+ * If this is the last thread to use the notifier, unregister the
+ * notifier window class.
+ */
- Tcl_MutexLock(&notifierMutex);
- notifierCount--;
- if (notifierCount == 0) {
- UnregisterClassA("TclNotifier", TclWinGetTclInstance());
+ Tcl_MutexLock(&notifierMutex);
+ notifierCount--;
+ if (notifierCount == 0) {
+ UnregisterClass(classname, TclWinGetTclInstance());
+ }
+ Tcl_MutexUnlock(&notifierMutex);
}
- Tcl_MutexUnlock(&notifierMutex);
}
/*
@@ -212,27 +219,32 @@ void
Tcl_AlertNotifier(
ClientData clientData) /* Pointer to thread data. */
{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
-
- /*
- * Note that we do not need to lock around access to the hwnd because the
- * race condition has no effect since any race condition implies that the
- * notifier thread is already awake.
- */
+ if (tclNotifierHooks.alertNotifierProc) {
+ tclNotifierHooks.alertNotifierProc(clientData);
+ return;
+ } else {
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
- if (tsdPtr->hwnd) {
/*
- * We do need to lock around access to the pending flag.
+ * Note that we do not need to lock around access to the hwnd because
+ * the race condition has no effect since any race condition implies
+ * that the notifier thread is already awake.
*/
- EnterCriticalSection(&tsdPtr->crit);
- if (!tsdPtr->pending) {
- PostMessage(tsdPtr->hwnd, WM_WAKEUP, 0, 0);
+ if (tsdPtr->hwnd) {
+ /*
+ * We do need to lock around access to the pending flag.
+ */
+
+ EnterCriticalSection(&tsdPtr->crit);
+ if (!tsdPtr->pending) {
+ PostMessage(tsdPtr->hwnd, WM_WAKEUP, 0, 0);
+ }
+ tsdPtr->pending = 1;
+ LeaveCriticalSection(&tsdPtr->crit);
+ } else {
+ SetEvent(tsdPtr->event);
}
- tsdPtr->pending = 1;
- LeaveCriticalSection(&tsdPtr->crit);
- } else {
- SetEvent(tsdPtr->event);
}
}
@@ -256,52 +268,47 @@ Tcl_AlertNotifier(
void
Tcl_SetTimer(
- Tcl_Time *timePtr) /* Maximum block time, or NULL. */
+ const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- UINT timeout;
-
- /*
- * Allow the notifier to be hooked. This may not make sense on Windows,
- * but mirrors the UNIX hook.
- */
-
- if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) {
- tclStubs.tcl_SetTimer(timePtr);
- return;
- }
-
- /*
- * We only need to set up an interval timer if we're being called from an
- * external event loop. If we don't have a window handle then we just
- * return immediately and let Tcl_WaitForEvent handle timeouts.
- */
-
- if (!tsdPtr->hwnd) {
+ if (tclNotifierHooks.setTimerProc) {
+ tclNotifierHooks.setTimerProc(timePtr);
return;
- }
-
- if (!timePtr) {
- timeout = 0;
} else {
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ UINT timeout;
+
/*
- * Make sure we pass a non-zero value into the timeout argument.
- * Windows seems to get confused by zero length timers.
+ * We only need to set up an interval timer if we're being called from
+ * an external event loop. If we don't have a window handle then we
+ * just return immediately and let Tcl_WaitForEvent handle timeouts.
*/
- timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
- if (timeout == 0) {
- timeout = 1;
+ if (!tsdPtr->hwnd) {
+ return;
+ }
+
+ if (!timePtr) {
+ timeout = 0;
+ } else {
+ /*
+ * Make sure we pass a non-zero value into the timeout argument.
+ * Windows seems to get confused by zero length timers.
+ */
+
+ timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
+ if (timeout == 0) {
+ timeout = 1;
+ }
+ }
+ tsdPtr->timeout = timeout;
+ if (timeout != 0) {
+ tsdPtr->timerActive = 1;
+ SetTimer(tsdPtr->hwnd, INTERVAL_TIMER,
+ (unsigned long) tsdPtr->timeout, NULL);
+ } else {
+ tsdPtr->timerActive = 0;
+ KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
}
- }
- tsdPtr->timeout = timeout;
- if (timeout != 0) {
- tsdPtr->timerActive = 1;
- SetTimer(tsdPtr->hwnd, INTERVAL_TIMER, (unsigned long) tsdPtr->timeout,
- NULL);
- } else {
- tsdPtr->timerActive = 0;
- KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
}
}
@@ -327,29 +334,36 @@ Tcl_ServiceModeHook(
int mode) /* Either TCL_SERVICE_ALL, or
* TCL_SERVICE_NONE. */
{
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
- /*
- * If this is the first time that the notifier has been used from a modal
- * loop, then create a communication window. Note that after this point,
- * the application needs to service events in a timely fashion or Windows
- * will hang waiting for the window to respond to synchronous system
- * messages. At some point, we may want to consider destroying the window
- * if we leave the modal loop, but for now we'll leave it around.
- */
-
- if (mode == TCL_SERVICE_ALL && !tsdPtr->hwnd) {
- tsdPtr->hwnd = CreateWindowA("TclNotifier", "TclNotifier", WS_TILED,
- 0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL);
+ if (tclNotifierHooks.serviceModeHookProc) {
+ tclNotifierHooks.serviceModeHookProc(mode);
+ return;
+ } else {
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
- * Send an initial message to the window to ensure that we wake up the
- * notifier once we get into the modal loop. This will force the
- * notifier to recompute the timeout value and schedule a timer if one
- * is needed.
+ * If this is the first time that the notifier has been used from a
+ * modal loop, then create a communication window. Note that after this
+ * point, the application needs to service events in a timely fashion
+ * or Windows will hang waiting for the window to respond to
+ * synchronous system messages. At some point, we may want to consider
+ * destroying the window if we leave the modal loop, but for now we'll
+ * leave it around.
*/
- Tcl_AlertNotifier((ClientData)tsdPtr);
+ if (mode == TCL_SERVICE_ALL && !tsdPtr->hwnd) {
+ tsdPtr->hwnd = CreateWindow(classname, classname,
+ WS_TILED, 0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(),
+ NULL);
+
+ /*
+ * Send an initial message to the window to ensure that we wake up
+ * the notifier once we get into the modal loop. This will force
+ * the notifier to recompute the timeout value and schedule a timer
+ * if one is needed.
+ */
+
+ Tcl_AlertNotifier(tsdPtr);
+ }
}
}
@@ -450,7 +464,7 @@ InitTimerResolution(void)
if (timerResolution.available == -1) {
TclpInitLock();
if (timerResolution.available == -1) {
- HMODULE hLib = GetModuleHandle("Ntdll");
+ HMODULE hLib = GetModuleHandle(TEXT("NTDLL"));
if (hLib) {
NtQueryTimerResolution =
(LPFN_NtQueryTimerResolution)GetProcAddress(hLib,
@@ -627,8 +641,11 @@ TclWinResetTimerResolution(void)
int
Tcl_WaitForEvent(
- Tcl_Time *timePtr) /* Maximum block time, or NULL. */
+ const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
+ if (tclNotifierHooks.waitForEventProc) {
+ return tclNotifierHooks.waitForEventProc(timePtr);
+ } else {
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
MSG msg;
DWORD timeout = INFINITE, result = WAIT_TIMEOUT;
@@ -639,15 +656,6 @@ Tcl_WaitForEvent(
unsigned long actualResolution = 0;
/*
- * Allow the notifier to be hooked. This may not make sense on windows,
- * but mirrors the UNIX hook.
- */
-
- if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) {
- return tclStubs.tcl_WaitForEvent(timePtr);
- }
-
- /*
* Compute the timeout in milliseconds.
*/
@@ -806,6 +814,7 @@ Tcl_WaitForEvent(
/* todo: move it to the service-thread (if available at some point) */
TclWinResetTimerResolution();
return status;
+ }
}
/*
@@ -848,7 +857,7 @@ TclpUSleep(
if (usec <= 9) { /* too short to start whole sleep process */
do {
/* causes context switch only (shortest waiting) */
- Sleep(0);
+ SleepEx(0, TRUE);
} while (--usec > 0);
return;
}
@@ -911,7 +920,7 @@ TclpUSleep(
}
wait:
- Sleep(sleepTime);
+ SleepEx(sleepTime, TRUE);
/* new difference to now (monotonic base) */
usec = desired - TclpGetUTimeMonotonic();