Release 960616
Sun Jun 16 16:51:31 1996 Alexandre Julliard <julliard@lrc.epfl.ch>
* [memory/heap.c]
Fixed bug in HeapRealloc (thanks to Bruce Milner).
* [misc/wsprintf.c]
Fixed argument size for %c format in wsprintf16().
* [objects/dc.c]
Don't free hFirstBitmap for saved DCs.
* [windows/event.c]
Added timer handling in EVENT_WaitXEvent().
* [windows/message.c]
In MSG_TranslateMouseMsg and MSG_TranslateKbdMsg, check if the
event is for the current task; if not, wake the other task.
* [windows/queue.c] [include/queue.h]
Added 'self' handle in queue structure.
* [windows/timer.c]
Added TIMER_ExpireTimers() function to mark expired timers and
wake up the corresponding tasks.
Thu Jun 13 01:46:33 EDT 1996 William Magro <wmagro@tc.cornell.edu>
* [windows/mapping.c]
First point in list was mapped multiple times in DPtoLP and
LPtoDP. Other points were not mapped.
Wed Jun 12 18:08:45 1996 Alex Korobka <alex@phm30.pharm.sunysb.edu>
* [misc/shell.c]
Some fixes for ExtractIcon function family.
* [documentation/user_module]
Chapter about windowing and messaging subsystems.
diff --git a/ANNOUNCE b/ANNOUNCE
index b4f14d3..9196873 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,12 +1,12 @@
-This is release 960611 of Wine, the MS Windows emulator. This is still a
+This is release 960616 of Wine, the MS Windows emulator. This is still a
developer's only release. There are many bugs and many unimplemented API
features. Most applications still do not work correctly.
Patches should be submitted to "julliard@lrc.epfl.ch". Please don't
forget to include a ChangeLog entry.
-WHAT'S NEW with Wine-960611: (see ChangeLog for details)
- - (surprise) More Win32 code.
+WHAT'S NEW with Wine-960616: (see ChangeLog for details)
+ - Inter-task messaging begins to work.
- Lots of bug fixes.
See the README file in the distribution for installation instructions.
@@ -15,10 +15,10 @@
the release is available at the ftp sites. The sources will be available
from the following locations:
- sunsite.unc.edu:/pub/Linux/ALPHA/wine/development/Wine-960611.tar.gz
- tsx-11.mit.edu:/pub/linux/ALPHA/Wine/development/Wine-960611.tar.gz
- ftp.infomagic.com:/pub/mirrors/linux/wine/development/Wine-960611.tar.gz
- aris.com:/pub/linux/ALPHA/Wine/development/Wine-960611.tar.gz
+ sunsite.unc.edu:/pub/Linux/ALPHA/wine/development/Wine-960616.tar.gz
+ tsx-11.mit.edu:/pub/linux/ALPHA/Wine/development/Wine-960616.tar.gz
+ ftp.infomagic.com:/pub/mirrors/linux/wine/development/Wine-960616.tar.gz
+ aris.com:/pub/linux/ALPHA/Wine/development/Wine-960616.tar.gz
It should also be available from any site that mirrors tsx-11 or sunsite.
diff --git a/ChangeLog b/ChangeLog
index 0d6d6c1..855adb2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,44 @@
----------------------------------------------------------------------
+Sun Jun 16 16:51:31 1996 Alexandre Julliard <julliard@lrc.epfl.ch>
+
+ * [memory/heap.c]
+ Fixed bug in HeapRealloc (thanks to Bruce Milner).
+
+ * [misc/wsprintf.c]
+ Fixed argument size for %c format in wsprintf16().
+
+ * [objects/dc.c]
+ Don't free hFirstBitmap for saved DCs.
+
+ * [windows/event.c]
+ Added timer handling in EVENT_WaitXEvent().
+
+ * [windows/message.c]
+ In MSG_TranslateMouseMsg and MSG_TranslateKbdMsg, check if the
+ event is for the current task; if not, wake the other task.
+
+ * [windows/queue.c] [include/queue.h]
+ Added 'self' handle in queue structure.
+
+ * [windows/timer.c]
+ Added TIMER_ExpireTimers() function to mark expired timers and
+ wake up the corresponding tasks.
+
+Thu Jun 13 01:46:33 EDT 1996 William Magro <wmagro@tc.cornell.edu>
+
+ * [windows/mapping.c]
+ First point in list was mapped multiple times in DPtoLP and
+ LPtoDP. Other points were not mapped.
+
+Wed Jun 12 18:08:45 1996 Alex Korobka <alex@phm30.pharm.sunysb.edu>
+
+ * [misc/shell.c]
+ Some fixes for ExtractIcon function family.
+
+ * [documentation/user_module]
+ Chapter about windowing and messaging subsystems.
+
+----------------------------------------------------------------------
Tue Jun 11 15:20:43 1996 Alexandre Julliard <julliard@lrc.epfl.ch>
* [debugger/break.c] [loader/signal.c]
diff --git a/documentation/user_module b/documentation/user_module
new file mode 100644
index 0000000..6b6bfd7
--- /dev/null
+++ b/documentation/user_module
@@ -0,0 +1,217 @@
+USER MODULE
+===========
+
+USER implements windowing and messaging subsystems. It also
+contains code for common controls and for other miscellaneous
+stuff (rectangles, clipboard, WNet, etc). Wine USER code is
+located in windows/, controls/, and misc/ directories.
+
+1. Windowing subsystem
+
+ Windows are arranged into parent/child hierarchy with one
+ common ancestor for all windows (desktop window). Each window
+ structure contains a pointer to the immediate ancestor (parent
+ window if WS_CHILD style bit is set), a pointer to the sibling
+ (returned by GetWindow(..., GW_NEXT)), a pointer to the owner
+ window (set only for popup window if it was created with valid
+ hwndParent parameter), and a pointer to the first child
+ window (GetWindow(.., GW_CHILD)). All popup and non-child windows
+ are therefore placed in the first level of this hierarchy and their
+ ancestor link (wnd->parent) points to the desktop window.
+
+ Desktop window - root window
+ | \ '-.
+ | \ '-.
+ popup -> wnd1 -> wnd2 - top level windows
+ | \ '-. '-.
+ | \ '-. '-.
+ child1 child2 -> child3 child4 - child windows
+
+ Horizontal arrows denote sibling relationship, vertical lines
+ - ancestor/child. To summarize, all windows with the same immediate
+ ancestor are sibling windows, all windows which do not have desktop
+ as their immediate ancestor are child windows. Popup windows behave
+ as topmost top-level windows unless they are owned. In this case the
+ only requirement is that they must precede their owners in the top-level
+ sibling list (they are not topmost). Child windows are confined to the
+ client area of their parent windows (client area is where window gets
+ to do its own drawing, non-client area consists of caption, menu, borders,
+ intrinsic scrollbars, and minimize/maximize/close buttons).
+
+ Another fairly important concept is "z-order". It is derived from
+ the ancestor/child hierarchy and is used to determine "above/below"
+ relationship. For instance, in the example above, z-order is
+ child1->popup->child2->child3->wnd1->child4->wnd2->desktop. Current
+ active window ("foreground window" in Win32) is moved to the front
+ of z-order unless its top-level ancestor owns popup windows.
+
+ All these issues are dealt with (or supposed to be) in
+ windows/winpos.c
+
+ Wine specifics: in default and managed mode each top-level window
+ gets its own X counterpart with desktop window being basically a
+ fake stub. In desktop mode, however, only desktop window has X
+ window associated with it.
+
+2. Messaging subsystem
+
+ Each Windows task/thread has its own message queue - this is where
+ it gets messages from. Messages can be generated on the fly
+ (WM_PAINT, WM_NCPAINT, WM_TIMER), they can be created by the system
+ (hardware messages), they can be posted by other tasks/threads
+ (PostMessage), or they can be sent by other tasks/threads (SendMessage).
+
+ Message priority:
+
+ First the system looks for sent messages, then for posted messages,
+ then for hardware messages, then it checks if the queue has the
+ "dirty window" bit set, and, finally, it checks for expired
+ timers. See windows/message.c.
+
+ From all these different types of messages, only posted messages go
+ directly into the private message queue. System messages (even in
+ Win95) are first collected in the system message queue and then
+ they either sit there until Get/PeekMessage gets to process them
+ or, as in Win95, if system queue is getting clobbered, a special
+ thread ("raw input thread") assigns them to the private
+ queues. Sent messages are queued separately and the sender sleeps
+ until it gets a reply. Special messages are generated on the fly
+ depending on the window/queue state. If the window update region is
+ not empty, the system sets the QS_PAINT bit in the owning queue and
+ eventually this window receives a WM_PAINT message (WM_NCPAINT too
+ if the update region intersects with the non-client area). A timer
+ event is raised when one of the queue timers expire. Depending on
+ the timer parameters DispatchMessage either calls the callback
+ function or the window procedure. If there are no messages pending
+ the task/thread sleeps until messages appear.
+
+ There are several tricky moments (open for discussion) -
+
+ a) System message order has to be honored and messages should be
+ processed within correct task/thread context. Therefore when
+ Get/PeekMessage encounters unassigned system message and this
+ message appears not to be for the current task/thread it should
+ either skip it (or get rid of it by moving it into the private
+ message queue of the target task/thread - Win95, AFAIK) and
+ look further or roll back and then yield until this message
+ gets processed when system switches to the correct context
+ (Win16). In the first case we lose correct message ordering, in
+ the second case we have the infamous synchronous system message
+ queue. Here is a post to one of the OS/2 newsgroup I found to
+ be relevant:
+
+ " Here's the problem in a nutshell, and there is no good solution.
+ Every possible solution creates a different problem.
+
+ With a windowing system, events can go to many different windows.
+ Most are sent by applications or by the OS when things relating to
+ that window happen (like repainting, timers, etc.)
+
+ Mouse input events go to the window you click on (unless some window
+ captures the mouse).
+
+ So far, no problem. Whenever an event happens, you put a message on
+ the target window's message queue. Every process has a message
+ queue. If the process queue fills up, the messages back up onto the
+ system queue.
+
+ This is the first cause of apps hanging the GUI. If an app doesn't
+ handle messages and they back up into the system queue, other apps
+ can't get any more messages. The reason is that the next message in
+ line can't go anywhere, and the system won't skip over it.
+
+ This can be fixed by making apps have bigger private message queues.
+ The SIQ fix does this. PMQSIZE does this for systems without the SIQ
+ fix. Applications can also request large queues on their own.
+
+ Another source of the problem, however, happens when you include
+ keyboard events. When you press a key, there's no easy way to know
+ what window the keystroke message should be delivered to.
+
+ Most windowing systems use a concept known as "focus". The window
+ with focus gets all incoming keyboard messages. Focus can be changed
+ from window to window by apps or by users clicking on winodws.
+
+ This is the second source of the problem. Suppose window A has focus.
+ You click on window B and start typing before the window gets focus.
+ Where should the keystrokes go? On the one hand, they should go to A
+ until the focus actually changes to B. On the other hand, you
+ probably want the keystrokes to go to B, since you clicked there
+ first.
+
+ OS/2's solution is that when a focus-changing event happens (like
+ clicking on a window), OS/2 holds all messages in the system queue
+ until the focus change actually happens. This way, subsequent
+ keystrokes go to the window you clicked on, even if it takes a while
+ for that window to get focus.
+
+ The downside is that if the window takes a real long time to get focus
+ (maybe it's not handling events, or maybe the window losing focus
+ isn't handling events), everything backs up in the system queue and
+ the system appears hung.
+
+ There are a few solutions to this problem.
+
+ One is to make focus policy asynchronous. That is, focus changing has
+ absolutely nothing to do with the keyboard. If you click on a window
+ and start typing before the focus actually changes, the keystrokes go
+ to the first window until focus changes, then they go to the second.
+ This is what X-windows does.
+
+ Another is what NT does. When focus changes, keyboard events are held
+ in the system message queue, but other events are allowed through.
+ This is "asynchronous" because the messages in the system queue are
+ delivered to the application queues in a different order from that
+ with which they were posted. If a bad app won't handle the "lose
+ focus" message, it's of no consequence - the app receiving focus will
+ get its "gain focus" message, and the keystrokes will go to it.
+
+ The NT solution also takes care of the application queue filling up
+ problem. Since the system delivers messages asynchronously, messages
+ waiting in the system queue will just sit there and the rest of the
+ messages will be delivered to their apps.
+
+ The OS/2 SIQ solution is this: When a focus-changing event happens,
+ in addition to blocking further messages from the application queues,
+ a timer is started. When the timer goes off, if the focus change has
+ not yet happened, the bad app has its focus taken away and all
+ messages targetted at that window are skipped. When the bad app
+ finally handles the focus change message, OS/2 will detect this and
+ stop skipping its messages.
+
+
+ As for the pros and cons:
+
+ The X-windows solution is probably the easiest. The problem is that
+ users generally don't like having to wait for the focus to change
+ before they start typing. On many occasions, you can type and the
+ characters end up in the wrong window because something (usually heavy
+ system load) is preventing the focus change from happening in a timely
+ manner.
+
+ The NT solution seems pretty nice, but making the system message queue
+ asynchronous can cause similar problems to the X-windows problem.
+ Since messages can be delivered out of order, programs must not assume
+ that two messages posted in a particular order will be delivered in
+ that same order. This can break legacy apps, but since Win32 always
+ had an asynchronous queue, it is fair to simply tell app designers
+ "don't do that". It's harder to tell app designers something like
+ that on OS/2 - they'll complain "you changed the rules and our apps
+ are breaking."
+
+ The OS/2 solution's problem is that nothing happens until you try to
+ change window focus, and then wait for the timeout. Until then, the
+ bad app is not detected and nothing is done." (by David Charlap)
+
+
+ b) Intertask/interthread SendMessage. The system has to inform the
+ target queue about the forthcoming message, then it has to
+ carry out the context switch and wait until the result is
+ available. In Win16 it is done by putting necessary parameters
+ into the queue structure and do a DirectedYield() call.
+ However, in Win32 there could be several messages pending sent
+ by preemptively executing threads, and in this case SendMessage
+ has to build some sort of message queue for sent
+ messages. Another issue is what to do with messages sent to the
+ sender when it is blocked inside its own SendMessage. At this
+ point Wine does not address any of these problems.
diff --git a/include/message.h b/include/message.h
index 72f64ad..365ee59 100644
--- a/include/message.h
+++ b/include/message.h
@@ -13,7 +13,6 @@
extern DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
/* message.c */
-extern BOOL MSG_GetHardwareMessage( LPMSG16 msg );
extern BOOL MSG_InternalGetMessage( SEGPTR msg, HWND hwnd, HWND hwndOwner,
short code, WORD flags, BOOL sendIdle );
@@ -21,13 +20,16 @@
extern void TIMER_RemoveWindowTimers( HWND hwnd );
extern void TIMER_RemoveQueueTimers( HQUEUE hqueue );
extern void TIMER_SwitchQueue( HQUEUE hOldQueue, HQUEUE hNewQueue );
-extern LONG TIMER_GetNextExp(void);
+extern LONG TIMER_GetNextExpiration(void);
+extern void TIMER_ExpireTimers(void);
+extern BOOL TIMER_GetTimerMsg( MSG16 *msg, HWND hwnd,
+ HQUEUE hQueue, BOOL remove );
/* event.c */
-extern BOOL EVENT_WaitXEvent( LONG maxWait );
+extern BOOL EVENT_WaitXEvent( BOOL sleep );
extern void EVENT_Synchronize(void);
extern void EVENT_ProcessEvent( XEvent *event );
-extern void EVENT_RegisterWindow( Window w, HWND hwnd );
+extern void EVENT_RegisterWindow( WND *pWnd );
extern void EVENT_DummyMotionNotify(void);
#endif /* __WINE_MESSAGE_H */
diff --git a/include/queue.h b/include/queue.h
index 553f7a4..cffd7e3 100644
--- a/include/queue.h
+++ b/include/queue.h
@@ -32,7 +32,7 @@
WORD queueSize; /* 0c Size of the queue */
DWORD GetMessageTimeVal WINE_PACKED; /* 0e Value for GetMessageTime */
DWORD GetMessagePosVal WINE_PACKED; /* 12 Value for GetMessagePos */
- WORD reserved1; /* 16 Unknown */
+ HQUEUE self; /* 16 Handle to self (was: reserved) */
DWORD GetMessageExtraInfoVal; /* 18 Value for GetMessageExtraInfo */
WORD reserved2; /* 1c Unknown */
LPARAM lParam WINE_PACKED; /* 1e Next 4 values set by SendMessage */
@@ -75,6 +75,7 @@
extern void QUEUE_WalkQueues(void);
extern MESSAGEQUEUE *QUEUE_GetSysQueue(void);
extern void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit );
+extern void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit );
extern void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue );
extern void QUEUE_WaitBits( WORD bits );
extern void QUEUE_IncPaintCount( HQUEUE hQueue );
diff --git a/include/windows.h b/include/windows.h
index 64363f0..d60ce19 100644
--- a/include/windows.h
+++ b/include/windows.h
@@ -469,6 +469,7 @@
/* CallMsgFilter() values */
#define MSGF_DIALOGBOX 0
+#define MSGF_MESSAGEBOX 1
#define MSGF_MENU 2
#define MSGF_MOVE 3
#define MSGF_SIZE 4
diff --git a/library/miscstubs.c b/library/miscstubs.c
index ed8aaa7..fa59b22 100644
--- a/library/miscstubs.c
+++ b/library/miscstubs.c
@@ -84,7 +84,7 @@
MAP_STR_TO_PROC("ColorDlgProc",ColorDlgProc);
MAP_STR_TO_PROC("ComboBoxWndProc",ComboBoxWndProc);
MAP_STR_TO_PROC("ComboLBoxWndProc",ComboLBoxWndProc);
- MAP_STR_TO_PROC("DefDlgProc",DefDlgProc);
+ MAP_STR_TO_PROC("DefDlgProc",DefDlgProc16);
MAP_STR_TO_PROC("EditWndProc",EditWndProc);
MAP_STR_TO_PROC("FileOpenDlgProc",FileOpenDlgProc);
MAP_STR_TO_PROC("FileSaveDlgProc",FileSaveDlgProc);
diff --git a/loader/task.c b/loader/task.c
index 8132b9d..b422d76 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -677,7 +677,7 @@
/* Flush any X events that happened in the meantime */
- EVENT_WaitXEvent( 0 );
+ EVENT_WaitXEvent( FALSE );
/* Find a task to yield to */
@@ -707,7 +707,7 @@
/* No task found, wait for some events to come in */
- EVENT_WaitXEvent( TIMER_GetNextExp() );
+ EVENT_WaitXEvent( TRUE );
}
if (hTask == hCurrentTask) return; /* Nothing to do */
diff --git a/memory/heap.c b/memory/heap.c
index 462cf77..2411161 100644
--- a/memory/heap.c
+++ b/memory/heap.c
@@ -1005,6 +1005,7 @@
SetLastError( ERROR_OUTOFMEMORY );
return NULL;
}
+ HEAP_ShrinkBlock( subheap, pArena, size );
}
else /* Do it the hard way */
{
@@ -1029,6 +1030,7 @@
+ sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
pInUse->threadId = GetCurrentTask();
pInUse->magic = ARENA_INUSE_MAGIC;
+ HEAP_ShrinkBlock( subheap, pInUse, size );
memcpy( pInUse + 1, pArena + 1, oldSize );
/* Free the previous block */
@@ -1038,11 +1040,7 @@
pArena = pInUse;
}
}
-
-
- /* Shrink the block */
-
- HEAP_ShrinkBlock( subheap, pArena, size );
+ else HEAP_ShrinkBlock( subheap, pArena, size ); /* Shrink the block */
/* Clear the extra bytes if needed */
diff --git a/misc/clipboard.c b/misc/clipboard.c
index 4ff267c..d25775c 100644
--- a/misc/clipboard.c
+++ b/misc/clipboard.c
@@ -129,7 +129,7 @@
WIN_GetXWindow(hWnd),CurrentTime);
/* TODO: need time-out for broken clients */
- while(wait_for_selection) EVENT_WaitXEvent(-1);
+ while(wait_for_selection) EVENT_WaitXEvent( TRUE );
return (BOOL)ClipFormats[0].wDataPresent;
}
diff --git a/misc/shell.c b/misc/shell.c
index 1eb5f54..a8eb3f9 100644
--- a/misc/shell.c
+++ b/misc/shell.c
@@ -501,8 +501,8 @@
for( i = nIconIndex; i < nIconIndex + n; i++ )
{
- hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + (i - nIconIndex),
- *(WORD*)pData );
+ hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + i,
+ *(WORD*)pData );
RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
GlobalFree16(hIcon);
}
@@ -547,18 +547,40 @@
/*************************************************************************
* ExtractAssociatedIcon [SHELL.36]
+ *
+ * Return icon for given file (either from file itself or from associated
+ * executable) and patch parameters if needed.
*/
HICON ExtractAssociatedIcon(HINSTANCE hInst,LPSTR lpIconPath, LPWORD lpiIcon)
{
HICON hIcon = ExtractIcon(hInst, lpIconPath, *lpiIcon);
- /* MAKEINTRESOURCE(2) seems to be "default" icon according to Progman
- *
- * For data files it probably should call FindExecutable and load
- * icon from there. As of now FindExecutable is empty stub.
- */
+ if( hIcon < 2 )
+ {
- if( hIcon < 2 ) hIcon = LoadIcon( hInst, MAKEINTRESOURCE(2));
+ if( hIcon == 1 ) /* no icons found in given file */
+ {
+ char tempPath[0x80];
+ UINT uRet = FindExecutable(lpIconPath,NULL,tempPath);
+
+ if( uRet > 32 && tempPath[0] )
+ {
+ strcpy(lpIconPath,tempPath);
+ hIcon = ExtractIcon(hInst, lpIconPath, *lpiIcon);
+
+ if( hIcon > 2 ) return hIcon;
+ }
+ else hIcon = 0;
+ }
+
+ if( hIcon == 1 )
+ *lpiIcon = 2; /* MSDOS icon - we found .exe but no icons in it */
+ else
+ *lpiIcon = 6; /* generic icon - found nothing */
+
+ GetModuleFileName(hInst, lpIconPath, 0x80);
+ hIcon = LoadIcon( hInst, MAKEINTRESOURCE(*lpiIcon));
+ }
return hIcon;
}
diff --git a/misc/wsprintf.c b/misc/wsprintf.c
index ac3b8bc..f8f77aa 100644
--- a/misc/wsprintf.c
+++ b/misc/wsprintf.c
@@ -248,7 +248,7 @@
{
case WPR_CHAR:
cur_arg = (DWORD)*(CHAR *)args;
- args = (CHAR *)args + 1;
+ args = (WORD *)args + 1;
break;
case WPR_STRING:
cur_arg = (DWORD)PTR_SEG_TO_LIN( *(SEGPTR *)args );
diff --git a/objects/dc.c b/objects/dc.c
index 6349560..d305001 100644
--- a/objects/dc.c
+++ b/objects/dc.c
@@ -621,9 +621,9 @@
SelectObject( hdc, STOCK_WHITE_BRUSH );
SelectObject( hdc, STOCK_SYSTEM_FONT );
XFreeGC( display, dc->u.x.gc );
+ if (dc->w.flags & DC_MEMORY) DeleteObject( dc->w.hFirstBitmap );
}
- if (dc->w.flags & DC_MEMORY) DeleteObject( dc->w.hFirstBitmap );
if (dc->w.hClipRgn) DeleteObject( dc->w.hClipRgn );
if (dc->w.hVisRgn) DeleteObject( dc->w.hVisRgn );
if (dc->w.hGCClipRgn) DeleteObject( dc->w.hGCClipRgn );
diff --git a/windows/class.c b/windows/class.c
index dc9865c..a2a37a2 100644
--- a/windows/class.c
+++ b/windows/class.c
@@ -200,7 +200,7 @@
if (classPtr->hbrBackground) DeleteObject( classPtr->hbrBackground );
GlobalDeleteAtom( classPtr->atomName );
CLASS_SetMenuNameA( classPtr, NULL );
- CLASS_SetWndProc( classPtr, (WNDPROC16)0, WIN_PROC_16 );
+ CLASS_SetWndProc( classPtr, (HANDLE32)0, WIN_PROC_16 );
HeapFree( SystemHeap, 0, classPtr );
return TRUE;
}
diff --git a/windows/dce.c b/windows/dce.c
index 8a809c9..f334bb9 100644
--- a/windows/dce.c
+++ b/windows/dce.c
@@ -159,9 +159,8 @@
dprintf_dc(stddeb,"\tgot hwnd %04x\n", wndCurrent->hwndSelf);
- if( wndCurrent->parent != wndScope )
- MapWindowPoints16(wndCurrent->parent->hwndSelf, wndScope->hwndSelf,
- (LPPOINT16)&wndRect, 2);
+ MapWindowPoints16(wndCurrent->parent->hwndSelf, wndScope->hwndSelf,
+ (LPPOINT16)&wndRect, 2);
if( IntersectRect16(&wndRect,&wndRect,pRectUpdate) )
SetHookFlags(dce->hDC, DCHF_INVALIDATEVISRGN);
break;
diff --git a/windows/event.c b/windows/event.c
index 66fb819..4f421a4 100644
--- a/windows/event.c
+++ b/windows/event.c
@@ -25,6 +25,7 @@
#include "class.h"
#include "clipboard.h"
#include "debugger.h"
+#include "message.h"
#include "module.h"
#include "options.h"
#include "queue.h"
@@ -35,19 +36,6 @@
#include "dde_proc.h"
-#ifdef ndef
-#ifndef FamilyAmoeba
-typedef char *XPointer;
-#endif
-#endif
-
-#ifdef WHO_NEEDS_DIRTY_HACKS
-#ifdef sparc
-/* Dirty hack to compile with Sun's OpenWindows */
-typedef char *XPointer;
-#endif
-#endif
-
#define NB_BUTTONS 3 /* Windows can handle 3 buttons */
/* X context to associate a hwnd to an X window */
@@ -152,13 +140,13 @@
static void EVENT_MotionNotify( XMotionEvent *event );
static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event );
static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event );
-static void EVENT_Expose( HWND hwnd, XExposeEvent *event );
-static void EVENT_GraphicsExpose( HWND hwnd, XGraphicsExposeEvent *event );
+static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
+static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
-static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event);
-static void EVENT_SelectionNotify( HWND hwnd, XSelectionEvent *event);
-static void EVENT_SelectionClear( HWND hwnd, XSelectionClearEvent *event);
-static void EVENT_ClientMessage( HWND hwnd, XClientMessageEvent *event );
+static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
+static void EVENT_SelectionNotify( XSelectionEvent *event);
+static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
+static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
/***********************************************************************
@@ -168,14 +156,14 @@
*/
void EVENT_ProcessEvent( XEvent *event )
{
- HWND hwnd;
- XPointer ptr;
+ WND *pWnd;
- XFindContext( display, ((XAnyEvent *)event)->window, winContext, &ptr );
- hwnd = (HWND) (int)ptr;
+ if (XFindContext( display, ((XAnyEvent *)event)->window, winContext,
+ (char **)&pWnd ) != 0)
+ return; /* Not for a registered window */
- dprintf_event(stddeb, "Got event %s for hwnd %04x\n",
- event_names[event->type], hwnd );
+ dprintf_event( stddeb, "Got event %s for hwnd %04x\n",
+ event_names[event->type], pWnd->hwndSelf );
switch(event->type)
{
@@ -207,46 +195,47 @@
break;
case FocusIn:
- EVENT_FocusIn( hwnd, (XFocusChangeEvent*)event );
+ EVENT_FocusIn( pWnd->hwndSelf, (XFocusChangeEvent*)event );
break;
case FocusOut:
- EVENT_FocusOut( hwnd, (XFocusChangeEvent*)event );
+ EVENT_FocusOut( pWnd->hwndSelf, (XFocusChangeEvent*)event );
break;
case Expose:
- EVENT_Expose( hwnd, (XExposeEvent*)event );
- break;
-
- case ConfigureNotify:
- EVENT_ConfigureNotify( hwnd, (XConfigureEvent*)event );
- break;
-
- case SelectionRequest:
- EVENT_SelectionRequest( hwnd, (XSelectionRequestEvent*)event );
- break;
-
- case SelectionNotify:
- EVENT_SelectionNotify( hwnd, (XSelectionEvent*)event );
- break;
-
- case SelectionClear:
- EVENT_SelectionClear( hwnd, (XSelectionClearEvent*) event );
- break;
-
- case ClientMessage:
- EVENT_ClientMessage( hwnd, (XClientMessageEvent *) event );
+ EVENT_Expose( pWnd, (XExposeEvent *)event );
break;
case GraphicsExpose:
- EVENT_GraphicsExpose( hwnd, (XGraphicsExposeEvent *) event );
+ EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
+ break;
+
+ case ConfigureNotify:
+ EVENT_ConfigureNotify( pWnd->hwndSelf, (XConfigureEvent*)event );
+ break;
+
+ case SelectionRequest:
+ EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
+ break;
+
+ case SelectionNotify:
+ EVENT_SelectionNotify( (XSelectionEvent *)event );
+ break;
+
+ case SelectionClear:
+ EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
+ break;
+
+ case ClientMessage:
+ EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
+ break;
case NoExpose:
break;
default:
dprintf_event(stddeb, "Unprocessed event %s for hwnd %04x\n",
- event_names[event->type], hwnd );
+ event_names[event->type], pWnd->hwndSelf );
break;
}
}
@@ -257,29 +246,31 @@
*
* Associate an X window to a HWND.
*/
-void EVENT_RegisterWindow( Window w, HWND hwnd )
+void EVENT_RegisterWindow( WND *pWnd )
{
if (!winContext) winContext = XUniqueContext();
- XSaveContext( display, w, winContext, (XPointer)(int)hwnd );
+ XSaveContext( display, pWnd->window, winContext, (char *)pWnd );
}
/***********************************************************************
* EVENT_WaitXEvent
*
- * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
+ * Wait for an X event, optionally sleeping until one arrives.
* Return TRUE if an event is pending, FALSE on timeout or error
* (for instance lost connection with the server).
*/
-BOOL EVENT_WaitXEvent( LONG maxWait )
+BOOL EVENT_WaitXEvent( BOOL sleep )
{
fd_set read_set;
struct timeval timeout;
XEvent event;
int fd = ConnectionNumber(display);
- if (!XPending(display) && (maxWait != -1))
+ if (!XPending(display))
{
+ LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
+
FD_ZERO( &read_set );
FD_SET( fd, &read_set );
@@ -295,18 +286,23 @@
;
return TRUE;
}
- stop_wait_op= STOP_WAIT_X;
- /* The code up to the next "stop_wait_op= CONT" must be reentrant */
+ stop_wait_op = STOP_WAIT_X;
+ /* The code up to the next "stop_wait_op = CONT" must be reentrant */
if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
- !XPending(display)) {
- stop_wait_op= CONT;
+ !XPending(display))
+ {
+ stop_wait_op = CONT;
+ TIMER_ExpireTimers();
return FALSE;
- } else {
- stop_wait_op= CONT;
}
+ else stop_wait_op = CONT;
#else /* CONFIG_IPC */
if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
- return FALSE; /* Timeout or error */
+ {
+ /* Timeout or error */
+ TIMER_ExpireTimers();
+ return FALSE;
+ }
#endif /* CONFIG_IPC */
}
@@ -371,19 +367,17 @@
/***********************************************************************
* EVENT_Expose
*/
-static void EVENT_Expose( HWND hwnd, XExposeEvent *event )
+static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
{
RECT32 rect;
- WND * wndPtr = WIN_FindWndPtr( hwnd );
- if (!wndPtr) return;
- /* Make position relative to client area instead of window */
- rect.left = event->x - (wndPtr->rectClient.left - wndPtr->rectWindow.left);
- rect.top = event->y - (wndPtr->rectClient.top - wndPtr->rectWindow.top);
+ /* Make position relative to client area instead of window */
+ rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
+ rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
rect.right = rect.left + event->width;
rect.bottom = rect.top + event->height;
- RedrawWindow32( hwnd, &rect, 0,
+ RedrawWindow32( pWnd->hwndSelf, &rect, 0,
RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
(event->count ? 0 : RDW_ERASENOW) );
}
@@ -391,22 +385,21 @@
/***********************************************************************
* EVENT_GraphicsExpose
+ *
* This is needed when scrolling area is partially obscured
* by non-Wine X window.
*/
-static void EVENT_GraphicsExpose( HWND hwnd, XGraphicsExposeEvent *event )
+static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
{
- RECT16 rect;
- WND * wndPtr = WIN_FindWndPtr( hwnd );
- if (!wndPtr) return;
+ RECT32 rect;
- /* Make position relative to client area instead of window */
- rect.left = event->x - (wndPtr->rectClient.left - wndPtr->rectWindow.left);
- rect.top = event->y - (wndPtr->rectClient.top - wndPtr->rectWindow.top);
+ /* Make position relative to client area instead of window */
+ rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
+ rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
rect.right = rect.left + event->width;
rect.bottom = rect.top + event->height;
- RedrawWindow16( hwnd, &rect, 0,
+ RedrawWindow32( pWnd->hwndSelf, &rect, 0,
RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
(event->count ? 0 : RDW_ERASENOW) );
}
@@ -712,7 +705,7 @@
/***********************************************************************
* EVENT_SelectionRequest
*/
-static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event )
+static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
{
XSelectionEvent result;
Atom rprop = None;
@@ -731,7 +724,7 @@
else if(!CLIPBOARD_IsPresent(CF_TEXT)) rprop = None;
else{
/* Don't worry if we can't open */
- BOOL couldOpen=OpenClipboard(hwnd);
+ BOOL couldOpen=OpenClipboard( pWnd->hwndSelf );
hText=GetClipboardData(CF_TEXT);
text=GlobalLock16(hText);
XChangeProperty(display,request,rprop,XA_STRING,
@@ -759,28 +752,28 @@
/***********************************************************************
* EVENT_SelectionNotify
*/
-static void EVENT_SelectionNotify(HWND hwnd, XSelectionEvent *event)
+static void EVENT_SelectionNotify( XSelectionEvent *event )
{
- if(event->selection!=XA_PRIMARY)return;
- if(event->target!=XA_STRING)CLIPBOARD_ReadSelection(0,None);
- CLIPBOARD_ReadSelection(event->requestor,event->property);
+ if (event->selection != XA_PRIMARY) return;
+ if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
+ CLIPBOARD_ReadSelection( event->requestor, event->property );
}
/***********************************************************************
* EVENT_SelectionClear
*/
-static void EVENT_SelectionClear(HWND hwnd, XSelectionClearEvent *event)
+static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
{
- if(event->selection!=XA_PRIMARY)return;
- CLIPBOARD_ReleaseSelection(hwnd);
+ if (event->selection != XA_PRIMARY) return;
+ CLIPBOARD_ReleaseSelection( pWnd->hwndSelf );
}
/**********************************************************************
* EVENT_ClientMessage
*/
-static void EVENT_ClientMessage (HWND hwnd, XClientMessageEvent *event )
+static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
{
static Atom wmProtocols = None;
static Atom wmDeleteWindow = None;
@@ -796,7 +789,7 @@
dprintf_event( stddeb, "unrecognized ClientMessage\n" );
return;
}
- SendMessage16( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
+ SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
}
diff --git a/windows/mapping.c b/windows/mapping.c
index 9ae2b69..3d2be8a 100644
--- a/windows/mapping.c
+++ b/windows/mapping.c
@@ -48,6 +48,7 @@
{
points->x = XDPTOLP( dc, points->x );
points->y = YDPTOLP( dc, points->y );
+ points++;
}
return TRUE;
}
@@ -65,6 +66,7 @@
{
points->x = XDPTOLP( dc, points->x );
points->y = YDPTOLP( dc, points->y );
+ points++;
}
return TRUE;
}
@@ -82,6 +84,7 @@
{
points->x = XLPTODP( dc, points->x );
points->y = YLPTODP( dc, points->y );
+ points++;
}
return TRUE;
}
@@ -99,6 +102,7 @@
{
points->x = XLPTODP( dc, points->x );
points->y = YLPTODP( dc, points->y );
+ points++;
}
return TRUE;
}
diff --git a/windows/message.c b/windows/message.c
index 8ff4af2..c777683 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -29,10 +29,7 @@
extern BYTE* KeyStateTable; /* event.c */
extern WPARAM lastEventChar; /* event.c */
-extern BOOL TIMER_CheckTimer( LONG *next, MSG16 *msg,
- HWND hwnd, BOOL remove ); /* timer.c */
-
-DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
+DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
static WORD doubleClickSpeed = 452;
@@ -68,9 +65,8 @@
/* Find the window */
- if (GetCapture())
+ if ((msg->hwnd = GetCapture()) != 0)
{
- msg->hwnd = GetCapture();
ScreenToClient16( msg->hwnd, &pt );
msg->lParam = MAKELONG( pt.x, pt.y );
/* No need to further process the message */
@@ -80,6 +76,16 @@
}
hittest = WINPOS_WindowFromPoint( msg->pt, &pWnd );
+ if (pWnd->hmemTaskQ != GetTaskQueue(0))
+ {
+ /* Not for the current task */
+ MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
+ if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
+ /* Wake up the other task */
+ queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
+ if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
+ return FALSE;
+ }
msg->hwnd = pWnd->hwndSelf;
if ((hittest != HTERROR) && mouseClick)
{
@@ -172,6 +178,8 @@
*/
static BOOL MSG_TranslateKeyboardMsg( MSG16 *msg, BOOL remove )
{
+ WND *pWnd;
+
/* Should check Ctrl-Esc and PrintScreen here */
msg->hwnd = GetFocus();
@@ -185,6 +193,17 @@
if( msg->message < WM_SYSKEYDOWN )
msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
}
+ pWnd = WIN_FindWndPtr( msg->hwnd );
+ if (pWnd && (pWnd->hmemTaskQ != GetTaskQueue(0)))
+ {
+ /* Not for the current task */
+ MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
+ if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
+ /* Wake up the other task */
+ queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
+ if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
+ return FALSE;
+ }
return !HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
msg->wParam, msg->lParam );
}
@@ -202,7 +221,7 @@
int i, pos = sysMsgQueue->nextMessage;
/* If the queue is empty, attempt to fill it */
- if (!sysMsgQueue->msgCount && XPending(display)) EVENT_WaitXEvent( 0 );
+ if (!sysMsgQueue->msgCount && XPending(display)) EVENT_WaitXEvent( FALSE );
for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
{
@@ -267,38 +286,6 @@
/***********************************************************************
- * MSG_GetHardwareMessage
- *
- * Like GetMessage(), but only return mouse and keyboard events.
- * Used internally for window moving and resizing. Mouse messages
- * are not translated.
- * Warning: msg->hwnd is always 0.
- */
-BOOL MSG_GetHardwareMessage( LPMSG16 msg )
-{
-#if 0
- int pos;
- XEvent event;
- MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
-
- while(1)
- {
- if ((pos = QUEUE_FindMsg( sysMsgQueue, 0, 0, 0 )) != -1)
- {
- *msg = sysMsgQueue->messages[pos].msg;
- QUEUE_RemoveMsg( sysMsgQueue, pos );
- break;
- }
- XNextEvent( display, &event );
- EVENT_ProcessEvent( &event );
- }
-#endif
- MSG_PeekMessage( msg, 0, WM_KEYFIRST, WM_MOUSELAST, PM_REMOVE, 0 );
- return TRUE;
-}
-
-
-/***********************************************************************
* MSG_SendMessage
*
* Implementation of an inter-task SendMessage.
@@ -381,7 +368,6 @@
int pos, mask;
MESSAGEQUEUE *msgQueue;
HQUEUE hQueue;
- LONG nextExp; /* Next timer expiration time */
#ifdef CONFIG_IPC
DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
@@ -490,10 +476,8 @@
}
if ((msgQueue->wakeBits & mask) & QS_TIMER)
{
- if (TIMER_CheckTimer( &nextExp, msg, hwnd, flags & PM_REMOVE ))
- break; /* Got a timer msg */
+ if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
}
- else nextExp = -1; /* No timeout needed */
if (peek)
{
@@ -792,24 +776,7 @@
*/
void WaitMessage( void )
{
- MSG16 msg;
- MESSAGEQUEUE *queue;
- LONG nextExp = -1; /* Next timer expiration time */
-
-#ifdef CONFIG_IPC
- DDE_GetRemoteMessage();
-#endif /* CONFIG_IPC */
-
- if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return;
- if ((queue->wPostQMsg) ||
- (queue->wakeBits & (QS_SENDMESSAGE | QS_PAINT)) ||
- (queue->msgCount) || (QUEUE_GetSysQueue()->msgCount) )
- return;
- if ((queue->wakeBits & QS_TIMER) &&
- TIMER_CheckTimer( &nextExp, &msg, 0, FALSE))
- return;
- /* FIXME: (dde) must check DDE & X-events simultaneously */
- EVENT_WaitXEvent( nextExp );
+ QUEUE_WaitBits( QS_ALLINPUT );
}
diff --git a/windows/nonclient.c b/windows/nonclient.c
index a51ae71..67b052d 100644
--- a/windows/nonclient.c
+++ b/windows/nonclient.c
@@ -16,6 +16,7 @@
#include "menu.h"
#include "winpos.h"
#include "scroll.h"
+#include "stackframe.h"
#include "nonclient.h"
#include "graphics.h"
#include "queue.h"
@@ -907,7 +908,8 @@
SetCapture(hwnd);
while(!hittest)
{
- MSG_GetHardwareMessage( &msg );
+ MSG_InternalGetMessage( MAKE_SEGPTR(&msg), 0, 0, MSGF_SIZE,
+ PM_REMOVE, FALSE );
switch(msg.message)
{
case WM_MOUSEMOVE:
@@ -1046,7 +1048,8 @@
{
int dx = 0, dy = 0;
- MSG_GetHardwareMessage( &msg );
+ MSG_InternalGetMessage( MAKE_SEGPTR(&msg), 0, 0, MSGF_SIZE,
+ PM_REMOVE, FALSE );
/* Exit on button-up, Return, or Esc */
if ((msg.message == WM_LBUTTONUP) ||
@@ -1148,7 +1151,7 @@
do
{
BOOL oldstate = pressed;
- MSG_GetHardwareMessage( &msg );
+ MSG_InternalGetMessage( MAKE_SEGPTR(&msg), 0, 0, 0, PM_REMOVE, FALSE );
pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
if (pressed != oldstate)
diff --git a/windows/queue.c b/windows/queue.c
index eb457ed..c1406c1 100644
--- a/windows/queue.c
+++ b/windows/queue.c
@@ -16,6 +16,8 @@
static HQUEUE hFirstQueue = 0;
static HQUEUE hmemSysMsgQueue = 0;
+static MESSAGEQUEUE *pMouseQueue = NULL; /* Queue for last mouse message */
+static MESSAGEQUEUE *pKbdQueue = NULL; /* Queue for last kbd message */
static HQUEUE hDoomedQueue = 0;
static MESSAGEQUEUE *sysMsgQueue = NULL;
@@ -111,6 +113,7 @@
if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, queueSize )))
return 0;
msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
+ msgQueue->self = hQueue;
msgQueue->msgSize = sizeof(QMSG);
msgQueue->queueSize = size;
msgQueue->wWinVersion = pTask ? pTask->version : 0;
@@ -144,6 +147,7 @@
pPrev = &msgQ->next;
}
if (*pPrev) *pPrev = msgQueue->next;
+ msgQueue->self = 0;
GlobalFree16( hQueue );
return 1;
}
@@ -181,6 +185,8 @@
*/
void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
{
+ if (bit & QS_MOUSE) pMouseQueue = queue;
+ if (bit & QS_KEY) pKbdQueue = queue;
queue->changeBits |= bit;
queue->wakeBits |= bit;
if (queue->wakeMask & bit)
@@ -192,6 +198,16 @@
/***********************************************************************
+ * QUEUE_ClearWakeBit
+ */
+void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
+{
+ queue->changeBits &= ~bit;
+ queue->wakeBits &= ~bit;
+}
+
+
+/***********************************************************************
* QUEUE_WaitBits
*
* See "Windows Internals", p.447
@@ -233,16 +249,22 @@
WPARAM wParam;
LPARAM lParam;
LRESULT result = 0;
+ HQUEUE oldSender;
printf( "ReceiveMessage\n" );
if (!(queue->wakeBits & QS_SENDMESSAGE)) return;
if (!(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask))) return;
/* Remove sending queue from the list */
+ oldSender = queue->InSendMessageHandle;
queue->InSendMessageHandle = queue->hSendingTask;
queue->hSendingTask = senderQ->hPrevSendingTask;
senderQ->hPrevSendingTask = 0;
- if (!queue->hSendingTask) queue->wakeBits &= ~QS_SENDMESSAGE;
+ if (!queue->hSendingTask)
+ {
+ queue->wakeBits &= ~QS_SENDMESSAGE;
+ queue->changeBits &= ~QS_SENDMESSAGE;
+ }
/* Get the parameters from the sending task */
hwnd = senderQ->hWnd;
@@ -257,13 +279,21 @@
/* Call the window procedure */
/* FIXME: should we use CallWindowProc here? */
- if (IsWindow( hwnd )) result = SendMessage16( hwnd, msg, wParam, lParam );
+ if (IsWindow( hwnd ))
+ {
+ DWORD extraInfo = queue->GetMessageExtraInfoVal;
+ queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
+ result = SendMessage16( hwnd, msg, wParam, lParam );
+ queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */
+ }
printf( "ReceiveMessage: wnd proc %04x %04x %04x %08x ret = %08x\n",
hwnd, msg, wParam, lParam, result );
/* Return the result to the sender task */
ReplyMessage( result );
+
+ queue->InSendMessageHandle = oldSender;
}
@@ -373,15 +403,18 @@
if (!(hwnd = GetSysModalWindow()))
{
- hwnd = (wakeBit == QS_KEY) ? GetFocus() : GetCapture();
- if (!hwnd) hwnd = GetActiveWindow();
+ if (wakeBit == QS_KEY)
+ {
+ if (!(hwnd = GetFocus())) hwnd = GetActiveWindow();
+ }
+ else hwnd = GetCapture();
}
if (hwnd)
{
WND *wndPtr = WIN_FindWndPtr( hwnd );
if (wndPtr) queue = (MESSAGEQUEUE *)GlobalLock16( wndPtr->hmemTaskQ );
}
- else
+ else if (!(queue = pMouseQueue))
{
hQueue = hFirstQueue;
while (hQueue)
diff --git a/windows/timer.c b/windows/timer.c
index 53156d2..31e3940 100644
--- a/windows/timer.c
+++ b/windows/timer.c
@@ -19,7 +19,7 @@
WORD id;
WORD timeout;
struct tagTIMER *next;
- DWORD expires;
+ DWORD expires; /* Next expiration, or 0 if already expired */
FARPROC proc;
} TIMER;
@@ -70,6 +70,7 @@
while (*ppTimer && (*ppTimer != pTimer)) ppTimer = &(*ppTimer)->next;
if (*ppTimer) *ppTimer = pTimer->next;
pTimer->next = NULL;
+ if (!pTimer->expires) QUEUE_DecTimerCount( pTimer->hq );
}
@@ -81,7 +82,6 @@
static void TIMER_ClearTimer( TIMER * pTimer )
{
TIMER_RemoveTimer( pTimer );
- QUEUE_DecTimerCount( pTimer->hq );
pTimer->hwnd = 0;
pTimer->msg = 0;
pTimer->id = 0;
@@ -151,44 +151,58 @@
/***********************************************************************
- * TIMER_GetNextExp
+ * TIMER_GetNextExpiration
*
* Return next timer expiration time, or -1 if none.
*/
-LONG TIMER_GetNextExp(void)
+LONG TIMER_GetNextExpiration(void)
{
return pNextTimer ? EXPIRE_TIME( pNextTimer, GetTickCount() ) : -1;
}
/***********************************************************************
- * TIMER_CheckTimer
+ * TIMER_ExpireTimers
*
- * Check whether a timer has expired, and create a message if necessary.
- * Otherwise, return time until next timer expiration in 'next'.
- * If 'hwnd' is not NULL, only consider timers for this window.
- * If 'remove' is TRUE, remove all expired timers up to the returned one.
+ * Mark expired timers and wake the appropriate queues.
*/
-BOOL TIMER_CheckTimer( LONG *next, MSG16 *msg, HWND hwnd, BOOL remove )
+void TIMER_ExpireTimers(void)
{
- TIMER * pTimer = pNextTimer;
+ TIMER *pTimer = pNextTimer;
+ DWORD curTime = GetTickCount();
+
+ while (pTimer && !pTimer->expires) /* Skip already expired timers */
+ pTimer = pTimer->next;
+ while (pTimer && (pTimer->expires <= curTime))
+ {
+ pTimer->expires = 0;
+ QUEUE_IncTimerCount( pTimer->hq );
+ pTimer = pTimer->next;
+ }
+}
+
+
+/***********************************************************************
+ * TIMER_GetTimerMsg
+ *
+ * Build a message for an expired timer.
+ */
+BOOL TIMER_GetTimerMsg( MSG16 *msg, HWND hwnd, HQUEUE hQueue, BOOL remove )
+{
+ TIMER *pTimer = pNextTimer;
DWORD curTime = GetTickCount();
if (hwnd) /* Find first timer for this window */
while (pTimer && (pTimer->hwnd != hwnd)) pTimer = pTimer->next;
+ else /* Find first timer for this queue */
+ while (pTimer && (pTimer->hq != hQueue)) pTimer = pTimer->next;
- if (!pTimer) *next = -1;
- else *next = EXPIRE_TIME( pTimer, curTime );
- if (*next != 0) return FALSE; /* No timer expired */
+ if (!pTimer || (pTimer->expires > curTime)) return FALSE; /* No timer */
+ if (remove) TIMER_RestartTimer( pTimer, curTime ); /* Restart it */
- if (remove) /* Restart all timers before pTimer, and then pTimer itself */
- {
- while (pNextTimer != pTimer) TIMER_RestartTimer( pNextTimer, curTime );
- TIMER_RestartTimer( pTimer, curTime );
- }
+ dprintf_timer( stddeb, "Timer expired: %04x, %04x, %04x, %08lx\n",
+ pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
- dprintf_timer(stddeb, "Timer expired: %p, %04x, %04x, %04x, %08lx\n",
- pTimer, pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
/* Build the message */
msg->hwnd = pTimer->hwnd;
msg->message = pTimer->msg;
@@ -218,10 +232,10 @@
(pTimer->timeout != 0))
{
/* Got one: set new values and return */
- pTimer->timeout = timeout;
- pTimer->expires = GetTickCount() + timeout;
- pTimer->proc = proc;
TIMER_RemoveTimer( pTimer );
+ pTimer->timeout = timeout;
+ pTimer->proc = proc;
+ pTimer->expires = GetTickCount() + timeout;
TIMER_InsertTimer( pTimer );
return id;
}
@@ -248,7 +262,6 @@
dprintf_timer(stddeb, "Timer added: %p, %04x, %04x, %04x, %08lx\n",
pTimer, pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
TIMER_InsertTimer( pTimer );
- QUEUE_IncTimerCount( pTimer->hq );
if (!id)
return TRUE;
else
diff --git a/windows/win.c b/windows/win.c
index 8c23889..c6e5188 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -347,7 +347,7 @@
if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
if (wndPtr->window) XDestroyWindow( display, wndPtr->window );
if (wndPtr->class->style & CS_OWNDC) DCE_FreeDCE( wndPtr->hdce );
- WIN_SetWndProc( wndPtr, (WNDPROC16)0, WIN_PROC_16 );
+ WIN_SetWndProc( wndPtr, (HANDLE32)0, WIN_PROC_16 );
wndPtr->class->cWindows--;
USER_HEAP_FREE( hwnd );
}
@@ -426,7 +426,7 @@
pWndDesktop->hProp = 0;
pWndDesktop->userdata = 0;
- EVENT_RegisterWindow( pWndDesktop->window, hwndDesktop );
+ EVENT_RegisterWindow( pWndDesktop );
SendMessage32A( hwndDesktop, WM_NCCREATE, 0, 0 );
if ((hdc = GetDC( hwndDesktop )) != 0)
{
@@ -628,7 +628,7 @@
Window win = WIN_GetXWindow( cs->hwndParent );
if (win) XSetTransientForHint( display, wndPtr->window, win );
}
- EVENT_RegisterWindow( wndPtr->window, hwnd );
+ EVENT_RegisterWindow( wndPtr );
}
/* Set the window menu */