From 8b9156307994a7bd159925e8f32cde34874f6c21 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sun, 16 Jun 1996 16:16:05 +0000 Subject: [PATCH] Release 960616 Sun Jun 16 16:51:31 1996 Alexandre Julliard * [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 * [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 * [misc/shell.c] Some fixes for ExtractIcon function family. * [documentation/user_module] Chapter about windowing and messaging subsystems. --- ANNOUNCE | 14 +-- ChangeLog | 40 +++++++ documentation/user_module | 217 ++++++++++++++++++++++++++++++++++++++ include/message.h | 10 +- include/queue.h | 3 +- include/windows.h | 1 + library/miscstubs.c | 2 +- loader/task.c | 4 +- memory/heap.c | 8 +- misc/clipboard.c | 2 +- misc/shell.c | 38 +++++-- misc/wsprintf.c | 2 +- objects/dc.c | 2 +- windows/class.c | 2 +- windows/dce.c | 5 +- windows/event.c | 169 ++++++++++++++--------------- windows/mapping.c | 4 + windows/message.c | 89 +++++----------- windows/nonclient.c | 9 +- windows/queue.c | 43 +++++++- windows/timer.c | 63 ++++++----- windows/win.c | 6 +- 22 files changed, 513 insertions(+), 220 deletions(-) create mode 100644 documentation/user_module diff --git a/ANNOUNCE b/ANNOUNCE index b4f14d30ffc..91968732147 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 @@ Because of lags created by using mirror, this message may reach you before 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 0d6d6c1adfa..855adb2007e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,43 @@ +---------------------------------------------------------------------- +Sun Jun 16 16:51:31 1996 Alexandre Julliard + + * [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 + + * [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 + + * [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 diff --git a/documentation/user_module b/documentation/user_module new file mode 100644 index 00000000000..6b6bfd74c26 --- /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 72f64adc198..365ee599606 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 BOOL MSG_InternalGetMessage( SEGPTR msg, HWND hwnd, HWND hwndOwner, 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 553f7a41e6f..cffd7e3bf8e 100644 --- a/include/queue.h +++ b/include/queue.h @@ -32,7 +32,7 @@ typedef struct tagMESSAGEQUEUE 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_DumpQueue( HQUEUE hQueue ); 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 64363f0470c..d60ce19a040 100644 --- a/include/windows.h +++ b/include/windows.h @@ -469,6 +469,7 @@ DECL_WINELIB_TYPE(LPNCCALCSIZE_PARAMS); /* 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 ed8aaa7e7f8..fa59b22456a 100644 --- a/library/miscstubs.c +++ b/library/miscstubs.c @@ -84,7 +84,7 @@ WNDPROC MODULE_GetWndProcEntry16( char *name ) 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 8132b9de0c6..b422d76b556 100644 --- a/loader/task.c +++ b/loader/task.c @@ -677,7 +677,7 @@ void TASK_Reschedule(void) /* 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 @@ void TASK_Reschedule(void) /* 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 462cf77a0bf..241116120e0 100644 --- a/memory/heap.c +++ b/memory/heap.c @@ -1005,6 +1005,7 @@ LPVOID HeapReAlloc( HANDLE32 heap, DWORD flags, LPVOID ptr, DWORD size ) SetLastError( ERROR_OUTOFMEMORY ); return NULL; } + HEAP_ShrinkBlock( subheap, pArena, size ); } else /* Do it the hard way */ { @@ -1029,6 +1030,7 @@ LPVOID HeapReAlloc( HANDLE32 heap, DWORD flags, LPVOID ptr, DWORD size ) + 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 @@ LPVOID HeapReAlloc( HANDLE32 heap, DWORD flags, LPVOID ptr, DWORD size ) 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 4ff267ca3f4..d25775cd39d 100644 --- a/misc/clipboard.c +++ b/misc/clipboard.c @@ -129,7 +129,7 @@ BOOL CLIPBOARD_RequestXSelection() 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 1eb5f540b7c..a8eb3f943ac 100644 --- a/misc/shell.c +++ b/misc/shell.c @@ -501,8 +501,8 @@ HICON InternalExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, UINT nIco 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 @@ HICON ExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, WORD nIconIndex) /************************************************************************* * 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 ac3b8bc1974..f8f77aaa71c 100644 --- a/misc/wsprintf.c +++ b/misc/wsprintf.c @@ -248,7 +248,7 @@ INT16 wvsnprintf16( LPSTR buffer, UINT16 maxlen, LPCSTR spec, LPCVOID args ) { 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 63495609af2..d305001929b 100644 --- a/objects/dc.c +++ b/objects/dc.c @@ -621,9 +621,9 @@ BOOL DeleteDC( HDC hdc ) 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 dc9865cce62..a2a37a2e87b 100644 --- a/windows/class.c +++ b/windows/class.c @@ -200,7 +200,7 @@ static BOOL CLASS_FreeClass( CLASS *classPtr ) 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 8a809c97602..f334bb9a706 100644 --- a/windows/dce.c +++ b/windows/dce.c @@ -159,9 +159,8 @@ BOOL DCE_InvalidateDCE(WND* wndScope, RECT16* pRectUpdate) 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 66fb8190b37..4f421a4cacb 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_ButtonRelease( XButtonEvent *event ); 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 @@ static void EVENT_ClientMessage( HWND hwnd, XClientMessageEvent *event ); */ 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 @@ void EVENT_ProcessEvent( XEvent *event ) 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 @@ void EVENT_ProcessEvent( XEvent *event ) * * 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 @@ BOOL EVENT_WaitXEvent( LONG maxWait ) ; 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 @@ static WORD EVENT_XStateToKeyState( int state ) /*********************************************************************** * 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 @@ static void EVENT_Expose( HWND hwnd, XExposeEvent *event ) /*********************************************************************** * 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 @@ static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event ) /*********************************************************************** * 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 @@ static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event ) 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 @@ static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event ) /*********************************************************************** * 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 @@ static void EVENT_ClientMessage (HWND hwnd, XClientMessageEvent *event ) 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 9ae2b69175c..3d2be8a9f00 100644 --- a/windows/mapping.c +++ b/windows/mapping.c @@ -48,6 +48,7 @@ BOOL16 DPtoLP16( HDC16 hdc, LPPOINT16 points, INT16 count ) { points->x = XDPTOLP( dc, points->x ); points->y = YDPTOLP( dc, points->y ); + points++; } return TRUE; } @@ -65,6 +66,7 @@ BOOL32 DPtoLP32( HDC32 hdc, LPPOINT32 points, INT32 count ) { points->x = XDPTOLP( dc, points->x ); points->y = YDPTOLP( dc, points->y ); + points++; } return TRUE; } @@ -82,6 +84,7 @@ BOOL16 LPtoDP16( HDC16 hdc, LPPOINT16 points, INT16 count ) { points->x = XLPTODP( dc, points->x ); points->y = YLPTODP( dc, points->y ); + points++; } return TRUE; } @@ -99,6 +102,7 @@ BOOL32 LPtoDP32( HDC32 hdc, LPPOINT32 points, INT32 count ) { 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 8ff4af2688e..c777683f143 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 @@ static BOOL MSG_TranslateMouseMsg( MSG16 *msg, BOOL remove ) /* 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 @@ static BOOL MSG_TranslateMouseMsg( MSG16 *msg, BOOL remove ) } 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_TranslateMouseMsg( MSG16 *msg, BOOL remove ) */ static BOOL MSG_TranslateKeyboardMsg( MSG16 *msg, BOOL remove ) { + WND *pWnd; + /* Should check Ctrl-Esc and PrintScreen here */ msg->hwnd = GetFocus(); @@ -185,6 +193,17 @@ static BOOL MSG_TranslateKeyboardMsg( MSG16 *msg, BOOL remove ) 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 @@ static BOOL MSG_PeekHardwareMsg( MSG16 *msg, HWND hwnd, WORD first, WORD last, 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++) { @@ -266,38 +285,6 @@ WORD GetDoubleClickTime() } -/*********************************************************************** - * 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 * @@ -381,7 +368,6 @@ static BOOL MSG_PeekMessage( LPMSG16 msg, HWND hwnd, WORD first, WORD last, 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 @@ static BOOL MSG_PeekMessage( LPMSG16 msg, HWND hwnd, WORD first, WORD last, } 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 @@ LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam) */ 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 a51ae71553a..67b052dedea 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 @@ static LONG NC_StartSizeMove( HWND hwnd, WPARAM wParam, POINT16 *capturePoint ) 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 @@ static void NC_DoSizeMove( HWND hwnd, WORD wParam, POINT16 pt ) { 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 @@ static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam ) 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 eb457edb676..c1406c1a586 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 @@ static HQUEUE QUEUE_CreateMsgQueue( int size ) 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 @@ BOOL QUEUE_DeleteMsgQueue( HQUEUE hQueue ) pPrev = &msgQ->next; } if (*pPrev) *pPrev = msgQueue->next; + msgQueue->self = 0; GlobalFree16( hQueue ); return 1; } @@ -181,6 +185,8 @@ MESSAGEQUEUE *QUEUE_GetSysQueue(void) */ 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) @@ -191,6 +197,16 @@ void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit ) } +/*********************************************************************** + * QUEUE_ClearWakeBit + */ +void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit ) +{ + queue->changeBits &= ~bit; + queue->wakeBits &= ~bit; +} + + /*********************************************************************** * QUEUE_WaitBits * @@ -233,16 +249,22 @@ void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue ) 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 @@ void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue ) /* 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 @@ static void QUEUE_WakeSomeone( UINT message ) 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 53156d2b70d..31e3940062f 100644 --- a/windows/timer.c +++ b/windows/timer.c @@ -19,7 +19,7 @@ typedef struct tagTIMER 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 @@ static void TIMER_RemoveTimer( TIMER * pTimer ) 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_RemoveTimer( TIMER * pTimer ) 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 @@ static void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime ) /*********************************************************************** - * 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 @@ static WORD TIMER_SetTimer( HWND hwnd, WORD id, WORD timeout, (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 @@ static WORD TIMER_SetTimer( HWND hwnd, WORD id, WORD timeout, 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 8c23889ac60..c6e5188cffb 100644 --- a/windows/win.c +++ b/windows/win.c @@ -347,7 +347,7 @@ static void WIN_DestroyWindow( HWND hwnd ) 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 @@ BOOL WIN_CreateDesktopWindow(void) 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 @@ static HWND WIN_CreateWindowEx( CREATESTRUCT32A *cs, ATOM classAtom, 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 */