diff options
Diffstat (limited to 'win/tclWinNotify.c')
| -rw-r--r-- | win/tclWinNotify.c | 218 |
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(¬ifierMutex); - } - TclpGlobalUnlock(); + WNDCLASS class; /* * Register Notifier window class if this is the first thread to use this * module. */ - EnterCriticalSection(¬ifierMutex); + Tcl_MutexLock(¬ifierMutex); 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(¬ifierMutex); + Tcl_MutexUnlock(¬ifierMutex); 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(¬ifierMutex); - if (notifierCount) { - notifierCount--; - if (notifierCount == 0) { - UnregisterClassW(className, TclWinGetTclInstance()); - } + Tcl_MutexLock(¬ifierMutex); + notifierCount--; + if (notifierCount == 0) { + UnregisterClassA("TclNotifier", TclWinGetTclInstance()); } - LeaveCriticalSection(¬ifierMutex); + Tcl_MutexUnlock(¬ifierMutex); } /* *---------------------------------------------------------------------- * - * 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; } } |
