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.
This commit is contained in:
Alexandre Julliard 1996-06-16 16:16:05 +00:00
parent d90840e180
commit 8b91563079
22 changed files with 513 additions and 220 deletions

View File

@ -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.

View File

@ -1,3 +1,43 @@
----------------------------------------------------------------------
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>

217
documentation/user_module Normal file
View File

@ -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.

View File

@ -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 */

View File

@ -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 );

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}

View File

@ -501,7 +501,7 @@ HICON InternalExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, UINT nIco
for( i = nIconIndex; i < nIconIndex + n; i++ )
{
hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + (i - nIconIndex),
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;
}

View File

@ -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 );

View File

@ -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 );

View File

@ -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;
}

View File

@ -159,7 +159,6 @@ 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);
if( IntersectRect16(&wndRect,&wndRect,pRectUpdate) )

View File

@ -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 );
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 );
@ -298,15 +289,20 @@ BOOL EVENT_WaitXEvent( LONG maxWait )
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)) {
!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);
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);
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,7 +752,7 @@ 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 );
@ -770,17 +763,17 @@ static void EVENT_SelectionNotify(HWND hwnd, XSelectionEvent *event)
/***********************************************************************
* 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);
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 );
}

View File

@ -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;
}

View File

@ -29,9 +29,6 @@
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 */
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 );
}

View File

@ -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)

View File

@ -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)

View File

@ -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;
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

View File

@ -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 */