Added management and allocation of the PERQUEUEDATA structure.
diff --git a/windows/queue.c b/windows/queue.c
index 463d78c..fcaff97 100644
--- a/windows/queue.c
+++ b/windows/queue.c
@@ -1,5 +1,4 @@
-/*
- * Message queues related functions
+/* * Message queues related functions
*
* Copyright 1993, 1994 Alexandre Julliard
*/
@@ -16,6 +15,7 @@
#include "heap.h"
#include "thread.h"
#include "process.h"
+#include <assert.h>
#include "debug.h"
#define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
@@ -24,6 +24,7 @@
static HQUEUE16 hExitingQueue = 0;
static HQUEUE16 hmemSysMsgQueue = 0;
static MESSAGEQUEUE *sysMsgQueue = NULL;
+static PERQUEUEDATA *pQDataWin16 = NULL; /* Global perQData for Win16 tasks */
static MESSAGEQUEUE *pMouseQueue = NULL; /* Queue for last mouse message */
static MESSAGEQUEUE *pKbdQueue = NULL; /* Queue for last kbd message */
@@ -33,9 +34,266 @@
/***********************************************************************
+ * PERQDATA_CreateInstance
+ *
+ * Creates an instance of a reference counted PERQUEUEDATA element
+ * for the message queue. perQData is stored globally for 16 bit tasks.
+ *
+ * Note: We don't implement perQdata exactly the same way Windows does.
+ * Each perQData element is reference counted since it may be potentially
+ * shared by multiple message Queues (via AttachThreadInput).
+ * We only store the current values for Active, Capture and focus windows
+ * currently.
+ */
+PERQUEUEDATA * PERQDATA_CreateInstance( )
+{
+ PERQUEUEDATA *pQData;
+
+ BOOL16 bIsWin16 = 0;
+
+ TRACE(msg,"()\n");
+
+ /* Share a single instance of perQData for all 16 bit tasks */
+ if ( ( bIsWin16 = THREAD_IsWin16( THREAD_Current() ) ) )
+ {
+ /* If previously allocated, just bump up ref count */
+ if ( pQDataWin16 )
+ {
+ PERQDATA_Addref( pQDataWin16 );
+ return pQDataWin16;
+ }
+ }
+
+ /* Allocate PERQUEUEDATA from the system heap */
+ if (!( pQData = (PERQUEUEDATA *) HeapAlloc( SystemHeap, 0,
+ sizeof(PERQUEUEDATA) ) ))
+ return 0;
+
+ /* Initialize */
+ pQData->hWndCapture = pQData->hWndFocus = pQData->hWndActive = 0;
+ pQData->ulRefCount = 1;
+ pQData->nCaptureHT = HTCLIENT;
+
+ /* Note: We have an independent critical section for the per queue data
+ * since this may be shared by different threads. see AttachThreadInput()
+ */
+ InitializeCriticalSection( &pQData->cSection );
+
+ /* Save perQData globally for 16 bit tasks */
+ if ( bIsWin16 )
+ pQDataWin16 = pQData;
+
+ return pQData;
+}
+
+
+/***********************************************************************
+ * PERQDATA_Addref
+ *
+ * Increment reference count for the PERQUEUEDATA instance
+ * Returns reference count for debugging purposes
+ */
+ULONG PERQDATA_Addref( PERQUEUEDATA *pQData )
+{
+ assert(pQData != 0 );
+ TRACE(msg,"(): current refcount %lu ...\n", pQData->ulRefCount);
+
+ EnterCriticalSection( &pQData->cSection );
+ ++pQData->ulRefCount;
+ LeaveCriticalSection( &pQData->cSection );
+
+ return pQData->ulRefCount;
+}
+
+
+/***********************************************************************
+ * PERQDATA_Release
+ *
+ * Release a reference to a PERQUEUEDATA instance.
+ * Destroy the instance if no more references exist
+ * Returns reference count for debugging purposes
+ */
+ULONG PERQDATA_Release( PERQUEUEDATA *pQData )
+{
+ assert(pQData != 0 );
+ TRACE(msg,"(): current refcount %lu ...\n",
+ (LONG)pQData->ulRefCount );
+
+ EnterCriticalSection( &pQData->cSection );
+ if ( --pQData->ulRefCount == 0 )
+ {
+ LeaveCriticalSection( &pQData->cSection );
+ DeleteCriticalSection( &pQData->cSection );
+
+ TRACE(msg,"(): deleting PERQUEUEDATA instance ...\n" );
+
+ /* Deleting our global 16 bit perQData? */
+ if ( pQData == pQDataWin16 )
+ pQDataWin16 = 0;
+
+ /* Free the PERQUEUEDATA instance */
+ HeapFree( SystemHeap, 0, pQData );
+
+ return 0;
+ }
+ LeaveCriticalSection( &pQData->cSection );
+
+ return pQData->ulRefCount;
+}
+
+
+/***********************************************************************
+ * PERQDATA_GetFocusWnd
+ *
+ * Get the focus hwnd member in a threadsafe manner
+ */
+HWND32 PERQDATA_GetFocusWnd( PERQUEUEDATA *pQData )
+{
+ HWND32 hWndFocus;
+ assert(pQData != 0 );
+
+ EnterCriticalSection( &pQData->cSection );
+ hWndFocus = pQData->hWndFocus;
+ LeaveCriticalSection( &pQData->cSection );
+
+ return hWndFocus;
+}
+
+
+/***********************************************************************
+ * PERQDATA_SetFocusWnd
+ *
+ * Set the focus hwnd member in a threadsafe manner
+ */
+HWND32 PERQDATA_SetFocusWnd( PERQUEUEDATA *pQData, HWND32 hWndFocus )
+{
+ HWND32 hWndFocusPrv;
+ assert(pQData != 0 );
+
+ EnterCriticalSection( &pQData->cSection );
+ hWndFocusPrv = pQData->hWndFocus;
+ pQData->hWndFocus = hWndFocus;
+ LeaveCriticalSection( &pQData->cSection );
+
+ return hWndFocusPrv;
+}
+
+
+/***********************************************************************
+ * PERQDATA_GetActiveWnd
+ *
+ * Get the active hwnd member in a threadsafe manner
+ */
+HWND32 PERQDATA_GetActiveWnd( PERQUEUEDATA *pQData )
+{
+ HWND32 hWndActive;
+ assert(pQData != 0 );
+
+ EnterCriticalSection( &pQData->cSection );
+ hWndActive = pQData->hWndActive;
+ LeaveCriticalSection( &pQData->cSection );
+
+ return hWndActive;
+}
+
+
+/***********************************************************************
+ * PERQDATA_SetActiveWnd
+ *
+ * Set the active focus hwnd member in a threadsafe manner
+ */
+HWND32 PERQDATA_SetActiveWnd( PERQUEUEDATA *pQData, HWND32 hWndActive )
+{
+ HWND32 hWndActivePrv;
+ assert(pQData != 0 );
+
+ EnterCriticalSection( &pQData->cSection );
+ hWndActivePrv = pQData->hWndActive;
+ pQData->hWndActive = hWndActive;
+ LeaveCriticalSection( &pQData->cSection );
+
+ return hWndActivePrv;
+}
+
+
+/***********************************************************************
+ * PERQDATA_GetCaptureWnd
+ *
+ * Get the capture hwnd member in a threadsafe manner
+ */
+HWND32 PERQDATA_GetCaptureWnd( PERQUEUEDATA *pQData )
+{
+ HWND32 hWndCapture;
+ assert(pQData != 0 );
+
+ EnterCriticalSection( &pQData->cSection );
+ hWndCapture = pQData->hWndCapture;
+ LeaveCriticalSection( &pQData->cSection );
+
+ return hWndCapture;
+}
+
+
+/***********************************************************************
+ * PERQDATA_SetCaptureWnd
+ *
+ * Set the capture hwnd member in a threadsafe manner
+ */
+HWND32 PERQDATA_SetCaptureWnd( PERQUEUEDATA *pQData, HWND32 hWndCapture )
+{
+ HWND32 hWndCapturePrv;
+ assert(pQData != 0 );
+
+ EnterCriticalSection( &pQData->cSection );
+ hWndCapturePrv = pQData->hWndCapture;
+ pQData->hWndCapture = hWndCapture;
+ LeaveCriticalSection( &pQData->cSection );
+
+ return hWndCapturePrv;
+}
+
+
+/***********************************************************************
+ * PERQDATA_GetCaptureInfo
+ *
+ * Get the capture info member in a threadsafe manner
+ */
+INT16 PERQDATA_GetCaptureInfo( PERQUEUEDATA *pQData )
+{
+ INT16 nCaptureHT;
+ assert(pQData != 0 );
+
+ EnterCriticalSection( &pQData->cSection );
+ nCaptureHT = pQData->nCaptureHT;
+ LeaveCriticalSection( &pQData->cSection );
+
+ return nCaptureHT;
+}
+
+
+/***********************************************************************
+ * PERQDATA_SetCaptureInfo
+ *
+ * Set the capture info member in a threadsafe manner
+ */
+INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT )
+{
+ INT16 nCaptureHTPrv;
+ assert(pQData != 0 );
+
+ EnterCriticalSection( &pQData->cSection );
+ nCaptureHTPrv = pQData->nCaptureHT;
+ pQData->nCaptureHT = nCaptureHT;
+ LeaveCriticalSection( &pQData->cSection );
+
+ return nCaptureHTPrv;
+}
+
+
+/***********************************************************************
* QUEUE_Lock
*
- * Fonction for getting a 32 bit pointer on queue strcture. For thread
+ * Function for getting a 32 bit pointer on queue strcture. For thread
* safeness programmers should use this function instead of GlobalLock to
* retrieve a pointer on the structure. QUEUE_Unlock should also be called
* when access to the queue structure is not required anymore.
@@ -58,6 +316,7 @@
return queue;
}
+
/***********************************************************************
* QUEUE_Unlock
*
@@ -169,13 +428,13 @@
*
* Creates a message queue. Doesn't link it into queue list!
*/
-static HQUEUE16 QUEUE_CreateMsgQueue( )
+static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
{
HQUEUE16 hQueue;
MESSAGEQUEUE * msgQueue;
TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
- TRACE(msg,"Creating message queue...\n");
+ TRACE(msg,"(): Creating message queue...\n");
if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT,
sizeof(MESSAGEQUEUE) )))
@@ -193,6 +452,9 @@
msgQueue->lockCount = 1;
msgQueue->magic = QUEUE_MAGIC;
+ /* Create and initialize our per queue data */
+ msgQueue->pQData = bCreatePerQData ? PERQDATA_CreateInstance() : NULL;
+
return hQueue;
}
@@ -211,7 +473,7 @@
HQUEUE16 senderQ;
HQUEUE16 *pPrev;
- TRACE(msg,"Deleting message queue %04x\n", hQueue);
+ TRACE(msg,"(): Deleting message queue %04x\n", hQueue);
if (!hQueue || !msgQueue)
{
@@ -238,6 +500,13 @@
SYSTEM_LOCK();
+ /* Release per queue data if present */
+ if ( msgQueue->pQData )
+ {
+ PERQDATA_Release( msgQueue->pQData );
+ msgQueue->pQData = 0;
+ }
+
/* remove the message queue from the global link list */
pPrev = &hFirstQueue;
while (*pPrev && (*pPrev != hQueue))
@@ -266,7 +535,10 @@
*/
BOOL32 QUEUE_CreateSysMsgQueue( int size )
{
- if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( ))) return FALSE;
+ /* Note: We dont need perQ data for the system message queue */
+ if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( FALSE )))
+ return FALSE;
+
sysMsgQueue = (MESSAGEQUEUE *) GlobalLock16( hmemSysMsgQueue );
return TRUE;
}
@@ -947,7 +1219,7 @@
if ( !hQueue )
{
/* Create thread message queue */
- if( !(hQueue = QUEUE_CreateMsgQueue( 0 )))
+ if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
{
WARN(msg, "failed!\n");
return FALSE;