summaryrefslogtreecommitdiffstats
path: root/win/tclWinNotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinNotify.c')
-rw-r--r--win/tclWinNotify.c218
1 files changed, 90 insertions, 128 deletions
diff --git a/win/tclWinNotify.c b/win/tclWinNotify.c
index 795db74..1cd5823 100644
--- a/win/tclWinNotify.c
+++ b/win/tclWinNotify.c
@@ -5,7 +5,7 @@
* is the lowest-level part of the Tcl event loop. This file works
* together with ../generic/tclNotify.c.
*
- * Copyright © 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -14,7 +14,7 @@
#include "tclInt.h"
/*
- * The following static indicates whether this module has been initialized.
+ * The follwing static indicates whether this module has been initialized.
*/
#define INTERVAL_TIMER 1 /* Handle of interval timer. */
@@ -27,7 +27,7 @@
* created for each thread that is using the notifier.
*/
-typedef struct {
+typedef struct ThreadSpecificData {
CRITICAL_SECTION crit; /* Monitor for this notifier. */
DWORD thread; /* Identifier for thread associated with this
* notifier. */
@@ -36,11 +36,15 @@ typedef struct {
int pending; /* Alert message pending, this field is locked
* by the notifierMutex. */
HWND hwnd; /* Messaging window. */
+ int timeout; /* Current timeout value. */
int timerActive; /* 1 if interval timer is running. */
} 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.
@@ -49,16 +53,14 @@ static Tcl_ThreadDataKey dataKey;
*/
static int notifierCount = 0;
-static const WCHAR className[] = L"TclNotifier";
-static int initialized = 0;
-static CRITICAL_SECTION notifierMutex;
+TCL_DECLARE_MUTEX(notifierMutex)
/*
* Static routines defined in this file.
*/
-static LRESULT CALLBACK NotifierProc(HWND hwnd, UINT message,
- WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK NotifierProc(HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam);
/*
*----------------------------------------------------------------------
@@ -76,45 +78,36 @@ static LRESULT CALLBACK NotifierProc(HWND hwnd, UINT message,
*----------------------------------------------------------------------
*/
-void *
-TclpInitNotifier(void)
+ClientData
+Tcl_InitNotifier(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
- TclpGlobalLock();
- if (!initialized) {
- initialized = 1;
- InitializeCriticalSection(&notifierMutex);
- }
- TclpGlobalUnlock();
+ WNDCLASS class;
/*
* Register Notifier window class if this is the first thread to use this
* module.
*/
- EnterCriticalSection(&notifierMutex);
+ Tcl_MutexLock(&notifierMutex);
if (notifierCount == 0) {
- WNDCLASSW clazz;
-
- clazz.style = 0;
- clazz.cbClsExtra = 0;
- clazz.cbWndExtra = 0;
- clazz.hInstance = TclWinGetTclInstance();
- clazz.hbrBackground = NULL;
- clazz.lpszMenuName = NULL;
- clazz.lpszClassName = className;
- clazz.lpfnWndProc = NotifierProc;
- clazz.hIcon = NULL;
- clazz.hCursor = NULL;
-
- if (!RegisterClassW(&clazz)) {
- Tcl_Panic("Tcl_InitNotifier: %s",
- "unable to register TclNotifier window class");
+ class.style = 0;
+ class.cbClsExtra = 0;
+ class.cbWndExtra = 0;
+ class.hInstance = TclWinGetTclInstance();
+ class.hbrBackground = NULL;
+ class.lpszMenuName = NULL;
+ class.lpszClassName = "TclNotifier";
+ class.lpfnWndProc = NotifierProc;
+ class.hIcon = NULL;
+ class.hCursor = NULL;
+
+ if (!RegisterClassA(&class)) {
+ Tcl_Panic("Unable to register TclNotifier window class");
}
}
notifierCount++;
- LeaveCriticalSection(&notifierMutex);
+ Tcl_MutexUnlock(&notifierMutex);
tsdPtr->pending = 0;
tsdPtr->timerActive = 0;
@@ -123,16 +116,16 @@ TclpInitNotifier(void)
tsdPtr->hwnd = NULL;
tsdPtr->thread = GetCurrentThreadId();
- tsdPtr->event = CreateEventW(NULL, TRUE /* manual */,
+ tsdPtr->event = CreateEvent(NULL, TRUE /* manual */,
FALSE /* !signaled */, NULL);
- return tsdPtr;
+ return (ClientData) tsdPtr;
}
/*
*----------------------------------------------------------------------
*
- * TclpFinalizeNotifier --
+ * Tcl_FinalizeNotifier --
*
* This function is called to cleanup the notifier state before a thread
* is terminated.
@@ -147,8 +140,8 @@ TclpInitNotifier(void)
*/
void
-TclpFinalizeNotifier(
- void *clientData) /* Pointer to notifier data. */
+Tcl_FinalizeNotifier(
+ ClientData clientData) /* Pointer to notifier data. */
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
@@ -184,20 +177,18 @@ TclpFinalizeNotifier(
* window class.
*/
- EnterCriticalSection(&notifierMutex);
- if (notifierCount) {
- notifierCount--;
- if (notifierCount == 0) {
- UnregisterClassW(className, TclWinGetTclInstance());
- }
+ Tcl_MutexLock(&notifierMutex);
+ notifierCount--;
+ if (notifierCount == 0) {
+ UnregisterClassA("TclNotifier", TclWinGetTclInstance());
}
- LeaveCriticalSection(&notifierMutex);
+ Tcl_MutexUnlock(&notifierMutex);
}
/*
*----------------------------------------------------------------------
*
- * TclpAlertNotifier --
+ * Tcl_AlertNotifier --
*
* Wake up the specified notifier from any thread. This routine is called
* by the platform independent notifier code whenever the Tcl_ThreadAlert
@@ -217,8 +208,8 @@ TclpFinalizeNotifier(
*/
void
-TclpAlertNotifier(
- void *clientData) /* Pointer to thread data. */
+Tcl_AlertNotifier(
+ ClientData clientData) /* Pointer to thread data. */
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
@@ -235,7 +226,7 @@ TclpAlertNotifier(
EnterCriticalSection(&tsdPtr->crit);
if (!tsdPtr->pending) {
- PostMessageW(tsdPtr->hwnd, WM_WAKEUP, 0, 0);
+ PostMessage(tsdPtr->hwnd, WM_WAKEUP, 0, 0);
}
tsdPtr->pending = 1;
LeaveCriticalSection(&tsdPtr->crit);
@@ -247,7 +238,7 @@ TclpAlertNotifier(
/*
*----------------------------------------------------------------------
*
- * TclpSetTimer --
+ * Tcl_SetTimer --
*
* This procedure sets the current notifier timer value. The notifier
* will ensure that Tcl_ServiceAll() is called after the specified
@@ -263,13 +254,23 @@ TclpAlertNotifier(
*/
void
-TclpSetTimer(
- const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
+Tcl_SetTimer(
+ 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.
@@ -292,10 +293,11 @@ TclpSetTimer(
timeout = 1;
}
}
-
+ tsdPtr->timeout = timeout;
if (timeout != 0) {
tsdPtr->timerActive = 1;
- SetTimer(tsdPtr->hwnd, INTERVAL_TIMER, timeout, NULL);
+ SetTimer(tsdPtr->hwnd, INTERVAL_TIMER, (unsigned long) tsdPtr->timeout,
+ NULL);
} else {
tsdPtr->timerActive = 0;
KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
@@ -305,7 +307,7 @@ TclpSetTimer(
/*
*----------------------------------------------------------------------
*
- * TclpServiceModeHook --
+ * Tcl_ServiceModeHook --
*
* This function is invoked whenever the service mode changes.
*
@@ -320,7 +322,7 @@ TclpSetTimer(
*/
void
-TclpServiceModeHook(
+Tcl_ServiceModeHook(
int mode) /* Either TCL_SERVICE_ALL, or
* TCL_SERVICE_NONE. */
{
@@ -336,7 +338,7 @@ TclpServiceModeHook(
*/
if (mode == TCL_SERVICE_ALL && !tsdPtr->hwnd) {
- tsdPtr->hwnd = CreateWindowW(className, className, WS_TILED,
+ tsdPtr->hwnd = CreateWindowA("TclNotifier", "TclNotifier", WS_TILED,
0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL);
/*
@@ -346,39 +348,13 @@ TclpServiceModeHook(
* is needed.
*/
- Tcl_AlertNotifier(tsdPtr);
+ Tcl_AlertNotifier((ClientData)tsdPtr);
}
}
/*
*----------------------------------------------------------------------
*
- * TclAsyncNotifier --
- *
- * This procedure is a no-op on Windows.
- *
- * Result:
- * Always true.
- *
- * Side effetcs:
- * None.
- *----------------------------------------------------------------------
- */
-
-int
-TclAsyncNotifier(
- TCL_UNUSED(int), /* Signal number. */
- TCL_UNUSED(Tcl_ThreadId), /* Target thread. */
- TCL_UNUSED(void *), /* Notifier data. */
- TCL_UNUSED(int *), /* Flag to mark. */
- TCL_UNUSED(int)) /* Value of mark. */
-{
- return 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
* NotifierProc --
*
* This procedure is invoked by Windows to process events on the notifier
@@ -408,7 +384,7 @@ NotifierProc(
tsdPtr->pending = 0;
LeaveCriticalSection(&tsdPtr->crit);
} else if (message != WM_TIMER) {
- return DefWindowProcW(hwnd, message, wParam, lParam);
+ return DefWindowProc(hwnd, message, wParam, lParam);
}
/*
@@ -422,30 +398,7 @@ NotifierProc(
/*
*----------------------------------------------------------------------
*
- * TclpNotifierData --
- *
- * This function returns a void pointer to be associated
- * with a Tcl_AsyncHandler.
- *
- * Results:
- * On Windows, returns always NULL.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void *
-TclpNotifierData(void)
-{
- return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpWaitForEvent --
+ * Tcl_WaitForEvent --
*
* This function is called by Tcl_DoOneEvent to wait for new events on
* the message queue. If the block time is 0, then Tcl_WaitForEvent just
@@ -462,8 +415,8 @@ TclpNotifierData(void)
*/
int
-TclpWaitForEvent(
- const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
+Tcl_WaitForEvent(
+ Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
MSG msg;
@@ -471,6 +424,15 @@ TclpWaitForEvent(
int status;
/*
+ * 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.
*/
@@ -486,7 +448,7 @@ TclpWaitForEvent(
myTime.usec = timePtr->usec;
if (myTime.sec != 0 || myTime.usec != 0) {
- TclScaleTime(&myTime);
+ (*tclScaleTimeProcPtr) (&myTime, tclTimeClientData);
}
timeout = myTime.sec * 1000 + myTime.usec / 1000;
@@ -500,19 +462,19 @@ TclpWaitForEvent(
* currently sitting in the queue.
*/
- if (!PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE)) {
+ if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
/*
* Wait for something to happen (a signal from another thread, a
* message, or timeout) or loop servicing asynchronous procedure calls
* queued to this thread.
*/
- do {
- result = MsgWaitForMultipleObjectsEx(1, &tsdPtr->event, timeout,
- QS_ALLINPUT, MWMO_ALERTABLE);
- } while (result == WAIT_IO_COMPLETION);
-
- if (result == WAIT_FAILED) {
+ again:
+ result = MsgWaitForMultipleObjectsEx(1, &tsdPtr->event, timeout,
+ QS_ALLINPUT, MWMO_ALERTABLE);
+ if (result == WAIT_IO_COMPLETION) {
+ goto again;
+ } else if (result == WAIT_FAILED) {
status = -1;
goto end;
}
@@ -522,12 +484,12 @@ TclpWaitForEvent(
* Check to see if there are any messages to process.
*/
- if (PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE)) {
+ if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
/*
* Retrieve and dispatch the first message.
*/
- result = GetMessageW(&msg, NULL, 0, 0);
+ result = GetMessage(&msg, NULL, 0, 0);
if (result == 0) {
/*
* We received a request to exit this thread (WM_QUIT), so
@@ -536,7 +498,7 @@ TclpWaitForEvent(
PostQuitMessage((int) msg.wParam);
status = -1;
- } else if (result == (DWORD) -1) {
+ } else if (result == (DWORD)-1) {
/*
* We got an error from the system. I have no idea why this would
* happen, so we'll just unwind.
@@ -545,7 +507,7 @@ TclpWaitForEvent(
status = -1;
} else {
TranslateMessage(&msg);
- DispatchMessageW(&msg);
+ DispatchMessage(&msg);
status = 1;
}
} else {
@@ -608,11 +570,11 @@ Tcl_Sleep(
* TIP #233: Scale delay from virtual to real-time.
*/
- TclScaleTime(&vdelay);
+ (*tclScaleTimeProcPtr) (&vdelay, tclTimeClientData);
sleepTime = vdelay.sec * 1000 + vdelay.usec / 1000;
for (;;) {
- SleepEx(sleepTime, TRUE);
+ Sleep(sleepTime);
Tcl_GetTime(&now);
if (now.sec > desired.sec) {
break;
@@ -623,7 +585,7 @@ Tcl_Sleep(
vdelay.sec = desired.sec - now.sec;
vdelay.usec = desired.usec - now.usec;
- TclScaleTime(&vdelay);
+ (*tclScaleTimeProcPtr) (&vdelay, tclTimeClientData);
sleepTime = vdelay.sec * 1000 + vdelay.usec / 1000;
}
}