Release 0.5

Sun Jan  2 12:38:53 1994  David Metcalfe <david@prism.demon.co.uk>

	* [windows/class.c]
	Implemented GetClassName and GetClassInfo.

	* [windows/caret.c]
	Various improvements to text caret code.

Fri Dec 31 15:22:22 1993  John Brezak <brezak@apollo.hp.com>

	* [misc/comm.c]
	Patches to work with NetBSD.

Thu Dec 30 12:11:55 1993  John Richardson <jrichard@cs.uml.edu>

	* [objects/bitblt.c] Added StretchBlt().

Tue Jan  4 05:22:07 1994  julliard@di.epfl.ch (Alexandre Julliard)

	* [misc/user.c]
	Added creation of system message queue.

	* [objects/bitmap.c] [objects/dcvalues.c] [windows/dc.c]
	Added DC size fields into DC structure.		

	* [objects/clipping.c]
	Bug fix in CLIPPING_IntersectRect().

	* [windows/class.c]
	Allocate a DCE instead of a DC for CS_CLASSDC classes.

	* [windows/clipping.c]
	Fixed GetUpdateRect() and GetUpdateRgn() to clip to the client area.

	* [windows/dce.c]
	Implemented GetDCEx() and GetWindowDC().

	* [windows/defwnd.c]
	Implemented WM_WINDOWPOSCHANGED handling.

	* [windows/event.c]
	Preliminary support for Xlib event handling instead of Xt callbacks.
	Changed MSG_AddMsg() calls to hardware_event() or PostMessage().

	* [windows/message.c]
	Preliminary support for multiple message queues.
	Implemented hardware_event() to store messages into the system queue.
	Implemented Get/SetTaskQueue().
	Better WM_PAINT and WM_TIMER handling.
	Changes to use Xlib instead of Xt for events.

	* [windows/painting.c]
	Use GetDCEx() to retrieve the DC, to get a correct visible region.

	* [windows/timer.c]
	Moved the timer procedure callback into DispatchMessage().
	Changed implementation to get rid of Xt timeouts.  Timer checking
	is now done inside GetMessage().

	* [windows/win.c]
	Allocate a DCE instead of a DC for CS_OWNDC windows.
	Replaced Xt calls with Xlib calls.
	Moved window positioning functions into windows/winpos.c

	* [windows/winpos.c]  (New file)
	Rewritten most of the window positioning functions.
	Implemented SetWindowPos() and MapWindowPoints().

Jan 3, 94 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [if1632/user.spec]
	Bad arguments description for function SetDlgItemText.

	* [objects/text.c]
	Function DrawText now handle DT_CALCRECT request.

	* [misc/message.c]
	Message boxes now use DrawText with DT_CALCRECT.

	* [windows/graphics.c]
	Bug fix in function FrameRect, (it was using PEN instead of BRUSH).

	* [windows/win.c]
	Bug fix for flags in function ShowWindow.
	More accurate WM_SIZE generated by function ShowWindow.

	* [controls/listbox.c]
	More code for LBS_MULTIPLESEL.
	More code for LBS_MULTICOLUMN.

	* [include/windows.h]
	Bad define for MF_SEPARATOR.

	* [controls/menu.c]
	New functions: PopMenuWndProc() with 'glues',
	CreatePopupMenu(), AppendMenu(), InsertMenu(), RemoveMenu(), 
	DeleteMenu(), ModifyMenu(), TrackPopupMenu().
	Code in stubs: CreateMenu(), DestroyMenu(). 

Sat Jan  1 10:22:43 1994  Bob Amstadt  (bob@pooh)

	* loader/wine.c: Added support for relocation types 5 and 6.

Mon Dec 27 11:06:03 1993  Erik Bos (erik@trashcan.hacktic.nl)

	* [misc/comm.c]
	new functions: BuildCommDCB(), OpenComm(), CloseComm(),
	SetCommBreak(), ClearCommBreak(), EscapeCommFunction(), FlushComm(),
	GetCommError(), SetCommEventMask(), GetCommEventMask(),
	SetCommState(), GetCommState(), TransmitCommChar(), ReadComm(), 
	WriteComm().

Wed Dec 22 13:00:15 1993  David Metcalfe <david@prism.demon.co.uk>

	* [windows/caret.c]
	Implemented text caret functions.

Tue Dec 21 06:13:58 1993  julliard@di.epfl.ch (Alexandre Julliard)

	* [loader/wine.c]
	Bug fix in LoadImage().

	* [objects/bitblt.c] [objects/clipping.c] [objects/text.c]
	  [windows/dc.c] [windows/dce.c] [windows/graphics.c]
	Modified graphics calls to take into account the DC origin.

	* [windows/defwnd.c]
	Added preliminary WM_NCCALCSIZE handling.

	* [windows/event.c]
	Send WM_NCCALCSIZE message on resize event.

	* [windows/win.c]
	Send WM_NCCALCSIZE message in CreateWindow().
	Realize widgets at creation time (should prevent problems with
	unrealized widgets).

Dec 19, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [controls/static.c]
	Send mouse & keyboard message received to its parent.

	* [controls/scroll.c]
	Send keyboard message received to its parent.

	* [controls/listbox.c]
	Add Navigation keys .
	ListBox now use VSCROLL & HSCROLL instead of children.
	Alpha version of LBS_MULTIPLESEL.
	Alpha version of LBS_MULTICOLUMN.

	* [controls/combo.c]
	Add Navigation keys on closed ComboBox.
	Remove useless 'COMBOBOX_CreateComboBox' function.

Mon Dec 19 20:39:34 1993  Erik Bos (erik@trashcan.hacktic.nl)

	* [loader/wine.
	LoadImage() modified to use FindFile().

	* [misc/file.c]
	SetErrorMode added

	* [misc/dos_fs.c]
	bug fixes.

Dec 13, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [memory/global.c]
	bug fix in GlobalGetFreeSegment : good ptr in 'g_prev'.

	* [sysres.dll]
	preliminary version of a 'glass of wine' bitmap

	* [windows/event.c]
	New function 'GetCapture'.

	* [controls/scroll.c]
	Remove useless 'SCROLLBAR_CreateScrollBar' function.

	* [controls/listbox.c]
	Remove useless 'LISTBOX_CreateListBox' function.

Mon Dec 13 13:51:00 1993  David Metcalfe <david@prism.demon.co.uk>

	* [objects/font.c]
	Corrected bugs in GetCharWidth().

	* [windows/event.c]
	Modified EVENT_key to send Windows virtual key codes for
	WM_KEYDOWN and WM_KEYUP messages, and a WM_CHAR message
	for printable characters.

Wed Dec 08 19:20:00 1993  Karl Guenter Wuensch (hn324wu@unidui.uni-duisburg.de)

	* [windows/graphics.c]
	Added Polyline and Polygon

Mon Dec 13 14:51:54 1993  Erik Bos (erik@trashcan.hacktic.nl)

	* [controls/listbox.c]
	ListBoxDirectory() modified to use dos_fs.c's functions to
	access files&|drives.

Sat Dec 04 17:04:23 1993  Erik Bos (erik@trashcan.hacktic.nl)

       	* [misc/dos_fs.c]
       	Added FindFile() to search a file in a dos/unix style path.
	
	* [misc/file.c]
	New Win31 functions: OpenFile, _lcreate, _llseek, GetTempDrive,
	GetTempFileName, GetWindowsDirectory, GetSystemDirectory,
	GetDriveType.			   

       	* [misc/int21.c]
       	Modified.

Wed Dec  1 16:20:45 1993  Miguel de Icaza  (miguel@roxanne.nuclecu.unam.mx)

        * [misc/profile.c]
        The Profile functions now return the correct values. They now
        implement all the features described in the SDK.

Tue Nov 30 13:55:27 1993  Bob Amstadt  (bob at amscons)

	* [loader/selector.c]
	Rewrote selector aliasing routines to use System V IPC
	routine to alias memory segments.

Nov 28, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [controls/listbox.c]
	More consistency in functions using wIndexes

	* [controls/scroll.c]
	New function : ShowScrollBar().

	* [loader/cursor.c] ... New file
	Move cursor functions from [loader/resource.c].
	New function : ClipCursor().
	New function : GetClipCursor().
	New function : CreateCursor().
	SetCursor() now working using gloabal variable 'winHasCursor'.

	*[object/palette.c]
	New stub only : SelectPalette().
	New stub only : RealizePalette().

	*[win/event.c]
	New function : EVENT_enter_notify(),
		update 'winHasCursor' and send WM_SETCURSOR.

	*[win/defwnd.c]
	Add processing of WM_SETCURSOR message.

	*[win/win.c]
	New members in WND structure : hCursor, hWndVScroll & hWndHScroll. 
	CreateWindowEx() now create children for WM_HSCROLL & WM_VSCROLL.
	New function ClientToScreen().
	New function ScreenToClient().

Mon Nov 25 18:25:40 1993  Erik Bos (erik@trashcan.hacktic.nl)

       	* [files.h / regfunc.h / misc/dos.c]
       	Removed.

       	* [misc/dos_fs.c]
       	Added support for loading dosdrive cfg from wine.ini.

       	* [misc/int21.c]
       	Modified.


Wed Nov 24 11:37:33 1993  julliard@disuns2.epfl.ch (Alexandre Julliard)

	* [include/atom.h] [memory/atom.c]
	Implemented atoms.

	* [windows/class.c]
	Modified RegisterClass() to use atoms.
	Implemented CS_GLOBALCLASS style.

	* [windows/message.c]
	Implemented RegisterWindowMessage().

	* [loader/resource.c]
	Bug fix in LoadResource().

	* [windows/dialog.c]
	Modified CreateDialogParam() to use Find/LoadResource().
diff --git a/windows/message.c b/windows/message.c
index 7307461..09b49e7 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -12,10 +12,8 @@
 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
 
 #include <stdlib.h>
-
-#ifdef __NetBSD__
-#define HZ 100
-#endif
+#include <sys/time.h>
+#include <sys/types.h>
 
 #include "message.h"
 #include "win.h"
@@ -23,30 +21,72 @@
 
 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
 
-extern HWND WIN_FindWinToRepaint( HWND hwnd );
+extern BOOL TIMER_CheckTimer( DWORD *next );    /* timer.c */
 
 extern Display * XT_display;
 extern Screen * XT_screen;
 extern XtAppContext XT_app_context;
 
-static MESSAGEQUEUE * msgQueue = NULL;
+  /* System message queue (for hardware events) */
+static HANDLE hmemSysMsgQueue = 0;
+static MESSAGEQUEUE * sysMsgQueue = NULL;
+
+  /* Application message queue (should be a list, one queue per task) */
+static HANDLE hmemAppMsgQueue = 0;
+static MESSAGEQUEUE * appMsgQueue = NULL;
+
+/***********************************************************************
+ *           MSG_CreateMsgQueue
+ *
+ * Create a message queue.
+ */
+static HANDLE MSG_CreateMsgQueue( int size )
+{
+    HANDLE hQueue;
+    MESSAGEQUEUE * msgQueue;
+    int queueSize;
+
+    queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
+    if (!(hQueue = GlobalAlloc( GMEM_FIXED, queueSize ))) return 0;
+    msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue );
+    msgQueue->next = 0;
+    msgQueue->hTask = 0;
+    msgQueue->msgSize = sizeof(QMSG);
+    msgQueue->msgCount = 0;
+    msgQueue->nextMessage = 0;
+    msgQueue->nextFreeMessage = 0;
+    msgQueue->queueSize = size;
+    msgQueue->GetMessageTimeVal = 0;
+    msgQueue->GetMessagePosVal = 0;
+    msgQueue->GetMessageExtraInfoVal = 0;
+    msgQueue->lParam = 0;
+    msgQueue->wParam = 0;
+    msgQueue->msg = 0;
+    msgQueue->hWnd = 0;
+    msgQueue->wPostQMsg = 0;
+    msgQueue->wExitCode = 0;
+    msgQueue->InSendMessageHandle = 0;
+    msgQueue->wPaintCount = 0;
+    msgQueue->wTimerCount = 0;
+    msgQueue->tempStatus = 0;
+    msgQueue->status = 0;
+    GlobalUnlock( hQueue );
+    return hQueue;
+}
 
 
 /***********************************************************************
- *           MSG_GetMessageType
+ *           MSG_CreateSysMsgQueue
  *
+ * Create the system message queue. Must be called only once.
  */
-int MSG_GetMessageType( int msg )
+BOOL MSG_CreateSysMsgQueue( int size )
 {
-    if ((msg >= WM_KEYFIRST) && (msg <= WM_KEYLAST)) return QS_KEY;
-    else if ((msg >= WM_MOUSEFIRST) && (msg <= WM_MOUSELAST))
-    {
-	if (msg == WM_MOUSEMOVE) return QS_MOUSEMOVE;
-	else return QS_MOUSEBUTTON;
-    }
-    else if (msg == WM_PAINT) return QS_PAINT;
-    else if (msg == WM_TIMER) return QS_TIMER;
-    return QS_POSTMESSAGE;
+    if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
+    else if (size <= 0) size = 1;
+    if (!(hmemSysMsgQueue = MSG_CreateMsgQueue( size ))) return FALSE;
+    sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue );
+    return TRUE;
 }
 
 
@@ -55,16 +95,13 @@
  *
  * Add a message to the queue. Return FALSE if queue is full.
  */
-int MSG_AddMsg( MSG * msg, DWORD extraInfo )
+static int MSG_AddMsg( MESSAGEQUEUE * msgQueue, MSG * msg, DWORD extraInfo )
 {
-    int pos, type;
+    int pos;
   
     if (!msgQueue) return FALSE;
     pos = msgQueue->nextFreeMessage;
 
-      /* No need to store WM_PAINT messages */
-    if (msg->message == WM_PAINT) return TRUE;
-        
       /* Check if queue is full */
     if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0))
 	return FALSE;
@@ -72,17 +109,12 @@
       /* Store message */
     msgQueue->messages[pos].msg = *msg;
     msgQueue->messages[pos].extraInfo = extraInfo;
-
-      /* Store message type */
-    type = MSG_GetMessageType( msg->message );   
-    msgQueue->status |= type;
-    msgQueue->tempStatus |= type;
-    
     if (pos < msgQueue->queueSize-1) pos++;
     else pos = 0;
     msgQueue->nextFreeMessage = pos;
     msgQueue->msgCount++;
-    
+    msgQueue->status |= QS_POSTMESSAGE;
+    msgQueue->tempStatus |= QS_POSTMESSAGE;
     return TRUE;
 }
 
@@ -92,7 +124,7 @@
  *
  * Find a message matching the given parameters. Return -1 if none available.
  */
-int MSG_FindMsg( HWND hwnd, int first, int last )
+static int MSG_FindMsg(MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last)
 {
     int i, pos = msgQueue->nextMessage;
 
@@ -120,9 +152,8 @@
  *
  * Remove a message from the queue (pos must be a valid position).
  */
-void MSG_RemoveMsg( int pos )
+static void MSG_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
 {
-    int i, type;
     QMSG * qmsg;
     
     if (!msgQueue) return;
@@ -147,56 +178,118 @@
 	else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
     }
     msgQueue->msgCount--;
-
-      /* Recalc status */
-    type = 0;
-    pos = msgQueue->nextMessage;
-    for (i = 0; i < msgQueue->msgCount; i++)
-    {
-	type |= MSG_GetMessageType( msgQueue->messages[pos].msg.message );
-	if (++pos >= msgQueue->queueSize-1) pos = 0;
-    }
-    msgQueue->status = (msgQueue->status & QS_SENDMESSAGE) | type;
+    if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
     msgQueue->tempStatus = 0;
 }
 
 
 /***********************************************************************
+ *           MSG_IncPaintCount
+ */
+void MSG_IncPaintCount( HANDLE hQueue )
+{
+    if (hQueue != hmemAppMsgQueue) return;
+    appMsgQueue->wPaintCount++;
+    appMsgQueue->status |= QS_PAINT;
+    appMsgQueue->tempStatus |= QS_PAINT;    
+}
+
+
+/***********************************************************************
+ *           MSG_DecPaintCount
+ */
+void MSG_DecPaintCount( HANDLE hQueue )
+{
+    if (hQueue != hmemAppMsgQueue) return;
+    appMsgQueue->wPaintCount--;
+    if (!appMsgQueue->wPaintCount) appMsgQueue->status &= ~QS_PAINT;
+}
+
+
+/***********************************************************************
+ *           MSG_IncTimerCount
+ */
+void MSG_IncTimerCount( HANDLE hQueue )
+{
+    if (hQueue != hmemAppMsgQueue) return;
+    appMsgQueue->wTimerCount++;
+    appMsgQueue->status |= QS_TIMER;
+    appMsgQueue->tempStatus |= QS_TIMER;
+}
+
+
+/***********************************************************************
+ *           MSG_DecTimerCount
+ */
+void MSG_DecTimerCount( HANDLE hQueue )
+{
+    if (hQueue != hmemAppMsgQueue) return;
+    appMsgQueue->wTimerCount--;
+    if (!appMsgQueue->wTimerCount) appMsgQueue->status &= ~QS_TIMER;
+}
+
+
+/***********************************************************************
+ *           hardware_event
+ *
+ * Add an event to the system message queue.
+ */
+void hardware_event( HWND hwnd, WORD message, WORD wParam, LONG lParam,
+		     WORD xPos, WORD yPos, DWORD time, DWORD extraInfo )
+{
+    MSG msg;
+
+    msg.hwnd    = hwnd;
+    msg.message = message;
+    msg.wParam  = wParam;
+    msg.lParam  = lParam;
+    msg.time    = time;
+    msg.pt.x    = xPos;
+    msg.pt.y    = yPos;    
+    if (!MSG_AddMsg( sysMsgQueue, &msg, extraInfo ))
+	printf( "hardware_event: Queue is full\n" );
+}
+
+		    
+/***********************************************************************
+ *           SetTaskQueue  (KERNEL.34)
+ */
+WORD SetTaskQueue( HANDLE hTask, HANDLE hQueue )
+{
+    HANDLE prev = hmemAppMsgQueue;
+    hmemAppMsgQueue = hQueue;
+    return prev;
+}
+
+
+/***********************************************************************
+ *           GetTaskQueue  (KERNEL.35)
+ */
+WORD GetTaskQueue( HANDLE hTask )
+{
+    return hmemAppMsgQueue;
+}
+
+
+/***********************************************************************
  *           SetMessageQueue  (USER.266)
  */
 BOOL SetMessageQueue( int size )
 {
-    int queueSize;
-  
+    HANDLE hQueue;
+
+    if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
+
       /* Free the old message queue */
-    if (msgQueue) free(msgQueue);
+    if ((hQueue = GetTaskQueue(0)) != 0)
+    {
+	GlobalUnlock( hQueue );
+	GlobalFree( hQueue );
+    }
   
-    if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return FALSE;
-  
-    queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
-    msgQueue = (MESSAGEQUEUE *) malloc(queueSize);
-    if (!msgQueue) return FALSE;
-
-    msgQueue->next = 0;
-    msgQueue->hTask = 0;
-    msgQueue->msgSize = sizeof(QMSG);
-    msgQueue->msgCount = 0;
-    msgQueue->nextMessage = 0;
-    msgQueue->nextFreeMessage = 0;
-    msgQueue->queueSize = size;
-    msgQueue->GetMessageTimeVal = 0;
-    msgQueue->GetMessagePosVal = 0;
-    msgQueue->GetMessageExtraInfoVal = 0;
-    msgQueue->lParam = 0;
-    msgQueue->wParam = 0;
-    msgQueue->msg = 0;
-    msgQueue->hWnd = 0;
-    msgQueue->wPostQMsg = 0;
-    msgQueue->wExitCode = 0;
-    msgQueue->InSendMessageHandle = 0;
-    msgQueue->tempStatus = 0;
-    msgQueue->status = 0;
-
+    if (!(hQueue = MSG_CreateMsgQueue( size ))) return FALSE;
+    SetTaskQueue( 0, hQueue );
+    appMsgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue );
     return TRUE;
 }
 
@@ -206,9 +299,9 @@
  */
 void PostQuitMessage( int exitCode )
 {
-    if (!msgQueue) return;
-    msgQueue->wPostQMsg = TRUE;
-    msgQueue->wExitCode = exitCode;
+    if (!appMsgQueue) return;
+    appMsgQueue->wPostQMsg = TRUE;
+    appMsgQueue->wExitCode = exitCode;
 }
 
 
@@ -217,12 +310,8 @@
  */
 DWORD GetQueueStatus( int flags )
 {
-    unsigned long ret = (msgQueue->status << 16) | msgQueue->tempStatus;
-    if (flags & QS_PAINT)
-    {
-	if (WIN_FindWinToRepaint(0)) ret |= QS_PAINT | (QS_PAINT << 16);
-    }
-    msgQueue->tempStatus = 0;
+    unsigned long ret = (appMsgQueue->status << 16) | appMsgQueue->tempStatus;
+    appMsgQueue->tempStatus = 0;
     return ret & ((flags << 16) | flags);
 }
 
@@ -232,70 +321,169 @@
  */
 BOOL GetInputState()
 {
-    return msgQueue->status & (QS_KEY | QS_MOUSEBUTTON);
+    return appMsgQueue->status & (QS_KEY | QS_MOUSEBUTTON);
 }
 
 
+#ifndef USE_XLIB
+static XtIntervalId xt_timer = 0;
+
+/***********************************************************************
+ *           MSG_TimerCallback
+ */
+static void MSG_TimerCallback( XtPointer data, XtIntervalId * xtid )
+{
+    DWORD nextExp;
+    TIMER_CheckTimer( &nextExp );
+    if (nextExp != (DWORD)-1)
+	xt_timer = XtAppAddTimeOut( XT_app_context, nextExp,
+				    MSG_TimerCallback, NULL );
+    else xt_timer = 0;
+}
+#endif  /* USE_XLIB */
+
+
 /***********************************************************************
  *           MSG_PeekMessage
  */
-BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
+static BOOL MSG_PeekMessage( MESSAGEQUEUE * msgQueue, LPMSG msg, HWND hwnd,
+			     WORD first, WORD last, WORD flags, BOOL peek )
 {
-    int pos;
+    int pos, mask;
+    DWORD nextExp;  /* Next timer expiration time */
+#ifdef USE_XLIB
+    XEvent event;
+#endif
 
-      /* First handle a WM_QUIT message */
-    if (msgQueue->wPostQMsg)
+    if (first || last)
     {
-	msg->hwnd    = hwnd;
-	msg->message = WM_QUIT;
-	msg->wParam  = msgQueue->wExitCode;
-	msg->lParam  = 0;
-	return TRUE;
+	mask = QS_POSTMESSAGE;  /* Always selectioned */
+	if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
+	if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE;
+	if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= WM_TIMER;
+	if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= WM_TIMER;
+	if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= WM_PAINT;
     }
+    else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT;
 
-      /* Then handle a message put by SendMessage() */
-    if (msgQueue->status & QS_SENDMESSAGE)
+#ifdef USE_XLIB
+    while (XPending( XT_display ))
     {
-	if (!hwnd || (msgQueue->hWnd == hwnd))
+	XNextEvent( XT_display, &event );
+	EVENT_ProcessEvent( &event );
+    }    
+#else
+    while (XtAppPending( XT_app_context ))
+	XtAppProcessEvent( XT_app_context, XtIMAll );
+#endif
+
+    while(1)
+    {    
+	  /* First handle a WM_QUIT message */
+	if (msgQueue->wPostQMsg)
 	{
-	    if ((!first && !last) || 
-		((msgQueue->msg >= first) && (msgQueue->msg <= last)))
+	    msg->hwnd    = hwnd;
+	    msg->message = WM_QUIT;
+	    msg->wParam  = msgQueue->wExitCode;
+	    msg->lParam  = 0;
+	    break;
+	}
+
+	  /* Then handle a message put by SendMessage() */
+	if (msgQueue->status & QS_SENDMESSAGE)
+	{
+	    if (!hwnd || (msgQueue->hWnd == hwnd))
 	    {
-		msg->hwnd    = msgQueue->hWnd;
-		msg->message = msgQueue->msg;
-		msg->wParam  = msgQueue->wParam;
-		msg->lParam  = msgQueue->lParam;
-		if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
-		return TRUE;
+		if ((!first && !last) || 
+		    ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
+		{
+		    msg->hwnd    = msgQueue->hWnd;
+		    msg->message = msgQueue->msg;
+		    msg->wParam  = msgQueue->wParam;
+		    msg->lParam  = msgQueue->lParam;
+		    if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
+		    break;
+		}
 	    }
 	}
-	
-    }
     
-      /* Now find a normal message */
-    pos = MSG_FindMsg( hwnd, first, last );
-    if (pos != -1)
-    {
-	QMSG *qmsg = &msgQueue->messages[pos];
-	*msg = qmsg->msg;
-	msgQueue->GetMessageTimeVal      = msg->time;
-	msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
-	msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
+	  /* Now find a normal message */
+	pos = MSG_FindMsg( msgQueue, hwnd, first, last );
+	if (pos != -1)
+	{
+	    QMSG *qmsg = &msgQueue->messages[pos];
+	    *msg = qmsg->msg;
+	    msgQueue->GetMessageTimeVal      = msg->time;
+	    msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
+	    msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
 
-	if (flags & PM_REMOVE) MSG_RemoveMsg(pos);
-    	return TRUE;
+	    if (flags & PM_REMOVE) MSG_RemoveMsg( msgQueue, pos );
+	    break;
+	}
+
+	  /* Now find a hardware event */
+	pos = MSG_FindMsg( sysMsgQueue, hwnd, first, last );
+	if (pos != -1)
+	{
+	    QMSG *qmsg = &sysMsgQueue->messages[pos];
+	    *msg = qmsg->msg;
+	    msgQueue->GetMessageTimeVal      = msg->time;
+	    msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
+	    msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
+
+	    if (flags & PM_REMOVE) MSG_RemoveMsg( sysMsgQueue, pos );
+	    break;
+	}
+
+	  /* Now find a WM_PAINT message */
+	if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT))
+	{
+	    msg->hwnd = WIN_FindWinToRepaint( hwnd );
+	    msg->message = WM_PAINT;
+	    msg->wParam = 0;
+	    msg->lParam = 0;
+	    if (msg->hwnd != 0) break;
+	}
+
+	  /* Finally handle WM_TIMER messages */
+	if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER))
+	{
+	    BOOL posted = TIMER_CheckTimer( &nextExp );
+#ifndef USE_XLIB
+	    if (xt_timer) XtRemoveTimeOut( xt_timer );
+	    if (nextExp != (DWORD)-1)
+		xt_timer = XtAppAddTimeOut( XT_app_context, nextExp,
+					    MSG_TimerCallback, NULL );
+	    else xt_timer = 0;
+#endif
+	    if (posted) continue;  /* Restart the whole thing */
+	}
+
+	  /* Wait until something happens */
+	if (peek) return FALSE;
+#ifdef USE_XLIB
+	if (!XPending( XT_display ) && (nextExp != -1))
+	{
+	    fd_set read_set;
+	    struct timeval timeout;
+	    int fd = ConnectionNumber(XT_display);
+	    FD_ZERO( &read_set );
+	    FD_SET( fd, &read_set );
+	    timeout.tv_sec = nextExp / 1000;
+	    timeout.tv_usec = (nextExp % 1000) * 1000;
+	    if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
+		continue;  /* On timeout or error, restart from the start */
+	}
+	XNextEvent( XT_display, &event );
+	EVENT_ProcessEvent( &event );
+#else       
+	XtAppProcessEvent( XT_app_context, XtIMAll );
+#endif	
     }
 
-      /* If nothing else, return a WM_PAINT message */
-    if ((!first && !last) || ((first <= WM_PAINT) && (last >= WM_PAINT)))
-    {
-	msg->hwnd = WIN_FindWinToRepaint( hwnd );
-	msg->message = WM_PAINT;
-	msg->wParam = 0;
-	msg->lParam = 0;
-	return (msg->hwnd != 0);
-    }	
-    return FALSE;
+      /* We got a message */
+    if (peek) return TRUE;
+    else return (msg->message != WM_QUIT);
 }
 
 
@@ -304,10 +492,7 @@
  */
 BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
 {
-    while (XtAppPending( XT_app_context ))
-	XtAppProcessEvent( XT_app_context, XtIMAll );
-
-    return MSG_PeekMessage( msg, hwnd, first, last, flags );
+    return MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, flags, TRUE );
 }
 
 
@@ -316,13 +501,7 @@
  */
 BOOL GetMessage( LPMSG msg, HWND hwnd, WORD first, WORD last ) 
 {
-    while(1)
-    {
-	if (MSG_PeekMessage( msg, hwnd, first, last, PM_REMOVE )) break;
-	XtAppProcessEvent( XT_app_context, XtIMAll );
-    }
-
-    return (msg->message != WM_QUIT);
+    return MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, PM_REMOVE, FALSE );
 }
 
 
@@ -341,7 +520,7 @@
     msg.pt.x    = 0;
     msg.pt.y    = 0;
     
-    return MSG_AddMsg( &msg, 0 );
+    return MSG_AddMsg( appMsgQueue, &msg, 0 );
 }
 
 
@@ -380,16 +559,39 @@
  */
 LONG DispatchMessage( LPMSG msg )
 {
-    WND * wndPtr = WIN_FindWndPtr( msg->hwnd );
-
+    WND * wndPtr;
+    LONG retval;
+    int painting;
+    
 #ifdef DEBUG_MSG
     printf( "Dispatch message hwnd=%08x msg=%d w=%d l=%d time=%u pt=%d,%d\n",
 	    msg->hwnd, msg->message, msg->wParam, msg->lParam, 
 	    msg->time, msg->pt.x, msg->pt.y );
 #endif
-    if (!wndPtr)  return 0;
-    return CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
-			   msg->wParam, msg->lParam );
+
+      /* Process timer messages */
+    if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
+    {
+	if (msg->lParam)
+	    return CallWindowProc( (FARPROC)msg->lParam, msg->hwnd,
+				   msg->message, msg->wParam, GetTickCount() );
+    }
+
+    if (!msg->hwnd) return 0;
+    if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
+    if (!wndPtr->lpfnWndProc) return 0;
+    painting = (msg->message == WM_PAINT);
+    if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
+    retval = CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
+			     msg->wParam, msg->lParam );
+    if (painting && (wndPtr->flags & WIN_NEEDS_BEGINPAINT))
+    {
+#ifdef DEBUG_WIN
+	printf( "BeginPaint not called on WM_PAINT!\n" );
+#endif
+	wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
+    }
+    return retval;
 }
 
 
@@ -398,7 +600,7 @@
  */
 DWORD GetMessagePos(void)
 {
-    return msgQueue->GetMessagePosVal;
+    return appMsgQueue->GetMessagePosVal;
 }
 
 
@@ -407,14 +609,27 @@
  */
 LONG GetMessageTime(void)
 {
-    return msgQueue->GetMessageTimeVal;
+    return appMsgQueue->GetMessageTimeVal;
 }
 
+
 /***********************************************************************
  *           GetMessageExtraInfo   (USER.288)
  */
 LONG GetMessageExtraInfo(void)
 {
-    return msgQueue->GetMessageExtraInfoVal;
+    return appMsgQueue->GetMessageExtraInfoVal;
+}
+
+
+/***********************************************************************
+ *           RegisterWindowMessage   (USER.118)
+ */
+WORD RegisterWindowMessage( LPCSTR str )
+{
+#ifdef DEBUG_MSG
+    printf( "RegisterWindowMessage: '%s'\n", str );
+#endif
+    return GlobalAddAtom( str );
 }