diff --git a/reactos/include/user32/caret.h b/reactos/include/user32/caret.h new file mode 100644 index 00000000000..87231681ba5 --- /dev/null +++ b/reactos/include/user32/caret.h @@ -0,0 +1,37 @@ +#ifndef __WINE_CARET_H +#define __WINE_CARET_H + + +#define DCX_USESTYLE 0x00010000 + +typedef struct +{ + HWND hwnd; + UINT hidden; + WINBOOL on; + INT x; + INT y; + INT width; + INT height; + HBRUSH hBrush; + UINT timeout; + UINT timerid; +} CARET; + +typedef enum +{ + CARET_OFF = 0, + CARET_ON, + CARET_TOGGLE, +} DISPLAY_CARET; + +HWND CARET_GetHwnd(void); +void CARET_GetRect(LPRECT lprc); /* windows/caret.c */ +void CARET_DisplayCaret( DISPLAY_CARET status ); +//VOID CALLBACK CARET_Callback( HWND hwnd, UINT msg, UINT id, DWORD ctime); +void CARET_SetTimer(void); +void CARET_ResetTimer(void); +void CARET_KillTimer(void); + + +#endif \ No newline at end of file diff --git a/reactos/include/user32/class.h b/reactos/include/user32/class.h index 9a99288c00b..8f3f6ad36cf 100644 --- a/reactos/include/user32/class.h +++ b/reactos/include/user32/class.h @@ -7,9 +7,9 @@ #ifndef __WINE_CLASS_H #define __WINE_CLASS_H +#include #include - -struct tagDCE; +#include #define MAX_CLASSNAME 255 @@ -17,32 +17,30 @@ struct tagDCE; #define CLASS_MAGIC ('C' | ('L' << 8) | ('A' << 16) | ('S' << 24)) + typedef struct tagCLASS { - struct tagCLASS *next; /* Next class */ + struct tagCLASS *next; /* Next class */ UINT magic; /* Magic number */ UINT cWindows; /* Count of existing windows */ UINT style; /* Class style */ WNDPROC winproc; /* Window procedure */ INT cbClsExtra; /* Class extra bytes */ INT cbWndExtra; /* Window extra bytes */ - char menuNameA[MAX_CLASSNAME]; - WCHAR menuNameW[MAX_CLASSNAME]; /* Default menu name (Unicode) */ - struct tagDCE *dce; /* Class DCE (if CS_CLASSDC) */ + void * menuName; /* Menu name */ + struct tagDCE *dce; /* Class DCE (if CS_CLASSDC) */ HINSTANCE hInstance; /* Module that created the task */ HICON hIcon; /* Default icon */ HICON hIconSm; /* Default small icon */ HCURSOR hCursor; /* Default cursor */ HBRUSH hbrBackground; /* Default background */ - ATOM atomName; /* Name of the class */ - char classNameA[MAX_CLASSNAME]; /* Class name (ASCII string) */ - WCHAR classNameW[MAX_CLASSNAME]; /* Class name (Unicode) */ - LONG wExtra[1]; /* Class extra bytes */ + ATOM atomName; /* Name of the class */ + void * className; /* Class name (Unicode) */ + WINBOOL bUnicode; /* Unicode or Ascii window */ + LONG wExtra[1]; /* Class extra bytes */ } CLASS; -void CLASS_DumpClass( CLASS *class ); -void CLASS_WalkClasses(void); -void CLASS_FreeModuleClasses( HMODULE hModule ); -CLASS *CLASS_FindClassByAtom( ATOM atom, HINSTANCE hinstance ); +CLASS *CLASS_FindClassByAtom( ATOM classAtom, HINSTANCE hInstance ); +WINBOOL CLASS_FreeClass(CLASS *classPtr); #endif /* __WINE_CLASS_H */ diff --git a/reactos/include/user32/dce.h b/reactos/include/user32/dce.h new file mode 100644 index 00000000000..417ada8d20d --- /dev/null +++ b/reactos/include/user32/dce.h @@ -0,0 +1,58 @@ +/* + * USER DCE definitions + * + * Copyright 1993 Alexandre Julliard + */ + +#ifndef __WINE_DCE_H +#define __WINE_DCE_H + +#include + +struct tagWND; +/* additional DCX flags + */ + +#define DCX_NORESETATTR 0x00000004 +#define DCX_EXCLUDEUPDATE 0x00000100 +#define DCX_INTERSECTUPDATE 0x00000200 +//#define DCX_LOCKWINDOWUPDATE 0x00000400 +#define DCX_NORECOMPUTE 0x00100000 +//#define DCX_VALIDATE 0x00200000 + +#define DCX_DCEEMPTY 0x00000800 +#define DCX_DCEBUSY 0x00001000 +#define DCX_DCEDIRTY 0x00002000 +#define DCX_WINDOWPAINT 0x00020000 +#define DCX_KEEPCLIPRGN 0x00040000 +#define DCX_NOCLIPCHILDREN 0x00080000 + +typedef enum +{ + DCE_CACHE_DC, /* This is a cached DC (allocated by USER) */ + DCE_CLASS_DC, /* This is a class DC (style CS_CLASSDC) */ + DCE_WINDOW_DC /* This is a window DC (style CS_OWNDC) */ +} DCE_TYPE; + + +typedef struct tagDCE +{ + struct tagDCE *next; + HDC hDC; + HWND hwndCurrent; + HWND hwndDC; + HRGN hClipRgn; + DCE_TYPE type; + DWORD DCXflags; +} DCE; + + +void DCE_Init(void); +DCE* DCE_AllocDCE( HWND hWnd, DCE_TYPE type ); +DCE* DCE_FreeDCE( DCE *dce ); +void DCE_FreeWindowDCE( struct tagWND* ); +INT DCE_ExcludeRgn( HDC, struct tagWND*, HRGN ); +HRGN DCE_GetVisRgn( HWND, WORD ); +WINBOOL DCE_InvalidateDCE( struct tagWND *, const RECT* ); + +#endif /* __WINE_DCE_H */ diff --git a/reactos/include/user32/debug.h b/reactos/include/user32/debug.h new file mode 100644 index 00000000000..5a5c4259b30 --- /dev/null +++ b/reactos/include/user32/debug.h @@ -0,0 +1,5 @@ +#ifndef DEBUG_H +#define DEBUG_H + #include + #define DPRINT printf +#endif \ No newline at end of file diff --git a/reactos/include/user32/heapdup.h b/reactos/include/user32/heapdup.h new file mode 100644 index 00000000000..05a177b1ef2 --- /dev/null +++ b/reactos/include/user32/heapdup.h @@ -0,0 +1,11 @@ + +int lstrcpynWtoA( LPSTR ptr1, LPWSTR ptr2, int n ); +int lstrcpynAtoW( LPWSTR ptr1, LPSTR ptr2, int n ); +int lstrcpyWtoA( LPSTR ptr1, LPWSTR ptr2 ); +int lstrcpyAtoW( LPWSTR ptr1, LPSTR ptr2 ); +int lpstrncpyA( LPSTR ptr1,LPSTR ptr2, int nMaxCount); +int lpstrncpyW( LPWSTR ptr1,LPWSTR ptr2, int nMaxCount); +LPVOID HEAP_strdupAtoW(HANDLE hHeap,DWORD dwFlags, LPCSTR lpszAsciiString ); +LPVOID HEAP_strdupWtoA(HANDLE hHeap,DWORD dwFlags, LPCWSTR lpszUnicodeString ); +LPSTR HEAP_strdupA(LPSTR ptr); +LPWSTR HEAP_strdupW(LPWSTR ptr); \ No newline at end of file diff --git a/reactos/include/user32/hook.h b/reactos/include/user32/hook.h index c71b43e7fab..a84f7645cc8 100644 --- a/reactos/include/user32/hook.h +++ b/reactos/include/user32/hook.h @@ -9,21 +9,58 @@ #include +#define HOOK_WINA 0x01 +#define HOOK_WINW 0x02 #define HOOK_WIN32A 0x01 #define HOOK_WIN32W 0x02 #define HOOK_INUSE 0x80 - +#define HQUEUE HANDLE /* hook type mask */ #define HOOK_MAPTYPE (HOOK_WIN32A | HOOK_WIN32W) -HOOKPROC HOOK_GetProc( HHOOK hhook ); + +#define HOOK_MAGIC ((int)'H' | (int)'K' << 8) /* 'HK' */ + +/***** Window hooks *****/ + + /* Hook values */ +#define WH_MIN (-1) +#define WH_MAX 12 + +#define WH_MINHOOK WH_MIN +#define WH_MAXHOOK WH_MAX +#define WH_NB_HOOKS (WH_MAXHOOK-WH_MINHOOK+1) + + + /* Hook data (pointed to by a HHOOK) */ +typedef struct +{ + HANDLE next; /* 00 Next hook in chain */ + HOOKPROC proc; /* 02 Hook procedure */ + INT id; /* 06 Hook id (WH_xxx) */ + HQUEUE ownerQueue; /* 08 Owner queue (0 for system hook) */ + HMODULE ownerModule; /* 0a Owner module */ + WORD flags; /* 0c flags */ +} HOOKDATA; + +HANDLE HOOK_SetHook( INT id, LPVOID proc, INT type, + HINSTANCE hInst, DWORD dwThreadId ); + +WINBOOL HOOK_RemoveHook( HANDLE hook ); + WINBOOL HOOK_IsHooked( INT id ); LRESULT HOOK_CallHooksA( INT id, INT code, WPARAM wParam, LPARAM lParam ); LRESULT HOOK_CallHooksW( INT id, INT code, WPARAM wParam, LPARAM lParam ); + +LRESULT HOOK_CallHook( HHOOK hook, INT fromtype, INT code, + WPARAM wParam, LPARAM lParam ); + +HANDLE HOOK_GetNextHook( HHOOK hook ); + void HOOK_FreeModuleHooks( HMODULE hModule ); void HOOK_FreeQueueHooks( HQUEUE hQueue ); void HOOK_ResetQueueHooks( HQUEUE hQueue ); diff --git a/reactos/include/user32/menu.h b/reactos/include/user32/menu.h new file mode 100644 index 00000000000..0f42ba075ce --- /dev/null +++ b/reactos/include/user32/menu.h @@ -0,0 +1,182 @@ +/* + * Menu definitions + */ + +#ifndef __WINE_MENU_H +#define __WINE_MENU_H + +#include +#include +#include + +#define PUT_WORD(ptr,w) (*(WORD *)(ptr) = (w)) +#define GET_WORD(ptr) (*(WORD *)(ptr)) +#define PUT_DWORD(ptr,dw) (*(DWORD *)(ptr) = (dw)) +#define GET_DWORD(ptr) (*(DWORD *)(ptr)) + + +#define WM_NEXTMENU 0x0213 + +#define MF_INSERT 0x0000 +#define MF_CHANGE 0x0080 +#define MF_APPEND 0x0100 +#define MF_DELETE 0x0200 +#define MF_REMOVE 0x1000 +#define MF_END 0x0080 + +/* internal popup menu window messages */ + +#define MM_SETMENUHANDLE (WM_USER + 0) +#define MM_GETMENUHANDLE (WM_USER + 1) + +extern WND* pTopPopupWnd; +extern UINT uSubPWndLevel; + + +/* Menu item structure */ +typedef struct { + /* ----------- MENUITEMINFO Stuff ----------- */ + UINT fType; /* Item type. */ + UINT fState; /* Item state. */ + UINT wID; /* Item id. */ + HMENU hSubMenu; /* Pop-up menu. */ + HBITMAP hCheckBit; /* Bitmap when checked. */ + HBITMAP hUnCheckBit; /* Bitmap when unchecked. */ + LPWSTR text; /* Item text or bitmap handle. */ + DWORD dwItemData; /* Application defined. */ + /* ----------- Wine stuff ----------- */ + RECT rect; /* Item area (relative to menu window) */ + UINT xTab; /* X position of text after Tab */ +} MENUITEM; + +/* Popup menu structure */ +typedef struct { + WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */ + WORD wMagic; /* Magic number */ + HQUEUE hTaskQ; /* Task queue for this menu */ + WORD Width; /* Width of the whole menu */ + WORD Height; /* Height of the whole menu */ + WORD nItems; /* Number of items in the menu */ + HWND hWnd; /* Window containing the menu */ + MENUITEM *items; /* Array of menu items */ + UINT FocusedItem; /* Currently focused item */ + WORD defitem; /* default item position. */ + DWORD dwContextHelpId; /* Context help id */ +} POPUPMENU, *LPPOPUPMENU; + +/* internal flags for menu tracking */ + +#define TF_ENDMENU 0x0001 +#define TF_SUSPENDPOPUP 0x0002 +#define TF_SKIPREMOVE 0x0004 + +typedef struct +{ + UINT trackFlags; + HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/ + HMENU hTopMenu; /* initial menu */ + HWND hOwnerWnd; /* where notifications are sent */ + POINT pt; +} MTRACKER; + +#define MENU_MAGIC 0x554d /* 'MU' */ +#define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC) + +#define ITEM_PREV -1 +#define ITEM_NEXT 1 + + /* Internal MENU_TrackMenu() flags */ +#define TPM_INTERNAL 0xF0000000 +#define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */ +#define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */ + + /* popup menu shade thickness */ +#define POPUP_XSHADE 4 +#define POPUP_YSHADE 4 + + /* Space between 2 menu bar items */ +#define MENU_BAR_ITEMS_SPACE 12 + + /* Minimum width of a tab character */ +#define MENU_TAB_SPACE 8 + + /* Height of a separator item */ +#define SEPARATOR_HEIGHT 5 + + /* (other menu->FocusedItem values give the position of the focused item) */ +#define NO_SELECTED_ITEM 0xffff + +#define MENU_ITEM_TYPE(flags) \ + ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)) + +#define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING) + +#define IS_SYSTEM_MENU(menu) \ + (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU) +#define IS_SYSTEM_POPUP(menu) \ + ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU) + +#define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \ + MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \ + MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \ + MF_POPUP | MF_SYSMENU | MF_HELP) +#define STATE_MASK (~TYPE_MASK) + +extern HMENU MENU_DefSysPopup; + +WINBOOL MENU_Init(void); +HMENU MENU_GetSysMenu(HWND hWndOwner, HMENU hSysPopup); +UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth, + INT orgX, INT orgY ); +BOOL MENU_PatchResidentPopup( HQUEUE, WND* ); +void MENU_TrackMouseMenuBar( WND *wnd, INT ht, POINT pt ); +void MENU_TrackKbdMenuBar( WND *wnd, UINT wParam, INT vkey ); +UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, + HWND hwnd, WINBOOL suppress_draw ); +WINBOOL MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y, + HWND hwnd, const RECT *lprect ); + +WINBOOL MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu ); +WINBOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu ); +LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk ); +void MENU_KeyLeft( MTRACKER* pmt ); +void MENU_KeyRight( MTRACKER* pmt ); +WINBOOL MENU_InitTracking(HWND hWnd, HMENU hMenu); +void MENU_TrackMouseMenuBar( WND* wndPtr, INT ht, POINT pt ); + +WINBOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id, + INT x, INT y, INT xanchor, INT yanchor ); +void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu ); +UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd, + WINBOOL suppress_draw); +MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags ); + +void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, + LPPOPUPMENU lppop, HWND hwndOwner ); + +void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner, + INT orgX, INT orgY, WINBOOL menuBar ); + +void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu, + WINBOOL sendMenuSelect ); + +void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex, + WINBOOL sendMenuSelect ); + +MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags ); + +WINBOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id, + LPCWSTR str ); + +void MENU_FreeItemData( MENUITEM* item ); + +HMENU MENU_CopySysPopup(void); + +// addition to win32 + + +HPEN STDCALL GetSysColorPen(INT); + + + +#endif /* __WINE_MENU_H */ diff --git a/reactos/include/user32/message.h b/reactos/include/user32/message.h index ad37acf5eb7..748ea5ad95e 100644 --- a/reactos/include/user32/message.h +++ b/reactos/include/user32/message.h @@ -38,10 +38,8 @@ WINBOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, void MSG_CallWndProcHook( LPMSG pmsg, WINBOOL bUnicode ); -LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam, WORD flags ); +LRESULT MSG_SendMessage( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, + WINBOOL bUnicode ); -void joySendMessages(void); - #endif /* __WINE_MESSAGE_H */ diff --git a/reactos/include/user32/msg.h b/reactos/include/user32/msg.h new file mode 100644 index 00000000000..1b2ac1140ee --- /dev/null +++ b/reactos/include/user32/msg.h @@ -0,0 +1,64 @@ + +#ifndef __WINE_MSG_H +#define __WINE_MSG_H + + + +#define WM_SYSTIMER 0x0118 + +#define WH_HARDWARE 8 + + +#include +#include +#include +//#include + +typedef struct +{ + HWND hWnd; + UINT wMessage; + WPARAM wParam; + LPARAM lParam; +} HARDWAREHOOKSTRUCT, *LPHARDWAREHOOKSTRUCT; + + + +#define MAX_QUEUE_SIZE 256 + +extern WINBOOL MouseButtonsStates[3]; +extern WINBOOL AsyncMouseButtonsStates[3]; +extern BYTE InputKeyStateTable[256]; +extern BYTE QueueKeyStateTable[256]; +extern BYTE AsyncKeyStateTable[256]; + +#define WM_NCMOUSEFIRST WM_NCMOUSEMOVE +#define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK + +typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP, + SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS; + +extern MESSAGEQUEUE *pCursorQueue; /* queue.c */ +extern MESSAGEQUEUE *pActiveQueue; + + +/* message.c */ +WINBOOL MSG_InternalGetMessage( MSG *msg, HWND hwnd, + HWND hwndOwner, WPARAM code, + WORD flags, WINBOOL sendIdle ); + +WINBOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, + WORD flags, WINBOOL peek ); + +void MSG_CallWndProcHook( LPMSG pmsg, WINBOOL bUnicode ); + +LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam, WORD flags ); + + +void joySendMessages(void); + + + + +#endif \ No newline at end of file diff --git a/reactos/include/user32/nc.h b/reactos/include/user32/nc.h new file mode 100644 index 00000000000..e09fbbae3e5 --- /dev/null +++ b/reactos/include/user32/nc.h @@ -0,0 +1,80 @@ +/* + * Window non-client functions definitions + * + * Copyright 1995 Alexandre Julliard + */ + +#ifndef __WINE_NONCLIENT_H +#define __WINE_NONCLIENT_H + +//#include "config.h" + +#define WIN95_LOOK 1 +#define WIN31_LOOK 0 +extern int TWEAK_WineLook; + + +#include +#include +#include +#include +#include +#include +#include + +#define SC_ARRANGE 0xf110 + +#define WM_SETVISIBLE 0x0009 + + /* WM_NCHITTEST return codes */ +#define HTERROR (-2) +#define HTTRANSPARENT (-1) + + + +#define HTMINBUTTON 8 +#define HTMAXBUTTON 9 + + + +#define HTBORDER 18 + +#define HTOBJECT 19 +#define HTCLOSE 20 +#define HTHELP 21 +#define HTSIZEFIRST HTLEFT +#define HTSIZELAST HTBOTTOMRIGHT + + /* CallMsgFilter() values */ + +#define MSGF_MESSAGEBOX 1 + +#define MSGF_MOVE 3 +#define MSGF_SIZE 4 + + +#define MAKEINTRESOURCEA(i) (LPSTR) ((DWORD) ((WORD) (i))) + +#define DCX_USESTYLE 0x00010000 + +LONG NC_HandleNCPaint( HWND hwnd , HRGN clip); +LONG NC_HandleNCActivate( WND *pwnd, WPARAM wParam ); +LONG NC_HandleNCCalcSize( WND *pWnd, RECT *winRect ); +LONG NC_HandleNCHitTest( HWND hwnd, POINT pt ); +LONG NC_HandleNCLButtonDown( WND* pWnd, WPARAM wParam, LPARAM lParam ); +LONG NC_HandleNCLButtonDblClk( WND *pWnd, WPARAM wParam, LPARAM lParam); +LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, POINT pt ); +LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam ); +void NC_DrawSysButton( HWND hwnd, HDC hdc, WINBOOL down ); +WINBOOL NC_DrawSysButton95( HWND hwnd, HDC hdc, WINBOOL down ); +WINBOOL NC_GetSysPopupPos( WND* wndPtr, RECT* rect ); +void NC_AdjustRect( LPRECT rect, DWORD style, WINBOOL menu, + DWORD exStyle ); + +//gdi +WINBOOL STDCALL FastWindowFrame(HDC,const RECT*,INT,INT,DWORD); +void NC_AdjustRectOuter95 (LPRECT rect, DWORD style, WINBOOL menu, DWORD exStyle); +void NC_AdjustRectInner95 (LPRECT rect, DWORD style, DWORD exStyle); + + +#endif /* __WINE_NONCLIENT_H */ diff --git a/reactos/include/user32/property.h b/reactos/include/user32/property.h new file mode 100644 index 00000000000..2b5c50c9514 --- /dev/null +++ b/reactos/include/user32/property.h @@ -0,0 +1,22 @@ + +typedef struct tagPROPERTY +{ + struct tagPROPERTY *next; /* Next property in window list */ + HANDLE handle; /* User's data */ + ATOM atom; + HANDLE app; +} PROPERTY; + + +typedef struct tagPROPVALUE +{ + HANDLE hwnd; + HANDLE handle; + ATOM atom; +} PROPVALUE; + +HANDLE PROPERTY_FindProp( HWND hwnd, ATOM Atom ); +WINBOOL PROPERTY_SetProp( HANDLE hwnd, ATOM atom,HANDLE hData); +HANDLE PROPERTY_RemoveProp( HANDLE hwnd , ATOM atom ); +void PROPERTY_RemoveWindowProps( HANDLE hwnd ); +WINBOOL PROPERTY_EnumPropEx(HWND hwnd, PROPVALUE **pv , int maxsize, int *size ); \ No newline at end of file diff --git a/reactos/include/user32/queue.h b/reactos/include/user32/queue.h index 93906407afa..300263d3441 100644 --- a/reactos/include/user32/queue.h +++ b/reactos/include/user32/queue.h @@ -7,8 +7,9 @@ #ifndef __WINE_QUEUE_H #define __WINE_QUEUE_H -//#include "wine/winuser16.h" + #include +#include /***** Window hooks *****/ @@ -20,7 +21,6 @@ #define WH_MAXHOOK WH_MAX #define WH_NB_HOOKS (WH_MAXHOOK-WH_MINHOOK+1) -#define HQUEUE HANDLE /* Message as stored in the queue (contains the extraInfo field) */ @@ -113,11 +113,11 @@ void QUEUE_FlushMessages(HQUEUE); void hardware_event( WORD message, WORD wParam, LONG lParam, int xPos, int yPos, DWORD time, DWORD extraInfo ); -HQUEUE STDCALL InitThreadInput( WORD unknown, WORD flags ); +HQUEUE InitThreadInput( WORD unknown, WORD flags ); -HQUEUE WINAPI SetThreadQueue( DWORD thread, HQUEUE hQueue ); -HQUEUE WINAPI GetThreadQueue( DWORD thread ); -VOID WINAPI SetFastQueue( DWORD thread, HANDLE hQueue ); -HANDLE STDCALL GetFastQueue( void ); +HQUEUE SetThreadQueue( DWORD thread, HQUEUE hQueue ); +HQUEUE GetThreadQueue( DWORD thread ); +VOID SetFastQueue( DWORD thread, HANDLE hQueue ); +HANDLE GetFastQueue( void ); #endif /* __WINE_QUEUE_H */ diff --git a/reactos/include/user32/resource.h b/reactos/include/user32/resource.h new file mode 100644 index 00000000000..440a93893cc --- /dev/null +++ b/reactos/include/user32/resource.h @@ -0,0 +1,62 @@ +/* + * Resource definitions + * + * Copyright 1995 Alexandre Julliard + */ + +#ifndef __WINE_RESOURCE_H +#define __WINE_RESOURCE_H + +#include + +//#ifndef __WRC_RSC_H +//#include "wrc_rsc.h" +//#endif + +/* + * BS: I comment this out to catch all occurences + * of reference to this structure which is now + * rendered obsolete. + * + * struct resource + * { + * int id; + * int type; + * const char *name; + * const unsigned char* bytes; + * unsigned size; + * }; + */ + +/* Built-in resources */ +typedef enum +{ + SYSRES_MENU_SYSMENU, + SYSRES_MENU_EDITMENU, + SYSRES_DIALOG_MSGBOX, + SYSRES_DIALOG_SHELL_ABOUT_MSGBOX, + SYSRES_DIALOG_OPEN_FILE, + SYSRES_DIALOG_SAVE_FILE, + SYSRES_DIALOG_PRINT, + SYSRES_DIALOG_PRINT_SETUP, + SYSRES_DIALOG_CHOOSE_FONT, + SYSRES_DIALOG_CHOOSE_COLOR, + SYSRES_DIALOG_FIND_TEXT, + SYSRES_DIALOG_REPLACE_TEXT +} SYSTEM_RESOURCE; + +//extern void LIBRES_RegisterResources(const wrc_resource32_t * const * Res); + +#if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ >= 7) +#define WINE_CONSTRUCTOR __attribute__((constructor)) +#define HAVE_WINE_CONSTRUCTOR +#else +#define WINE_CONSTRUCTOR +#undef HAVE_WINE_CONSTRUCTOR +#endif + +HGLOBAL SYSRES_LoadResource( SYSTEM_RESOURCE id ); +void SYSRES_FreeResource( HGLOBAL handle ); +LPCVOID SYSRES_GetResPtr( SYSTEM_RESOURCE id ); + +#endif /* __WINE_RESOURCE_H */ diff --git a/reactos/include/user32/scroll.h b/reactos/include/user32/scroll.h new file mode 100644 index 00000000000..665c587da42 --- /dev/null +++ b/reactos/include/user32/scroll.h @@ -0,0 +1,32 @@ +/* + * Scroll-bar class extra info + * + * Copyright 1993 Martin Ayotte + * Copyright 1994 Alexandre Julliard + */ + +#ifndef __WINE_SCROLL_H +#define __WINE_SCROLL_H + +#include "windows.h" + +typedef struct +{ + INT CurVal; /* Current scroll-bar value */ + INT MinVal; /* Minimum scroll-bar value */ + INT MaxVal; /* Maximum scroll-bar value */ + INT Page; /* Page size of scroll bar (Win32) */ + UINT flags; /* EnableScrollBar flags */ +} SCROLLBAR_INFO; + +LRESULT STDCALL ScrollBarWndProc( HWND hwnd, UINT uMsg, + WPARAM wParam, LPARAM lParam ); +void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, INT nBar, + WINBOOL arrows, WINBOOL interior ); +void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, + UINT msg, POINT pt ); + + +//#define WM_SYSTIMER (0x118) + +#endif /* __WINE_SCROLL_H */ diff --git a/reactos/include/user32/signal.h b/reactos/include/user32/signal.h new file mode 100644 index 00000000000..c6cf1a11bd2 --- /dev/null +++ b/reactos/include/user32/signal.h @@ -0,0 +1,4 @@ +/* loader/signal.c */ +WINBOOL SIGNAL_Init(void); +void SIGNAL_SetHandler( int sig, void (*func)(), int flags ); +void SIGNAL_MaskAsyncEvents( BOOL flag ); \ No newline at end of file diff --git a/reactos/include/user32/sysmetr.h b/reactos/include/user32/sysmetr.h new file mode 100644 index 00000000000..eee188ad631 --- /dev/null +++ b/reactos/include/user32/sysmetr.h @@ -0,0 +1,145 @@ +/* + * System metrics definitions + * + * Copyright 1994 Alexandre Julliard + */ + +#ifndef __WINE_SYSMETRICS_H +#define __WINE_SYSMETRICS_H + +#include + + + /* Constant system metrics */ +#if 0 +#ifdef WIN_95_LOOK +#define SYSMETRICS_CXDLGFRAME 3 +#define SYSMETRICS_CYDLGFRAME 3 +#define SYSMETRICS_CYVTHUMB 13 +#define SYSMETRICS_CXHTHUMB 13 +#else +#define SYSMETRICS_CXDLGFRAME 4 +#define SYSMETRICS_CYDLGFRAME 4 +#define SYSMETRICS_CYVTHUMB 16 +#define SYSMETRICS_CXHTHUMB 16 +#endif +#define SYSMETRICS_CXICON 32 +#define SYSMETRICS_CYICON 32 +#define SYSMETRICS_CXCURSOR 32 +#define SYSMETRICS_CYCURSOR 32 +#ifdef WIN_95_LOOK +#define SYSMETRICS_CYVSCROLL 14 +#define SYSMETRICS_CXHSCROLL 14 +#define SYSMETRICS_CXMIN 112 +#define SYSMETRICS_CYMIN 27 +#else +#define SYSMETRICS_CYVSCROLL 16 +#define SYSMETRICS_CXHSCROLL 16 +#define SYSMETRICS_CXMIN 100 +#define SYSMETRICS_CYMIN 28 +#endif +#ifdef WIN_95_LOOK +#define SYSMETRICS_CXMINTRACK 112 +#define SYSMETRICS_CYMINTRACK 27 +#else +#define SYSMETRICS_CXMINTRACK 100 +#define SYSMETRICS_CYMINTRACK 28 +#endif +#endif 0 + +/* Some non-constant system metrics */ +#define SYSMETRICS_CXSCREEN sysMetrics[SM_CXSCREEN] /* 0 */ +#define SYSMETRICS_CYSCREEN sysMetrics[SM_CYSCREEN] /* 1 */ +#define SYSMETRICS_CXVSCROLL sysMetrics[SM_CXVSCROLL] /* 2 */ +#define SYSMETRICS_CYHSCROLL sysMetrics[SM_CYHSCROLL] /* 3 */ +#define SYSMETRICS_CYCAPTION sysMetrics[SM_CYCAPTION] /* 4 */ +#define SYSMETRICS_CXBORDER sysMetrics[SM_CXBORDER] /* 5 */ +#define SYSMETRICS_CYBORDER sysMetrics[SM_CYBORDER] /* 6 */ +#define SYSMETRICS_CXDLGFRAME sysMetrics[SM_CXDLGFRAME] /* 7 */ +#define SYSMETRICS_CYDLGFRAME sysMetrics[SM_CYDLGFRAME] /* 8 */ +#define SYSMETRICS_CYVTHUMB sysMetrics[SM_CYVTHUMB] /* 9 */ +#define SYSMETRICS_CXHTHUMB sysMetrics[SM_CXHTHUMB] /* 10 */ +#define SYSMETRICS_CXICON sysMetrics[SM_CXICON] /* 11 */ +#define SYSMETRICS_CYICON sysMetrics[SM_CYICON] /* 12 */ +#define SYSMETRICS_CXCURSOR sysMetrics[SM_CXCURSOR] /* 13 */ +#define SYSMETRICS_CYCURSOR sysMetrics[SM_CYCURSOR] /* 14 */ +#define SYSMETRICS_CYMENU sysMetrics[SM_CYMENU] /* 15 */ +#define SYSMETRICS_CXFULLSCREEN sysMetrics[SM_CXFULLSCREEN] /* 16 */ +#define SYSMETRICS_CYFULLSCREEN sysMetrics[SM_CYFULLSCREEN] /* 17 */ +#define SYSMETRICS_CYKANJIWINDOW sysMetrics[SM_CYKANJIWINDOW] /* 18 */ +#define SYSMETRICS_MOUSEPRESENT sysMetrics[SM_MOUSEPRESENT] /* 19 */ +#define SYSMETRICS_CYVSCROLL sysMetrics[SM_CYVSCROLL] /* 20 */ +#define SYSMETRICS_CXHSCROLL sysMetrics[SM_CXHSCROLL] /* 21 */ +#define SYSMETRICS_DEBUG sysMetrics[SM_DEBUG] /* 22 */ +#define SYSMETRICS_SWAPBUTTON sysMetrics[SM_SWAPBUTTON] /* 23 */ +#define SYSMETRICS_RESERVED1 sysMetrics[SM_RESERVED1] /* 24 */ +#define SYSMETRICS_RESERVED2 sysMetrics[SM_RESERVED2] /* 25 */ +#define SYSMETRICS_RESERVED3 sysMetrics[SM_RESERVED3] /* 26 */ +#define SYSMETRICS_RESERVED4 sysMetrics[SM_RESERVED4] /* 27 */ +#define SYSMETRICS_CXMIN sysMetrics[SM_CXMIN] /* 28 */ +#define SYSMETRICS_CYMIN sysMetrics[SM_CYMIN] /* 29 */ +#define SYSMETRICS_CXSIZE sysMetrics[SM_CXSIZE] /* 30 */ +#define SYSMETRICS_CYSIZE sysMetrics[SM_CYSIZE] /* 31 */ +#define SYSMETRICS_CXFRAME sysMetrics[SM_CXFRAME] /* 32 */ +#define SYSMETRICS_CYFRAME sysMetrics[SM_CYFRAME] /* 33 */ +#define SYSMETRICS_CXMINTRACK sysMetrics[SM_CXMINTRACK] /* 34 */ +#define SYSMETRICS_CYMINTRACK sysMetrics[SM_CYMINTRACK] /* 35 */ +#define SYSMETRICS_CXDOUBLECLK sysMetrics[SM_CXDOUBLECLK] /* 36 */ +#define SYSMETRICS_CYDOUBLECLK sysMetrics[SM_CYDOUBLECLK] /* 37 */ +#define SYSMETRICS_CXICONSPACING sysMetrics[SM_CXICONSPACING] /* 38 */ +#define SYSMETRICS_CYICONSPACING sysMetrics[SM_CYICONSPACING] /* 39 */ +#define SYSMETRICS_MENUDROPALIGNMENT sysMetrics[SM_MENUDROPALIGNMENT] /* 40 */ +#define SYSMETRICS_PENWINDOWS sysMetrics[SM_PENWINDOWS] /* 41 */ +#define SYSMETRICS_DBCSENABLED sysMetrics[SM_DBCSENABLED] /* 42 */ +#define SYSMETRICS_CMOUSEBUTTONS sysMetrics[SM_CMOUSEBUTTONS] /* 43 */ +#define SYSMETRICS_CXFIXEDFRAME sysMetrics[SM_CXDLGFRAME] /* win40 name change */ +#define SYSMETRICS_CYFIXEDFRAME sysMetrics[SM_CYDLGFRAME] /* win40 name change */ +#define SYSMETRICS_CXSIZEFRAME sysMetrics[SM_CXFRAME] /* win40 name change */ +#define SYSMETRICS_CYSIZEFRAME sysMetrics[SM_CYFRAME] /* win40 name change */ +#define SYSMETRICS_SECURE sysMetrics[SM_SECURE] /* 44 */ +#define SYSMETRICS_CXEDGE sysMetrics[SM_CXEDGE] /* 45 */ +#define SYSMETRICS_CYEDGE sysMetrics[SM_CYEDGE] /* 46 */ +#define SYSMETRICS_CXMINSPACING sysMetrics[SM_CXMINSPACING] /* 47 */ +#define SYSMETRICS_CYMINSPACING sysMetrics[SM_CYMINSPACING] /* 48 */ +#define SYSMETRICS_CXSMICON sysMetrics[SM_CXSMICON] /* 49 */ +#define SYSMETRICS_CYSMICON sysMetrics[SM_CYSMICON] /* 50 */ +#define SYSMETRICS_CYSMCAPTION sysMetrics[SM_CYSMCAPTION] /* 51 */ +#define SYSMETRICS_CXSMSIZE sysMetrics[SM_CXSMSIZE] /* 52 */ +#define SYSMETRICS_CYSMSIZE sysMetrics[SM_CYSMSIZE] /* 53 */ +#define SYSMETRICS_CXMENUSIZE sysMetrics[SM_CXMENUSIZE] /* 54 */ +#define SYSMETRICS_CYMENUSIZE sysMetrics[SM_CYMENUSIZE] /* 55 */ +#define SYSMETRICS_ARRANGE sysMetrics[SM_ARRANGE] /* 56 */ +#define SYSMETRICS_CXMINIMIZED sysMetrics[SM_CXMINIMIZED] /* 57 */ +#define SYSMETRICS_CYMINIMIZED sysMetrics[SM_CYMINIMIZED] /* 58 */ +#define SYSMETRICS_CXMAXTRACK sysMetrics[SM_CXMAXTRACK] /* 59 */ +#define SYSMETRICS_CYMAXTRACK sysMetrics[SM_CYMAXTRACK] /* 60 */ +#define SYSMETRICS_CXMAXIMIZED sysMetrics[SM_CXMAXIMIZED] /* 61 */ +#define SYSMETRICS_CYMAXIMIZED sysMetrics[SM_CYMAXIMIZED] /* 62 */ +#define SYSMETRICS_NETWORK sysMetrics[SM_NETWORK] /* 63 */ +#define SYSMETRICS_CLEANBOOT sysMetrics[SM_CLEANBOOT] /* 67 */ +#define SYSMETRICS_CXDRAG sysMetrics[SM_CXDRAG] /* 68 */ +#define SYSMETRICS_CYDRAG sysMetrics[SM_CYDRAG] /* 69 */ +#define SYSMETRICS_SHOWSOUNDS sysMetrics[SM_SHOWSOUNDS] /* 70 */ + +/* Use the following instead of sysMetrics[SM_CXMENUCHECK] GetMenuCheckMarkDimensions()! */ +#define SYSMETRICS_CXMENUCHECK sysMetrics[SM_CXMENUCHECK] /* 71 */ +#define SYSMETRICS_CYMENUCHECK sysMetrics[SM_CYMENUCHECK] /* 72 */ + +#define SYSMETRICS_SLOWMACHINE sysMetrics[SM_SLOWMACHINE] /* 73 */ +#define SYSMETRICS_MIDEASTENABLED sysMetrics[SM_MIDEASTENABLED] /* 74 */ +#define SYSMETRICS_MOUSEWHEELPRESENT sysMetrics[SM_MOUSEWHEELPRESENT] /* 75 */ + +#define SYSMETRICS_CXVIRTUALSCREEN sysMetrics[SM_CXVIRTUALSCREEN] /* 77 */ +#define SYSMETRICS_CYVIRTUALSCREEN sysMetrics[SM_CYVIRTUALSCREEN] /* 77 */ +#define SYSMETRICS_YVIRTUALSCREEN sysMetrics[SM_YVIRTUALSCREEN] /* 78 */ +#define SYSMETRICS_XVIRTUALSCREEN sysMetrics[SM_XVIRTUALSCREEN] /* 79 */ +#define SYSMETRICS_CMONITORS sysMetrics[SM_CMONITORS] /* 81 */ +#define SYSMETRICS_SAMEDISPLAYFORMAT sysMetrics[SM_SAMEDISPLAYFORMAT] /* 82 */ + +#undef SM_CMETRICS +#define SM_CMETRICS (83) + +extern short sysMetrics[SM_CMETRICS+1]; + + +#endif /* __WINE_SYSMETRICS_H */ diff --git a/reactos/include/user32/text.h b/reactos/include/user32/text.h new file mode 100644 index 00000000000..02aa8205137 --- /dev/null +++ b/reactos/include/user32/text.h @@ -0,0 +1,34 @@ + +#ifndef __WINE_TEXT_H +#define __WINE_TEXT_H + +//typedef WINBOOL (CALLBACK *GRAYSTRINGPROC)(HDC,LPARAM,INT); + +#define TAB 9 +#define LF 10 +#define CR 13 +#define SPACE 32 +#define PREFIX 38 + +#define SWAP_INT(a,b) { int t = a; a = b; b = t; } + +int TEXT_DrawTextEx(HDC hDC,void *strPtr,int nCount,LPRECT lpRect,UINT uFormat,LPDRAWTEXTPARAMS dtp,WINBOOL Unicode ); + +LPCSTR TEXT_NextLineA( HDC hdc, LPCSTR str, INT *count, + LPSTR dest, INT *len, INT width, WORD format); +LPCWSTR TEXT_NextLineW( HDC hdc, LPCWSTR str, INT *count, + LPWSTR dest, INT *len, INT width, WORD format); + +WINBOOL TEXT_GrayString(HDC hdc, HBRUSH hb, + GRAYSTRINGPROC fn, LPARAM lp, INT len, + INT x, INT y, INT cx, INT cy, WINBOOL Unicode); + +LONG TEXT_TabbedTextOutA( HDC hdc, INT x, INT y, LPCSTR lpstr, + INT count, INT cTabStops, const INT *lpTabPos, + INT nTabOrg, WINBOOL fDisplayText ); + +LONG TEXT_TabbedTextOutW( HDC hdc, INT x, INT y, LPCWSTR lpstr, + INT count, INT cTabStops, const INT *lpTabPos, + INT nTabOrg, WINBOOL fDisplayText ); + +#endif \ No newline at end of file diff --git a/reactos/include/user32/timer.h b/reactos/include/user32/timer.h new file mode 100644 index 00000000000..2c31715cf21 --- /dev/null +++ b/reactos/include/user32/timer.h @@ -0,0 +1,38 @@ + +#include +#include + +typedef struct tagTIMER +{ + HWND hwnd; + HQUEUE hq; + UINT msg; /* WM_TIMER or WM_SYSTIMER */ + UINT id; + UINT timeout; + struct tagTIMER *next; + DWORD expires; /* Next expiration, or 0 if already expired */ + TIMERPROC proc; +} TIMER; + +#define NB_TIMERS 34 +#define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */ + +#define WM_SYSTIMER 0x0118 + + + +void TIMER_InsertTimer( TIMER * pTimer ); +void TIMER_RemoveTimer( TIMER * pTimer ); +void TIMER_ClearTimer( TIMER * pTimer ); +void TIMER_SwitchQueue( HQUEUE old, HQUEUE newQ ); +void TIMER_RemoveWindowTimers( HWND hwnd ); +void TIMER_RemoveQueueTimers( HQUEUE hqueue ); +void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime ); +LONG TIMER_GetNextExpiration(void); +void TIMER_ExpireTimers(void); +WINBOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd, + HQUEUE hQueue,WINBOOL remove ); + +UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout, + TIMERPROC proc, WINBOOL sys ); +WINBOOL TIMER_KillTimer( HWND hwnd, UINT id,WINBOOL sys ); diff --git a/reactos/include/user32/win.h b/reactos/include/user32/win.h index 788e9522ba1..a76c050adab 100644 --- a/reactos/include/user32/win.h +++ b/reactos/include/user32/win.h @@ -11,9 +11,12 @@ typedef HANDLE HTASK; typedef HANDLE HQUEUE; +#define STRING2ATOMA(str) HIWORD(str) ? GlobalFindAtomA(str) : (ATOM)LOWORD(str) +#define STRING2ATOMW(str) HIWORD(str) ? GlobalFindAtomW(str) : (ATOM)LOWORD(str) #include - +#include +#include #define WND_MAGIC 0x444e4957 /* 'WIND' */ @@ -56,53 +59,50 @@ struct tagDCE; struct tagDC; struct tagCLASS; - typedef struct tagWND { struct tagWND *next; /* Next sibling */ struct tagWND *child; /* First child */ struct tagWND *parent; /* Window parent (from CreateWindow) */ struct tagWND *owner; /* Window owner */ - struct tagCLASS *class; /* Window class */ + struct tagCLASS *class; /* Window class */ void *winproc; /* Window procedure */ - DWORD dwMagic; /* Magic number (must be WND_MAGIC) */ - HWND hwndSelf; /* Handle of this window */ - HINSTANCE hInstance; /* Window hInstance (from CreateWindow) */ - RECT rectClient; /* Client area rel. to parent client area */ - RECT rectWindow; /* Whole window rel. to parent client area */ - LPWSTR text; /* Window text */ + HANDLE hmemTaskQ; /* This should be hThread */ + DWORD dwMagic; /* Magic number (must be WND_MAGIC) */ + HWND hwndSelf; /* Handle of this window */ + HINSTANCE hInstance; /* Window hInstance (from CreateWindow) */ + RECT rectClient; /* Client area rel. to parent client area */ + RECT rectWindow; /* Whole window rel. to parent client area */ + LPWSTR text; /* Window text */ void *pVScroll; /* Vertical scroll-bar info */ void *pHScroll; /* Horizontal scroll-bar info */ void *pProp; /* Pointer to properties list */ struct tagDCE *dce; /* Window DCE (if CS_OWNDC or CS_CLASSDC) */ - HGLOBAL hmemTaskQ; /* Task queue global memory handle */ - HRGN hrgnUpdate; /* Update region */ - HRGN hrgnWindow; /* region where the os permits drawing == max update region */ - HWND hwndLastActive;/* Last active popup hwnd */ - DWORD dwStyle; /* Window style (from CreateWindow) */ - DWORD dwExStyle; /* Extended style (from CreateWindowEx) */ - UINT wIDmenu; /* ID or hmenu (from CreateWindow) */ - DWORD helpContext; /* Help context ID */ - WORD flags; /* Misc. flags (see below) */ - HMENU hSysMenu; /* window's copy of System Menu */ - DWORD userdata; /* User private data */ -// struct _WND_DRIVER *pDriver; /* Window driver */ -// void *pDriverData; /* Window driver data */ - DWORD wExtra[1]; /* Window extra bytes */ + HRGN hrgnUpdate; /* Update region */ + HRGN hrgnWindow; /* region where the os permits drawing == max update region */ + HWND hwndLastActive;/* Last active popup hwnd */ + DWORD dwStyle; /* Window style (from CreateWindow) */ + DWORD dwExStyle; /* Extended style (from CreateWindowEx) */ + UINT wIDmenu; /* ID or hmenu (from CreateWindow) */ + DWORD helpContext; /* Help context ID */ + WORD flags; /* Misc. flags (see below) */ + HMENU hSysMenu; /* window's copy of System Menu */ + DWORD userdata; /* User private data */ + DWORD wExtra[1]; /* Window extra bytes */ } WND; typedef struct tagCREATESTRUCTA { LPVOID lpCreateParams; HINSTANCE hInstance; HMENU hMenu; - HWND hwndParent; + HWND hWndParent; int cy; int cx; int y; int x; LONG style; - LPCSTR lpszName; - LPCSTR lpszClass; + LPCSTR lpszName; + LPCSTR lpszClass; DWORD dwExStyle; } CREATESTRUCTA, *LPCREATESTRUCTA; @@ -110,7 +110,7 @@ typedef struct tagCREATESTRUCTW { LPVOID lpCreateParams; HINSTANCE hInstance; HMENU hMenu; - HWND hwndParent; + HWND hWndParent; int cy; int cx; int y; @@ -154,24 +154,7 @@ typedef struct _STARTUPINFOW { HANDLE hStdError; } STARTUPINFOW, *LPSTARTUPINFOW; -typedef struct _WND_DRIVER -{ - void (*pInitialize)(WND *); - void (*pFinalize)(WND *); - WINBOOL (*pCreateDesktopWindow)(WND *, struct tagCLASS *, WINBOOL); - WINBOOL (*pCreateWindow)(WND *, struct tagCLASS*, CREATESTRUCTW *, WINBOOL); - WINBOOL (*pDestroyWindow)(WND *); - WND* (*pSetParent)(WND *, WND *); - void (*pForceWindowRaise)(WND *); - void (*pSetWindowPos)(WND *, const WINDOWPOS *, WINBOOL); - void (*pSetText)(WND *, LPCSTR); - void (*pSetFocus)(WND *); - void (*pPreSizeMove)(WND *); - void (*pPostSizeMove)(WND *); - void (*pScrollWindow)(WND *, struct tagDC *, INT, INT, const RECT *, WINBOOL); - void (*pSetDrawable)(WND *, struct tagDC *, WORD, WINBOOL); - WINBOOL (*pIsSelfClipping)(WND *); -} WND_DRIVER; + typedef struct { @@ -212,11 +195,8 @@ typedef struct #define GWL_WNDPROC (-4) - - - /* Window functions */ -HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom ); +HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM atomName ); WND* WIN_FindWndPtr( HWND hwnd ); WND* WIN_GetDesktop(void); void WIN_DumpWindow( HWND hwnd ); @@ -235,7 +215,7 @@ WND** WIN_BuildWinArray( WND *wndPtr, UINT bwa, UINT* pnum ); void WIN_UpdateNCArea(WND* wnd, WINBOOL bUpdate); void WIN_SendDestroyMsg( WND* pWnd ); -WND* WIN_DestroyWindow( WND* wndPtr ); +WINBOOL WIN_DestroyWindow( WND* wndPtr ); HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title ); LONG WIN_GetWindowLong( HWND hwnd, INT offset ); diff --git a/reactos/include/user32/winpos.h b/reactos/include/user32/winpos.h new file mode 100644 index 00000000000..c21484ca8a3 --- /dev/null +++ b/reactos/include/user32/winpos.h @@ -0,0 +1,84 @@ +/* + * *DeferWindowPos() structure and definitions + * + * Copyright 1994 Alexandre Julliard + */ + +#ifndef __WINE_WINPOS_H +#define __WINE_WINPOS_H + +#include + +#define DWP_MAGIC ((INT)('W' | ('P' << 8) | ('O' << ) | ('S' << 24))) + +/* undocumented SWP flags - from SDK 3.1 */ +#define SWP_NOCLIENTSIZE 0x0800 +#define SWP_NOCLIENTMOVE 0x1000 + +#define SWP_DEFERERASE 0x2000 + + +#define HAS_DLGFRAME(style,exStyle) \ + (((exStyle) & WS_EX_DLGMODALFRAME) || \ + (((style) & WS_DLGFRAME) && !((style) & WS_BORDER))) + +#define HAS_THICKFRAME(style) \ + (((style) & WS_THICKFRAME) && \ + !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME)) + +#define SWP_AGG_NOGEOMETRYCHANGE \ + (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE) +#define SWP_AGG_NOPOSCHANGE \ + (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER) +#define SWP_AGG_STATUSFLAGS \ + (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW) + +#define EMPTYPOINT(pt) ((*(LONG*)&(pt)) == -1) + +#define PLACE_MIN 0x0001 +#define PLACE_MAX 0x0002 +#define PLACE_RECT 0x0004 + +#define SMC_NOCOPY 0x0001 +#define SMC_NOPARENTERASE 0x0002 +#define SMC_DRAWFRAME 0x0004 +#define SMC_SETXPOS 0x0008 + +typedef struct +{ + INT actualCount; + INT suggestedCount; + WINBOOL valid; + INT wMagic; + HWND hwndParent; + WINDOWPOS winPos[1]; +} DWP; + +WINBOOL WINPOS_RedrawIconTitle( HWND hWnd ); +WINBOOL WINPOS_ShowIconTitle( WND* pWnd, WINBOOL bShow ); +void WINPOS_GetMinMaxInfo( WND* pWnd, POINT *maxSize, + POINT *maxPos, POINT *minTrack, + POINT *maxTrack ); +UINT WINPOS_MinMaximize( WND* pWnd, UINT cmd, LPRECT lpPos); +WINBOOL WINPOS_SetActiveWindow( HWND hWnd, WINBOOL fMouse, + WINBOOL fChangeFocus ); +WINBOOL WINPOS_ChangeActiveWindow( HWND hwnd, WINBOOL mouseMsg ); +LONG WINPOS_SendNCCalcSize(HWND hwnd, WINBOOL calcValidRect, + RECT *newWindowRect, RECT *oldWindowRect, + RECT *oldClientRect, WINDOWPOS *winpos, + RECT *newClientRect ); +LONG WINPOS_HandleWindowPosChanging(WND *wndPtr, WINDOWPOS *winpos); +LONG WINPOS_HandleWindowPosChanging(WND *wndPtr, WINDOWPOS *winpos); +INT WINPOS_WindowFromPoint( WND* scopeWnd, POINT pt, WND **ppWnd ); +void WINPOS_CheckInternalPos( HWND hwnd ); +WINBOOL WINPOS_ActivateOtherWindow(WND* pWnd); +WINBOOL WINPOS_CreateInternalPosAtom(void); + +void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, + POINT *offset ); +WINBOOL WINPOS_CanActivate(WND* pWnd); +LPINTERNALPOS WINPOS_InitInternalPos( WND* wnd, POINT pt, + LPRECT restoreRect ); +WINBOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, + UINT flags ); +#endif /* __WINE_WINPOS_H */ diff --git a/reactos/include/user32/winproc.h b/reactos/include/user32/winproc.h index 56e459ab0dd..f0d9db43572 100644 --- a/reactos/include/user32/winproc.h +++ b/reactos/include/user32/winproc.h @@ -7,7 +7,7 @@ #ifndef __WINE_WINPROC_H #define __WINE_WINPROC_H -//#include "wintypes.h" +#include typedef enum { @@ -41,5 +41,10 @@ WINBOOL WINPROC_SetProc( HWINDOWPROC *pFirst, WNDPROC func, void WINPROC_FreeProc( HWINDOWPROC proc, WINDOWPROCUSER user ); WINDOWPROCTYPE WINPROC_GetProcType( HWINDOWPROC proc ); +INT WINPROC_MapMsg32ATo32W( HWND hwnd, UINT msg, WPARAM wParam, LPARAM *plparam ); +void WINPROC_UnmapMsg32ATo32W( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ); +INT WINPROC_MapMsg32WTo32A( HWND hwnd, UINT msg, WPARAM wParam, LPARAM *plparam ); +void WINPROC_UnmapMsg32WTo32A( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ); + #endif /* __WINE_WINPROC_H */ diff --git a/reactos/lib/user32/graphics/caret.c b/reactos/lib/user32/graphics/caret.c new file mode 100644 index 00000000000..bf818360dad --- /dev/null +++ b/reactos/lib/user32/graphics/caret.c @@ -0,0 +1,297 @@ +/* + * Caret functions + * + * Copyright 1993 David Metcalfe + * Copyright 1996 Frans van Dorsselaer + */ + +#include +#include +#include + +static CARET Caret = { 0, 0, FALSE, 0, 0, 2, 12, 0, 500, 0 }; + + +WINBOOL STDCALL CreateCaret( HWND hwnd, HBITMAP bitmap, + INT width, INT height ) +{ + DPRINT("hwnd=%04x\n",(UINT) hwnd); + + if (!hwnd) return FALSE; + + /* if cursor already exists, destroy it */ + if (Caret.hwnd) DestroyCaret(); + + if (bitmap && ((UINT)bitmap != 1)) + { + BITMAP bmp; + if (!GetObject( bitmap, sizeof(bmp), &bmp )) return FALSE; + Caret.width = bmp.bmWidth; + Caret.height = bmp.bmHeight; + /* FIXME: we should make a copy of the bitmap instead of a brush */ + Caret.hBrush = CreatePatternBrush( bitmap ); + } + else + { + Caret.width = width ? width : GetSystemMetrics(SM_CXBORDER); + Caret.height = height ? height : GetSystemMetrics(SM_CYBORDER); + Caret.hBrush = CreateSolidBrush(bitmap ? + GetSysColor(COLOR_GRAYTEXT) : + GetSysColor(COLOR_WINDOW) ); + } + + Caret.hwnd = hwnd; + Caret.hidden = 1; + Caret.on = FALSE; + Caret.x = 0; + Caret.y = 0; + + Caret.timeout = GetProfileIntA( "windows", "CursorBlinkRate", 500 ); + return TRUE; +} + + + +WINBOOL STDCALL DestroyCaret(void) +{ + if (!Caret.hwnd) return FALSE; + + DPRINT("hwnd=%04x, timerid=%d\n", (UINT)Caret.hwnd,(UINT) Caret.timerid); + + CARET_KillTimer(); + CARET_DisplayCaret(CARET_OFF); + DeleteObject( Caret.hBrush ); + Caret.hwnd = 0; + return TRUE; +} + + + +WINBOOL STDCALL SetCaretPos( INT x, INT y) +{ + if (!Caret.hwnd) return FALSE; + if ((x == Caret.x) && (y == Caret.y)) return TRUE; + + DPRINT("x=%d, y=%d\n", x, y); + + CARET_KillTimer(); + CARET_DisplayCaret(CARET_OFF); + Caret.x = x; + Caret.y = y; + if (!Caret.hidden) + { + CARET_DisplayCaret(CARET_ON); + CARET_SetTimer(); + } + return TRUE; +} + + + + + +/***************************************************************** + * HideCaret (USER.317) + */ +WINBOOL STDCALL HideCaret( HWND hwnd ) +{ + if (!Caret.hwnd) return FALSE; + if (hwnd && (Caret.hwnd != hwnd)) return FALSE; + + DPRINT("hwnd=%04x, hidden=%d\n", + hwnd, Caret.hidden); + + CARET_KillTimer(); + CARET_DisplayCaret(CARET_OFF); + Caret.hidden++; + return TRUE; +} + + + + +/***************************************************************** + * ShowCaret (USER.529) + */ +WINBOOL STDCALL ShowCaret( HWND hwnd ) +{ + if (!Caret.hwnd) return FALSE; + if (hwnd && (Caret.hwnd != hwnd)) return FALSE; + + DPRINT("hwnd=%04x, hidden=%d\n", + hwnd, Caret.hidden); + + if (Caret.hidden) + { + Caret.hidden--; + if (!Caret.hidden) + { + CARET_DisplayCaret(CARET_ON); + CARET_SetTimer(); + } + } + return TRUE; +} + + + +/***************************************************************** + * SetCaretBlinkTime (USER.465) + */ +WINBOOL STDCALL SetCaretBlinkTime( UINT msecs ) +{ + if (!Caret.hwnd) return FALSE; + + DPRINT("hwnd=%04x, msecs=%d\n", + Caret.hwnd, msecs); + + Caret.timeout = msecs; + CARET_ResetTimer(); + return TRUE; +} + + + + +/***************************************************************** + * GetCaretBlinkTime (USER.209) + */ +UINT STDCALL GetCaretBlinkTime(void) +{ + return Caret.timeout; +} + + + + + +/***************************************************************** + * GetCaretPos (USER.210) + */ +WINBOOL STDCALL GetCaretPos( LPPOINT pt ) +{ + if (!Caret.hwnd || !pt) return FALSE; + pt->x = Caret.x; + pt->y = Caret.y; + return TRUE; +} + + +/***************************************************************** + * CARET_GetHwnd + */ +HWND CARET_GetHwnd(void) +{ + return Caret.hwnd; +} + +/***************************************************************** + * CARET_GetRect + */ +void CARET_GetRect(LPRECT lprc) +{ + lprc->right = (lprc->left = Caret.x) + Caret.width - 1; + lprc->bottom = (lprc->top = Caret.y) + Caret.height - 1; +} + +/***************************************************************** + * CARET_DisplayCaret + */ +void CARET_DisplayCaret( DISPLAY_CARET status ) +{ + HDC hdc; + HBRUSH hPrevBrush; + + if (Caret.on && (status == CARET_ON)) return; + if (!Caret.on && (status == CARET_OFF)) return; + + /* So now it's always a toggle */ + + Caret.on = !Caret.on; + /* do not use DCX_CACHE here, for x,y,width,height are in logical units */ + if (!(hdc = GetDCEx( Caret.hwnd, 0, DCX_USESTYLE /*| DCX_CACHE*/ ))) return; + hPrevBrush = SelectObject( hdc, Caret.hBrush ); + PatBlt( hdc, Caret.x, Caret.y, Caret.width, Caret.height, PATINVERT ); + SelectObject( hdc, hPrevBrush ); + ReleaseDC( Caret.hwnd, hdc ); +} + + +/***************************************************************** + * CARET_Callback + */ +VOID CALLBACK CARET_Callback( HWND hwnd, UINT msg, UINT id, DWORD ctime) +{ + DPRINT("hwnd=%04x, timerid=%d, caret=%d\n", hwnd, id, Caret.on); + CARET_DisplayCaret(CARET_TOGGLE); +} + + +/***************************************************************** + * CARET_SetTimer + */ +void CARET_SetTimer(void) +{ + if (Caret.timerid) + KillTimer( (HWND)0, Caret.timerid ); + Caret.timerid = SetTimer( (HWND)0, 0, Caret.timeout,CARET_Callback ); +} + + +/***************************************************************** + * CARET_ResetTimer + */ +void CARET_ResetTimer(void) +{ + if (Caret.timerid) + { + KillTimer( (HWND)0, Caret.timerid ); + Caret.timerid = SetTimer( (HWND)0, 0, Caret.timeout, + CARET_Callback ); + } +} + + +/***************************************************************** + * CARET_KillTimer + */ +void CARET_KillTimer(void) +{ + if (Caret.timerid) + { + KillTimer( (HWND)0, Caret.timerid ); + Caret.timerid = 0; + } +} + + + +/********************************************************************** + * CreateIconFromResource (USER32.76) + */ +HICON STDCALL CreateIconFromResource( LPBYTE bits, UINT cbSize, + WINBOOL bIcon, DWORD dwVersion) +{ + return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0); +} + + +/********************************************************************** + * CreateIconFromResourceEx (USER32.77) + */ +HICON STDCALL CreateIconFromResourceEx( LPBYTE bits, UINT cbSize, + WINBOOL bIcon, DWORD dwVersion, + INT width, INT height, + UINT cFlag ) +{ +/* + TDB* pTask = (TDB*)GlobalLock( GetCurrentTask() ); + if( pTask ) + return CURSORICON_CreateFromResource( pTask->hInstance, 0, bits, cbSize, bIcon, dwVersion, + width, height, cFlag ); +*/ + return 0; +} + + + diff --git a/reactos/lib/user32/graphics/draw.c b/reactos/lib/user32/graphics/draw.c new file mode 100644 index 00000000000..6a9310d9331 --- /dev/null +++ b/reactos/lib/user32/graphics/draw.c @@ -0,0 +1,22 @@ +#include + +WINBOOL STDCALL DrawEdge( HDC hdc, LPRECT rc, UINT edge, UINT flags ) +{ + +} + +WINBOOL +STDCALL +DrawIconEx(HDC hdc, int xLeft, int yTop, + HICON hIcon, int cxWidth, int cyWidth, + UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags) +{ +} + +WINBOOL +STDCALL +DrawFocusRect( + HDC hDC, + CONST RECT * lprc) +{ +} \ No newline at end of file diff --git a/reactos/lib/user32/graphics/fill.c b/reactos/lib/user32/graphics/fill.c new file mode 100644 index 00000000000..29aaea6847e --- /dev/null +++ b/reactos/lib/user32/graphics/fill.c @@ -0,0 +1,20 @@ +#include + + +INT STDCALL FillRect( HDC hdc, const RECT *rect, HBRUSH hbrush ) +{ + HBRUSH prevBrush; + + if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0; + PatBlt( hdc, rect->left, rect->top, + rect->right - rect->left, rect->bottom - rect->top, PATCOPY ); + SelectObject( hdc, prevBrush ); + return 1; +} + + +WINBOOL STDCALL InvertRect( HDC hDC, CONST RECT *lprc) +{ + return PatBlt( hDC, lprc->left, lprc->top, + lprc->right - lprc->left, lprc->bottom - lprc->top, DSTINVERT ); +} diff --git a/reactos/lib/user32/graphics/rect.c b/reactos/lib/user32/graphics/rect.c new file mode 100644 index 00000000000..923f1fc3059 --- /dev/null +++ b/reactos/lib/user32/graphics/rect.c @@ -0,0 +1,251 @@ +/* + * Rectangle-related functions + * + * CopyxRight 1993, 1996 Alexandre Julliard + * + */ + +#include + +WINBOOL +STDCALL +SetRect( + LPRECT lprc, + int xLeft, + int yTop, + int xRight, + int yBottom) +{ + if ( lprc == NULL ) + return FALSE; + lprc->left = xLeft; + lprc->right = xRight; + lprc->top = yTop; + lprc->bottom = yBottom; + return TRUE; +} + + + + +/*********************************************************************** + * SetRectEmpty32 (USER32.500) + */ +WINBOOL STDCALL SetRectEmpty( LPRECT lprc ) +{ + if ( lprc == NULL ) + return FALSE; + lprc->left = lprc->right = lprc->top = lprc->bottom = 0; + return TRUE; +} + + + +//added memcpy and check BD + +/*********************************************************************** + * CopyRect32 (USER32.62) + */ +WINBOOL +STDCALL +CopyRect( + LPRECT lprcDst, + CONST RECT *lprcSrc) +{ + if ( lprcDst == NULL || lprcSrc == NULL ) + return FALSE; + *lprcDst = *lprcSrc; + return TRUE; +} + + + + + +/*********************************************************************** + * IsRectEmpty32 (USER32.347) + */ +WINBOOL STDCALL IsRectEmpty( const RECT *lprc ) +{ + if ( lprc == NULL ) + return TRUE; + return ((lprc->left == lprc->right) || (lprc->top == lprc->bottom)); +} + + + + + + +/*********************************************************************** + * PtInRect32 (USER32.424) + */ +WINBOOL +STDCALL +PtInRect( + CONST RECT *lprc, + POINT pt) +{ + return ((pt.x >= lprc->left) && (pt.x < lprc->right) && + (pt.y >= lprc->top) && (pt.y < lprc->bottom)); +} + + + + +/*********************************************************************** + * OffsetRect32 (USER32.406) + */ +WINBOOL +STDCALL +OffsetRect( + LPRECT lprc, + int dx, + int dy) +{ + if ( lprc == NULL ) + return FALSE; + lprc->left += dx; + lprc->right += dx; + lprc->top += dy; + lprc->bottom += dy; + return TRUE; +} + + + + + +/*********************************************************************** + * InflateRect32 (USER32.321) + */ +WINBOOL STDCALL InflateRect( LPRECT lprc, INT dx, INT dy ) +{ + lprc->left -= dx; + lprc->top -= dy; + lprc->right += dx; + lprc->bottom += dy; + return TRUE; +} + + + + + +/*********************************************************************** + * IntersectRect32 (USER32.327) + */ +WINBOOL +STDCALL +IntersectRect( + LPRECT lprcDst, + CONST RECT *lprcSrc1, + CONST RECT *lprcSrc2) +{ + if (IsRectEmpty(lprcSrc1) || IsRectEmpty(lprcSrc2) || + (lprcSrc1->left >= lprcSrc2->right) || (lprcSrc2->left >= lprcSrc1->right) || + (lprcSrc1->top >= lprcSrc2->bottom) || (lprcSrc2->top >= lprcSrc1->bottom)) + { + SetRectEmpty( lprcDst ); + return FALSE; + } + lprcDst->left = max( lprcSrc1->left, lprcSrc2->left ); + lprcDst->right = min( lprcSrc1->right, lprcSrc2->right ); + lprcDst->top = max( lprcSrc1->top, lprcSrc2->top ); + lprcDst->bottom = min( lprcSrc1->bottom, lprcSrc2->bottom ); + return TRUE; +} + + + + +/*********************************************************************** + * UnionRect32 (USER32.559) + */ +WINBOOL STDCALL UnionRect( LPRECT lprcDst, const RECT *lprcSrc1, + const RECT *lprcSrc2 ) +{ + if (IsRectEmpty(lprcSrc1)) + { + if (IsRectEmpty(lprcSrc2)) + { + SetRectEmpty( lprcDst ); + return FALSE; + } + else *lprcDst = *lprcSrc2; + } + else + { + if (IsRectEmpty(lprcSrc2)) + *lprcDst = *lprcSrc1; + else + { + lprcDst->left = min( lprcSrc1->left, lprcSrc2->left ); + lprcDst->right = max( lprcSrc1->right, lprcSrc2->right ); + lprcDst->top = min( lprcSrc1->top, lprcSrc2->top ); + lprcDst->bottom = max( lprcSrc1->bottom, lprcSrc2->bottom ); + } + } + return TRUE; +} + + + + +/*********************************************************************** + * EqualRect32 (USER32.194) + */ +WINBOOL +STDCALL +EqualRect( + CONST RECT *lprc1, + CONST RECT *lprc2) +{ + return ((lprc1->left == lprc2->left) && (lprc1->right == lprc2->right) && + (lprc1->top == lprc2->top) && (lprc1->bottom == lprc2->bottom)); +} + + + + + +/*********************************************************************** + * SubtractRect32 (USER32.536) + */ +WINBOOL +STDCALL +SubtractRect( + LPRECT lprcDst, + CONST RECT *lprcSrc1, + CONST RECT *lprcSrc2) +{ + RECT tmp; + + if (IsRectEmpty( lprcSrc1 )) + { + SetRectEmpty( lprcDst ); + return FALSE; + } +// changed BD + CopyRect(lprcDst,lprcSrc1); + + if (IntersectRect( &tmp, lprcSrc1, lprcSrc2 )) + { + if (EqualRect( &tmp, lprcDst )) + { + SetRectEmpty( lprcDst ); + return FALSE; + } + if ((tmp.top == lprcDst->top) && (tmp.bottom == lprcDst->bottom)) + { + if (tmp.left == lprcDst->left) lprcDst->left = tmp.right; + else if (tmp.right == lprcDst->right) lprcDst->right = tmp.left; + } + else if ((tmp.left == lprcDst->left) && (tmp.right == lprcDst->right)) + { + if (tmp.top == lprcDst->top) lprcDst->top = tmp.bottom; + else if (tmp.bottom == lprcDst->bottom) lprcDst->bottom = tmp.top; + } + } + return TRUE; +} diff --git a/reactos/lib/user32/graphics/syscol.c b/reactos/lib/user32/graphics/syscol.c new file mode 100644 index 00000000000..0a1b6ec0c87 --- /dev/null +++ b/reactos/lib/user32/graphics/syscol.c @@ -0,0 +1,95 @@ +/* + * Support for system colors + * + * Copyright David W. Metcalfe, 1993 + * Copyright Alexandre Julliard, 1994 + * + */ + + +#include +//#include + +void SYSCOLOR_SetColor( int index, COLORREF color ); + +//#define NUM_SYS_COLORS (COLOR_GRADIENTINACTIVECAPTION+1) +#define NUM_SYS_COLORS 100 + +static COLORREF SysColors[NUM_SYS_COLORS]; +static HBRUSH SysColorBrushes[NUM_SYS_COLORS]; +static HPEN SysColorPens[NUM_SYS_COLORS]; + +DWORD STDCALL GetSysColor( INT nIndex ) +{ + if (nIndex >= 0 && nIndex < NUM_SYS_COLORS) + return SysColors[nIndex]; + else + return 0; +} + + + + +/************************************************************************* + * SetSysColors (USER.505) + */ +WINBOOL STDCALL SetSysColors( INT nChanges, const INT *lpSysColor, + const COLORREF *lpColorValues ) +{ + int i; + + for (i = 0; i < nChanges; i++) + { + SYSCOLOR_SetColor( lpSysColor[i], lpColorValues[i] ); + } + + /* Send WM_SYSCOLORCHANGE message to all windows */ + + SendMessageA( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0 ); + + /* Repaint affected portions of all visible windows */ + + RedrawWindow( GetDesktopWindow(), NULL, 0, + RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN ); + return TRUE; +} + + +HBRUSH STDCALL GetSysColorBrush( INT index ) +{ + if (0 <= index && index < NUM_SYS_COLORS) + return SysColorBrushes[index]; + + return GetStockObject(LTGRAY_BRUSH); +} + + +///////////////////////////////////////////////////////////////////////////////////// + +void SYSCOLOR_SetColor( int index, COLORREF color ) +{ + if (index < 0 || index >= NUM_SYS_COLORS) return; + SysColors[index] = color; + if (SysColorBrushes[index]) DeleteObject( SysColorBrushes[index] ); + SysColorBrushes[index] = CreateSolidBrush( color ); + if (SysColorPens[index]) DeleteObject( SysColorPens[index] ); + SysColorPens[index] = CreatePen( PS_SOLID, 1, color ); +} + + + +/*********************************************************************** + * GetSysColorPen (Not a Windows API) + * + * This function is new to the Wine lib -- it does not exist in + * Windows. However, it is a natural complement for GetSysColorBrush + * in the Win API and is needed quite a bit inside Wine. + */ +HPEN STDCALL GetSysColorPen( INT index ) +{ + /* We can assert here, because this function is internal to Wine */ + //assert (0 <= index && index < NUM_SYS_COLORS); + return SysColorPens[index]; + +} + diff --git a/reactos/lib/user32/graphics/text.c b/reactos/lib/user32/graphics/text.c new file mode 100644 index 00000000000..8a9670a52b2 --- /dev/null +++ b/reactos/lib/user32/graphics/text.c @@ -0,0 +1,28 @@ +#include + + +int +STDCALL +DrawTextA( + HDC hDC,LPCSTR lpString, + int nCount, LPRECT lpRect, UINT uFormat) +{ + DRAWTEXTPARAMS dtp; + dtp.cbSize = sizeof(DRAWTEXTPARAMS); + dtp.iTabLength = 0; + //return TEXT_DrawTextEx(hDC,(void *)lpString, nCount,lpRect,uFormat, &dtp, FALSE); +} + + +int +STDCALL +DrawTextW( + HDC hDC, LPCWSTR lpString, + int nCount, LPRECT lpRect, UINT uFormat) +{ + DRAWTEXTPARAMS dtp; + dtp.cbSize = sizeof(DRAWTEXTPARAMS); + dtp.iTabLength = 0; + return TEXT_DrawTextEx(hDC,(void *)lpString,nCount,lpRect,uFormat, &dtp,TRUE); + +} \ No newline at end of file diff --git a/reactos/lib/user32/internal/dce.c b/reactos/lib/user32/internal/dce.c new file mode 100644 index 00000000000..83b719cfd9b --- /dev/null +++ b/reactos/lib/user32/internal/dce.c @@ -0,0 +1,320 @@ +#include +#include +#include + +DCE *firstDCE = 0; +HDC defaultDCstate = 0; + +/*********************************************************************** + * DCE_AllocDCE + * + * Allocate a new DCE. + */ +DCE *DCE_AllocDCE( HWND hWnd, DCE_TYPE type ) +{ + DCE * dce; + if (!(dce = HeapAlloc( GetProcessHeap(), 0, sizeof(DCE) ))) return NULL; + if (!(dce->hDC = CreateDC( "DISPLAY", NULL, NULL, NULL ))) + { + HeapFree( GetProcessHeap(), 0, dce ); + return 0; + } + + /* store DCE handle in DC hook data field */ + + //SetDCHook( dce->hDC, (FARPROC)DCHook, (DWORD)dce ); + + dce->hwndCurrent = hWnd; + dce->hClipRgn = 0; + dce->next = firstDCE; + firstDCE = dce; + + if( type != DCE_CACHE_DC ) /* owned or class DC */ + { + dce->DCXflags = DCX_DCEBUSY; + if( hWnd ) + { + WND* wnd = WIN_FindWndPtr(hWnd); + + if( wnd->dwStyle & WS_CLIPCHILDREN ) dce->DCXflags |= DCX_CLIPCHILDREN; + if( wnd->dwStyle & WS_CLIPSIBLINGS ) dce->DCXflags |= DCX_CLIPSIBLINGS; + } + //SetHookFlags(dce->hDC,DCHF_INVALIDATEVISRGN); + } + else dce->DCXflags = DCX_CACHE | DCX_DCEEMPTY; + + return dce; +} + + +/*********************************************************************** + * DCE_FreeDCE + */ +DCE* DCE_FreeDCE( DCE *dce ) +{ + DCE **ppDCE = &firstDCE; + + if (!dce) return NULL; + while (*ppDCE && (*ppDCE != dce)) ppDCE = &(*ppDCE)->next; + if (*ppDCE == dce) *ppDCE = dce->next; + + // SetDCHook(dce->hDC, NULL, 0L); + + DeleteDC( dce->hDC ); + if( dce->hClipRgn && !(dce->DCXflags & DCX_KEEPCLIPRGN) ) + DeleteObject(dce->hClipRgn); + HeapFree( GetProcessHeap(), 0, dce ); + return *ppDCE; +} + +/*********************************************************************** + * DCE_DeleteClipRgn + */ +void DCE_DeleteClipRgn( DCE* dce ) +{ + dce->DCXflags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN | DCX_WINDOWPAINT); + + if( dce->DCXflags & DCX_KEEPCLIPRGN ) + dce->DCXflags &= ~DCX_KEEPCLIPRGN; + else + if( dce->hClipRgn > 1 ) + DeleteObject( dce->hClipRgn ); + + dce->hClipRgn = 0; + + //TRACE(dc,"\trestoring VisRgn\n"); + + RestoreVisRgn(dce->hDC); + +} + +/*********************************************************************** + * DCE_GetVisRect + * + * Calculate the visible rectangle of a window (i.e. the client or + * window area clipped by the client area of all ancestors) in the + * corresponding coordinates. Return FALSE if the visible region is empty. + */ +WINBOOL DCE_GetVisRect( WND *wndPtr, WINBOOL clientArea, RECT *lprect ) +{ + *lprect = clientArea ? wndPtr->rectClient : wndPtr->rectWindow; + + if (wndPtr->dwStyle & WS_VISIBLE) + { + INT xoffset = lprect->left; + INT yoffset = lprect->top; + + while (wndPtr->dwStyle & WS_CHILD) + { + wndPtr = wndPtr->parent; + + if ( (wndPtr->dwStyle & (WS_ICONIC | WS_VISIBLE)) != WS_VISIBLE ) + goto fail; + + xoffset += wndPtr->rectClient.left; + yoffset += wndPtr->rectClient.top; + OffsetRect( lprect, wndPtr->rectClient.left, + wndPtr->rectClient.top ); + + if( (wndPtr->rectClient.left >= wndPtr->rectClient.right) || + (wndPtr->rectClient.top >= wndPtr->rectClient.bottom) || + (lprect->left >= wndPtr->rectClient.right) || + (lprect->right <= wndPtr->rectClient.left) || + (lprect->top >= wndPtr->rectClient.bottom) || + (lprect->bottom <= wndPtr->rectClient.top) ) + goto fail; + + lprect->left = max( lprect->left, wndPtr->rectClient.left ); + lprect->right = min( lprect->right, wndPtr->rectClient.right ); + lprect->top = max( lprect->top, wndPtr->rectClient.top ); + lprect->bottom = min( lprect->bottom, wndPtr->rectClient.bottom ); + } + OffsetRect( lprect, -xoffset, -yoffset ); + return TRUE; + } + +fail: + SetRectEmpty( lprect ); + return FALSE; +} + + +/*********************************************************************** + * DCE_AddClipRects + * + * Go through the linked list of windows from pWndStart to pWndEnd, + * adding to the clip region the intersection of the target rectangle + * with an offset window rectangle. + */ +WINBOOL DCE_AddClipRects( WND *pWndStart, WND *pWndEnd, + HRGN hrgnClip, LPRECT lpRect, int x, int y ) +{ + RECT rect; + +// if( pWndStart->pDriver->pIsSelfClipping( pWndStart ) ) + // return TRUE; /* The driver itself will do the clipping */ + + for (; pWndStart != pWndEnd; pWndStart = pWndStart->next) + { + if( !(pWndStart->dwStyle & WS_VISIBLE) ) continue; + + rect.left = pWndStart->rectWindow.left + x; + rect.top = pWndStart->rectWindow.top + y; + rect.right = pWndStart->rectWindow.right + x; + rect.bottom = pWndStart->rectWindow.bottom + y; + + if( IntersectRect( &rect, &rect, lpRect )) + if(!REGION_UnionRectWithRgn( hrgnClip, &rect )) + break; + } + return (pWndStart == pWndEnd); +} + + + +/*********************************************************************** + * DCE_GetVisRgn + * + * Return the visible region of a window, i.e. the client or window area + * clipped by the client area of all ancestors, and then optionally + * by siblings and children. + */ +HRGN DCE_GetVisRgn( HWND hwnd, WORD flags ) +{ + HRGN hrgnVis = 0; + RECT rect; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + /* Get visible rectangle and create a region with it. */ + + if (wndPtr && DCE_GetVisRect(wndPtr, !(flags & DCX_WINDOW), &rect)) + { + if((hrgnVis = CreateRectRgnIndirect( &rect ))) + { + HRGN hrgnClip = CreateRectRgn( 0, 0, 0, 0 ); + INT xoffset, yoffset; + + if( hrgnClip ) + { + /* Compute obscured region for the visible rectangle by + * clipping children, siblings, and ancestors. Note that + * DCE_GetVisRect() returns a rectangle either in client + * or in window coordinates (for DCX_WINDOW request). */ + + if( (flags & DCX_CLIPCHILDREN) && wndPtr->child ) + { + if( flags & DCX_WINDOW ) + { + /* adjust offsets since child window rectangles are + * in client coordinates */ + + xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left; + yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top; + } + else + xoffset = yoffset = 0; + + DCE_AddClipRects( wndPtr->child, NULL, hrgnClip, + &rect, xoffset, yoffset ); + } + + /* sibling window rectangles are in client + * coordinates of the parent window */ + + if (flags & DCX_WINDOW) + { + xoffset = -wndPtr->rectWindow.left; + yoffset = -wndPtr->rectWindow.top; + } + else + { + xoffset = -wndPtr->rectClient.left; + yoffset = -wndPtr->rectClient.top; + } + + if (flags & DCX_CLIPSIBLINGS && wndPtr->parent ) + DCE_AddClipRects( wndPtr->parent->child, + wndPtr, hrgnClip, &rect, xoffset, yoffset ); + + /* Clip siblings of all ancestors that have the + * WS_CLIPSIBLINGS style + */ + + while (wndPtr->dwStyle & WS_CHILD) + { + wndPtr = wndPtr->parent; + xoffset -= wndPtr->rectClient.left; + yoffset -= wndPtr->rectClient.top; + if(wndPtr->dwStyle & WS_CLIPSIBLINGS && wndPtr->parent) + { + DCE_AddClipRects( wndPtr->parent->child, wndPtr, + hrgnClip, &rect, xoffset, yoffset ); + } + } + + /* Now once we've got a jumbo clip region we have + * to substract it from the visible rectangle. + */ + + CombineRgn( hrgnVis, hrgnVis, hrgnClip, RGN_DIFF ); + DeleteObject( hrgnClip ); + } + else + { + DeleteObject( hrgnVis ); + hrgnVis = 0; + } + } + } + else + hrgnVis = CreateRectRgn(0, 0, 0, 0); /* empty */ + return hrgnVis; +} + +/*********************************************************************** + * DCE_OffsetVisRgn + * + * Change region from DC-origin relative coordinates to screen coords. + */ + +void DCE_OffsetVisRgn( HDC hDC, HRGN hVisRgn ) +{ +/* + DC *dc; + if (!(dc = (DC *) GDI_GetObjPtr( hDC, DC_MAGIC ))) return; + + OffsetRgn( hVisRgn, dc->w.DCOrgX, dc->w.DCOrgY ); + + GDI_HEAP_UNLOCK( hDC ); +*/ +} + + + +/*********************************************************************** + * DCE_ExcludeRgn + * + * Translate given region from the wnd client to the DC coordinates + * and add it to the clipping region. + */ +INT DCE_ExcludeRgn( HDC hDC, WND* wnd, HRGN hRgn ) +{ + POINT pt = {0, 0}; + DCE *dce = firstDCE; + + while (dce && (dce->hDC != hDC)) dce = dce->next; + if( dce ) + { + MapWindowPoints( wnd->hwndSelf, dce->hwndCurrent, &pt, 1); + if( dce->DCXflags & DCX_WINDOW ) + { + wnd = WIN_FindWndPtr(dce->hwndCurrent); + pt.x += wnd->rectClient.left - wnd->rectWindow.left; + pt.y += wnd->rectClient.top - wnd->rectWindow.top; + } + } + else return ERROR; + OffsetRgn(hRgn, pt.x, pt.y); + + return ExtSelectClipRgn( hDC, hRgn, RGN_DIFF ); +} \ No newline at end of file diff --git a/reactos/lib/user32/internal/defwnd.c b/reactos/lib/user32/internal/defwnd.c new file mode 100644 index 00000000000..a3fe99bd2ea --- /dev/null +++ b/reactos/lib/user32/internal/defwnd.c @@ -0,0 +1,399 @@ +/* + * Default window procedure + * + * Copyright 1993, 1996 Alexandre Julliard + * 1995 Alex Korobka + */ + +#include +#include +#include "user.h" +#include "heap.h" +#include "nonclient.h" +#include "winpos.h" +#include "dce.h" +#include "sysmetrics.h" +#include "debug.h" +#include "spy.h" +#include "tweak.h" +#include "wine/winuser.h" + + /* Last COLOR id */ +#define COLOR_MAX COLOR_BTNHIGHLIGHT + + /* bits in the dwKeyData */ +#define KEYDATA_ALT 0x2000 +#define KEYDATA_PREVSTATE 0x4000 + +static short iF10Key = 0; +static short iMenuSysKey = 0; + +/*********************************************************************** + * DEFWND_HandleWindowPosChanged + * + * Handle the WM_WINDOWPOSCHANGED message. + */ +static void DEFWND_HandleWindowPosChanged( WND *wndPtr, UINT flags ) +{ + WPARAM wp = SIZE_RESTORED; + + if (!(flags & SWP_NOCLIENTMOVE)) + SendMessage( wndPtr->hwndSelf, WM_MOVE, 0, + MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top)); + if (!(flags & SWP_NOCLIENTSIZE)) + { + if (wndPtr->dwStyle & WS_MAXIMIZE) wp = SIZE_MAXIMIZED; + else if (wndPtr->dwStyle & WS_MINIMIZE) wp = SIZE_MINIMIZED; + + SendMessage( wndPtr->hwndSelf, WM_SIZE, wp, + MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left, + wndPtr->rectClient.bottom-wndPtr->rectClient.top)); + } +} + + +/*********************************************************************** + * DEFWND_SetText + * + * Set the window text. + */ +void DEFWND_SetTextA( WND *wndPtr, LPCSTR text ) +{ + if (!text) text = ""; + if (wndPtr->text) HeapFree( GetProcessHeap(), 0, wndPtr->text ); + wndPtr->text = HEAP_strdupA( GetProcessHeap(), 0, text ); + wndPtr->pDriver->pSetText(wndPtr, wndPtr->text); +} + + +void DEFWND_SetTextW( WND *wndPtr, LPCSTR text ) +{ + if (!text) text = ""; + if (wndPtr->text) HeapFree( GetProcessHeap(), 0, wndPtr->text ); + wndPtr->text = HEAP_strdupW( GetProcessHeap(), 0, text ); + +} +/*********************************************************************** + * DEFWND_ControlColor + * + * Default colors for control painting. + */ +HBRUSH DEFWND_ControlColor( HDC hDC, UINT ctlType ) +{ + if( ctlType == CTLCOLOR_SCROLLBAR) + { + HBRUSH hb = GetSysColorBrush(COLOR_SCROLLBAR); + SetBkColor( hDC, RGB(255, 255, 255) ); + SetTextColor( hDC, RGB(0, 0, 0) ); + UnrealizeObject( hb ); + return hb; + } + + SetTextColor( hDC, GetSysColor(COLOR_WINDOWTEXT)); + + if (TWEAK_WineLook > WIN31_LOOK) { + if ((ctlType == CTLCOLOR_EDIT) || (ctlType == CTLCOLOR_LISTBOX)) + SetBkColor( hDC, GetSysColor(COLOR_WINDOW) ); + else { + SetBkColor( hDC, GetSysColor(COLOR_3DFACE) ); + return GetSysColorBrush(COLOR_3DFACE); + } + } + else + SetBkColor( hDC, GetSysColor(COLOR_WINDOW) ); + return GetSysColorBrush(COLOR_WINDOW); +} + + +/*********************************************************************** + * DEFWND_SetRedraw + */ +static void DEFWND_SetRedraw( WND* wndPtr, WPARAM wParam ) +{ + WINBOOL bVisible = wndPtr->dwStyle & WS_VISIBLE; + + TRACE(win,"%04x %i\n", wndPtr->hwndSelf, (wParam!=0) ); + + if( wParam ) + { + if( !bVisible ) + { + wndPtr->dwStyle |= WS_VISIBLE; + DCE_InvalidateDCE( wndPtr, &wndPtr->rectWindow ); + } + } + else if( bVisible ) + { + if( wndPtr->dwStyle & WS_MINIMIZE ) wParam = RDW_VALIDATE; + else wParam = RDW_ALLCHILDREN | RDW_VALIDATE; + + PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, 0, wParam, 0 ); + DCE_InvalidateDCE( wndPtr, &wndPtr->rectWindow ); + wndPtr->dwStyle &= ~WS_VISIBLE; + } +} + +/*********************************************************************** + * DEFWND_DefWinProc + * + * Default window procedure for messages that are the same in Win and Win. + */ +static LRESULT DEFWND_DefWinProc( WND *wndPtr, UINT msg, WPARAM wParam, + LPARAM lParam ) +{ + switch(msg) + { + case WM_NCPAINT: + return NC_HandleNCPaint( wndPtr->hwndSelf, (HRGN)wParam ); + + case WM_NCHITTEST: + return NC_HandleNCHitTest( wndPtr->hwndSelf, MAKEPOINT(lParam) ); + + case WM_NCLBUTTONDOWN: + return NC_HandleNCLButtonDown( wndPtr, wParam, lParam ); + + case WM_LBUTTONDBLCLK: + case WM_NCLBUTTONDBLCLK: + return NC_HandleNCLButtonDblClk( wndPtr, wParam, lParam ); + + case WM_RBUTTONDOWN: + case WM_NCRBUTTONDOWN: + if ((wndPtr->flags & WIN_ISWIN) || (TWEAK_WineLook > WIN31_LOOK)) + { + ClientToScreen(wndPtr->hwndSelf, (LPPOINT)&lParam); + SendMessageA( wndPtr->hwndSelf, WM_CONTEXTMENU, + wndPtr->hwndSelf, lParam); + } + break; + + case WM_CONTEXTMENU: + if( wndPtr->dwStyle & WS_CHILD ) + SendMessageA( wndPtr->parent->hwndSelf, msg, wParam, lParam ); + else + if (wndPtr->hSysMenu) + { /* + TrackPopupMenu(wndPtr->hSysMenu,TPM_LEFTALIGN | TPM_RETURNCMD,LOWORD(lParam),HIWORD(lParam),0,wndPtr->hwndSelf,NULL); + DestroyMenu(wndPtr->hSysMenu); + */ + FIXME(win,"Display default popup menu\n"); + /* Track system popup if click was in the caption area. */ + } + break; + + case WM_NCACTIVATE: + return NC_HandleNCActivate( wndPtr, wParam ); + + case WM_NCDESTROY: + if (wndPtr->text) HeapFree( GetProcessHeap(), 0, wndPtr->text ); + wndPtr->text = NULL; + if (wndPtr->pVScroll) HeapFree( GetProcessHeap(), 0, wndPtr->pVScroll ); + if (wndPtr->pHScroll) HeapFree( GetProcessHeap(), 0, wndPtr->pHScroll ); + wndPtr->pVScroll = wndPtr->pHScroll = NULL; + return 0; + + case WM_PAINTICON: + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint( wndPtr->hwndSelf, &ps ); + if( hdc ) + { + if( (wndPtr->dwStyle & WS_MINIMIZE) && wndPtr->class->hIcon ) + { + int x = (wndPtr->rectWindow.right - wndPtr->rectWindow.left - + SYSMETRICS_CXICON)/2; + int y = (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top - + SYSMETRICS_CYICON)/2; + TRACE(win,"Painting class icon: vis rect=(%i,%i - %i,%i)\n", + ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom ); + DrawIcon( hdc, x, y, wndPtr->class->hIcon ); + } + EndPaint( wndPtr->hwndSelf, &ps ); + } + return 0; + } + + case WM_SETREDRAW: + DEFWND_SetRedraw( wndPtr, wParam ); + return 0; + + case WM_CLOSE: + DestroyWindow( wndPtr->hwndSelf ); + return 0; + + case WM_MOUSEACTIVATE: + if (wndPtr->dwStyle & WS_CHILD) + { + LONG ret = SendMessage( wndPtr->parent->hwndSelf, + WM_MOUSEACTIVATE, wParam, lParam ); + if (ret) return ret; + } + + /* Caption clicks are handled by the NC_HandleNCLButtonDown() */ + return (LOWORD(lParam) == HTCAPTION) ? MA_NOACTIVATE : MA_ACTIVATE; + + case WM_ACTIVATE: + if (LOWORD(wParam) != WA_INACTIVE) + SetWindowPos(wndPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE); + break; + + case WM_ERASEBKGND: + case WM_ICONERASEBKGND: + { + if (!wndPtr->class->hbrBackground) return 0; + + if (wndPtr->class->hbrBackground <= (HBRUSH)(COLOR_MAX+1)) + { + HBRUSH hbrush = CreateSolidBrush( + GetSysColor(((DWORD)wndPtr->class->hbrBackground)-1)); + FillWindow( GetParent(wndPtr->hwndSelf), wndPtr->hwndSelf, + (HDC)wParam, hbrush); + DeleteObject( hbrush ); + } + else FillWindow( GetParent(wndPtr->hwndSelf), wndPtr->hwndSelf, + (HDC)wParam, wndPtr->class->hbrBackground ); + return 1; + } + + case WM_GETDLGCODE: + return 0; + + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSTATIC: + case WM_CTLCOLORSCROLLBAR: + return (LRESULT)DEFWND_ControlColor( (HDC)wParam, msg - WM_CTLCOLORMSGBOX ); + + case WM_CTLCOLOR: + return (LRESULT)DEFWND_ControlColor( (HDC)wParam, HIWORD(lParam) ); + + case WM_GETTEXTLENGTH: + if (wndPtr->text) return (LRESULT)strlen(wndPtr->text); + return 0; + + case WM_SETCURSOR: + if (wndPtr->dwStyle & WS_CHILD) + if (SendMessage(wndPtr->parent->hwndSelf, WM_SETCURSOR, + wParam, lParam)) + return TRUE; + return NC_HandleSetCursor( wndPtr->hwndSelf, wParam, lParam ); + + case WM_SYSCOMMAND: + return NC_HandleSysCommand( wndPtr->hwndSelf, wParam, + MAKEPOINT(lParam) ); + + case WM_KEYDOWN: + if(wParam == VK_F10) iF10Key = VK_F10; + break; + + case WM_SYSKEYDOWN: + if( HIWORD(lParam) & KEYDATA_ALT ) + { + /* if( HIWORD(lParam) & ~KEYDATA_PREVSTATE ) */ + if( wParam == VK_MENU && !iMenuSysKey ) + iMenuSysKey = 1; + else + iMenuSysKey = 0; + + iF10Key = 0; + + if( wParam == VK_F4 ) /* try to close the window */ + { + HWND hWnd = WIN_GetTopParent( wndPtr->hwndSelf ); + wndPtr = WIN_FindWndPtr( hWnd ); + if( wndPtr && !(wndPtr->class->style & CS_NOCLOSE) ) + PostMessage( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 ); + } + } + else if( wParam == VK_F10 ) + iF10Key = 1; + else + if( wParam == VK_ESCAPE && (GetKeyState(VK_SHIFT) & 0x8000)) + SendMessage( wndPtr->hwndSelf, WM_SYSCOMMAND, + (WPARAM)SC_KEYMENU, (LPARAM)VK_SPACE); + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + /* Press and release F10 or ALT */ + if (((wParam == VK_MENU) && iMenuSysKey) || + ((wParam == VK_F10) && iF10Key)) + SendMessage( WIN_GetTopParent(wndPtr->hwndSelf), + WM_SYSCOMMAND, SC_KEYMENU, 0L ); + iMenuSysKey = iF10Key = 0; + break; + + case WM_SYSCHAR: + iMenuSysKey = 0; + if (wParam == VK_RETURN && (wndPtr->dwStyle & WS_MINIMIZE)) + { + PostMessage( wndPtr->hwndSelf, WM_SYSCOMMAND, + (WPARAM)SC_RESTORE, 0L ); + break; + } + if ((HIWORD(lParam) & KEYDATA_ALT) && wParam) + { + if (wParam == VK_TAB || wParam == VK_ESCAPE) break; + if (wParam == VK_SPACE && (wndPtr->dwStyle & WS_CHILD)) + SendMessage( wndPtr->parent->hwndSelf, msg, wParam, lParam ); + else + SendMessage( wndPtr->hwndSelf, WM_SYSCOMMAND, + (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)wParam ); + } + else /* check for Ctrl-Esc */ + if (wParam != VK_ESCAPE) MessageBeep(0); + break; + + case WM_SHOWWINDOW: + if (!lParam) return 0; /* sent from ShowWindow */ + if (!(wndPtr->dwStyle & WS_POPUP) || !wndPtr->owner) return 0; + if ((wndPtr->dwStyle & WS_VISIBLE) && wParam) return 0; + else if (!(wndPtr->dwStyle & WS_VISIBLE) && !wParam) return 0; + ShowWindow( wndPtr->hwndSelf, wParam ? SW_SHOWNOACTIVATE : SW_HIDE ); + break; + + case WM_CANCELMODE: + if (wndPtr->parent == WIN_GetDesktop()) EndMenu(); + if (GetCapture() == wndPtr->hwndSelf) ReleaseCapture(); + break; + + case WM_VKEYTOITEM: + case WM_CHARTOITEM: + return -1; + + case WM_DROPOBJECT: + return DRAG_FILE; + + case WM_QUERYDROPOBJECT: + if (wndPtr->dwExStyle & WS_EX_ACCEPTFILES) return 1; + break; + + case WM_QUERYDRAGICON: + { + HICON hIcon=0; + UINT len; + + if( (hIcon=wndPtr->class->hCursor) ) return (LRESULT)hIcon; + for(len=1; len<64; len++) + if((hIcon=LoadIcon(wndPtr->hInstance,MAKEINTRESOURCE(len)))) + return (LRESULT)hIcon; + return (LRESULT)LoadIcon(0,IDI_APPLICATION); + } + break; + + case WM_ISACTIVEICON: + return ((wndPtr->flags & WIN_NCACTIVATED) != 0); + + case WM_QUERYOPEN: + case WM_QUERYENDSESSION: + return 1; + } + return 0; +} + + + diff --git a/reactos/lib/user32/internal/event.c b/reactos/lib/user32/internal/event.c new file mode 100644 index 00000000000..427d7884c30 --- /dev/null +++ b/reactos/lib/user32/internal/event.c @@ -0,0 +1,45 @@ +/* + * X events handling functions + * + * Copyright 1993 Alexandre Julliard + * + */ + +#include + +/*********************************************************************** + * EVENT_WaitNetEvent + * + * Wait for a network 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). + */ +WINBOOL EVENT_WaitNetEvent(WINBOOL sleep, WINBOOL peek) +{ + return TRUE; +} + + + +/********************************************************************** + * EVENT_CheckFocus + */ +WINBOOL EVENT_CheckFocus(void) +{ + return TRUE; +} + + + +/********************************************************************** + * X11DRV_EVENT_Pending + */ +WINBOOL EVENT_Pending() +{ + return FALSE; +} + +UINT EVENT_GetCaptureInfo(void) +{ +} + diff --git a/reactos/lib/user32/internal/heapdup.c b/reactos/lib/user32/internal/heapdup.c new file mode 100644 index 00000000000..7c5b65a1886 --- /dev/null +++ b/reactos/lib/user32/internal/heapdup.c @@ -0,0 +1,112 @@ +#include +#include + +LPVOID HEAP_strdupAtoW(HANDLE hHeap,DWORD dwFlags, LPCSTR lpszAsciiString ) +{ + int i; + INT len = lstrlenA(lpszAsciiString); + LPWSTR lpszUnicodeString = HeapAlloc( GetProcessHeap(), 0, (len + 1)*2 ); + for(i=0;i +#include +//#include +#include +#include +#include +#include +#include + +#include +#include + +typedef struct tagMDINEXTMENU +{ + HMENU hmenuIn; + HMENU hmenuNext; + HWND hwndNext; +} MDINEXTMENU, *PMDINEXTMENU, * LPMDINEXTMENU; + +//FIXME should be defined in defines.h +#define MFT_RIGHTORDER 0x00002000L + +/* Wine extension, I think. */ +#define OBM_RADIOCHECK 32727 + + /* Dimension of the menu bitmaps */ +static WORD check_bitmap_width = 0, check_bitmap_height = 0; +static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0; + +#define MAX(x,y) x > y ? x : y + +DWORD STDCALL GetTextExtent(HDC,LPCWSTR,INT); + +static HBITMAP hStdRadioCheck = 0; +static HBITMAP hStdCheck = 0; +static HBITMAP hStdMnArrow = 0; +static HBRUSH hShadeBrush = 0; +HMENU MENU_DefSysPopup = 0; /* Default system menu popup */ + +/* Use global popup window because there's no way 2 menus can + * be tracked at the same time. */ + +WND* pTopPopupWnd = 0; +UINT uSubPWndLevel = 0; + + /* Flag set by EndMenu() to force an exit from menu tracking */ +WINBOOL fEndMenu = FALSE; + + +#include +#define DPRINT printf + + +/*********************************************************************** + * debug_print_menuitem + * + * Print a menuitem in readable form. + */ +#if 0 + +#define debug_print_menuitem(pre, mp, post) \ + if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post) + +#define MENUOUT(text) \ + sprintf(menu, "%s%s", (count++ ? "," : ""), (text)) + + + +#define MENUFLAG(bit,text) \ + do { \ + if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \ + } while (0) + +static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp, + const char *postfix) +{ + //dbg_decl_str(menu, 256); + + char menu[256]; + if (mp) { + UINT flags = mp->fType; + int typ = MENU_ITEM_TYPE(flags); + sprintf(menu, "{ ID=0x%x", mp->wID); + if (flags & MF_POPUP) + sprintf(menu, ", Sub=0x%x",(int) mp->hSubMenu); + if (flags) { + int count = 0; + sprintf(menu, ", Typ="); + if (typ == MFT_STRING) + /* Nothing */ ; + else if (typ == MFT_SEPARATOR) + MENUOUT("sep"); + else if (typ == MFT_OWNERDRAW) + MENUOUT("own"); + else if (typ == MFT_BITMAP) + MENUOUT("bit"); + else + MENUOUT("???"); + flags -= typ; + + MENUFLAG(MF_POPUP, "pop"); + MENUFLAG(MFT_MENUBARBREAK, "barbrk"); + MENUFLAG(MFT_MENUBREAK, "brk"); + MENUFLAG(MFT_RADIOCHECK, "radio"); + MENUFLAG(MFT_RIGHTORDER, "rorder"); + MENUFLAG(MF_SYSMENU, "sys"); + MENUFLAG(MFT_RIGHTJUSTIFY, "right"); + + if (flags) + sprintf(menu, "+0x%x", flags); + } + flags = mp->fState; + if (flags) { + int count = 0; + sprintf(menu, ", State="); + MENUFLAG(MFS_GRAYED, "grey"); + MENUFLAG(MFS_DISABLED, "dis"); + MENUFLAG(MFS_CHECKED, "check"); + MENUFLAG(MFS_HILITE, "hi"); + MENUFLAG(MF_USECHECKBITMAPS, "usebit"); + MENUFLAG(MF_MOUSESELECT, "mouse"); + if (flags) + sprintf(menu, "+0x%x", flags); + } + if (mp->hCheckBit) + sprintf(menu, ", Chk=0x%x",(int) mp->hCheckBit); + if (mp->hUnCheckBit) + sprintf(menu, ", Unc=0x%x",(int)mp->hUnCheckBit); + + if (typ == MFT_STRING) { + if (mp->text) + sprintf(menu, ", Text=\"%s\"", mp->text); + else + sprintf(menu, ", Text=Null"); + } else if (mp->text == NULL) + /* Nothing */ ; + else + sprintf(menu, ", Text=%p", mp->text); + sprintf(menu, " }"); + } else { + sprintf(menu, "NULL"); + } + + //DPRINT( "%s %s %s\n", prefix, dbg_str(menu), postfix); +} + +#undef MENUOUT +#undef MENUFLAG +#endif +/*********************************************************************** + * MENU_CopySysPopup + * + * Return the default system menu. + */ +HMENU MENU_CopySysPopup(void) +{ + HMENU hMenu = LoadMenuIndirectA(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU)); + + if( hMenu ) { + POPUPMENU* menu = (POPUPMENU *)(hMenu); + menu->wFlags |= MF_SYSMENU | MF_POPUP; + } + else { + hMenu = 0; +// DPRINT( "Unable to load default system menu\n" ); + } + +// DPRINT( "returning %x.\n", hMenu ); + + return hMenu; +} + + +/********************************************************************** + * MENU_GetSysMenu + * + * Create a copy of the system menu. System menu in Windows is + * a special menu-bar with the single entry - system menu popup. + * This popup is presented to the outside world as a "system menu". + * However, the real system menu handle is sometimes seen in the + * WM_MENUSELECT paramemters (and Word 6 likes it this way). + */ +HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu ) +{ + HMENU hMenu; + + if ((hMenu = CreateMenu())) + { + POPUPMENU *menu = (POPUPMENU*) (hMenu); + menu->wFlags = MF_SYSMENU; + menu->hWnd = hWnd; + + if (hPopupMenu == (HMENU)(-1)) + hPopupMenu = MENU_CopySysPopup(); + else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup; + + if (hPopupMenu) + { + InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, (int)hPopupMenu, NULL ); + + menu->items[0].fType = MF_SYSMENU | MF_POPUP; + menu->items[0].fState = 0; + menu = (POPUPMENU*) (hPopupMenu); + menu->wFlags |= MF_SYSMENU; + +// DPRINT("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu ); + return hMenu; + } + DestroyMenu( hMenu ); + } +// ERR(menu, "failed to load system menu!\n"); + return 0; +} + + +/*********************************************************************** + * MENU_Init + * + * Menus initialisation. + */ +WINBOOL MENU_Init() +{ + HBITMAP hBitmap; + static unsigned char shade_bits[] = { 0x55, 0, 0xAA, 0, + 0x55, 0, 0xAA, 0, + 0x55, 0, 0xAA, 0, + 0x55, 0, 0xAA, 0 }; + + /* Load menu bitmaps */ + hStdCheck = LoadBitmapA(0, MAKEINTRESOURCE(OBM_CHECK)); + hStdRadioCheck = LoadBitmapA(0, MAKEINTRESOURCE(OBM_RADIOCHECK)); + hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCE(OBM_MNARROW)); + + if (hStdCheck) + { + BITMAP bm; + GetObjectA( hStdCheck, sizeof(bm), &bm ); + check_bitmap_width = bm.bmWidth; + check_bitmap_height = bm.bmHeight; + } else + return FALSE; + + /* Assume that radio checks have the same size as regular check. */ + if (!hStdRadioCheck) + return FALSE; + + if (hStdMnArrow) + { + BITMAP bm; + GetObjectA( hStdMnArrow, sizeof(bm), &bm ); + arrow_bitmap_width = bm.bmWidth; + arrow_bitmap_height = bm.bmHeight; + } else + return FALSE; + + if ((hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits))) + { + if((hShadeBrush = CreatePatternBrush( hBitmap ))) + { + DeleteObject( hBitmap ); + if ((MENU_DefSysPopup = MENU_CopySysPopup())) + return TRUE; + } + } + + return FALSE; +} + +/*********************************************************************** + * MENU_InitSysMenuPopup + * + * Grey the appropriate items in System menu. + */ + void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle ) +{ + WINBOOL gray; + + gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE)); + EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = ((style & WS_MAXIMIZE) != 0); + EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE); + EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE); + EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE)); + EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) ); + gray = (clsStyle & CS_NOCLOSE) != 0; + EnableMenuItem( hmenu, SC_CLOSE, (gray ? MF_GRAYED : MF_ENABLED) ); +} + + +/****************************************************************************** + * + * UINT MENU_GetStartOfNextColumn( + * HMENU hMenu ) + * + *****************************************************************************/ + + UINT MENU_GetStartOfNextColumn( + HMENU hMenu ) +{ + POPUPMENU *menu = (POPUPMENU *)(hMenu); + UINT i = menu->FocusedItem + 1; + + if(!menu) + return NO_SELECTED_ITEM; + + if( i == NO_SELECTED_ITEM ) + return i; + + for( ; i < menu->nItems; ++i ) { + if (menu->items[i].fType & MF_MENUBARBREAK) + return i; + } + + return NO_SELECTED_ITEM; +} + + +/****************************************************************************** + * + * UINT MENU_GetStartOfPrevColumn( + * HMENU hMenu ) + * + *****************************************************************************/ + + UINT MENU_GetStartOfPrevColumn( + HMENU hMenu ) +{ + POPUPMENU const *menu = (POPUPMENU *)(hMenu); + UINT i; + + if( !menu ) + return NO_SELECTED_ITEM; + + if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM ) + return NO_SELECTED_ITEM; + + /* Find the start of the column */ + + for(i = menu->FocusedItem; i != 0 && + !(menu->items[i].fType & MF_MENUBARBREAK); + --i); /* empty */ + + if(i == 0) + return NO_SELECTED_ITEM; + + for(--i; i != 0; --i) { + if (menu->items[i].fType & MF_MENUBARBREAK) + break; + } + +// DPRINT( "ret %d.\n", i ); + + return i; +} + + + +/*********************************************************************** + * MENU_GetMenuBarHeight + * + * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize(). + */ +UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth, + INT orgX, INT orgY ) +{ + HDC hdc; + RECT rectBar; + WND *wndPtr; + LPPOPUPMENU lppop; + + + + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0; + if (!(lppop = (LPPOPUPMENU)((HMENU)wndPtr->wIDmenu))) + return 0; + hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW ); + SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+SYSMETRICS_CYMENU); + MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd ); + ReleaseDC( hwnd, hdc ); + return lppop->Height; +} + + + +/*********************************************************************** + * MENU_FindItem + * + * Find a menu item. Return a pointer on the item, and modifies *hmenu + * in case the item was in a sub-menu. + */ + MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags ) +{ + POPUPMENU *menu; + UINT i; + + if (!(menu = (POPUPMENU *)(*hmenu))) return NULL; + if (wFlags & MF_BYPOSITION) + { + if (*nPos >= menu->nItems) return NULL; + return &menu->items[*nPos]; + } + else + { + MENUITEM *item = menu->items; + for (i = 0; i < menu->nItems; i++, item++) + { + if (item->wID == *nPos) + { + *nPos = i; + return item; + } + else if (item->fType & MF_POPUP) + { + HMENU hsubmenu = item->hSubMenu; + MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags ); + if (subitem) + { + *hmenu = hsubmenu; + return subitem; + } + } + } + } + return NULL; +} + +/*********************************************************************** + * MENU_FreeItemData + */ +void MENU_FreeItemData( MENUITEM* item ) +{ + /* delete text */ + if (IS_STRING_ITEM(item->fType) && item->text) + HeapFree( GetProcessHeap(), 0, item->text ); +} + +/*********************************************************************** + * MENU_FindItemByCoords + * + * Find the item at the specified coordinates (screen coords). Does + * not work for child windows and therefore should not be called for + * an arbitrary system menu. + */ +MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, + POINT pt, UINT *pos ) +{ + MENUITEM *item; + WND *wndPtr; + UINT i; + + if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return NULL; + pt.x -= wndPtr->rectWindow.left; + pt.y -= wndPtr->rectWindow.top; + item = menu->items; + for (i = 0; i < menu->nItems; i++, item++) + { + if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) && + (pt.y >= item->rect.top) && (pt.y < item->rect.bottom)) + { + if (pos) *pos = i; + return item; + } + } + return NULL; +} + + +/*********************************************************************** + * MENU_FindItemByKey + * + * Find the menu item selected by a key press. + * Return item id, -1 if none, -2 if we should close the menu. + */ +UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu, + UINT key, WINBOOL forceMenuChar ) +{ +// DPRINT("\tlooking for '%c' in [%04x]\n", (char)key, (UINT)hmenu ); + + if (!IsMenu( hmenu )) + { + WND* w = WIN_FindWndPtr(hwndOwner); + hmenu = GetSubMenu(w->hSysMenu, 0); + } + + if (hmenu) + { + POPUPMENU *menu = (POPUPMENU *) ( hmenu ); + MENUITEM *item = menu->items; + LONG menuchar; + + if( !forceMenuChar ) + { + UINT i; + + key = toupper(key); + for (i = 0; i < menu->nItems; i++, item++) + { + if (item->text && (IS_STRING_ITEM(item->fType))) + { + WCHAR *p = item->text - 2; + do + { + p = wcschr (p + 2, '&'); + } + while (p != NULL && p [1] == '&'); + if (p && (towupper(p[1]) == key)) return i; + } + } + } + menuchar = SendMessageW( hwndOwner, WM_MENUCHAR, (WPARAM)MAKEWPARAM( key, menu->wFlags ),(LPARAM) hmenu ); + if (HIWORD(menuchar) == 2) return LOWORD(menuchar); + if (HIWORD(menuchar) == 1) return (UINT)(-2); + } + return (UINT)(-1); +} + + +/*********************************************************************** + * MENU_CalcItemSize + * + * Calculate the size of the menu item and store it in lpitem->rect. + */ +void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner, + INT orgX, INT orgY, WINBOOL menuBar ) +{ + SIZE szSize; + WCHAR *p; + +// DPRINT( "HDC 0x%x at (%d,%d)\n", +// hdc, orgX, orgY); +// debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem, +// (menuBar ? " (MenuBar)" : "")); + + SetRect( &lpitem->rect, orgX, orgY, orgX, orgY ); + + if (lpitem->fType & MF_OWNERDRAW) + { + MEASUREITEMSTRUCT mis; + mis.CtlType = ODT_MENU; + mis.itemID = lpitem->wID; + mis.itemData = (DWORD)lpitem->text; + mis.itemHeight = 16; + mis.itemWidth = 30; + SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis ); + lpitem->rect.bottom += mis.itemHeight; + lpitem->rect.right += mis.itemWidth; +// DPRINT( "%08x %dx%d\n", +// lpitem->wID, mis.itemWidth, mis.itemHeight); + return; + } + + if (lpitem->fType & MF_SEPARATOR) + { + lpitem->rect.bottom += SEPARATOR_HEIGHT; + return; + } + + if (!menuBar) + { + lpitem->rect.right += 2 * check_bitmap_width; + if (lpitem->fType & MF_POPUP) + lpitem->rect.right += arrow_bitmap_width; + } + + if (lpitem->fType & MF_BITMAP) + { + BITMAP bm; + if (GetObjectA( (HBITMAP)lpitem->text, sizeof(bm), &bm )) + { + lpitem->rect.right += bm.bmWidth; + lpitem->rect.bottom += bm.bmHeight; + } + return; + } + + /* If we get here, then it must be a text item */ + + if (IS_STRING_ITEM( lpitem->fType )) + { + GetTextExtentPointW( hdc, lpitem->text, wcslen(lpitem->text), &szSize ); + lpitem->rect.right += LOWORD(szSize.cx); + if (TWEAK_WineLook == WIN31_LOOK) + lpitem->rect.bottom += max( HIWORD(szSize.cy), SYSMETRICS_CYMENU ); + else + lpitem->rect.bottom += max(HIWORD(szSize.cy), sysMetrics[SM_CYMENU]- 1); + lpitem->xTab = 0; + + if (menuBar) lpitem->rect.right += MENU_BAR_ITEMS_SPACE; + else if ((p = wcschr( lpitem->text, '\t' )) != NULL) + { + /* Item contains a tab (only meaningful in popup menus) */ + lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE; + GetTextExtentPoint32W( hdc, lpitem->text,(int)(p - lpitem->text) , &szSize); + lpitem->xTab += szSize.cx; + lpitem->rect.right += MENU_TAB_SPACE; + } + else + { + if (wcschr( lpitem->text, '\b' )) + lpitem->rect.right += MENU_TAB_SPACE; + lpitem->xTab = lpitem->rect.right - check_bitmap_width + - arrow_bitmap_width; + } + } +} + + +/*********************************************************************** + * MENU_PopupMenuCalcSize + * + * Calculate the size of a popup menu. + */ +void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner ) +{ + MENUITEM *lpitem; + HDC hdc; + int start, i; + int orgX, orgY, maxX, maxTab, maxTabWidth; + + lppop->Width = lppop->Height = 0; + if (lppop->nItems == 0) return; + hdc = GetDC( 0 ); + start = 0; + maxX = SYSMETRICS_CXBORDER; + while (start < lppop->nItems) + { + lpitem = &lppop->items[start]; + orgX = maxX; + orgY = SYSMETRICS_CYBORDER; + + maxTab = maxTabWidth = 0; + + /* Parse items until column break or end of menu */ + for (i = start; i < lppop->nItems; i++, lpitem++) + { + if ((i != start) && + (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; + + + if (TWEAK_WineLook > WIN31_LOOK) + ++orgY; + + MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE ); + if (lpitem->fType & MF_MENUBARBREAK) orgX++; + maxX = max( maxX, lpitem->rect.right ); + orgY = lpitem->rect.bottom; + if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab) + { + maxTab = max( maxTab, lpitem->xTab ); + maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab); + } + } + + /* Finish the column (set all items to the largest width found) */ + maxX = max( maxX, maxTab + maxTabWidth ); + for (lpitem = &lppop->items[start]; start < i; start++, lpitem++) + { + lpitem->rect.right = maxX; + if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab) + lpitem->xTab = maxTab; + } + lppop->Height = max( lppop->Height, orgY ); + } + + + if(TWEAK_WineLook > WIN31_LOOK) + lppop->Height++; + + lppop->Width = maxX; + ReleaseDC( 0, hdc ); +} + + +/*********************************************************************** + * MENU_MenuBarCalcSize + * + * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap + * height is off by 1 pixel which causes lengthy window relocations when + * active document window is maximized/restored. + * + * Calculate the size of the menu bar. + */ +static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, + LPPOPUPMENU lppop, HWND hwndOwner ) +{ + MENUITEM *lpitem; + int start, i, orgX, orgY, maxY, helpPos; + + if ((lprect == NULL) || (lppop == NULL)) return; + if (lppop->nItems == 0) return; + DPRINT("left=%d top=%d right=%d bottom=%d\n", + lprect->left, lprect->top, lprect->right, lprect->bottom); + lppop->Width = lprect->right - lprect->left; + lppop->Height = 0; + maxY = lprect->top; + start = 0; + helpPos = -1; + while (start < lppop->nItems) + { + lpitem = &lppop->items[start]; + orgX = lprect->left; + orgY = maxY; + + /* Parse items until line break or end of menu */ + for (i = start; i < lppop->nItems; i++, lpitem++) + { + if ((helpPos == -1) && (lpitem->fType & MF_HELP)) helpPos = i; + if ((i != start) && + (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; + + DPRINT( "calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY ); +// debug_print_menuitem (" item: ", lpitem, ""); + MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE ); + if (lpitem->rect.right > lprect->right) + { + if (i != start) break; + else lpitem->rect.right = lprect->right; + } + maxY = MAX( maxY, lpitem->rect.bottom ); + orgX = lpitem->rect.right; + } + + /* Finish the line (set all items to the largest height found) */ + while (start < i) lppop->items[start++].rect.bottom = maxY; + } + + lprect->bottom = maxY; + lppop->Height = lprect->bottom - lprect->top; + + /* Flush right all items between the MF_HELP and the last item */ + /* (if several lines, only move the last line) */ + if (helpPos != -1) + { + lpitem = &lppop->items[lppop->nItems-1]; + orgY = lpitem->rect.top; + orgX = lprect->right; + for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) + { + if (lpitem->rect.top != orgY) break; /* Other line */ + if (lpitem->rect.right >= orgX) break; /* Too far right already */ + lpitem->rect.left += orgX - lpitem->rect.right; + lpitem->rect.right = orgX; + orgX = lpitem->rect.left; + } + } +} + +/*********************************************************************** + * MENU_DrawMenuItem + * + * Draw a single menu item. + */ + void MENU_DrawMenuItem( HWND hwnd, HDC hdc, MENUITEM *lpitem, + UINT height, WINBOOL menuBar, UINT odaction ) +{ + RECT rect; + + //debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, ""); + + if (lpitem->fType & MF_SYSMENU) + { + if( !IsIconic(hwnd) ) { + if (TWEAK_WineLook > WIN31_LOOK) + NC_DrawSysButton95( hwnd, hdc, + lpitem->fState & + (MF_HILITE | MF_MOUSESELECT) ); + else + NC_DrawSysButton( hwnd, hdc, + lpitem->fState & + (MF_HILITE | MF_MOUSESELECT) ); + } + + return; + } + + if (lpitem->fType & MF_OWNERDRAW) + { + DRAWITEMSTRUCT dis; + + dis.CtlType = ODT_MENU; + dis.itemID = lpitem->wID; + dis.itemData = (DWORD)lpitem->text; + dis.itemState = 0; + if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED; + if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED; + if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED; + dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */ + dis.hwndItem = hwnd; + dis.hDC = hdc; + dis.rcItem = lpitem->rect; + //DPRINT( "Ownerdraw: itemID=%d, itemState=%d, itemAction=%d, " + // "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n",dis.itemID, + // dis.itemState, dis.itemAction, dis.hwndItem, dis.hDC, + // dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, + // dis.rcItem.bottom ); + SendMessageW( GetWindow(hwnd,GW_OWNER), WM_DRAWITEM, 0, (LPARAM)&dis ); + return; + } + + if (menuBar && (lpitem->fType & MF_SEPARATOR)) return; + rect = lpitem->rect; + + /* Draw the background */ + if (TWEAK_WineLook > WIN31_LOOK) { + rect.left += 2; + rect.right -= 2; + + /* + if(menuBar) { + --rect.left; + ++rect.bottom; + --rect.top; + } + InflateRect( &rect, -1, -1 ); + */ + } + + if (lpitem->fState & MF_HILITE) + FillRect( hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) ); + else + FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) ); + + SetBkMode( hdc, TRANSPARENT ); + + /* Draw the separator bar (if any) */ + + if (!menuBar && (lpitem->fType & MF_MENUBARBREAK)) + { + /* vertical separator */ + if (TWEAK_WineLook > WIN31_LOOK) { + RECT rc = rect; + rc.top = 3; + rc.bottom = height - 3; + DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT); + } + else { + SelectObject( hdc,(HGDIOBJ) GetSysColorPen(COLOR_WINDOWFRAME) ); + MoveToEx( hdc, rect.left, 0,NULL ); + LineTo( hdc, rect.left, height ); + } + } + if (lpitem->fType & MF_SEPARATOR) + { + /* horizontal separator */ + if (TWEAK_WineLook > WIN31_LOOK) { + RECT rc = rect; + rc.left++; + rc.right--; + rc.top += SEPARATOR_HEIGHT / 2; + DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP); + } + else { + SelectObject( hdc,(HGDIOBJ) GetSysColorPen(COLOR_WINDOWFRAME) ); + MoveToEx( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 ,NULL); + LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 ); + } + + return; + } + + /* Setup colors */ + + if (lpitem->fState & MF_HILITE) + { + if (lpitem->fState & MF_GRAYED) + SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); + else + SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) ); + SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) ); + } + else + { + if (lpitem->fState & MF_GRAYED) + SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); + else + SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) ); + SetBkColor( hdc, GetSysColor( COLOR_MENU ) ); + } + + if (!menuBar) + { + INT y = rect.top + rect.bottom; + + /* Draw the check mark + * + * FIXME: + * Custom checkmark bitmaps are monochrome but not always 1bpp. + */ + + if (lpitem->fState & MF_CHECKED) + { + HBITMAP bm = + lpitem->hCheckBit ? lpitem->hCheckBit : + ((lpitem->fType & MFT_RADIOCHECK) + ? hStdRadioCheck : hStdCheck); + HDC hdcMem = CreateCompatibleDC( hdc ); + + SelectObject( hdcMem, bm ); + BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2, + check_bitmap_width, check_bitmap_height, + hdcMem, 0, 0, SRCCOPY ); + DeleteDC( hdcMem ); + } else if (lpitem->hUnCheckBit) { + HDC hdcMem = CreateCompatibleDC( hdc ); + + SelectObject( hdcMem, lpitem->hUnCheckBit ); + BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2, + check_bitmap_width, check_bitmap_height, + hdcMem, 0, 0, SRCCOPY ); + DeleteDC( hdcMem ); + } + + /* Draw the popup-menu arrow */ + + if (lpitem->fType & MF_POPUP) + { + HDC hdcMem = CreateCompatibleDC( hdc ); + + SelectObject( hdcMem, hStdMnArrow ); + BitBlt( hdc, rect.right - arrow_bitmap_width - 1, + (y - arrow_bitmap_height) / 2, + arrow_bitmap_width, arrow_bitmap_height, + hdcMem, 0, 0, SRCCOPY ); + DeleteDC( hdcMem ); + } + + rect.left += check_bitmap_width; + rect.right -= arrow_bitmap_width; + } + + /* Draw the item text or bitmap */ + + if (lpitem->fType & MF_BITMAP) + { + HDC hdcMem = CreateCompatibleDC( hdc ); + + SelectObject( hdcMem, (HBITMAP)lpitem->text ); + BitBlt( hdc, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, hdcMem, 0, 0, SRCCOPY ); + DeleteDC( hdcMem ); + return; + } + /* No bitmap - process text if present */ + else if (IS_STRING_ITEM(lpitem->fType)) + { + register int i; + + if (menuBar) + { + rect.left += MENU_BAR_ITEMS_SPACE / 2; + rect.right -= MENU_BAR_ITEMS_SPACE / 2; + i = wcslen( lpitem->text ); + } + else + { + for (i = 0; lpitem->text[i]; i++) + if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b')) + break; + } + + if((TWEAK_WineLook == WIN31_LOOK) || !(lpitem->fState & MF_GRAYED)) { + DrawTextW( hdc, lpitem->text, i, &rect, + DT_LEFT | DT_VCENTER | DT_SINGLELINE ); + } + + else { + if (!(lpitem->fState & MF_HILITE)) + { + ++rect.left; + ++rect.top; + ++rect.right; + ++rect.bottom; + SetTextColor(hdc, RGB(0xff, 0xff, 0xff)); + DrawTextW( hdc, lpitem->text, i, &rect, + DT_LEFT | DT_VCENTER | DT_SINGLELINE ); + --rect.left; + --rect.top; + --rect.right; + --rect.bottom; + } + SetTextColor(hdc, RGB(0x80, 0x80, 0x80)); + DrawTextW( hdc, lpitem->text, i, &rect, + DT_LEFT | DT_VCENTER | DT_SINGLELINE ); + } + + if (lpitem->text[i]) /* There's a tab or flush-right char */ + { + if (lpitem->text[i] == '\t') + { + rect.left = lpitem->xTab; + DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, + DT_LEFT | DT_VCENTER | DT_SINGLELINE ); + } + else DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, + DT_RIGHT | DT_VCENTER | DT_SINGLELINE ); + } + } +} + +/*********************************************************************** + * MENU_DrawPopupMenu + * + * Paint a popup menu. + */ +void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu ) +{ + HBRUSH hPrevBrush = 0; + RECT rect; + + GetClientRect( hwnd, &rect ); + + + rect.bottom -= POPUP_YSHADE * SYSMETRICS_CYBORDER; + rect.right -= POPUP_XSHADE * SYSMETRICS_CXBORDER; + + + if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))) + { + HPEN hPrevPen; + + Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom ); + + hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) ); + if( hPrevPen ) + { + POPUPMENU *menu; + + INT ropPrev, i; + + + /* draw 3-d shade */ + if(TWEAK_WineLook == WIN31_LOOK) { + SelectObject( hdc, hShadeBrush ); + SetBkMode( hdc, TRANSPARENT ); + ropPrev = SetROP2( hdc, R2_MASKPEN ); + + i = rect.right; /* why SetBrushOrg() doesn't? */ + PatBlt( hdc, i & 0xfffffffe, + rect.top + POPUP_YSHADE*SYSMETRICS_CYBORDER, + i%2 + POPUP_XSHADE*SYSMETRICS_CXBORDER, + rect.bottom - rect.top, 0x00a000c9 ); + i = rect.bottom; + PatBlt( hdc, rect.left + POPUP_XSHADE*SYSMETRICS_CXBORDER, + i & 0xfffffffe,rect.right - rect.left, + i%2 + POPUP_YSHADE*SYSMETRICS_CYBORDER, 0x00a000c9 ); + SelectObject( hdc, hPrevPen ); + SelectObject( hdc, hPrevBrush ); + SetROP2( hdc, ropPrev ); + } + else + DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT); + + /* draw menu items */ + + menu = (POPUPMENU *) ( hmenu ); + if (menu && menu->nItems) + { + MENUITEM *item; + UINT u; + + for (u = menu->nItems, item = menu->items; u > 0; u--, item++) + MENU_DrawMenuItem( hwnd, hdc, item, menu->Height, FALSE, + ODA_DRAWENTIRE ); + + } + } else SelectObject( hdc, hPrevBrush ); + } +} + + +/*********************************************************************** + * MENU_DrawMenuBar + * + * Paint a menu bar. Returns the height of the menu bar. + */ +UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd, + WINBOOL suppress_draw) +{ + LPPOPUPMENU lppop; + UINT i; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + lppop = (LPPOPUPMENU) ( (HMENU)wndPtr->wIDmenu ); + if (lppop == NULL || lprect == NULL) return SYSMETRICS_CYMENU; +// DPRINT("(%04x, %p, %p); !\n", hDC, lprect, lppop); + if (lppop->Height == 0) MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd); + lprect->bottom = lprect->top + lppop->Height; + if (suppress_draw) return lppop->Height; + + FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) ); + +// if (TWEAK_WineLook == WIN31_LOOK) { + SelectObject( hDC,(HGDIOBJ)GetSysColorPen(COLOR_WINDOWFRAME) ); + MoveToEx( hDC, lprect->left, lprect->bottom,NULL ); + LineTo( hDC, lprect->right, lprect->bottom ); +// } +// else { +// SelectObject( hDC,(HGDIOBJ) GetSysColorPen(COLOR_3DFACE)); +// MoveToEx( hDC, lprect->left, lprect->bottom,NULL ); +// LineTo( hDC, lprect->right, lprect->bottom ); +// } + + if (lppop->nItems == 0) return SYSMETRICS_CYMENU; + for (i = 0; i < lppop->nItems; i++) + { + MENU_DrawMenuItem( hwnd, hDC, &lppop->items[i], lppop->Height, TRUE, + ODA_DRAWENTIRE ); + } + return lppop->Height; +} + + +/*********************************************************************** + * MENU_PatchResidentPopup + */ +WINBOOL MENU_PatchResidentPopup( HQUEUE checkQueue, WND* checkWnd ) +{ + + return FALSE; +} + + +/*********************************************************************** + * MENU_ShowPopup + * + * Display a popup menu. + */ + WINBOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id, + INT x, INT y, INT xanchor, INT yanchor ) +{ + POPUPMENU *menu; + WND *wndOwner = NULL; + + if (!(menu = (POPUPMENU *) ( hmenu ))) return FALSE; + if (menu->FocusedItem != NO_SELECTED_ITEM) + { + menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT); + menu->FocusedItem = NO_SELECTED_ITEM; + } + + if( (wndOwner = WIN_FindWndPtr( hwndOwner )) ) + { + UINT width, height; + + MENU_PopupMenuCalcSize( menu, hwndOwner ); + + /* adjust popup menu pos so that it fits within the desktop */ + + width = menu->Width + SYSMETRICS_CXBORDER; + height = menu->Height + SYSMETRICS_CYBORDER; + + if( x + width > SYSMETRICS_CXSCREEN ) + { + if( xanchor ) + x -= width - xanchor; + if( x + width > SYSMETRICS_CXSCREEN) + x = SYSMETRICS_CXSCREEN - width; + } + if( x < 0 ) x = 0; + + if( y + height > SYSMETRICS_CYSCREEN ) + { + if( yanchor ) + y -= height + yanchor; + if( y + height > SYSMETRICS_CYSCREEN ) + y = SYSMETRICS_CYSCREEN - height; + } + if( y < 0 ) y = 0; + + width += POPUP_XSHADE * SYSMETRICS_CXBORDER; /* add space for shading */ + height += POPUP_YSHADE * SYSMETRICS_CYBORDER; + + /* NOTE: In Windows, top menu popup is not owned. */ + if (!pTopPopupWnd) /* create top level popup menu window */ + { +// assert( uSubPWndLevel == 0 ); + + pTopPopupWnd = WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM, NULL, + WS_POPUP, x, y, width, height, + hwndOwner, 0, wndOwner->hInstance, + (LPVOID)hmenu )); + if (!pTopPopupWnd) return FALSE; + menu->hWnd = pTopPopupWnd->hwndSelf; + } + else + if( uSubPWndLevel ) + { + /* create a new window for the submenu */ + + menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL, + WS_POPUP, x, y, width, height, + menu->hWnd, 0, wndOwner->hInstance, + (LPVOID)hmenu ); + if( !menu->hWnd ) return FALSE; + } + else /* top level popup menu window already exists */ + { + menu->hWnd = pTopPopupWnd->hwndSelf; + MENU_PatchResidentPopup( 0, wndOwner ); + SendMessageW( pTopPopupWnd->hwndSelf, MM_SETMENUHANDLE, (WPARAM)hmenu, 0L); + + /* adjust its size */ + + SetWindowPos( menu->hWnd, 0, x, y, width, height, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW); + } + + uSubPWndLevel++; /* menu level counter */ + + /* Display the window */ + + SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0, + SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE ); + UpdateWindow( menu->hWnd ); + return TRUE; + } + return FALSE; +} + + +/*********************************************************************** + * MENU_SelectItem + */ + void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex, + WINBOOL sendMenuSelect ) +{ + LPPOPUPMENU lppop; + HDC hdc; + + lppop = (POPUPMENU *) ( hmenu ); + if (!lppop->nItems) return; + + if ((wIndex != NO_SELECTED_ITEM) && + (lppop->items[wIndex].fType & MF_SEPARATOR)) + wIndex = NO_SELECTED_ITEM; + + if (lppop->FocusedItem == wIndex) return; + if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd ); + else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW); + + /* Clear previous highlighted item */ + if (lppop->FocusedItem != NO_SELECTED_ITEM) + { + lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT); + MENU_DrawMenuItem(lppop->hWnd,hdc,&lppop->items[lppop->FocusedItem], + lppop->Height, !(lppop->wFlags & MF_POPUP), + ODA_SELECT ); + } + + /* Highlight new item (if any) */ + lppop->FocusedItem = wIndex; + if (lppop->FocusedItem != NO_SELECTED_ITEM) + { + lppop->items[lppop->FocusedItem].fState |= MF_HILITE; + MENU_DrawMenuItem( lppop->hWnd, hdc, &lppop->items[lppop->FocusedItem], + lppop->Height, !(lppop->wFlags & MF_POPUP), + ODA_SELECT ); + if (sendMenuSelect) + { + MENUITEM *ip = &lppop->items[lppop->FocusedItem]; + SendMessageW( hwndOwner, WM_MENUSELECT, ip->wID, + MAKELONG(ip->fType | (ip->fState | MF_MOUSESELECT), + hmenu) ); + } + } + else if (sendMenuSelect) { + SendMessageW( hwndOwner, WM_MENUSELECT, (WPARAM)hmenu, + (LPARAM)MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) ); + } + ReleaseDC( lppop->hWnd, hdc ); +} + + +/*********************************************************************** + * MENU_MoveSelection + * + * Moves currently selected item according to the offset parameter. + * If there is no selection then it should select the last item if + * offset is ITEM_PREV or the first item if offset is ITEM_NEXT. + */ + void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset ) +{ + INT i; + POPUPMENU *menu; + + menu = (POPUPMENU *) ( hmenu ); + if (!menu->items) return; + + if ( menu->FocusedItem != NO_SELECTED_ITEM ) + { + if( menu->nItems == 1 ) return; else + for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems + ; i += offset) + if (!(menu->items[i].fType & MF_SEPARATOR)) + { + MENU_SelectItem( hwndOwner, hmenu, i, TRUE ); + return; + } + } + + for ( i = (offset > 0) ? 0 : menu->nItems - 1; + i >= 0 && i < menu->nItems ; i += offset) + if (!(menu->items[i].fType & MF_SEPARATOR)) + { + MENU_SelectItem( hwndOwner, hmenu, i, TRUE ); + return; + } +} + + +/********************************************************************** + * MENU_SetItemData + * + * Set an item flags, id and text ptr. Called by InsertMenu() and + * ModifyMenu(). + */ + WINBOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id, + LPCWSTR str ) +{ + LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL; + +// debug_print_menuitem("MENU_SetItemData from: ", item, ""); + + if (IS_STRING_ITEM(flags)) + { + if (!str || !*str) + { + flags |= MF_SEPARATOR; + item->text = NULL; + } + else + { + LPWSTR text; + /* Item beginning with a backspace is a help item */ + if (*str == '\b') + { + flags |= MF_HELP; + str++; + } + + if ( ! (text = HEAP_wcsdup(GetProcessHeap,0, str ) )) + return FALSE; + item->text = text; + } + } + else if (flags & MF_BITMAP) item->text = (LPWSTR)(HBITMAP)LOWORD(str); + else item->text = NULL; + + if (flags & MF_OWNERDRAW) + item->dwItemData = (DWORD)str; + else + item->dwItemData = 0; + + if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) ) + DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */ + + if (flags & MF_POPUP) + { + POPUPMENU *menu = (POPUPMENU *)((UINT)id); + if (IS_A_MENU(menu)) menu->wFlags |= MF_POPUP; + else + { + item->wID = 0; + item->hSubMenu = 0; + item->fType = 0; + item->fState = 0; + return FALSE; + } + } + + item->wID = id; + if (flags & MF_POPUP) + item->hSubMenu = id; + + if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) ) + flags |= MF_POPUP; /* keep popup */ + + item->fType = flags & TYPE_MASK; + item->fState = (flags & STATE_MASK) & + ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION); + + + /* Don't call SetRectEmpty here! */ + + + if (prevText) HeapFree( GetProcessHeap(), 0, prevText ); + +// debug_print_menuitem("MENU_SetItemData to : ", item, ""); + return TRUE; +} + + +/********************************************************************** + * MENU_InsertItem + * + * Insert a new item into a menu. + */ + MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags ) +{ + MENUITEM *newItems; + POPUPMENU *menu; + + if (!(menu = (POPUPMENU *)(hMenu))) + { + DPRINT( "%04x not a menu handle\n",(UINT)hMenu ); + return NULL; + } + + /* Find where to insert new item */ + + if ((flags & MF_BYPOSITION) && + ((pos == (UINT)-1) || (pos == menu->nItems))) + { + /* Special case: append to menu */ + /* Some programs specify the menu length to do that */ + pos = menu->nItems; + } + else + { + if (!MENU_FindItem( &hMenu, &pos, flags )) + { + DPRINT( "item %x not found\n",pos ); + return NULL; + } + if (!(menu = (LPPOPUPMENU) (hMenu))) + { + DPRINT("%04x not a menu handle\n",(UINT)hMenu); + return NULL; + } + } + + /* Create new items array */ + + newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) ); + if (!newItems) + { + DPRINT( "allocation failed\n" ); + return NULL; + } + if (menu->nItems > 0) + { + /* Copy the old array into the new */ + if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) ); + if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos], + (menu->nItems-pos)*sizeof(MENUITEM) ); + HeapFree( GetProcessHeap(), 0, menu->items ); + } + menu->items = newItems; + menu->nItems++; + memset( &newItems[pos], 0, sizeof(*newItems) ); + return &newItems[pos]; +} + + +/********************************************************************** + * MENU_ParseResource + * + * Parse a standard menu resource and add items to the menu. + * Return a pointer to the end of the resource. + */ +LPCWSTR MENU_ParseResource( LPCWSTR res, HMENU hMenu) +{ + WORD flags, id = 0; + LPWSTR str; + + do + { + flags = GET_WORD(res); + res += sizeof(WORD); + if (!(flags & MF_POPUP)) + { + id = GET_WORD(res); + res += sizeof(WORD); + } + if (!IS_STRING_ITEM(flags)) { + // DPRINT( "not a string item %04x\n", flags ); + } + str = (LPWSTR)res; + res += (lstrlenW((LPCWSTR)str) + 1) * sizeof(WCHAR); + if (flags & MF_POPUP) + { + HMENU hSubMenu = CreatePopupMenu(); + if (!hSubMenu) return NULL; + if (!(res = MENU_ParseResource( res, hSubMenu))) + return NULL; + AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str ); + } + else /* Not a popup */ + { + AppendMenuW( hMenu, flags, id, + *(LPCWSTR)str ? (LPCWSTR)str : NULL ); + } + } while (!(flags & MF_END)); + return res; +} + + +/********************************************************************** + * MENUEX_ParseResource + * + * Parse an extended menu resource and add items to the menu. + * Return a pointer to the end of the resource. + */ +LPCWSTR MENUEX_ParseResource( LPCWSTR res, HMENU hMenu) +{ + WORD resinfo; + do { + MENUITEMINFO mii; + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE; + mii.fType = GET_DWORD(res); + res += sizeof(DWORD); + mii.fState = GET_DWORD(res); + res += sizeof(DWORD); + mii.wID = GET_DWORD(res); + res += sizeof(DWORD); + resinfo = GET_WORD(res); /* FIXME: for -bit apps this is a byte. */ + res += sizeof(WORD); + /* Align the text on a word boundary. */ + res += (~((int)res - 1)) & 1; + mii.dwTypeData = (LPWSTR) res; + res += (1 + lstrlenW((LPWSTR)mii.dwTypeData)) * sizeof(WCHAR); + /* Align the following fields on a dword boundary. */ + res += (~((int)res - 1)) & 3; + + /* FIXME: This is inefficient and cannot be optimised away by gcc. */ +/* + { + LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(), + 0, mii.dwTypeData); + DPRINT( "Menu item: [%08x,%08x,%04x,%04x,%s]\n", + mii.fType, mii.fState, mii.wID, resinfo, newstr); + HeapFree( GetProcessHeap(), 0, newstr ); + } +*/ + if (resinfo & 1) { /* Pop-up? */ + // DWORD helpid = GET_DWORD(res); /* FIXME: use this. */ + res += sizeof(DWORD); + mii.hSubMenu = CreatePopupMenu(); + if (!mii.hSubMenu) + return NULL; + if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) { + DestroyMenu(mii.hSubMenu); + return NULL; + } + mii.fMask |= MIIM_SUBMENU; + mii.fType |= MF_POPUP; + } + InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii); + } while (!(resinfo & MF_END)); + return res; +} + + +/*********************************************************************** + * MENU_GetSubPopup + * + * Return the handle of the selected sub-popup menu (if any). + */ + HMENU MENU_GetSubPopup( HMENU hmenu ) +{ + POPUPMENU *menu; + MENUITEM *item; + + menu = (POPUPMENU *) ( hmenu ); + + if (menu->FocusedItem == NO_SELECTED_ITEM) return 0; + + item = &menu->items[menu->FocusedItem]; + if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT)) + return item->hSubMenu; + return 0; +} + + +/*********************************************************************** + * MENU_HideSubPopups + * + * Hide the sub-popup menus of this menu. + */ + void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu, + WINBOOL sendMenuSelect ) +{ + POPUPMENU *menu = (POPUPMENU*) ( hmenu );; + + if (menu && uSubPWndLevel) + { + HMENU hsubmenu; + POPUPMENU *submenu; + MENUITEM *item; + + if (menu->FocusedItem != NO_SELECTED_ITEM) + { + item = &menu->items[menu->FocusedItem]; + if (!(item->fType & MF_POPUP) || + !(item->fState & MF_MOUSESELECT)) return; + item->fState &= ~MF_MOUSESELECT; + hsubmenu = item->hSubMenu; + } else return; + + submenu = (POPUPMENU *) ( hsubmenu ); + MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE ); + MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect ); + + if (submenu->hWnd == pTopPopupWnd->hwndSelf ) + { + ShowWindow( submenu->hWnd, SW_HIDE ); + uSubPWndLevel = 0; + } + else + { + DestroyWindow( submenu->hWnd ); + submenu->hWnd = 0; + } + } +} + + +/*********************************************************************** + * MENU_ShowSubPopup + * + * Display the sub-menu of the selected item of this menu. + * Return the handle of the submenu, or hmenu if no submenu to display. + */ + HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu, + WINBOOL selectFirst ) +{ + RECT rect; + POPUPMENU *menu; + MENUITEM *item; + WND *wndPtr; + HDC hdc; + + if (!(menu = (POPUPMENU *) ( hmenu ))) return hmenu; + + if (!(wndPtr = WIN_FindWndPtr( menu->hWnd )) || + (menu->FocusedItem == NO_SELECTED_ITEM)) return hmenu; + + item = &menu->items[menu->FocusedItem]; + if (!(item->fType & MF_POPUP) || + (item->fState & (MF_GRAYED | MF_DISABLED))) return hmenu; + + /* message must be send before using item, + because nearly everything may by changed by the application ! */ + + SendMessageW( hwndOwner, WM_INITMENUPOPUP, (WPARAM)item->hSubMenu, + MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) )); + + item = &menu->items[menu->FocusedItem]; + rect = item->rect; + + /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */ + if (!(item->fState & MF_HILITE)) + { + if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd ); + else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW); + item->fState |= MF_HILITE; + MENU_DrawMenuItem( menu->hWnd, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE ); + ReleaseDC( menu->hWnd, hdc ); + } + if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right) + item->rect = rect; + + item->fState |= MF_MOUSESELECT; + + if (IS_SYSTEM_MENU(menu)) + { + MENU_InitSysMenuPopup(item->hSubMenu, wndPtr->dwStyle, wndPtr->class->style); + + NC_GetSysPopupPos( wndPtr, &rect ); + rect.top = rect.bottom; + rect.right = SYSMETRICS_CXSIZE; + rect.bottom = SYSMETRICS_CYSIZE; + } + else + { + if (menu->wFlags & MF_POPUP) + { + rect.left = wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width; + rect.top = wndPtr->rectWindow.top + item->rect.top; + rect.right = item->rect.left - item->rect.right + 2*arrow_bitmap_width; + rect.bottom = item->rect.top - item->rect.bottom; + } + else + { + rect.left = wndPtr->rectWindow.left + item->rect.left; + rect.top = wndPtr->rectWindow.top + item->rect.bottom; + rect.right = item->rect.right - item->rect.left; + rect.bottom = item->rect.bottom - item->rect.top; + } + } + + MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem, + rect.left, rect.top, rect.right, rect.bottom ); + if (selectFirst) + MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT ); + return item->hSubMenu; +} + +/*********************************************************************** + * MENU_PtMenu + * + * Walks menu chain trying to find a menu pt maps to. + */ + HMENU MENU_PtMenu( HMENU hMenu, POINT pt ) +{ + POPUPMENU *menu = (POPUPMENU *) ( hMenu ); + register UINT ht = menu->FocusedItem; + + /* try subpopup first (if any) */ + ht = (ht != NO_SELECTED_ITEM && + (menu->items[ht].fType & MF_POPUP) && + (menu->items[ht].fState & MF_MOUSESELECT)) + ? (UINT) MENU_PtMenu(menu->items[ht].hSubMenu, pt) : 0; + + if( !ht ) /* check the current window (avoiding WM_HITTEST) */ + { + ht = (UINT)NC_HandleNCHitTest( menu->hWnd, pt ); + if( menu->wFlags & MF_POPUP ) + ht = (ht != (UINT)HTNOWHERE && + ht != (UINT)HTERROR) ? (UINT)hMenu : 0; + else + { + WND* wndPtr = WIN_FindWndPtr(menu->hWnd); + + ht = ( ht == HTSYSMENU ) ? (UINT)(wndPtr->hSysMenu) + : ( ht == HTMENU ) ? (UINT)(wndPtr->wIDmenu) : 0; + } + } + return (HMENU)ht; +} + +/*********************************************************************** + * MENU_ExecFocusedItem + * + * Execute a menu item (for instance when user pressed Enter). + * Return TRUE if we can go on with menu tracking. + */ + WINBOOL MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu ) +{ + MENUITEM *item; + POPUPMENU *menu = (POPUPMENU *) ( hMenu ); + if (!menu || !menu->nItems || + (menu->FocusedItem == NO_SELECTED_ITEM)) return TRUE; + + item = &menu->items[menu->FocusedItem]; + +// DPRINT( "%08x %08x %08x\n", +// hMenu, item->wID, item->hSubMenu); + + if (!(item->fType & MF_POPUP)) + { + if (!(item->fState & (MF_GRAYED | MF_DISABLED))) + { + if( menu->wFlags & MF_SYSMENU ) + { + PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID, + MAKELPARAM((INT)pmt->pt.x, (INT)pmt->pt.y) ); + } + else + PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 ); + return FALSE; + } + else return TRUE; + } + else + { + pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hMenu, TRUE ); + return TRUE; + } +} + + +/*********************************************************************** + * MENU_SwitchTracking + * + * Helper function for menu navigation routines. + */ + void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id ) +{ + POPUPMENU *ptmenu = (POPUPMENU *) ( hPtMenu ); + POPUPMENU *topmenu = (POPUPMENU *) ( pmt->hTopMenu ); + + if( pmt->hTopMenu != hPtMenu && + !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) ) + { + /* both are top level menus (system and menu-bar) */ + + MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE ); + MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE ); + pmt->hTopMenu = hPtMenu; + } + else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE ); + MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE ); +} + + +/*********************************************************************** + * MENU_ButtonDown + * + * Return TRUE if we can go on with menu tracking. + */ + WINBOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu ) +{ + if (hPtMenu) + { + UINT id = 0; + POPUPMENU *ptmenu = (POPUPMENU *) ( hPtMenu ); + MENUITEM *item; + + if( IS_SYSTEM_MENU(ptmenu) ) + item = ptmenu->items; + else + item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id ); + + if( item ) + { + if( ptmenu->FocusedItem == id ) + { + /* nothing to do with already selected non-popup */ + if( !(item->fType & MF_POPUP) ) return TRUE; + + if( item->fState & MF_MOUSESELECT ) + { + if( ptmenu->wFlags & MF_POPUP ) + { + /* hide selected subpopup */ + + MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, TRUE ); + pmt->hCurrentMenu = hPtMenu; + return TRUE; + } + return FALSE; /* shouldn't get here */ + } + } + else MENU_SwitchTracking( pmt, hPtMenu, id ); + + /* try to display a subpopup */ + + pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE ); + return TRUE; + } + else DPRINT("\tunable to find clicked item!\n"); + } + return FALSE; +} + + + + + + + +/*********************************************************************** + * MENU_TrackMenu + * + * Menu tracking code. + */ + WINBOOL MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y, + HWND hwnd, const RECT *lprect ) +{ + MSG msg; + POPUPMENU *menu; + WINBOOL fRemove; + MTRACKER mt = { 0, hmenu, hmenu, hwnd, {x, y} }; /* control struct */ + + fEndMenu = FALSE; + if (!(menu = (POPUPMENU *) ( hmenu ))) return FALSE; + + if (wFlags & TPM_BUTTONDOWN) MENU_ButtonDown( &mt, hmenu ); + + EVENT_Capture( mt.hOwnerWnd, HTMENU ); + + while (!fEndMenu) + { + menu = (POPUPMENU *) ( mt.hCurrentMenu ); + msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0; + + /* we have to keep the message in the queue until it's + * clear that menu loop is not over yet. */ + + if (!MSG_InternalGetMessage( &msg, msg.hwnd, mt.hOwnerWnd, + MSGF_MENU, PM_NOREMOVE, TRUE )) break; + + TranslateMessage( &msg ); + memcpy( &msg.pt, &mt.pt ,sizeof(POINT)); + + fRemove = FALSE; + if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST)) + { + /* Find a menu for this mouse event */ + + hmenu = MENU_PtMenu( mt.hTopMenu, msg.pt ); + + switch(msg.message) + { + /* no WM_NC... messages in captured state */ + + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + if (!(wFlags & TPM_RIGHTBUTTON)) break; + /* fall through */ + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + fEndMenu |= !MENU_ButtonDown( &mt, hmenu ); + break; + + case WM_RBUTTONUP: + if (!(wFlags & TPM_RIGHTBUTTON)) break; + /* fall through */ + case WM_LBUTTONUP: + /* If outside all menus but inside lprect, ignore it */ + if (hmenu || !lprect || !PtInRect(lprect, mt.pt)) + { + fEndMenu |= !MENU_ButtonUp( &mt, hmenu ); + fRemove = TRUE; + } + break; + + case WM_MOUSEMOVE: + if ((msg.wParam & MK_LBUTTON) || ((wFlags & TPM_RIGHTBUTTON) + && (msg.wParam & MK_RBUTTON))) + { + fEndMenu |= !MENU_MouseMove( &mt, hmenu ); + } + } /* switch(msg.message) - mouse */ + } + else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST)) + { + fRemove = TRUE; /* Keyboard messages are always removed */ + switch(msg.message) + { + case WM_KEYDOWN: + switch(msg.wParam) + { + case VK_HOME: + case VK_END: + MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, + NO_SELECTED_ITEM, FALSE ); + /* fall through */ + case VK_UP: + MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, + (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV ); + break; + + case VK_DOWN: /* If on menu bar, pull-down the menu */ + + menu = (POPUPMENU *) ( mt.hCurrentMenu ); + if (!(menu->wFlags & MF_POPUP)) + mt.hCurrentMenu = MENU_ShowSubPopup( mt.hOwnerWnd, mt.hTopMenu, TRUE ); + else /* otherwise try to move selection */ + MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT ); + break; + + case VK_LEFT: + MENU_KeyLeft( &mt ); + break; + + case VK_RIGHT: + MENU_KeyRight( &mt ); + break; + + case VK_ESCAPE: + fEndMenu = TRUE; + break; + + default: + break; + } + break; /* WM_KEYDOWN */ + + case WM_SYSKEYDOWN: + switch(msg.wParam) + { + case VK_MENU: + fEndMenu = TRUE; + break; + + } + break; /* WM_SYSKEYDOWN */ + + case WM_CHAR: + { + UINT pos; + + if (msg.wParam == '\r' || msg.wParam == ' ') + { + fEndMenu |= !MENU_ExecFocusedItem( &mt, mt.hCurrentMenu ); + break; + } + + /* Hack to avoid control chars. */ + /* We will find a better way real soon... */ + if ((msg.wParam <= 32) || (msg.wParam >= 127)) break; + + pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu, + msg.wParam, FALSE ); + if (pos == (UINT)-2) fEndMenu = TRUE; + else if (pos == (UINT)-1) MessageBeep(0); + else + { + MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos, TRUE ); + fEndMenu |= !MENU_ExecFocusedItem( &mt, mt.hCurrentMenu ); + } + } + break; + } /* switch(msg.message) - kbd */ + } + else + { + DispatchMessageA( &msg ); + } + + if (!fEndMenu) fRemove = TRUE; + + /* finally remove message from the queue */ + + if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) ) + PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE ); + else mt.trackFlags &= ~TF_SKIPREMOVE; + } + + ReleaseCapture(); + if( IsWindow( mt.hOwnerWnd ) ) + { + MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE ); + + menu = (POPUPMENU *) ( mt.hTopMenu ); + if (menu && menu->wFlags & MF_POPUP) + { + ShowWindow( menu->hWnd, SW_HIDE ); + uSubPWndLevel = 0; + } + MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE ); + SendMessageW( mt.hOwnerWnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) ); + } + fEndMenu = FALSE; + return TRUE; +} + + + + + +/*********************************************************************** + * MENU_ButtonUp + * + * Return TRUE if we can go on with menu tracking. + */ + WINBOOL MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu ) +{ + if (hPtMenu) + { + UINT id = 0; + POPUPMENU *ptmenu = (POPUPMENU *) ( hPtMenu ); + MENUITEM *item; + + if( IS_SYSTEM_MENU(ptmenu) ) + item = ptmenu->items; + else + item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id ); + + if( item && (ptmenu->FocusedItem == id )) + { + if( !(item->fType & MF_POPUP) ) + return MENU_ExecFocusedItem( pmt, hPtMenu ); + hPtMenu = item->hSubMenu; + if( hPtMenu == pmt->hCurrentMenu ) + { + /* Select first item of sub-popup */ + + MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, NO_SELECTED_ITEM, FALSE ); + MENU_MoveSelection( pmt->hOwnerWnd, hPtMenu, ITEM_NEXT ); + } + return TRUE; + } + } + return FALSE; +} + + +/*********************************************************************** + * MENU_MouseMove + * + * Return TRUE if we can go on with menu tracking. + */ + WINBOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu ) +{ + UINT id = NO_SELECTED_ITEM; + POPUPMENU *ptmenu = NULL; + + if( hPtMenu ) + { + ptmenu = (POPUPMENU *) ( hPtMenu ); + if( IS_SYSTEM_MENU(ptmenu) ) + id = 0; + else + MENU_FindItemByCoords( ptmenu, pmt->pt, &id ); + } + + if( id == NO_SELECTED_ITEM ) + { + MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu, + NO_SELECTED_ITEM, TRUE ); + } + else if( ptmenu->FocusedItem != id ) + { + MENU_SwitchTracking( pmt, hPtMenu, id ); + pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE ); + } + return TRUE; +} + + +/*********************************************************************** + * MENU_DoNextMenu + * + * NOTE: WM_NEXTMENU documented in Win is a bit different. + */ + LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk ) +{ + POPUPMENU *menu = (POPUPMENU *) ( pmt->hTopMenu ); + + if( (vk == VK_LEFT && menu->FocusedItem == 0 ) || + (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1)) + { + WND* wndPtr; + HMENU hNewMenu; + HWND hNewWnd; + UINT id = 0; + MDINEXTMENU MdiNextMenu; + LRESULT l; + + MdiNextMenu.hmenuIn = menu; + if (IS_SYSTEM_MENU(menu)) + MdiNextMenu.hmenuNext = GetSubMenu(pmt->hTopMenu,0); + else + MdiNextMenu.hmenuNext = pmt->hTopMenu; + + MdiNextMenu.hwndNext = pmt->hOwnerWnd; + + l = SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, (WPARAM)vk, &MdiNextMenu); + + if( l == 0 ) + { + wndPtr = WIN_FindWndPtr(pmt->hOwnerWnd); + + hNewWnd = pmt->hOwnerWnd; + if( IS_SYSTEM_MENU(menu) ) + { + /* switch to the menu bar */ + + if( ((wndPtr->dwStyle & WS_CHILD) == WS_CHILD) || !wndPtr->wIDmenu ) + return FALSE; + + hNewMenu = (HMENU)wndPtr->wIDmenu; + if( vk == VK_LEFT ) + { + menu = (POPUPMENU *) ( hNewMenu ); + id = menu->nItems - 1; + } + } + else if( (( wndPtr->dwStyle & WS_SYSMENU) == WS_SYSMENU ) ) + { + /* switch to the system menu */ + hNewMenu = wndPtr->hSysMenu; + } + else return FALSE; + } + else /* application returned a new menu to switch to */ + { + hNewMenu = MdiNextMenu.hmenuNext; + hNewWnd = MdiNextMenu.hwndNext; + + if( IsMenu(hNewMenu) && IsWindow(hNewWnd) ) + { + wndPtr = WIN_FindWndPtr(hNewWnd); + + if( ( (wndPtr->dwStyle & WS_SYSMENU) == WS_SYSMENU ) && + GetSubMenu(wndPtr->hSysMenu, 0) == hNewMenu ) + { + /* get the real system menu */ + hNewMenu = wndPtr->hSysMenu; + } + else if( ((wndPtr->dwStyle & WS_CHILD) == WS_CHILD) || (HANDLE)wndPtr->wIDmenu != hNewMenu ) + { + /* FIXME: Not sure what to do here, perhaps, + * try to track hNewMenu as a popup? */ + + //DPRINT(" -- got confused.\n"); + return FALSE; + } + } + else return FALSE; + } + + if( hNewMenu != pmt->hTopMenu ) + { + MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE ); + if( pmt->hCurrentMenu != pmt->hTopMenu ) + MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE ); + } + + if( hNewWnd != pmt->hOwnerWnd ) + { + ReleaseCapture(); + pmt->hOwnerWnd = hNewWnd; + EVENT_Capture( pmt->hOwnerWnd, HTMENU ); + } + + pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */ + MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE ); + + return TRUE; + } + return FALSE; +} + +/*********************************************************************** + * MENU_SuspendPopup + * + * The idea is not to show the popup if the next input message is + * going to hide it anyway. + */ +WINBOOL MENU_SuspendPopup( MTRACKER* pmt, UINT uMsg ) +{ + MSG msg; + + msg.hwnd = pmt->hOwnerWnd; + + PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE); + pmt->trackFlags |= TF_SKIPREMOVE; + + switch( uMsg ) + { + case WM_KEYDOWN: + PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE); + if( msg.message == WM_KEYUP || msg.message == WM_PAINT ) + { + PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE); + PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE); + if( msg.message == WM_KEYDOWN && + (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT)) + { + pmt->trackFlags |= TF_SUSPENDPOPUP; + return TRUE; + } + } + break; + } + + /* failures go through this */ + pmt->trackFlags &= ~TF_SUSPENDPOPUP; + return FALSE; +} + +/*********************************************************************** + * MENU_KeyLeft + * + * Handle a VK_LEFT key event in a menu. + */ +void MENU_KeyLeft( MTRACKER* pmt ) +{ + POPUPMENU *menu; + HMENU hmenutmp, hmenuprev; + UINT prevcol; + + hmenuprev = hmenutmp = pmt->hTopMenu; + menu = (POPUPMENU *) ( hmenutmp ); + + /* Try to move 1 column left (if possible) */ + if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) != + NO_SELECTED_ITEM ) { + + MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu, + prevcol, TRUE ); + return; + } + + /* close topmost popup */ + while (hmenutmp != pmt->hCurrentMenu) + { + hmenuprev = hmenutmp; + hmenutmp = MENU_GetSubPopup( hmenuprev ); + } + + MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE ); + pmt->hCurrentMenu = hmenuprev; + + if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) ) + { + /* move menu bar selection if no more popups are left */ + + if( !MENU_DoNextMenu( pmt, VK_LEFT) ) + MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV ); + + if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP ) + { + /* A sublevel menu was displayed - display the next one + * unless there is another displacement coming up */ + + if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) ) + pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, + pmt->hTopMenu, TRUE ); + } + } +} + + +/*********************************************************************** + * MENU_KeyRight + * + * Handle a VK_RIGHT key event in a menu. + */ +void MENU_KeyRight( MTRACKER* pmt ) +{ + HMENU hmenutmp; + POPUPMENU *menu = (POPUPMENU *) ( pmt->hTopMenu ); + UINT nextcol; + +// DPRINT( "MENU_KeyRight called, cur %x (%s), top %x (%s).\n", +// pmt->hCurrentMenu, +// ((POPUPMENU *)(pmt->hCurrentMenu))-> +// items[0].text, +// pmt->hTopMenu, menu->items[0].text ); + + if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu)) + { + /* If already displaying a popup, try to display sub-popup */ + + hmenutmp = pmt->hCurrentMenu; + pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hmenutmp, TRUE ); + + /* if subpopup was displayed then we are done */ + if (hmenutmp != pmt->hCurrentMenu) return; + } + + /* Check to see if there's another column */ + if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) != + NO_SELECTED_ITEM ) { +// DPRINT( "Going to %d.\n", nextcol ); + MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu, + nextcol, TRUE ); + return; + } + + if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */ + { + if( pmt->hCurrentMenu != pmt->hTopMenu ) + { + MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE ); + hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu; + } else hmenutmp = 0; + + /* try to move to the next item */ + if( !MENU_DoNextMenu( pmt, VK_RIGHT) ) + MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT ); + + if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP ) + if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) ) + pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, + pmt->hTopMenu, TRUE ); + } +} + + + + +/*********************************************************************** + * MENU_InitTracking + */ +WINBOOL MENU_InitTracking(HWND hWnd, HMENU hMenu) +{ + HideCaret(0); + SendMessageW( hWnd, WM_ENTERMENULOOP, (WPARAM)0, (LPARAM)0 ); + SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, (LPARAM)HTCAPTION ); + SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, (LPARAM)0 ); + return TRUE; +} + +/*********************************************************************** + * MENU_TrackMouseMenuBar + * + * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand(). + */ +void MENU_TrackMouseMenuBar( WND* wndPtr, INT ht, POINT pt ) +{ + HWND hWnd = (HWND)(wndPtr->hwndSelf); + HMENU hMenu = ((ht == (HTSYSMENU)) ? (HMENU)wndPtr->hSysMenu : (HMENU)wndPtr->wIDmenu); + + if (IsMenu(hMenu)) + { + MENU_InitTracking( hWnd, hMenu ); + MENU_TrackMenu( hMenu, TPM_ENTERIDLEEX | TPM_BUTTONDOWN | + TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, hWnd, NULL ); + + SendMessageW( hWnd, WM_EXITMENULOOP,(WPARAM)0,(LPARAM)0 ); + ShowCaret(0); + } +} + + + + +/*********************************************************************** + * MENU_TrackKbdMenuBar + * + * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand(). + */ +void MENU_TrackKbdMenuBar( WND* wndPtr, UINT wParam, INT vkey) +{ + UINT uItem = NO_SELECTED_ITEM; + HMENU hTrackMenu; + + /* find window that has a menu */ + + while( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwStyle & WS_SYSMENU) ) + if( !(wndPtr = wndPtr->parent) ) return; + + /* check if we have to track a system menu */ + + if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) || + !wndPtr->wIDmenu || vkey == VK_SPACE ) + { + if( !(wndPtr->dwStyle & WS_SYSMENU) ) return; + hTrackMenu = wndPtr->hSysMenu; + uItem = 0; + wParam |= HTSYSMENU; /* prevent item lookup */ + } + else + hTrackMenu = (HANDLE)wndPtr->wIDmenu; + + if (IsMenu( hTrackMenu )) + { + MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu ); + + if( vkey && vkey != VK_SPACE ) + { + uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu, + vkey, (wParam & HTSYSMENU) ); + if( uItem >= (UINT)(-2) ) + { + if( uItem == (UINT)(-1) ) MessageBeep(0); + hTrackMenu = 0; + } + } + + if( hTrackMenu ) + { + MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE ); + + if( uItem == NO_SELECTED_ITEM ) + MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT ); + else if( vkey ) + PostMessage( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L ); + + MENU_TrackMenu( hTrackMenu, TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON, + 0, 0, wndPtr->hwndSelf, NULL ); + } + SendMessage( wndPtr->hwndSelf, WM_EXITMENULOOP, 0, 0 ); + ShowCaret(0); + } +} + +#if 0 + + +/*********************************************************************** + * MENU_TrackKbdMenuBar + * + * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand(). + */ +void MENU_TrackMouseMenuBar( WND* wndPtr, INT ht, POINT pt ) +{ + UINT uItem = NO_SELECTED_ITEM; + HMENU hTrackMenu; + + /* find window that has a menu */ + + while( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwStyle & WS_SYSMENU) ) + if( !(wndPtr = wndPtr->parent) ) return; + + /* check if we have to track a system menu */ + + if( (wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) || + !wndPtr->wIDmenu || vkey == VK_SPACE ) + { + if( !(wndPtr->dwStyle & WS_SYSMENU) ) return; + hTrackMenu = wndPtr->hSysMenu; + uItem = 0; + wParam |= HTSYSMENU; /* prevent item lookup */ + } + else + hTrackMenu = (HANDLE)wndPtr->wIDmenu; + + if (IsMenu( hTrackMenu )) + { + MENU_InitTracking( wndPtr->hwndSelf, hTrackMenu ); + + if( vkey && vkey != VK_SPACE ) + { + uItem = MENU_FindItemByKey( wndPtr->hwndSelf, hTrackMenu, + vkey, (wParam & HTSYSMENU) ); + if( uItem >= (UINT)(-2) ) + { + if( uItem == (UINT)(-1) ) MessageBeep(0); + hTrackMenu = 0; + } + } + + if( hTrackMenu ) + { + MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE ); + + if( uItem == NO_SELECTED_ITEM ) + MENU_MoveSelection( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT ); + else if( vkey ) + PostMessageA( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L ); + + MENU_TrackMenu( hTrackMenu, TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON, + 0, 0, wndPtr->hwndSelf, NULL ); + } + SendMessageW( wndPtr->hwndSelf, WM_EXITMENULOOP, 0, 0 ); + ShowCaret(0); + } +} + +#endif \ No newline at end of file diff --git a/reactos/lib/user32/internal/msg.c b/reactos/lib/user32/internal/msg.c new file mode 100644 index 00000000000..73cfc106287 --- /dev/null +++ b/reactos/lib/user32/internal/msg.c @@ -0,0 +1,1072 @@ +/* + * Message queues related functions + * + * Copyright 1993, 1994 Alexandre Julliard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +UINT doubleClickSpeed = 452; +INT debugSMRL = 0; /* intertask SendMessage() recursion level */ + +/*********************************************************************** + * MSG_CheckFilter + */ +WINBOOL MSG_CheckFilter(WORD uMsg, DWORD filter) +{ + if( filter ) + return (uMsg >= LOWORD(filter) && uMsg <= HIWORD(filter)); + return TRUE; +} + +/*********************************************************************** + * MSG_SendParentNotify + * + * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless + * the window has the WS_EX_NOPARENTNOTIFY style. + */ +void MSG_SendParentNotify(WND* wndPtr, WORD event, WORD idChild, LPARAM lValue) +{ +#define lppt ((LPPOINT)&lValue) + + /* pt has to be in the client coordinates of the parent window */ + + MapWindowPoints( 0, wndPtr->hwndSelf, lppt, 1 ); + while (wndPtr) + { + if (!(wndPtr->dwStyle & WS_CHILD) || (wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY)) break; + lppt->x += wndPtr->rectClient.left; + lppt->y += wndPtr->rectClient.top; + wndPtr = wndPtr->parent; + SendMessageW( wndPtr->hwndSelf, WM_PARENTNOTIFY, + MAKEWPARAM( event, idChild ), lValue ); + } +#undef lppt +} + + +/*********************************************************************** + * MSG_TranslateMouseMsg + * + * Translate an mouse hardware event into a real mouse message. + * Return value indicates whether the translated message must be passed + * to the user, left in the queue, or skipped entirely (in this case + * HIWORD contains hit test code). + */ +DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD filter, + MSG *msg, WINBOOL remove, WND* pWndScope ) +{ + DWORD dblclk_time_limit = 0; + UINT clk_message = 0; + HWND clk_hwnd = 0; + POINT clk_pos = { 0, 0 }; + + WND *pWnd; + HWND hWnd; + INT ht, hittest, sendSC = 0; + UINT message = msg->message; + POINT screen_pt, pt; + HANDLE hQ = GetFastQueue(); + MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock(hQ); + WINBOOL eatMsg = FALSE; + WINBOOL mouseClick = ((message == WM_LBUTTONDOWN) || + (message == WM_RBUTTONDOWN) || + (message == WM_MBUTTONDOWN))?1:0; + SYSQ_STATUS ret = 0; + + /* Find the window */ + + ht = hittest = HTCLIENT; + hWnd = GetCapture(); + if( !hWnd ) + { + ht = hittest = WINPOS_WindowFromPoint( pWndScope, msg->pt, &pWnd ); + if( !pWnd ) pWnd = WIN_GetDesktop(); + hWnd = pWnd->hwndSelf; + sendSC = 1; + } + else + { + pWnd = WIN_FindWndPtr(hWnd); + ht = EVENT_GetCaptureInfo(); + } + + /* stop if not the right queue */ + + if (pWnd->hmemTaskQ != hQ) + { + /* Not for the current task */ + if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE ); + /* Wake up the other task */ + queue = (MESSAGEQUEUE *)GlobalLock( pWnd->hmemTaskQ ); + if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE ); + return SYSQ_MSG_ABANDON; + } + + /* check if hWnd is within hWndScope */ + + if( hTopWnd && hWnd != hTopWnd ) + if( !IsChild(hTopWnd, hWnd) ) return SYSQ_MSG_CONTINUE; + + if( mouseClick ) + { + /* translate double clicks - + * note that ...MOUSEMOVEs can slip in between + * ...BUTTONDOWN and ...BUTTONDBLCLK messages */ + + if( pWnd->class->style & CS_DBLCLKS || ht != HTCLIENT ) + { + if ((message == clk_message) && (hWnd == clk_hwnd) && + (msg->time - dblclk_time_limit < doubleClickSpeed) && + (abs(msg->pt.x - clk_pos.x) < SYSMETRICS_CXDOUBLECLK/2) && + (abs(msg->pt.y - clk_pos.y) < SYSMETRICS_CYDOUBLECLK/2)) + { + message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN); + mouseClick++; /* == 2 */ + } + } + } + screen_pt = pt = msg->pt; + + if (hittest != HTCLIENT) + { + message += ((INT)WM_NCMOUSEMOVE - WM_MOUSEMOVE); + msg->wParam = hittest; + } + else ScreenToClient( hWnd, &pt ); + + /* check message filter */ + + if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE; + + pCursorQueue = queue; + + /* call WH_MOUSE */ + + if (HOOK_IsHooked( WH_MOUSE )) + { + MOUSEHOOKSTRUCT *hook = malloc(sizeof(MOUSEHOOKSTRUCT)); + if( hook ) + { + hook->pt = screen_pt; + hook->hwnd = hWnd; + hook->wHitTestCode = hittest; + hook->dwExtraInfo = 0; + ret = HOOK_CallHooksA( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE, + message, (LPARAM)(hook) ); + free(hook); + } + if( ret ) return MAKELONG((INT)SYSQ_MSG_SKIP, hittest); + } + + if ((hittest == HTERROR) || (hittest == HTNOWHERE)) + eatMsg = sendSC = 1; + else if( remove && mouseClick ) + { + HWND hwndTop = WIN_GetTopParent( hWnd ); + + if( mouseClick == 1 ) + { + /* set conditions */ + dblclk_time_limit = msg->time; + clk_message = msg->message; + clk_hwnd = hWnd; + clk_pos = screen_pt; + } else + /* got double click - zero them out */ + dblclk_time_limit = clk_hwnd = 0; + + if( sendSC ) + { + /* Send the WM_PARENTNOTIFY, + * note that even for double/nonclient clicks + * notification message is still WM_L/M/RBUTTONDOWN. + */ + + MSG_SendParentNotify( pWnd, msg->message, 0, MAKELPARAM(screen_pt.x, screen_pt.y) ); + + /* Activate the window if needed */ + + if (hWnd != GetActiveWindow() && hWnd != GetDesktopWindow()) + { + LONG ret = SendMessageW( hWnd, WM_MOUSEACTIVATE,(WPARAM) hwndTop, + (LPARAM)MAKELONG( hittest, message ) ); + + if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT)) + eatMsg = TRUE; + + if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT)) + && hwndTop != GetActiveWindow() ) + if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE )) + eatMsg = TRUE; + } + } + } else sendSC = (remove && sendSC); + + /* Send the WM_SETCURSOR message */ + + if (sendSC) + SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, + MAKELONG( hittest, message )); + if (eatMsg) return MAKELONG( (UINT)SYSQ_MSG_SKIP, hittest); + + msg->hwnd = hWnd; + msg->message = message; + msg->lParam = MAKELONG( pt.x, pt.y ); + return SYSQ_MSG_ACCEPT; +} + + +/*********************************************************************** + * MSG_TranslateKbdMsg + * + * Translate an keyboard hardware event into a real message. + */ +DWORD MSG_TranslateKbdMsg( HWND hTopWnd, DWORD filter, + MSG *msg, WINBOOL remove ) +{ + WORD message = msg->message; + HWND hWnd = GetFocus(); + WND *pWnd; + + /* Should check Ctrl-Esc and PrintScreen here */ + + if (!hWnd) + { + /* Send the message to the active window instead, */ + /* translating messages to their WM_SYS equivalent */ + + hWnd = GetActiveWindow(); + + if( message < WM_SYSKEYDOWN ) + message += WM_SYSKEYDOWN - WM_KEYDOWN; + } + pWnd = WIN_FindWndPtr( hWnd ); + if (pWnd && (pWnd->hmemTaskQ != GetFastQueue())) + { + /* Not for the current task */ + MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock( GetFastQueue() ); + if (queue) QUEUE_ClearWakeBit( queue, QS_KEY ); + /* Wake up the other task */ + queue = (MESSAGEQUEUE *)GlobalLock( pWnd->hmemTaskQ ); + if (queue) QUEUE_SetWakeBit( queue, QS_KEY ); + return SYSQ_MSG_ABANDON; + } + + if (hTopWnd && hWnd != hTopWnd) + if (!IsChild(hTopWnd, hWnd)) return SYSQ_MSG_CONTINUE; + if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE; + + msg->hwnd = hWnd; + msg->message = message; + + return (HOOK_CallHooksA( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE, + msg->wParam, msg->lParam ) + ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT); +} + + +/*********************************************************************** + * MSG_JournalRecordMsg + * + * Build an EVENTMSG structure and call JOURNALRECORD hook + */ +void MSG_JournalRecordMsg( MSG *msg ) +{ + EVENTMSG *event = malloc(sizeof(EVENTMSG)); + if (!event) return; + event->message = msg->message; + event->time = msg->time; + if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST)) + { + event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8); + event->paramH = msg->lParam & 0x7FFF; + if (HIWORD(msg->lParam) & 0x0100) + event->paramH |= 0x8000; /* special_key - bit */ + HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, + (LPARAM)(event) ); + } + else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST)) + { + event->paramL = LOWORD(msg->lParam); /* X pos */ + event->paramH = HIWORD(msg->lParam); /* Y pos */ + ClientToScreen( msg->hwnd, (LPPOINT)&event->paramL ); + HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, + (LPARAM)(event) ); + } + else if ((msg->message >= WM_NCMOUSEFIRST) && + (msg->message <= WM_NCMOUSELAST)) + { + event->paramL = LOWORD(msg->lParam); /* X pos */ + event->paramH = HIWORD(msg->lParam); /* Y pos */ + event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */ + HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, + (LPARAM)(event) ); + } + free(event); +} + +/*********************************************************************** + * MSG_JournalPlayBackMsg + * + * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function + */ +int MSG_JournalPlayBackMsg(void) +{ + EVENTMSG *tmpMsg; + long wtime,lParam; + WORD keyDown,i,wParam,result=0; + + if ( HOOK_IsHooked( WH_JOURNALPLAYBACK ) ) + { + tmpMsg = malloc(sizeof(EVENTMSG)); + wtime=HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_GETNEXT, 0, + (LPARAM)(tmpMsg)); + /* DPRINT("Playback wait time =%ld\n",wtime); */ + if (wtime<=0) + { + wtime=0; + if ((tmpMsg->message>= WM_KEYFIRST) && (tmpMsg->message <= WM_KEYLAST)) + { + wParam=tmpMsg->paramL & 0xFF; + lParam=MAKELONG(tmpMsg->paramH&0x7ffff,tmpMsg->paramL>>8); + if (tmpMsg->message == WM_KEYDOWN || tmpMsg->message == WM_SYSKEYDOWN) + { + for (keyDown=i=0; i<256 && !keyDown; i++) + if (InputKeyStateTable[i] & 0x80) + keyDown++; + if (!keyDown) + lParam |= 0x40000000; + AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80; + } + else /* WM_KEYUP, WM_SYSKEYUP */ + { + lParam |= 0xC0000000; + AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80; + } + if (InputKeyStateTable[VK_MENU] & 0x80) + lParam |= 0x20000000; + if (tmpMsg->paramH & 0x8000) /*special_key bit*/ + lParam |= 0x01000000; + hardware_event( tmpMsg->message, wParam, lParam,0, 0, tmpMsg->time, 0 ); + } + else + { + if ((tmpMsg->message>= WM_MOUSEFIRST) && (tmpMsg->message <= WM_MOUSELAST)) + { + switch (tmpMsg->message) + { + case WM_LBUTTONDOWN: + MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=TRUE;break; + case WM_LBUTTONUP: + MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=FALSE;break; + case WM_MBUTTONDOWN: + MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=TRUE;break; + case WM_MBUTTONUP: + MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=FALSE;break; + case WM_RBUTTONDOWN: + MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=TRUE;break; + case WM_RBUTTONUP: + MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=FALSE;break; + } + AsyncKeyStateTable[VK_LBUTTON]= InputKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0; + AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0; + AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0; + SetCursorPos(tmpMsg->paramL,tmpMsg->paramH); + lParam=MAKELONG(tmpMsg->paramL,tmpMsg->paramH); + wParam=0; + if (MouseButtonsStates[0]) wParam |= MK_LBUTTON; + if (MouseButtonsStates[1]) wParam |= MK_MBUTTON; + if (MouseButtonsStates[2]) wParam |= MK_RBUTTON; + hardware_event( tmpMsg->message, wParam, lParam, + tmpMsg->paramL, tmpMsg->paramH, tmpMsg->time, 0 ); + } + } + HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_SKIP, 0, + (LPARAM)(tmpMsg)); + } + else + { + if( tmpMsg->message == WM_QUEUESYNC ) + if (HOOK_IsHooked( WH_CBT )) + HOOK_CallHooksA( WH_CBT, HCBT_QS, 0, 0L); + + result= QS_MOUSE | QS_KEY; /* ? */ + } + free(tmpMsg); + } + return result; +} + +/*********************************************************************** + * MSG_PeekHardwareMsg + * + * Peek for a hardware message matching the hwnd and message filters. + */ +WINBOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, DWORD filter, + WINBOOL remove ) +{ + DWORD status = SYSQ_MSG_ACCEPT; + MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue(); + int i, kbd_msg, pos = sysMsgQueue->nextMessage; + + /* FIXME: there has to be a better way to do this */ +// joySendMessages(); + + /* If the queue is empty, attempt to fill it */ +//&& THREAD_IsWinA( THREAD_Current() ) + if (!sysMsgQueue->msgCount && EVENT_Pending()) + EVENT_WaitNetEvent( FALSE, FALSE ); + + for (i = kbd_msg = 0; i < sysMsgQueue->msgCount; i++, pos++) + { + if (pos >= sysMsgQueue->queueSize) pos = 0; + *msg = sysMsgQueue->messages[pos].msg; + + /* Translate message */ + + if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST)) + { + HWND hWndScope = (HWND)sysMsgQueue->messages[pos].extraInfo; +// removed Options.managed && + status = MSG_TranslateMouseMsg(hwnd, filter, msg, remove, + ( IsWindow(hWndScope) ) + ? WIN_FindWndPtr(hWndScope) : WIN_GetDesktop() ); + kbd_msg = 0; + } + else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST)) + { + status = MSG_TranslateKbdMsg(hwnd, filter, msg, remove); + kbd_msg = 1; + } + else /* Non-standard hardware event */ + { + HARDWAREHOOKSTRUCT *hook; + if ( (hook = malloc(sizeof(HARDWAREHOOKSTRUCT))) ) + { + WINBOOL ret; + hook->hWnd = msg->hwnd; + hook->wMessage = msg->message; + hook->wParam = msg->wParam; + hook->lParam = msg->lParam; + ret = HOOK_CallHooksA( WH_HARDWARE, + remove ? HC_ACTION : HC_NOREMOVE, + 0, (LPARAM)hook ); + free(hook); + if (ret) + { + QUEUE_RemoveMsg( sysMsgQueue, pos ); + continue; + } + status = SYSQ_MSG_ACCEPT; + } + } + + switch (LOWORD(status)) + { + case SYSQ_MSG_ACCEPT: + break; + + case SYSQ_MSG_SKIP: + if (HOOK_IsHooked( WH_CBT )) + { + if( kbd_msg ) + HOOK_CallHooksA( WH_CBT, HCBT_KEYSKIPPED, + msg->wParam, msg->lParam ); + else + { + MOUSEHOOKSTRUCT *hook = malloc(sizeof(MOUSEHOOKSTRUCT)); + if (hook) + { + hook->pt = msg->pt; + hook->hwnd = msg->hwnd; + hook->wHitTestCode = HIWORD(status); + hook->dwExtraInfo = 0; + HOOK_CallHooksA( WH_CBT, HCBT_CLICKSKIPPED ,msg->message, + (LPARAM)hook ); + free(hook); + } + } + } + + if (remove) + QUEUE_RemoveMsg( sysMsgQueue, pos ); + /* continue */ + + case SYSQ_MSG_CONTINUE: + continue; + + case SYSQ_MSG_ABANDON: + return FALSE; + } + + if (remove) + { + if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg ); + QUEUE_RemoveMsg( sysMsgQueue, pos ); + } + return TRUE; + } + return FALSE; +} + +/*********************************************************************** + * MSG_SendMessage + * + * Implementation of an inter-task SendMessage. + */ +LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam, WORD flags ) +{ + INT prevSMRL = debugSMRL; + QSMCTRL qCtrl = { 0, 1}; + MESSAGEQUEUE *queue, *destQ; + + if (!(queue = (MESSAGEQUEUE*)GlobalLock( GetFastQueue() ))) return 0; + if (!(destQ = (MESSAGEQUEUE*)GlobalLock( hDestQueue ))) return 0; + + if ( + //IsTaskLocked() || + !IsWindow(hwnd)) return 0; + + debugSMRL+=4; + DPRINT("%*sSM: %s [%04x] (%04x -> %04x)\n", + prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue ); + + if( !(queue->wakeBits & QS_SMPARAMSFREE) ) + { + DPRINT("\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n"); + QUEUE_WaitBits( QS_SMPARAMSFREE ); + } + + /* resume sending */ + + queue->hWnd = hwnd; + queue->msg = msg; + queue->wParam = LOWORD(wParam); + queue->wParamHigh = HIWORD(wParam); + queue->lParam = lParam; + queue->hPrevSendingTask = destQ->hSendingTask; + destQ->hSendingTask = GetFastQueue(); + + QUEUE_ClearWakeBit( queue, QS_SMPARAMSFREE ); + queue->flags = (queue->flags & ~(QUEUE_SM_ASCII|QUEUE_SM_UNICODE)) | flags; + + DPRINT("%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl); + + queue->smResultInit = &qCtrl; + + QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE ); + + /* perform task switch and wait for the result */ + + while( qCtrl.bPending ) + { + if (!(queue->wakeBits & QS_SMRESULT)) + { + //if (THREAD_IsWinA( THREAD_Current() )) DirectedYield( destQ->hTask ); + QUEUE_WaitBits( QS_SMRESULT ); + DPRINT("\tsm: have result!\n"); + } + /* got something */ + + DPRINT("%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult ); + + if (queue->smResult) { /* FIXME, smResult should always be set */ + queue->smResult->lResult = queue->SendMessageReturn; + queue->smResult->bPending = FALSE; + } + QUEUE_ClearWakeBit( queue, QS_SMRESULT ); + + if( queue->smResult != &qCtrl ) + DPRINT( "%*ssm: weird scenes inside the goldmine!\n", prevSMRL, ""); + } + queue->smResultInit = NULL; + + DPRINT("%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult); + debugSMRL-=4; + + return qCtrl.lResult; +} + + + +/*********************************************************************** + * MSG_PeekMessage + */ +WINBOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, + WORD flags, WINBOOL peek ) +{ + int pos, mask; + MESSAGEQUEUE *msgQueue; + HQUEUE hQueue; + +#ifdef CONFIG_IPC + DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/ + DDE_GetRemoteMessage(); +#endif /* CONFIG_IPC */ + + mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */ + if (first || last) + { + if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY; + if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) || + ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE; + if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER; + if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER; + if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT; + } + else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT; + + //if (IsTaskLocked()) flags |= PM_NOYIELD; + + /* Never yield on Win32 threads */ +// if (!THREAD_IsWinA(THREAD_Current())) + flags |= PM_NOYIELD; + + while(1) + { + hQueue = GetFastQueue(); + msgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue ); + if (!msgQueue) return FALSE; + msgQueue->changeBits = 0; + + /* First handle a message put by SendMessage() */ + + while (msgQueue->wakeBits & QS_SENDMESSAGE) + QUEUE_ReceiveMessage( msgQueue ); + + /* Now handle a WM_QUIT message */ + + if (msgQueue->wPostQMsg && + (!first || WM_QUIT >= first) && + (!last || WM_QUIT <= last) ) + { + msg->hwnd = hwnd; + msg->message = WM_QUIT; + msg->wParam = msgQueue->wExitCode; + msg->lParam = 0; + if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0; + break; + } + + /* Now find a normal message */ + + if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) && + ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1)) + { + QMSG *qmsg = &msgQueue->messages[pos]; + *msg = qmsg->msg; + msgQueue->GetMessageTimeVal = msg->time; + msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt; + msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo; + + if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos ); + break; + } + + msgQueue->changeBits |= MSG_JournalPlayBackMsg(); + + /* Now find a hardware event */ + + if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) && + MSG_PeekHardwareMsg( msg, hwnd, MAKELONG(first,last), flags & PM_REMOVE )) + { + /* Got one */ + msgQueue->GetMessageTimeVal = msg->time; + msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt; + msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */ + break; + } + + /* Check again for SendMessage */ + + while (msgQueue->wakeBits & QS_SENDMESSAGE) + QUEUE_ReceiveMessage( msgQueue ); + + /* Now find a WM_PAINT message */ + + if ((msgQueue->wakeBits & mask) & QS_PAINT) + { + WND* wndPtr; + msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue ); + msg->message = WM_PAINT; + msg->wParam = 0; + msg->lParam = 0; + + if ((wndPtr = WIN_FindWndPtr(msg->hwnd))) + { + if( wndPtr->dwStyle & WS_MINIMIZE && + wndPtr->class->hIcon ) + { + msg->message = WM_PAINTICON; + msg->wParam = 1; + } + + if( !hwnd || msg->hwnd == hwnd || IsChild(hwnd,msg->hwnd) ) + { + if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate) + { + wndPtr->flags &= ~WIN_INTERNAL_PAINT; + QUEUE_DecPaintCount( hQueue ); + } + break; + } + } + } + + /* Check for timer messages, but yield first */ + + if (!(flags & PM_NOYIELD)) + { + UserYield(); + while (msgQueue->wakeBits & QS_SENDMESSAGE) + QUEUE_ReceiveMessage( msgQueue ); + } + if ((msgQueue->wakeBits & mask) & QS_TIMER) + { + if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break; + } + + if (peek) + { + if (!(flags & PM_NOYIELD)) UserYield(); + return FALSE; + } + msgQueue->wakeMask = mask; + QUEUE_WaitBits( mask ); + } + + /* We got a message */ + if (flags & PM_REMOVE) + { + WORD message = msg->message; + + if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) + { + BYTE *p = &QueueKeyStateTable[msg->wParam & 0xff]; + + if (!(*p & 0x80)) + *p ^= 0x01; + *p |= 0x80; + } + else if (message == WM_KEYUP || message == WM_SYSKEYUP) + QueueKeyStateTable[msg->wParam & 0xff] &= ~0x80; + } + if (peek) return TRUE; + else return (msg->message != WM_QUIT); +} + +/*********************************************************************** + * MSG_InternalGetMessage + * + * GetMessage() function for internal use. Behave like GetMessage(), + * but also call message filters and optionally send WM_ENTERIDLE messages. + * 'hwnd' must be the handle of the dialog or menu window. + * 'code' is the message filter value (MSGF_??? codes). + */ +WINBOOL MSG_InternalGetMessage( MSG *msg, HWND hwnd, HWND hwndOwner, + WPARAM code, WORD flags, WINBOOL sendIdle ) +{ + for (;;) + { + if (sendIdle) + { + if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE )) + { + /* No message present -> send ENTERIDLE and wait */ + if (IsWindow(hwndOwner)) + SendMessageW( hwndOwner, WM_ENTERIDLE, + code, (LPARAM)hwnd ); + MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE ); + } + } + else /* Always wait for a message */ + MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE ); + + /* Call message filters */ + + if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER )) + { + MSG *pmsg = malloc(sizeof(MSG)); + if (pmsg) + { + WINBOOL ret; + *pmsg = *msg; + ret = ((WINBOOL)HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0, + (LPARAM)(pmsg) ) || + (WINBOOL)HOOK_CallHooksA( WH_MSGFILTER, code, 0, + (LPARAM)(pmsg) )); + free(pmsg); + if (ret) + { + /* Message filtered -> remove it from the queue */ + /* if it's still there. */ + if (!(flags & PM_REMOVE)) + MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE ); + continue; + } + } + } + + return (msg->message != WM_QUIT); + } +} + +/************************************************************************ + * MSG_CallWndProcHook + */ +void MSG_CallWndProcHook( LPMSG pmsg, WINBOOL bUnicode ) +{ + CWPSTRUCT cwp; + + cwp.lParam = pmsg->lParam; + cwp.wParam = pmsg->wParam; + cwp.message = pmsg->message; + cwp.hwnd = pmsg->hwnd; + + if (bUnicode) HOOK_CallHooksW(WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp); + else HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp ); + + pmsg->lParam = cwp.lParam; + pmsg->wParam = cwp.wParam; + pmsg->message = cwp.message; + pmsg->hwnd = cwp.hwnd; +} + +struct accent_char +{ + BYTE ac_accent; + BYTE ac_char; + BYTE ac_result; +}; + +static const struct accent_char accent_chars[] = +{ +/* A good idea should be to read /usr/X11/lib/X11/locale/iso8859-x/Compose */ + {'`', 'A', '\300'}, {'`', 'a', '\340'}, + {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, + {'^', 'A', '\302'}, {'^', 'a', '\342'}, + {'~', 'A', '\303'}, {'~', 'a', '\343'}, + {'"', 'A', '\304'}, {'"', 'a', '\344'}, + {'O', 'A', '\305'}, {'o', 'a', '\345'}, + {'0', 'A', '\305'}, {'0', 'a', '\345'}, + {'A', 'A', '\305'}, {'a', 'a', '\345'}, + {'A', 'E', '\306'}, {'a', 'e', '\346'}, + {',', 'C', '\307'}, {',', 'c', '\347'}, + {'`', 'E', '\310'}, {'`', 'e', '\350'}, + {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, + {'^', 'E', '\312'}, {'^', 'e', '\352'}, + {'"', 'E', '\313'}, {'"', 'e', '\353'}, + {'`', 'I', '\314'}, {'`', 'i', '\354'}, + {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, + {'^', 'I', '\316'}, {'^', 'i', '\356'}, + {'"', 'I', '\317'}, {'"', 'i', '\357'}, + {'-', 'D', '\320'}, {'-', 'd', '\360'}, + {'~', 'N', '\321'}, {'~', 'n', '\361'}, + {'`', 'O', '\322'}, {'`', 'o', '\362'}, + {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, + {'^', 'O', '\324'}, {'^', 'o', '\364'}, + {'~', 'O', '\325'}, {'~', 'o', '\365'}, + {'"', 'O', '\326'}, {'"', 'o', '\366'}, + {'/', 'O', '\330'}, {'/', 'o', '\370'}, + {'`', 'U', '\331'}, {'`', 'u', '\371'}, + {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, + {'^', 'U', '\333'}, {'^', 'u', '\373'}, + {'"', 'U', '\334'}, {'"', 'u', '\374'}, + {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, + {'T', 'H', '\336'}, {'t', 'h', '\376'}, + {'s', 's', '\337'}, {'"', 'y', '\377'}, + {'s', 'z', '\337'}, {'i', 'j', '\377'}, + /* iso-8859-2 uses this */ + {'<', 'L', '\245'}, {'<', 'l', '\265'}, /* caron */ + {'<', 'S', '\251'}, {'<', 's', '\271'}, + {'<', 'T', '\253'}, {'<', 't', '\273'}, + {'<', 'Z', '\256'}, {'<', 'z', '\276'}, + {'<', 'C', '\310'}, {'<', 'c', '\350'}, + {'<', 'E', '\314'}, {'<', 'e', '\354'}, + {'<', 'D', '\317'}, {'<', 'd', '\357'}, + {'<', 'N', '\322'}, {'<', 'n', '\362'}, + {'<', 'R', '\330'}, {'<', 'r', '\370'}, + {';', 'A', '\241'}, {';', 'a', '\261'}, /* ogonek */ + {';', 'E', '\312'}, {';', 'e', '\332'}, + {'\'', 'Z', '\254'}, {'\'', 'z', '\274'}, /* acute */ + {'\'', 'R', '\300'}, {'\'', 'r', '\340'}, + {'\'', 'L', '\305'}, {'\'', 'l', '\345'}, + {'\'', 'C', '\306'}, {'\'', 'c', '\346'}, + {'\'', 'N', '\321'}, {'\'', 'n', '\361'}, +/* collision whith S, from iso-8859-9 !!! */ + {',', 'S', '\252'}, {',', 's', '\272'}, /* cedilla */ + {',', 'T', '\336'}, {',', 't', '\376'}, + {'.', 'Z', '\257'}, {'.', 'z', '\277'}, /* dot above */ + {'/', 'L', '\243'}, {'/', 'l', '\263'}, /* slash */ + {'/', 'D', '\320'}, {'/', 'd', '\360'}, + {'(', 'A', '\303'}, {'(', 'a', '\343'}, /* breve */ + {'\275', 'O', '\325'}, {'\275', 'o', '\365'}, /* double acute */ + {'\275', 'U', '\334'}, {'\275', 'u', '\374'}, + {'0', 'U', '\332'}, {'0', 'u', '\372'}, /* ring above */ + /* iso-8859-3 uses this */ + {'/', 'H', '\241'}, {'/', 'h', '\261'}, /* slash */ + {'>', 'H', '\246'}, {'>', 'h', '\266'}, /* circumflex */ + {'>', 'J', '\254'}, {'>', 'j', '\274'}, + {'>', 'C', '\306'}, {'>', 'c', '\346'}, + {'>', 'G', '\330'}, {'>', 'g', '\370'}, + {'>', 'S', '\336'}, {'>', 's', '\376'}, +/* collision whith G( from iso-8859-9 !!! */ + {'(', 'G', '\253'}, {'(', 'g', '\273'}, /* breve */ + {'(', 'U', '\335'}, {'(', 'u', '\375'}, +/* collision whith I. from iso-8859-3 !!! */ + {'.', 'I', '\251'}, {'.', 'i', '\271'}, /* dot above */ + {'.', 'C', '\305'}, {'.', 'c', '\345'}, + {'.', 'G', '\325'}, {'.', 'g', '\365'}, + /* iso-8859-4 uses this */ + {',', 'R', '\243'}, {',', 'r', '\263'}, /* cedilla */ + {',', 'L', '\246'}, {',', 'l', '\266'}, + {',', 'G', '\253'}, {',', 'g', '\273'}, + {',', 'N', '\321'}, {',', 'n', '\361'}, + {',', 'K', '\323'}, {',', 'k', '\363'}, + {'~', 'I', '\245'}, {'~', 'i', '\265'}, /* tilde */ + {'-', 'E', '\252'}, {'-', 'e', '\272'}, /* macron */ + {'-', 'A', '\300'}, {'-', 'a', '\340'}, + {'-', 'I', '\317'}, {'-', 'i', '\357'}, + {'-', 'O', '\322'}, {'-', 'o', '\362'}, + {'-', 'U', '\336'}, {'-', 'u', '\376'}, + {'/', 'T', '\254'}, {'/', 't', '\274'}, /* slash */ + {'.', 'E', '\314'}, {'.', 'e', '\344'}, /* dot above */ + {';', 'I', '\307'}, {';', 'i', '\347'}, /* ogonek */ + {';', 'U', '\331'}, {';', 'u', '\371'}, + /* iso-8859-9 uses this */ + /* iso-8859-9 has really bad choosen G( S, and I. as they collide + * whith the same letters on other iso-8859-x (that is they are on + * different places :-( ), if you use turkish uncomment these and + * comment out the lines in iso-8859-2 and iso-8859-3 sections + * FIXME: should be dynamic according to chosen language + * if/when Wine has turkish support. + */ +/* collision whith G( from iso-8859-3 !!! */ +/* {'(', 'G', '\320'}, {'(', 'g', '\360'}, */ /* breve */ +/* collision whith S, from iso-8859-2 !!! */ +/* {',', 'S', '\336'}, {',', 's', '\376'}, */ /* cedilla */ +/* collision whith I. from iso-8859-3 !!! */ +/* {'.', 'I', '\335'}, {'.', 'i', '\375'}, */ /* dot above */ +}; + + +/*********************************************************************** + * MSG_DoTranslateMessage + * + * Implementation of TranslateMessage. + * + * TranslateMessage translates virtual-key messages into character-messages, + * as follows : + * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message. + * ditto replacing WM_* with WM_SYS* + * This produces WM_CHAR messages only for keys mapped to ASCII characters + * by the keyboard driver. + */ +WINBOOL MSG_DoTranslateMessage( UINT message, HWND hwnd, + WPARAM wParam, LPARAM lParam ) +{ + int dead_char = 0; + BYTE wp[2]; + + if (message != WM_MOUSEMOVE && message != WM_TIMER) + DPRINT( "(%s, %04X, %08lX)\n", + SPY_GetMsgName(message), wParam, lParam ); + if(message >= WM_KEYFIRST && message <= WM_KEYLAST) + DPRINT( "(%s, %04X, %08lX)\n", + SPY_GetMsgName(message), wParam, lParam ); + + if ((message != WM_KEYDOWN) && (message != WM_SYSKEYDOWN)) return FALSE; + + DPRINT( "Translating key %04X, scancode %04X\n", + wParam, HIWORD(lParam) ); + + /* FIXME : should handle ToAscii yielding 2 */ + switch (ToAscii(wParam, HIWORD(lParam), + QueueKeyStateTable,(LPWORD)wp, 0)) + { + case 1 : + message = (message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR; + /* Should dead chars handling go in ToAscii ? */ + if (dead_char) + { + int i; + + if (wp[0] == ' ') wp[0] = dead_char; + if (dead_char == 0xa2) dead_char = '('; + else if (dead_char == 0xa8) dead_char = '"'; + else if (dead_char == 0xb2) dead_char = ';'; + else if (dead_char == 0xb4) dead_char = '\''; + else if (dead_char == 0xb7) dead_char = '<'; + else if (dead_char == 0xb8) dead_char = ','; + else if (dead_char == 0xff) dead_char = '.'; + for (i = 0; i < sizeof(accent_chars)/sizeof(accent_chars[0]); i++) + if ((accent_chars[i].ac_accent == dead_char) && + (accent_chars[i].ac_char == wp[0])) + { + wp[0] = accent_chars[i].ac_result; + break; + } + dead_char = 0; + } + DPRINT( "1 -> PostMessage(%s)\n", SPY_GetMsgName(message)); + PostMessageA( hwnd, message, wp[0], lParam ); + return TRUE; + + case -1 : + message = (message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR; + dead_char = wp[0]; + DPRINT( "-1 -> PostMessage(%s)\n", + SPY_GetMsgName(message)); + PostMessageA( hwnd, message, wp[0], lParam ); + return TRUE; + } + return FALSE; +} + + +HTASK GetCurrentTask(void) +{ + return (HTASK)-2; +} + +//FIXME +HQUEUE hThreadQ; + +HQUEUE GetThreadQueue( DWORD thread ) +{ + return hThreadQ; +} + + + +HQUEUE SetThreadQueue( DWORD thread, HQUEUE hQueue ) +{ + HQUEUE oldQueue = hThreadQ; + hThreadQ = hQueue; + return oldQueue; +} + +HANDLE GetFastQueue( void ) +{ + return hThreadQ; +} + +int UserYield(void) +{ + return SuspendThread(GetCurrentThread()); +} diff --git a/reactos/lib/user32/internal/nc.c b/reactos/lib/user32/internal/nc.c new file mode 100644 index 00000000000..50bf59cbf90 --- /dev/null +++ b/reactos/lib/user32/internal/nc.c @@ -0,0 +1,2259 @@ +#include +#include +#include +#include + +static HBITMAP hbitmapClose = 0; +static HBITMAP hbitmapCloseD = 0; +static HBITMAP hbitmapMinimize = 0; +static HBITMAP hbitmapMinimizeD = 0; +static HBITMAP hbitmapMaximize = 0; +static HBITMAP hbitmapMaximizeD = 0; +static HBITMAP hbitmapRestore = 0; +static HBITMAP hbitmapRestoreD = 0; + +#define SC_ABOUTWINE (SC_SCREENSAVE+1) +#define SC_PUTMARK (SC_SCREENSAVE+2) + + /* Some useful macros */ +#define HAS_DLGFRAME(style,exStyle) \ + (((exStyle) & WS_EX_DLGMODALFRAME) || \ + (((style) & WS_DLGFRAME) && !((style) & WS_BORDER))) + +#define HAS_THICKFRAME(style) \ + (((style) & WS_THICKFRAME) && \ + !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME)) + +#define HAS_FIXEDFRAME(style,exStyle) \ + (((((exStyle) & WS_EX_DLGMODALFRAME) || \ + ((style) & WS_DLGFRAME)) && ((style) & WS_BORDER)) && \ + !((style) & WS_THICKFRAME)) + +#define HAS_SIZEFRAME(style) \ + (((style) & WS_THICKFRAME) && \ + !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME)) + +#define HAS_MENU(w) (!((w)->dwStyle & WS_CHILD) && ((w)->wIDmenu != 0)) + +#define ON_LEFT_BORDER(hit) \ + (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT)) +#define ON_RIGHT_BORDER(hit) \ + (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT)) +#define ON_TOP_BORDER(hit) \ + (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT)) +#define ON_BOTTOM_BORDER(hit) \ + (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT)) + + +int TWEAK_WineLook = WIN95_LOOK; + +/*********************************************************************** + * NC_AdjustRect + * + * Compute the size of the window rectangle from the size of the + * client rectangle. + */ +void NC_AdjustRect( LPRECT rect, DWORD style, WINBOOL menu, + DWORD exStyle ) +{ + + if(style & WS_ICONIC) return; + /* Decide if the window will be managed (see CreateWindowEx) */ + // removed Options.managed && + if (!( !(style & WS_CHILD) && + ((style & (WS_DLGFRAME | WS_THICKFRAME)) || + (exStyle & WS_EX_DLGMODALFRAME)))) + { + if (HAS_DLGFRAME( style, exStyle )) + InflateRect(rect, SYSMETRICS_CXDLGFRAME, SYSMETRICS_CYDLGFRAME ); + else + { + if (HAS_THICKFRAME(style)) + InflateRect( rect, SYSMETRICS_CXFRAME, SYSMETRICS_CYFRAME ); + if (style & WS_BORDER) + InflateRect( rect, SYSMETRICS_CXBORDER, SYSMETRICS_CYBORDER); + } + + if ((style & WS_CAPTION) == WS_CAPTION) + rect->top -= SYSMETRICS_CYCAPTION - SYSMETRICS_CYBORDER; + } + if (menu) rect->top -= SYSMETRICS_CYMENU + SYSMETRICS_CYBORDER; + + if (style & WS_VSCROLL) { + rect->right += SYSMETRICS_CXVSCROLL - 1; + if(!(style & WS_BORDER)) + rect->right++; + } + + if (style & WS_HSCROLL) { + rect->bottom += SYSMETRICS_CYHSCROLL - 1; + if(!(style & WS_BORDER)) + rect->bottom++; + } +} + +/****************************************************************************** + * NC_AdjustRectOuter95 + * + * Computes the size of the "outside" parts of the window based on the + * parameters of the client area. + * + + PARAMS + * LPRECT rect + * DWORD style + * WINBOOL menu + * DWORD exStyle + * + * NOTES + * "Outer" parts of a window means the whole window frame, caption and + * menu bar. It does not include "inner" parts of the frame like client + * edge, static edge or scroll bars. + * + * Revision history + * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original (NC_AdjustRect95) cut & paste from NC_AdjustRect + * + * 20-Jun-1998 Eric Kohl (ekohl@abo.rhein-zeitung.de) + * Split NC_AdjustRect95 into NC_AdjustRectOuter95 and + * NC_AdjustRectInner95 and added handling of Win95 styles. + * + *****************************************************************************/ + +void +NC_AdjustRectOuter95 (LPRECT rect, DWORD style, WINBOOL menu, DWORD exStyle) +{ + if(style & WS_ICONIC) return; + + /* Decide if the window will be managed (see CreateWindowEx) */ + // Options.managed && + if (!( !(style & WS_CHILD) && + ((style & (WS_DLGFRAME | WS_THICKFRAME)) || + (exStyle & WS_EX_DLGMODALFRAME)))) + { + if (HAS_FIXEDFRAME( style, exStyle )) + InflateRect(rect, SYSMETRICS_CXDLGFRAME, SYSMETRICS_CYDLGFRAME ); + else + { + if (HAS_SIZEFRAME(style)) + InflateRect( rect, SYSMETRICS_CXFRAME, SYSMETRICS_CYFRAME ); +#if 0 + if (style & WS_BORDER) + InflateRect( rect, SYSMETRICS_CXBORDER, SYSMETRICS_CYBORDER); +#endif + } + + if ((style & WS_CAPTION) == WS_CAPTION) + { + if (exStyle & WS_EX_TOOLWINDOW) + rect->top -= SYSMETRICS_CYSMCAPTION; + else + rect->top -= SYSMETRICS_CYCAPTION; + } + } + + if (menu) + rect->top -= sysMetrics[SM_CYMENU]; +} + + +/****************************************************************************** + * NC_AdjustRectInner95 + * + * Computes the size of the "inside" part of the window based on the + * parameters of the client area. + * + + PARAMS + * LPRECT rect + * DWORD style + * DWORD exStyle + * + * NOTES + * "Inner" part of a window means the window frame inside of the flat + * window frame. It includes the client edge, the static edge and the + * scroll bars. + * + * Revision history + * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original (NC_AdjustRect95) cut & paste from NC_AdjustRect + * + * 20-Jun-1998 Eric Kohl (ekohl@abo.rhein-zeitung.de) + * Split NC_AdjustRect95 into NC_AdjustRectOuter95 and + * NC_AdjustRectInner95 and added handling of Win95 styles. + * + *****************************************************************************/ + +void +NC_AdjustRectInner95 (LPRECT rect, DWORD style, DWORD exStyle) +{ + if(style & WS_ICONIC) return; + + if (exStyle & WS_EX_CLIENTEDGE) + InflateRect (rect, sysMetrics[SM_CXEDGE], sysMetrics[SM_CYEDGE]); + + if (exStyle & WS_EX_STATICEDGE) + InflateRect (rect, sysMetrics[SM_CXBORDER], sysMetrics[SM_CYBORDER]); + + if (style & WS_VSCROLL) rect->right += SYSMETRICS_CXVSCROLL; + if (style & WS_HSCROLL) rect->bottom += SYSMETRICS_CYHSCROLL; +} + +/*********************************************************************** + * NC_HandleNCCalcSize + * + * Handle a WM_NCCALCSIZE message. Called from DefWindowProc(). + */ +LONG NC_HandleNCCalcSize( WND *pWnd, RECT *winRect ) +{ + RECT tmpRect = { 0, 0, 0, 0 }; + LONG result = 0; + + if (pWnd->class->style & CS_VREDRAW) result |= WVR_VREDRAW; + if (pWnd->class->style & CS_HREDRAW) result |= WVR_HREDRAW; + + if( !( pWnd->dwStyle & WS_MINIMIZE ) ) { + if (TWEAK_WineLook == WIN31_LOOK) + NC_AdjustRect( &tmpRect, pWnd->dwStyle, FALSE, pWnd->dwExStyle ); + else + NC_AdjustRectOuter95( &tmpRect, pWnd->dwStyle, FALSE, pWnd->dwExStyle ); + + winRect->left -= tmpRect.left; + winRect->top -= tmpRect.top; + winRect->right -= tmpRect.right; + winRect->bottom -= tmpRect.bottom; + + if (HAS_MENU(pWnd)) { + DPRINT( "Calling GetMenuBarHeight with HWND 0x%x, width %d, at (%d, %d).\n", pWnd->hwndSelf, + winRect->right - winRect->left, -tmpRect.left, -tmpRect.top ); + + winRect->top += + MENU_GetMenuBarHeight( pWnd->hwndSelf, + winRect->right - winRect->left, + -tmpRect.left, -tmpRect.top ) + 1; + } + + if (TWEAK_WineLook > WIN31_LOOK) { + SetRect (&tmpRect, 0, 0, 0, 0); + NC_AdjustRectInner95 (&tmpRect, pWnd->dwStyle, pWnd->dwExStyle); + winRect->left -= tmpRect.left; + winRect->top -= tmpRect.top; + winRect->right -= tmpRect.right; + winRect->bottom -= tmpRect.bottom; + } + } + return result; +} + + +/*********************************************************************** + * NC_GetInsideRect + * + * Get the 'inside' rectangle of a window, i.e. the whole window rectangle + * but without the borders (if any). + * The rectangle is in window coordinates (for drawing with GetWindowDC()). + */ +static void NC_GetInsideRect( HWND hwnd, RECT *rect ) +{ + WND * wndPtr = WIN_FindWndPtr( hwnd ); + + rect->top = rect->left = 0; + rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left; + rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top; + + if ((wndPtr->dwStyle & WS_ICONIC) || (wndPtr->flags & WIN_MANAGED)) return; + + /* Remove frame from rectangle */ + if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle )) + { + InflateRect( rect, -SYSMETRICS_CXDLGFRAME, -SYSMETRICS_CYDLGFRAME); + if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) + InflateRect( rect, -1, 0 ); + } + else + { + if (HAS_THICKFRAME( wndPtr->dwStyle )) + InflateRect( rect, -SYSMETRICS_CXFRAME, -SYSMETRICS_CYFRAME ); + if (wndPtr->dwStyle & WS_BORDER) + InflateRect( rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER ); + } + + return; +} + + +/*********************************************************************** + * NC_GetInsideRect95 + * + * Get the 'inside' rectangle of a window, i.e. the whole window rectangle + * but without the borders (if any). + * The rectangle is in window coordinates (for drawing with GetWindowDC()). + */ + +static void +NC_GetInsideRect95 (HWND hwnd, RECT *rect) +{ + WND * wndPtr = WIN_FindWndPtr( hwnd ); + + rect->top = rect->left = 0; + rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left; + rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top; + + if ((wndPtr->dwStyle & WS_ICONIC) || (wndPtr->flags & WIN_MANAGED)) return; + + /* Remove frame from rectangle */ + if (HAS_FIXEDFRAME (wndPtr->dwStyle, wndPtr->dwExStyle )) + { + InflateRect( rect, -SYSMETRICS_CXFIXEDFRAME, -SYSMETRICS_CYFIXEDFRAME); + } + else if (HAS_SIZEFRAME (wndPtr->dwStyle)) + { + InflateRect( rect, -SYSMETRICS_CXSIZEFRAME, -SYSMETRICS_CYSIZEFRAME ); + +/* if (wndPtr->dwStyle & WS_BORDER) + InflateRect( rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER );*/ + } + + if (wndPtr->dwStyle & WS_CHILD) { + if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE) + InflateRect(rect, -SYSMETRICS_CXEDGE, -SYSMETRICS_CYEDGE); + + if (wndPtr->dwExStyle & WS_EX_STATICEDGE) + InflateRect(rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER); + } + + return; +} + + +/*********************************************************************** + * NC_DoNCHitTest + * + * Handle a WM_NCHITTEST message. Called from NC_HandleNcHitTest(). + */ + +LONG NC_DoNCHitTest (WND *wndPtr, POINT pt ) +{ + RECT rect; + + DPRINT( "hwnd=%04x pt=%d,%d\n", + wndPtr->hwndSelf, pt.x, pt.y ); + + GetWindowRect (wndPtr->hwndSelf, &rect ); + if (!PtInRect( &rect, pt )) return HTNOWHERE; + + if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION; + + if (!(wndPtr->flags & WIN_MANAGED)) + { + /* Check borders */ + if (HAS_THICKFRAME( wndPtr->dwStyle )) + { + InflateRect( &rect, -SYSMETRICS_CXFRAME, -SYSMETRICS_CYFRAME ); + if (wndPtr->dwStyle & WS_BORDER) + InflateRect(&rect,-SYSMETRICS_CXBORDER,-SYSMETRICS_CYBORDER); + if (!PtInRect( &rect, pt )) + { + /* Check top sizing border */ + if (pt.y < rect.top) + { + if (pt.x < rect.left+SYSMETRICS_CXSIZE) return HTTOPLEFT; + if (pt.x >= rect.right-SYSMETRICS_CXSIZE) return HTTOPRIGHT; + return HTTOP; + } + /* Check bottom sizing border */ + if (pt.y >= rect.bottom) + { + if (pt.x < rect.left+SYSMETRICS_CXSIZE) return HTBOTTOMLEFT; + if (pt.x >= rect.right-SYSMETRICS_CXSIZE) return HTBOTTOMRIGHT; + return HTBOTTOM; + } + /* Check left sizing border */ + if (pt.x < rect.left) + { + if (pt.y < rect.top+SYSMETRICS_CYSIZE) return HTTOPLEFT; + if (pt.y >= rect.bottom-SYSMETRICS_CYSIZE) return HTBOTTOMLEFT; + return HTLEFT; + } + /* Check right sizing border */ + if (pt.x >= rect.right) + { + if (pt.y < rect.top+SYSMETRICS_CYSIZE) return HTTOPRIGHT; + if (pt.y >= rect.bottom-SYSMETRICS_CYSIZE) return HTBOTTOMRIGHT; + return HTRIGHT; + } + } + } + else /* No thick frame */ + { + if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle )) + InflateRect(&rect, -SYSMETRICS_CXDLGFRAME, -SYSMETRICS_CYDLGFRAME); + else if (wndPtr->dwStyle & WS_BORDER) + InflateRect(&rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER); + if (!PtInRect( &rect, pt )) return HTBORDER; + } + + /* Check caption */ + + if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION) + { + rect.top += sysMetrics[SM_CYCAPTION] - 1; + if (!PtInRect( &rect, pt )) + { + /* Check system menu */ + if (wndPtr->dwStyle & WS_SYSMENU) + rect.left += SYSMETRICS_CXSIZE; + if (pt.x <= rect.left) return HTSYSMENU; + /* Check maximize box */ + if (wndPtr->dwStyle & WS_MAXIMIZEBOX) + rect.right -= SYSMETRICS_CXSIZE + 1; + if (pt.x >= rect.right) return HTMAXBUTTON; + /* Check minimize box */ + if (wndPtr->dwStyle & WS_MINIMIZEBOX) + rect.right -= SYSMETRICS_CXSIZE + 1; + if (pt.x >= rect.right) return HTMINBUTTON; + return HTCAPTION; + } + } + } + + /* Check client area */ + + ScreenToClient( wndPtr->hwndSelf, &pt ); + GetClientRect( wndPtr->hwndSelf, &rect ); + if (PtInRect( &rect, pt )) return HTCLIENT; + + /* Check vertical scroll bar */ + + if (wndPtr->dwStyle & WS_VSCROLL) + { + rect.right += SYSMETRICS_CXVSCROLL; + if (PtInRect( &rect, pt )) return HTVSCROLL; + } + + /* Check horizontal scroll bar */ + + if (wndPtr->dwStyle & WS_HSCROLL) + { + rect.bottom += SYSMETRICS_CYHSCROLL; + if (PtInRect( &rect, pt )) + { + /* Check size box */ + if ((wndPtr->dwStyle & WS_VSCROLL) && + (pt.x >= rect.right - SYSMETRICS_CXVSCROLL)) + return HTSIZE; + return HTHSCROLL; + } + } + + /* Check menu bar */ + + if (HAS_MENU(wndPtr)) + { + if ((pt.y < 0) && (pt.x >= 0) && (pt.x < rect.right)) + return HTMENU; + } + + /* Should never get here */ + return HTERROR; +} + + +/*********************************************************************** + * NC_DoNCHitTest95 + * + * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest(). + * + * FIXME: Just a modified copy of the Win 3.1 version. + */ + +LONG +NC_DoNCHitTest95 (WND *wndPtr, POINT pt ) +{ + RECT rect; + + DPRINT( "hwnd=%04x pt=%d,%d\n", + wndPtr->hwndSelf, pt.x, pt.y ); + + GetWindowRect (wndPtr->hwndSelf, &rect ); + if (!PtInRect( &rect, pt )) return HTNOWHERE; + + if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION; + + if (!(wndPtr->flags & WIN_MANAGED)) + { + /* Check borders */ + if (HAS_SIZEFRAME( wndPtr->dwStyle )) + { + InflateRect( &rect, -SYSMETRICS_CXFRAME, -SYSMETRICS_CYFRAME ); +/* if (wndPtr->dwStyle & WS_BORDER) */ +/* InflateRect(&rect,-SYSMETRICS_CXBORDER,-SYSMETRICS_CYBORDER); */ + if (!PtInRect( &rect, pt )) + { + /* Check top sizing border */ + if (pt.y < rect.top) + { + if (pt.x < rect.left+SYSMETRICS_CXSIZE) return HTTOPLEFT; + if (pt.x >= rect.right-SYSMETRICS_CXSIZE) return HTTOPRIGHT; + return HTTOP; + } + /* Check bottom sizing border */ + if (pt.y >= rect.bottom) + { + if (pt.x < rect.left+SYSMETRICS_CXSIZE) return HTBOTTOMLEFT; + if (pt.x >= rect.right-SYSMETRICS_CXSIZE) return HTBOTTOMRIGHT; + return HTBOTTOM; + } + /* Check left sizing border */ + if (pt.x < rect.left) + { + if (pt.y < rect.top+SYSMETRICS_CYSIZE) return HTTOPLEFT; + if (pt.y >= rect.bottom-SYSMETRICS_CYSIZE) return HTBOTTOMLEFT; + return HTLEFT; + } + /* Check right sizing border */ + if (pt.x >= rect.right) + { + if (pt.y < rect.top+SYSMETRICS_CYSIZE) return HTTOPRIGHT; + if (pt.y >= rect.bottom-SYSMETRICS_CYSIZE) return HTBOTTOMRIGHT; + return HTRIGHT; + } + } + } + else /* No thick frame */ + { + if (HAS_FIXEDFRAME( wndPtr->dwStyle, wndPtr->dwExStyle )) + InflateRect(&rect, -SYSMETRICS_CXDLGFRAME, -SYSMETRICS_CYDLGFRAME); +/* else if (wndPtr->dwStyle & WS_BORDER) */ +/* InflateRect(&rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER); */ + if (!PtInRect( &rect, pt )) return HTBORDER; + } + + /* Check caption */ + + if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION) + { + if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW) + rect.top += sysMetrics[SM_CYSMCAPTION] - 1; + else + rect.top += sysMetrics[SM_CYCAPTION] - 1; + if (!PtInRect( &rect, pt )) + { + /* Check system menu */ + if ((wndPtr->dwStyle & WS_SYSMENU) && + ((wndPtr->class->hIconSm) || (wndPtr->class->hIcon))) + rect.left += sysMetrics[SM_CYCAPTION] - 1; + if (pt.x < rect.left) return HTSYSMENU; + + /* Check close button */ + if (wndPtr->dwStyle & WS_SYSMENU) + rect.right -= sysMetrics[SM_CYCAPTION] - 1; + if (pt.x > rect.right) return HTCLOSE; + + /* Check maximize box */ + if (wndPtr->dwStyle & WS_MAXIMIZEBOX) + rect.right -= SYSMETRICS_CXSIZE + 1; + if (pt.x > rect.right) return HTMAXBUTTON; + + /* Check minimize box */ + if (wndPtr->dwStyle & WS_MINIMIZEBOX) + rect.right -= SYSMETRICS_CXSIZE + 1; + if (pt.x > rect.right) return HTMINBUTTON; + return HTCAPTION; + } + } + } + + /* Check client area */ + + ScreenToClient( wndPtr->hwndSelf, &pt ); + GetClientRect( wndPtr->hwndSelf, &rect ); + if (PtInRect( &rect, pt )) return HTCLIENT; + + /* Check vertical scroll bar */ + + if (wndPtr->dwStyle & WS_VSCROLL) + { + rect.right += SYSMETRICS_CXVSCROLL; + if (PtInRect( &rect, pt )) return HTVSCROLL; + } + + /* Check horizontal scroll bar */ + + if (wndPtr->dwStyle & WS_HSCROLL) + { + rect.bottom += SYSMETRICS_CYHSCROLL; + if (PtInRect( &rect, pt )) + { + /* Check size box */ + if ((wndPtr->dwStyle & WS_VSCROLL) && + (pt.x >= rect.right - SYSMETRICS_CXVSCROLL)) + return HTSIZE; + return HTHSCROLL; + } + } + + /* Check menu bar */ + + if (HAS_MENU(wndPtr)) + { + if ((pt.y < 0) && (pt.x >= 0) && (pt.x < rect.right)) + return HTMENU; + } + + /* Should never get here */ + return HTERROR; +} + + +/*********************************************************************** + * NC_HandleNCHitTest + * + * Handle a WM_NCHITTEST message. Called from DefWindowProc(). + */ +LONG +NC_HandleNCHitTest (HWND hwnd , POINT pt) +{ + WND *wndPtr = WIN_FindWndPtr (hwnd); + + if (!wndPtr) + return HTERROR; + + if (TWEAK_WineLook == WIN31_LOOK) + return NC_DoNCHitTest (wndPtr, pt); + else + return NC_DoNCHitTest95 (wndPtr, pt); +} + + +/*********************************************************************** + * NC_DrawSysButton + */ +void NC_DrawSysButton( HWND hwnd, HDC hdc, WINBOOL down ) +{ + RECT rect; + HDC hdcMem; + HBITMAP hbitmap; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + if( !(wndPtr->flags & WIN_MANAGED) ) + { + NC_GetInsideRect( hwnd, &rect ); + hdcMem = CreateCompatibleDC( hdc ); + hbitmap = SelectObject( hdcMem, hbitmapClose ); + BitBlt(hdc, rect.left, rect.top, SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE, + hdcMem, (wndPtr->dwStyle & WS_CHILD) ? SYSMETRICS_CXSIZE : 0, 0, + down ? NOTSRCCOPY : SRCCOPY ); + SelectObject( hdcMem, hbitmap ); + DeleteDC( hdcMem ); + } +} + + +/*********************************************************************** + * NC_DrawMaxButton + */ +static void NC_DrawMaxButton( HWND hwnd, HDC hdc, WINBOOL down ) +{ + RECT rect; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + HDC hdcMem; + + if( !(wndPtr->flags & WIN_MANAGED) ) + { + NC_GetInsideRect( hwnd, &rect ); + hdcMem = CreateCompatibleDC( hdc ); + SelectObject( hdcMem, (IsZoomed(hwnd) + ? (down ? hbitmapRestoreD : hbitmapRestore) + : (down ? hbitmapMaximizeD : hbitmapMaximize)) ); + BitBlt( hdc, rect.right - SYSMETRICS_CXSIZE - 1, rect.top, + SYSMETRICS_CXSIZE + 1, SYSMETRICS_CYSIZE, hdcMem, 0, 0, + SRCCOPY ); + DeleteDC( hdcMem ); + } +} + + +/*********************************************************************** + * NC_DrawMinButton + */ +static void NC_DrawMinButton( HWND hwnd, HDC hdc, WINBOOL down ) +{ + RECT rect; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + HDC hdcMem; + + if( !(wndPtr->flags & WIN_MANAGED) ) + { + NC_GetInsideRect( hwnd, &rect ); + hdcMem = CreateCompatibleDC( hdc ); + SelectObject( hdcMem, (down ? hbitmapMinimizeD : hbitmapMinimize) ); + if (wndPtr->dwStyle & WS_MAXIMIZEBOX) rect.right -= SYSMETRICS_CXSIZE+1; + BitBlt( hdc, rect.right - SYSMETRICS_CXSIZE - 1, rect.top, + SYSMETRICS_CXSIZE + 1, SYSMETRICS_CYSIZE, hdcMem, 0, 0, + SRCCOPY ); + DeleteDC( hdcMem ); + } +} + + +/****************************************************************************** + * + * void NC_DrawSysButton95( + * HWND hwnd, + * HDC hdc, + * WINBOOL down ) + * + * Draws the Win95 system icon. + * + * Revision history + * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original implementation from NC_DrawSysButton source. + * 11-Jun-1998 Eric Kohl (ekohl@abo.rhein-zeitung.de) + * Fixed most bugs. + * + *****************************************************************************/ + +WINBOOL +NC_DrawSysButton95 (HWND hwnd, HDC hdc, WINBOOL down) +{ + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + if( !(wndPtr->flags & WIN_MANAGED) ) + { + HICON hIcon = 0; + RECT rect; + + NC_GetInsideRect95( hwnd, &rect ); + + if (wndPtr->class->hIconSm) + hIcon = wndPtr->class->hIconSm; + else if (wndPtr->class->hIcon) + hIcon = wndPtr->class->hIcon; + + if (hIcon) + DrawIconEx(hdc, rect.left + 2, rect.top + 2, hIcon, + sysMetrics[SM_CXSMICON], + sysMetrics[SM_CYSMICON], + 0, 0, DI_NORMAL); + + return (hIcon != 0); + } + return FALSE; +} + + +/****************************************************************************** + * + * void NC_DrawCloseButton95( + * HWND hwnd, + * HDC hdc, + * WINBOOL down ) + * + * Draws the Win95 close button. + * + * Revision history + * 11-Jun-1998 Eric Kohl (ekohl@abo.rhein-zeitung.de) + * Original implementation from NC_DrawSysButton95 source. + * + *****************************************************************************/ + +void +NC_DrawCloseButton95 (HWND hwnd, HDC hdc, WINBOOL down) +{ + RECT rect; + HDC hdcMem; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + if( !(wndPtr->flags & WIN_MANAGED) ) + { + BITMAP bmp; + HBITMAP hBmp, hOldBmp; + + NC_GetInsideRect95( hwnd, &rect ); + + hdcMem = CreateCompatibleDC( hdc ); + hBmp = /*down ? hbitmapCloseD :*/ hbitmapClose; + hOldBmp = SelectObject (hdcMem, hBmp); + GetObject(hBmp, sizeof(BITMAP), &bmp); + BitBlt(hdc, rect.right - (sysMetrics[SM_CYCAPTION] + 1 + bmp.bmWidth) / 2, + rect.top + (sysMetrics[SM_CYCAPTION] - 1 - bmp.bmHeight) / 2, + bmp.bmWidth, bmp.bmHeight, hdcMem, 0, 0, down ? NOTSRCCOPY : SRCCOPY); + + SelectObject(hdcMem, hOldBmp); + DeleteDC (hdcMem); + } +} + + +/****************************************************************************** + * + * NC_DrawMaxButton95( + * HWND hwnd, + * HDC hdc, + * WINBOOL down ) + * + * Draws the maximize button for Win95 style windows. + * + * Bugs + * Many. Spacing might still be incorrect. Need to fit a close + * button between the max button and the edge. + * Should scale the image with the title bar. And more... + * + * Revision history + * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original implementation. + * + *****************************************************************************/ + +static void NC_DrawMaxButton95( + HWND hwnd, + HDC hdc, + WINBOOL down ) +{ + RECT rect; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + SIZE bmsz; + HBITMAP bm; + HDC hdcMem; + + if( !(wndPtr->flags & WIN_MANAGED) && + GetBitmapDimensionEx((bm = IsZoomed(hwnd) ? + (down ? hbitmapRestoreD : hbitmapRestore ) : + (down ? hbitmapMaximizeD : hbitmapMaximize)), + &bmsz)) { + + NC_GetInsideRect95( hwnd, &rect ); + + if (wndPtr->dwStyle & WS_SYSMENU) + rect.right -= sysMetrics[SM_CYCAPTION] + 1; + + hdcMem = CreateCompatibleDC( hdc ); + SelectObject( hdc, bm ); + BitBlt( hdc, rect.right - (sysMetrics[SM_CXSIZE] + bmsz.cx) / 2, + rect.top + (sysMetrics[SM_CYCAPTION] - 1 - bmsz.cy) / 2, + bmsz.cx, bmsz.cy, hdcMem, 0, 0, SRCCOPY ); + DeleteDC( hdcMem ); + } + + return; +} + + +/****************************************************************************** + * + * NC_DrawMinButton95( + * HWND hwnd, + * HDC hdc, + * WINBOOL down ) + * + * Draws the minimize button for Win95 style windows. + * + * Bugs + * Many. Spacing is still incorrect. Should scale the image with the + * title bar. And more... + * + * Revision history + * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original implementation. + * + *****************************************************************************/ + +static void NC_DrawMinButton95( + HWND hwnd, + HDC hdc, + WINBOOL down ) +{ + RECT rect; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + SIZE bmsz; + HBITMAP bm; + HDC hdcMem; + + if( !(wndPtr->flags & WIN_MANAGED) && + GetBitmapDimensionEx((bm = down ? hbitmapMinimizeD : + hbitmapMinimize), &bmsz)) { + + NC_GetInsideRect95( hwnd, &rect ); + + if (wndPtr->dwStyle & WS_SYSMENU) + rect.right -= sysMetrics[SM_CYCAPTION] + 1; + + if (wndPtr->dwStyle & WS_MAXIMIZEBOX) + rect.right += -1 - + (sysMetrics[SM_CXSIZE] + bmsz.cx) / 2; + + hdcMem = CreateCompatibleDC( hdc ); + SelectObject( hdc, bm ); + BitBlt( hdc, rect.right - (sysMetrics[SM_CXSIZE] + bmsz.cx) / 2, + rect.top + (sysMetrics[SM_CYCAPTION] - 1 - bmsz.cy) / 2, + bmsz.cx, bmsz.cy, hdcMem, 0, 0, SRCCOPY ); + DeleteDC( hdcMem ); + } + + return; +} + + +/*********************************************************************** + * NC_DrawFrame + * + * Draw a window frame inside the given rectangle, and update the rectangle. + * The correct pen for the frame must be selected in the DC. + */ +static void NC_DrawFrame( HDC hdc, RECT *rect, WINBOOL dlgFrame, + WINBOOL active ) +{ + INT width, height; + + // if (TWEAK_WineLook != WIN31_LOOK) +// DPRINT( "Called in Win95 mode. Aiee! Please report this.\n" ); + + if (dlgFrame) + { + width = SYSMETRICS_CXDLGFRAME - 1; + height = SYSMETRICS_CYDLGFRAME - 1; + SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVECAPTION : + COLOR_INACTIVECAPTION) ); + } + else + { + width = SYSMETRICS_CXFRAME - 1; + height = SYSMETRICS_CYFRAME - 1; + SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER : + COLOR_INACTIVEBORDER) ); + } + + /* Draw frame */ + PatBlt( hdc, rect->left, rect->top, + rect->right - rect->left, height, PATCOPY ); + PatBlt( hdc, rect->left, rect->top, + width, rect->bottom - rect->top, PATCOPY ); + PatBlt( hdc, rect->left, rect->bottom, + rect->right - rect->left, -height, PATCOPY ); + PatBlt( hdc, rect->right, rect->top, + -width, rect->bottom - rect->top, PATCOPY ); + + if (dlgFrame) + { + InflateRect( rect, -width, -height ); + } + else + { + INT decYOff = SYSMETRICS_CXFRAME + SYSMETRICS_CXSIZE; + INT decXOff = SYSMETRICS_CYFRAME + SYSMETRICS_CYSIZE; + + /* Draw inner rectangle */ + + SelectObject( hdc, GetStockObject(NULL_BRUSH) ); + Rectangle( hdc, rect->left + width, rect->top + height, + rect->right - width , rect->bottom - height ); + + /* Draw the decorations */ + + MoveToEx( hdc, rect->left, rect->top + decYOff, NULL ); + LineTo( hdc, rect->left + width, rect->top + decYOff ); + MoveToEx( hdc, rect->right - 1, rect->top + decYOff, NULL ); + LineTo( hdc, rect->right - width - 1, rect->top + decYOff ); + MoveToEx( hdc, rect->left, rect->bottom - decYOff, NULL ); + LineTo( hdc, rect->left + width, rect->bottom - decYOff ); + MoveToEx( hdc, rect->right - 1, rect->bottom - decYOff, NULL ); + LineTo( hdc, rect->right - width - 1, rect->bottom - decYOff ); + + MoveToEx( hdc, rect->left + decXOff, rect->top, NULL ); + LineTo( hdc, rect->left + decXOff, rect->top + height); + MoveToEx( hdc, rect->left + decXOff, rect->bottom - 1, NULL ); + LineTo( hdc, rect->left + decXOff, rect->bottom - height - 1 ); + MoveToEx( hdc, rect->right - decXOff, rect->top, NULL ); + LineTo( hdc, rect->right - decXOff, rect->top + height ); + MoveToEx( hdc, rect->right - decXOff, rect->bottom - 1, NULL ); + LineTo( hdc, rect->right - decXOff, rect->bottom - height - 1 ); + + InflateRect( rect, -width - 1, -height - 1 ); + } +} + + +/****************************************************************************** + * + * void NC_DrawFrame95( + * HDC hdc, + * RECT *rect, + * WINBOOL dlgFrame, + * WINBOOL active ) + * + * Draw a window frame inside the given rectangle, and update the rectangle. + * The correct pen for the frame must be selected in the DC. + * + * Bugs + * Many. First, just what IS a frame in Win95? Note that the 3D look + * on the outer edge is handled by NC_DoNCPaint95. As is the inner + * edge. The inner rectangle just inside the frame is handled by the + * Caption code. + * + * In short, for most people, this function should be a nop (unless + * you LIKE thick borders in Win95/NT4.0 -- I've been working with + * them lately, but just to get this code right). Even so, it doesn't + * appear to be so. It's being worked on... + * + * Revision history + * 06-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original implementation (based on NC_DrawFrame) + * 02-Jun-1998 Eric Kohl (ekohl@abo.rhein-zeitung.de) + * Some minor fixes. + * + *****************************************************************************/ + +static void NC_DrawFrame95( + HDC hdc, + RECT *rect, + WINBOOL dlgFrame, + WINBOOL active ) +{ + INT width, height; + + if (dlgFrame) + { + width = sysMetrics[SM_CXDLGFRAME] - sysMetrics[SM_CXEDGE]; + height = sysMetrics[SM_CYDLGFRAME] - sysMetrics[SM_CYEDGE]; + } + else + { + width = sysMetrics[SM_CXFRAME] - sysMetrics[SM_CXEDGE]; + height = sysMetrics[SM_CYFRAME] - sysMetrics[SM_CYEDGE]; + } + + SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER : + COLOR_INACTIVEBORDER) ); + + /* Draw frame */ + PatBlt( hdc, rect->left, rect->top, + rect->right - rect->left, height, PATCOPY ); + PatBlt( hdc, rect->left, rect->top, + width, rect->bottom - rect->top, PATCOPY ); + PatBlt( hdc, rect->left, rect->bottom, + rect->right - rect->left, -height, PATCOPY ); + PatBlt( hdc, rect->right, rect->top, + -width, rect->bottom - rect->top, PATCOPY ); + + InflateRect( rect, -width, -height ); +} + + + +/*********************************************************************** + * NC_DrawMovingFrame + * + * Draw the frame used when moving or resizing window. + * + * FIXME: This causes problems in Win95 mode. (why?) + */ +static void NC_DrawMovingFrame( HDC hdc, RECT *rect, WINBOOL thickframe ) +{ + if (thickframe) + { + FastWindowFrame( hdc, rect, SYSMETRICS_CXFRAME, + SYSMETRICS_CYFRAME, PATINVERT ); + } + else DrawFocusRect( hdc, rect ); +} + + +/*********************************************************************** + * NC_DrawCaption + * + * Draw the window caption. + * The correct pen for the window frame must be selected in the DC. + */ +static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, + DWORD style, WINBOOL active ) +{ + RECT r = *rect; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + char buffer[256]; + + if (wndPtr->flags & WIN_MANAGED) return; + + if (!hbitmapClose) + { + if (!(hbitmapClose = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_CLOSE) ))) + return; + hbitmapCloseD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_CLOSE) ); + hbitmapMinimize = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_REDUCE) ); + hbitmapMinimizeD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_REDUCED) ); + hbitmapMaximize = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_ZOOM) ); + hbitmapMaximizeD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_ZOOMD) ); + hbitmapRestore = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_RESTORE) ); + hbitmapRestoreD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_RESTORED) ); + } + + if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) + { + HBRUSH hbrushOld = SelectObject(hdc, GetSysColorBrush(COLOR_WINDOW) ); + PatBlt( hdc, r.left, r.top, 1, r.bottom-r.top+1,PATCOPY ); + PatBlt( hdc, r.right-1, r.top, 1, r.bottom-r.top+1, PATCOPY ); + PatBlt( hdc, r.left, r.top-1, r.right-r.left, 1, PATCOPY ); + r.left++; + r.right--; + SelectObject( hdc, hbrushOld ); + } + + MoveToEx( hdc, r.left, r.bottom,NULL ); + LineTo( hdc, r.right, r.bottom ); + + if (style & WS_SYSMENU) + { + NC_DrawSysButton( hwnd, hdc, FALSE ); + r.left += SYSMETRICS_CXSIZE + 1; + MoveToEx( hdc, r.left - 1, r.top,NULL ); + LineTo( hdc, r.left - 1, r.bottom ); + } + if (style & WS_MAXIMIZEBOX) + { + NC_DrawMaxButton( hwnd, hdc, FALSE ); + r.right -= SYSMETRICS_CXSIZE + 1; + } + if (style & WS_MINIMIZEBOX) + { + NC_DrawMinButton( hwnd, hdc, FALSE ); + r.right -= SYSMETRICS_CXSIZE + 1; + } + + FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION : + COLOR_INACTIVECAPTION) ); + + if (GetWindowTextA( hwnd, buffer, sizeof(buffer) )) + { + if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) ); + else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ); + SetBkMode( hdc, TRANSPARENT ); + DrawTextA( hdc, buffer, -1, &r, + DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOPREFIX ); + } +} + + +/****************************************************************************** + * + * NC_DrawCaption95( + * HDC hdc, + * RECT *rect, + * HWND hwnd, + * DWORD style, + * WINBOOL active ) + * + * Draw the window caption for Win95 style windows. + * The correct pen for the window frame must be selected in the DC. + * + * Bugs + * Hey, a function that finally works! Well, almost. + * It's being worked on. + * + * Revision history + * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original implementation. + * 02-Jun-1998 Eric Kohl (ekohl@abo.rhein-zeitung.de) + * Some minor fixes. + * + *****************************************************************************/ + +static void NC_DrawCaption95( + HDC hdc, + RECT *rect, + HWND hwnd, + DWORD style, + DWORD exStyle, + WINBOOL active ) +{ + RECT r = *rect; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + char buffer[256]; + HPEN hPrevPen; + + if (wndPtr->flags & WIN_MANAGED) return; + + hPrevPen = SelectObject( hdc, GetSysColorPen(COLOR_3DFACE) ); + MoveToEx( hdc, r.left, r.bottom - 1, NULL ); + LineTo( hdc, r.right, r.bottom - 1 ); + SelectObject( hdc, hPrevPen ); + r.bottom--; + + FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION : + COLOR_INACTIVECAPTION) ); + + if (!hbitmapClose) { + if (!(hbitmapClose = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_CLOSE) ))) + return; + hbitmapMinimize = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_REDUCE) ); + hbitmapMinimizeD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_REDUCED) ); + hbitmapMaximize = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_ZOOM) ); + hbitmapMaximizeD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_ZOOMD) ); + hbitmapRestore = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_RESTORE) ); + hbitmapRestoreD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_RESTORED) ); + } + + if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) { + if (NC_DrawSysButton95 (hwnd, hdc, FALSE)) + r.left += sysMetrics[SM_CYCAPTION] - 1; + } + if (style & WS_SYSMENU) { + NC_DrawCloseButton95 (hwnd, hdc, FALSE); + r.right -= sysMetrics[SM_CYCAPTION] - 1; + } + if (style & WS_MAXIMIZEBOX) { + NC_DrawMaxButton95( hwnd, hdc, FALSE ); + r.right -= SYSMETRICS_CXSIZE + 1; + } + if (style & WS_MINIMIZEBOX) { + NC_DrawMinButton95( hwnd, hdc, FALSE ); + r.right -= SYSMETRICS_CXSIZE + 1; + } + + if (GetWindowTextA( hwnd, buffer, sizeof(buffer) )) { + NONCLIENTMETRICS nclm; + HFONT hFont, hOldFont; + nclm.cbSize = sizeof(NONCLIENTMETRICS); + SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0); + if (exStyle & WS_EX_TOOLWINDOW) + hFont = CreateFontIndirectA (&nclm.lfSmCaptionFont); + else + hFont = CreateFontIndirectA (&nclm.lfCaptionFont); + hOldFont = SelectObject (hdc, hFont); + if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) ); + else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ); + SetBkMode( hdc, TRANSPARENT ); + r.left += 2; + DrawTextA( hdc, buffer, -1, &r, + DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT ); + DeleteObject(SelectObject (hdc, hOldFont)); + } +} + + + +/*********************************************************************** + * NC_DoNCPaint + * + * Paint the non-client area. clip is currently unused. + */ +void NC_DoNCPaint( WND* wndPtr, HRGN clip, WINBOOL suppress_menupaint ) +{ + HDC hdc; + RECT rect; + WINBOOL active; + HWND hwnd = wndPtr->hwndSelf; + + if ( wndPtr->dwStyle & WS_MINIMIZE || + !WIN_IsWindowDrawable( wndPtr, 0 )) return; /* Nothing to do */ + + active = wndPtr->flags & WIN_NCACTIVATED; + + DPRINT( "%04x %d\n", hwnd, active ); + + if (!(hdc = GetDCEx( hwnd, 0, DCX_USESTYLE | DCX_WINDOW ))) return; + + if (ExcludeVisRect( hdc, wndPtr->rectClient.left-wndPtr->rectWindow.left, + wndPtr->rectClient.top-wndPtr->rectWindow.top, + wndPtr->rectClient.right-wndPtr->rectWindow.left, + wndPtr->rectClient.bottom-wndPtr->rectWindow.top ) + == NULLREGION) + { + ReleaseDC( hwnd, hdc ); + return; + } + + rect.top = rect.left = 0; + rect.right = wndPtr->rectWindow.right - wndPtr->rectWindow.left; + rect.bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top; + + SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) ); + + if (!(wndPtr->flags & WIN_MANAGED)) + { + if ((wndPtr->dwStyle & WS_BORDER) || (wndPtr->dwStyle & WS_DLGFRAME) || + (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)) + { + SelectObject( hdc, GetStockObject(NULL_BRUSH) ); + Rectangle( hdc, 0, 0, rect.right, rect.bottom ); + InflateRect( &rect, -1, -1 ); + } + + if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle )) + NC_DrawFrame( hdc, &rect, TRUE, active ); + else if (wndPtr->dwStyle & WS_THICKFRAME) + NC_DrawFrame(hdc, &rect, FALSE, active ); + + if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION) + { + RECT r = rect; + r.bottom = rect.top + SYSMETRICS_CYSIZE; + rect.top += SYSMETRICS_CYSIZE + SYSMETRICS_CYBORDER; + NC_DrawCaption( hdc, &r, hwnd, wndPtr->dwStyle, active ); + } + } + + if (HAS_MENU(wndPtr)) + { + RECT r = rect; + r.bottom = rect.top + SYSMETRICS_CYMENU; /* default height */ + rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ); + } + + /* Draw the scroll-bars */ + + if (wndPtr->dwStyle & WS_VSCROLL) + SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE ); + if (wndPtr->dwStyle & WS_HSCROLL) + SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE ); + + /* Draw the "size-box" */ + + if ((wndPtr->dwStyle & WS_VSCROLL) && (wndPtr->dwStyle & WS_HSCROLL)) + { + RECT r = rect; + r.left = r.right - SYSMETRICS_CXVSCROLL + 1; + r.top = r.bottom - SYSMETRICS_CYHSCROLL + 1; + if(wndPtr->dwStyle & WS_BORDER) { + r.left++; + r.top++; + } + FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) ); + } + + ReleaseDC( hwnd, hdc ); +} + + +/****************************************************************************** + * + * void NC_DoNCPaint95( + * WND *wndPtr, + * HRGN clip, + * WINBOOL suppress_menupaint ) + * + * Paint the non-client area for Win95 windows. The clip region is + * currently ignored. + * + * Bugs + * grep -E -A10 -B5 \(95\)\|\(Bugs\)\|\(FIXME\) windows/nonclient.c \ + * misc/tweak.c controls/menu.c # :-) + * + * Revision history + * 03-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original implementation + * 10-Jun-1998 Eric Kohl (ekohl@abo.rhein-zeitung.de) + * Fixed some bugs. + * + *****************************************************************************/ + +void NC_DoNCPaint95( + WND *wndPtr, + HRGN clip, + WINBOOL suppress_menupaint ) +{ + HDC hdc; + RECT rect; + WINBOOL active; + HWND hwnd = wndPtr->hwndSelf; + + if ( wndPtr->dwStyle & WS_MINIMIZE || + !WIN_IsWindowDrawable( wndPtr, 0 )) return; /* Nothing to do */ + + active = wndPtr->flags & WIN_NCACTIVATED; + + DPRINT( "%04x %d\n", hwnd, active ); + + if (!(hdc = GetDCEx( hwnd, 0, DCX_USESTYLE | DCX_WINDOW ))) return; + + if (ExcludeVisRect( hdc, wndPtr->rectClient.left-wndPtr->rectWindow.left, + wndPtr->rectClient.top-wndPtr->rectWindow.top, + wndPtr->rectClient.right-wndPtr->rectWindow.left, + wndPtr->rectClient.bottom-wndPtr->rectWindow.top ) + == NULLREGION) + { + ReleaseDC( hwnd, hdc ); + return; + } + + rect.top = rect.left = 0; + rect.right = wndPtr->rectWindow.right - wndPtr->rectWindow.left; + rect.bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top; + + SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) ); + + if(!(wndPtr->flags & WIN_MANAGED)) { + if ((wndPtr->dwStyle & WS_BORDER) && ((wndPtr->dwStyle & WS_DLGFRAME) || + (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) || (wndPtr->dwStyle & WS_THICKFRAME))) { + DrawEdge(hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST); + } + + if (HAS_FIXEDFRAME( wndPtr->dwStyle, wndPtr->dwExStyle )) + NC_DrawFrame95( hdc, &rect, TRUE, active ); + else if (wndPtr->dwStyle & WS_THICKFRAME) + NC_DrawFrame95(hdc, &rect, FALSE, active ); + + if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION) + { + RECT r = rect; + if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW) { + r.bottom = rect.top + sysMetrics[SM_CYSMCAPTION]; + rect.top += sysMetrics[SM_CYSMCAPTION]; + } + else { + r.bottom = rect.top + sysMetrics[SM_CYCAPTION]; + rect.top += sysMetrics[SM_CYCAPTION]; + } + NC_DrawCaption95 (hdc, &r, hwnd, wndPtr->dwStyle, + wndPtr->dwExStyle, active); + } + } + + if (HAS_MENU(wndPtr)) + { + RECT r = rect; + r.bottom = rect.top + sysMetrics[SM_CYMENU]; + + DPRINT( "Calling DrawMenuBar with " + "rect (%d, %d)-(%d, %d)\n", r.left, r.top, + r.right, r.bottom); + + rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1; + } + + DPRINT( "After MenuBar, rect is (%d, %d)-(%d, %d).\n", + rect.left, rect.top, rect.right, rect.bottom ); + + if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE) + DrawEdge(hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + + if (wndPtr->dwExStyle & WS_EX_STATICEDGE) + DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST); + + /* Draw the scroll-bars */ + + if (wndPtr->dwStyle & WS_VSCROLL) + SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE ); + if (wndPtr->dwStyle & WS_HSCROLL) + SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE ); + + /* Draw the "size-box" */ + if ((wndPtr->dwStyle & WS_VSCROLL) && (wndPtr->dwStyle & WS_HSCROLL)) + { + RECT r = rect; + r.left = r.right - SYSMETRICS_CXVSCROLL + 1; + r.top = r.bottom - SYSMETRICS_CYHSCROLL + 1; + FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) ); + } + + ReleaseDC( hwnd, hdc ); +} + + + + +/*********************************************************************** + * NC_HandleNCPaint + * + * Handle a WM_NCPAINT message. Called from DefWindowProc(). + */ +LONG NC_HandleNCPaint( HWND hwnd , HRGN clip) +{ + WND* wndPtr = WIN_FindWndPtr( hwnd ); + + if( wndPtr && wndPtr->dwStyle & WS_VISIBLE ) + { + if( wndPtr->dwStyle & WS_MINIMIZE ) + WINPOS_RedrawIconTitle( hwnd ); + else if (TWEAK_WineLook == WIN31_LOOK) + NC_DoNCPaint( wndPtr, clip, FALSE ); + else + NC_DoNCPaint95( wndPtr, clip, FALSE ); + } + return 0; +} + + +/*********************************************************************** + * NC_HandleNCActivate + * + * Handle a WM_NCACTIVATE message. Called from DefWindowProc(). + */ +LONG NC_HandleNCActivate( WND *wndPtr, WPARAM wParam ) +{ + WORD wStateChange; + + if( wParam ) wStateChange = !(wndPtr->flags & WIN_NCACTIVATED); + else wStateChange = wndPtr->flags & WIN_NCACTIVATED; + + if( wStateChange ) + { + if (wParam) wndPtr->flags |= WIN_NCACTIVATED; + else wndPtr->flags &= ~WIN_NCACTIVATED; + + if( wndPtr->dwStyle & WS_MINIMIZE ) + WINPOS_RedrawIconTitle( wndPtr->hwndSelf ); + else if (TWEAK_WineLook == WIN31_LOOK) + NC_DoNCPaint( wndPtr, (HRGN)1, FALSE ); + else + NC_DoNCPaint95( wndPtr, (HRGN)1, FALSE ); + } + return TRUE; +} + + +/*********************************************************************** + * NC_HandleSetCursor + * + * Handle a WM_SETCURSOR message. Called from DefWindowProc(). + */ +LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam ) +{ + if (hwnd != (HWND)wParam) return 0; /* Don't set the cursor for child windows */ + + switch(LOWORD(lParam)) + { + case HTERROR: + { + WORD msg = HIWORD( lParam ); + if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) || + (msg == WM_RBUTTONDOWN)) + MessageBeep(0); + } + break; + + case HTCLIENT: + { + WND *wndPtr; + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) break; + if (wndPtr->class->hCursor) + { + SetCursor( wndPtr->class->hCursor ); + return TRUE; + } + else return FALSE; + } + + case HTLEFT: + case HTRIGHT: + return (LONG)SetCursor( LoadCursorA( 0, IDC_SIZEWE ) ); + + case HTTOP: + case HTBOTTOM: + return (LONG)SetCursor( LoadCursorA( 0, IDC_SIZENS ) ); + + case HTTOPLEFT: + case HTBOTTOMRIGHT: + return (LONG)SetCursor( LoadCursorA( 0, IDC_SIZENWSE ) ); + + case HTTOPRIGHT: + case HTBOTTOMLEFT: + return (LONG)SetCursor( LoadCursorA( 0, IDC_SIZENESW ) ); + } + + /* Default cursor: arrow */ + return (LONG)SetCursor( LoadCursorA( 0, IDC_ARROW ) ); +} + +/*********************************************************************** + * NC_GetSysPopupPos + */ +WINBOOL NC_GetSysPopupPos( WND* wndPtr, RECT* rect ) +{ + if( wndPtr->hSysMenu ) + { + if( wndPtr->dwStyle & WS_MINIMIZE ) + GetWindowRect( wndPtr->hwndSelf, rect ); + else + { + if (TWEAK_WineLook == WIN31_LOOK) + NC_GetInsideRect( wndPtr->hwndSelf, rect ); + else + NC_GetInsideRect95( wndPtr->hwndSelf, rect ); + OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top); + if (wndPtr->dwStyle & WS_CHILD) + ClientToScreen( wndPtr->parent->hwndSelf, (POINT *)rect ); + if (TWEAK_WineLook == WIN31_LOOK) { + rect->right = rect->left + SYSMETRICS_CXSIZE; + rect->bottom = rect->top + SYSMETRICS_CYSIZE; + } + else { + rect->right = rect->left + sysMetrics[SM_CYCAPTION] - 1; + rect->bottom = rect->top + sysMetrics[SM_CYCAPTION] - 1; + } + } + return TRUE; + } + return FALSE; +} + +/*********************************************************************** + * NC_StartSizeMove + * + * Initialisation of a move or resize, when initiatied from a menu choice. + * Return hit test code for caption or sizing border. + */ +static LONG NC_StartSizeMove( WND* wndPtr, WPARAM wParam, + POINT *capturePoint ) +{ + LONG hittest = 0; + POINT pt; + MSG msg; + + if ((wParam & 0xfff0) == SC_MOVE) + { + /* Move pointer at the center of the caption */ + RECT rect; + if (TWEAK_WineLook == WIN31_LOOK) + NC_GetInsideRect( wndPtr->hwndSelf, &rect ); + else + NC_GetInsideRect95( wndPtr->hwndSelf, &rect ); + if (wndPtr->dwStyle & WS_SYSMENU) + rect.left += SYSMETRICS_CXSIZE + 1; + if (wndPtr->dwStyle & WS_MINIMIZEBOX) + rect.right -= SYSMETRICS_CXSIZE + 1; + if (wndPtr->dwStyle & WS_MAXIMIZEBOX) + rect.right -= SYSMETRICS_CXSIZE + 1; + pt.x = wndPtr->rectWindow.left + (rect.right - rect.left) / 2; + pt.y = wndPtr->rectWindow.top + rect.top + SYSMETRICS_CYSIZE/2; + hittest = HTCAPTION; + *capturePoint = pt; + } + else /* SC_SIZE */ + { + while(!hittest) + { + MSG_InternalGetMessage( &msg, 0, 0, MSGF_SIZE, PM_REMOVE, FALSE ); + switch(msg.message) + { + case WM_MOUSEMOVE: + hittest = NC_HandleNCHitTest( wndPtr->hwndSelf, msg.pt ); + pt = msg.pt; + if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) + hittest = 0; + break; + + case WM_LBUTTONUP: + return 0; + + case WM_KEYDOWN: + switch(msg.wParam) + { + case VK_UP: + hittest = HTTOP; + pt.x =(wndPtr->rectWindow.left+wndPtr->rectWindow.right)/2; + pt.y = wndPtr->rectWindow.top + SYSMETRICS_CYFRAME / 2; + break; + case VK_DOWN: + hittest = HTBOTTOM; + pt.x =(wndPtr->rectWindow.left+wndPtr->rectWindow.right)/2; + pt.y = wndPtr->rectWindow.bottom - SYSMETRICS_CYFRAME / 2; + break; + case VK_LEFT: + hittest = HTLEFT; + pt.x = wndPtr->rectWindow.left + SYSMETRICS_CXFRAME / 2; + pt.y =(wndPtr->rectWindow.top+wndPtr->rectWindow.bottom)/2; + break; + case VK_RIGHT: + hittest = HTRIGHT; + pt.x = wndPtr->rectWindow.right - SYSMETRICS_CXFRAME / 2; + pt.y =(wndPtr->rectWindow.top+wndPtr->rectWindow.bottom)/2; + break; + case VK_RETURN: + case VK_ESCAPE: return 0; + } + } + } + *capturePoint = pt; + } + SetCursorPos( pt.x, pt.y ); + NC_HandleSetCursor( wndPtr->hwndSelf, + wndPtr->hwndSelf, MAKELONG( hittest, WM_MOUSEMOVE )); + return hittest; +} + + +/*********************************************************************** + * NC_DoSizeMove + * + * Perform SC_MOVE and SC_SIZE commands. + */ +static void NC_DoSizeMove( HWND hwnd, WORD wParam ) +{ + MSG msg; + RECT sizingRect, mouseRect; + HDC hdc; + LONG hittest = (LONG)(wParam & 0x0f); + HCURSOR hDragCursor = 0, hOldCursor = 0; + POINT minTrack, maxTrack; + POINT capturePoint, pt; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + WINBOOL thickframe = HAS_THICKFRAME( wndPtr->dwStyle ); + WINBOOL iconic = wndPtr->dwStyle & WS_MINIMIZE; + WINBOOL moved = FALSE; + DWORD dwPoint = GetMessagePos (); + + capturePoint = pt = *(POINT*)&dwPoint; + + if (IsZoomed(hwnd) || !IsWindowVisible(hwnd) || + (wndPtr->flags & WIN_MANAGED)) return; + + if ((wParam & 0xfff0) == SC_MOVE) + { + if (!(wndPtr->dwStyle & WS_CAPTION)) return; + if (!hittest) + hittest = NC_StartSizeMove( wndPtr, wParam, &capturePoint ); + if (!hittest) return; + } + else /* SC_SIZE */ + { + if (!thickframe) return; + if ( hittest && hittest != HTSYSMENU ) hittest += 2; + else + { + SetCapture(hwnd); + hittest = NC_StartSizeMove( wndPtr, wParam, &capturePoint ); + if (!hittest) + { + ReleaseCapture(); + return; + } + } + } + + /* Get min/max info */ + + WINPOS_GetMinMaxInfo( wndPtr, NULL, NULL, &minTrack, &maxTrack ); + sizingRect = wndPtr->rectWindow; + if (wndPtr->dwStyle & WS_CHILD) + GetClientRect( wndPtr->parent->hwndSelf, &mouseRect ); + else + SetRect(&mouseRect, 0, 0, SYSMETRICS_CXSCREEN, SYSMETRICS_CYSCREEN); + if (ON_LEFT_BORDER(hittest)) + { + mouseRect.left = max( mouseRect.left, sizingRect.right-maxTrack.x ); + mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x ); + } + else if (ON_RIGHT_BORDER(hittest)) + { + mouseRect.left = max( mouseRect.left, sizingRect.left+minTrack.x ); + mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x ); + } + if (ON_TOP_BORDER(hittest)) + { + mouseRect.top = max( mouseRect.top, sizingRect.bottom-maxTrack.y ); + mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y); + } + else if (ON_BOTTOM_BORDER(hittest)) + { + mouseRect.top = max( mouseRect.top, sizingRect.top+minTrack.y ); + mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y ); + } + if (wndPtr->dwStyle & WS_CHILD) + { + MapWindowPoints( wndPtr->parent->hwndSelf, 0, + (LPPOINT)&mouseRect, 2 ); + } + SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 ); + + if (GetCapture() != hwnd) SetCapture( hwnd ); + + if (wndPtr->dwStyle & WS_CHILD) + { + /* Retrieve a default cache DC (without using the window style) */ + hdc = GetDCEx( wndPtr->parent->hwndSelf, 0, DCX_CACHE ); + } + else + { /* Grab the server only when moving top-level windows without desktop */ + hdc = GetDC( 0 ); + } + +// wndPtr->pDriver->pPreSizeMove(wndPtr); + + if( iconic ) /* create a cursor for dragging */ + { + HICON hIcon = (wndPtr->class->hIcon) ? wndPtr->class->hIcon + : (HICON)SendMessageA( hwnd, WM_QUERYDRAGICON, 0, 0L); +// if( hIcon ) hDragCursor = CURSORICON_IconToCursor( hIcon, TRUE ); + if( !hDragCursor ) iconic = FALSE; + } + + if( !iconic ) NC_DrawMovingFrame( hdc, &sizingRect, thickframe ); + + while(1) + { + int dx = 0, dy = 0; + + MSG_InternalGetMessage( &msg, 0, 0, MSGF_SIZE, PM_REMOVE, FALSE ); + + /* Exit on button-up, Return, or Esc */ + if ((msg.message == WM_LBUTTONUP) || + ((msg.message == WM_KEYDOWN) && + ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break; + + if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE)) + continue; /* We are not interested in other messages */ + + dwPoint = GetMessagePos (); + pt = *(POINT*)&dwPoint; + + if (msg.message == WM_KEYDOWN) switch(msg.wParam) + { + case VK_UP: pt.y -= 8; break; + case VK_DOWN: pt.y += 8; break; + case VK_LEFT: pt.x -= 8; break; + case VK_RIGHT: pt.x += 8; break; + } + + pt.x = max( pt.x, mouseRect.left ); + pt.x = min( pt.x, mouseRect.right ); + pt.y = max( pt.y, mouseRect.top ); + pt.y = min( pt.y, mouseRect.bottom ); + + dx = pt.x - capturePoint.x; + dy = pt.y - capturePoint.y; + + if (dx || dy) + { + if( !moved ) + { + moved = TRUE; + if( iconic ) /* ok, no system popup tracking */ + { + hOldCursor = SetCursor(hDragCursor); + ShowCursor( TRUE ); + WINPOS_ShowIconTitle( wndPtr, FALSE ); + } + } + + if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y ); + else + { + RECT newRect = sizingRect; + + if (hittest == HTCAPTION) OffsetRect( &newRect, dx, dy ); + if (ON_LEFT_BORDER(hittest)) newRect.left += dx; + else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx; + if (ON_TOP_BORDER(hittest)) newRect.top += dy; + else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy; + if( !iconic ) + { + NC_DrawMovingFrame( hdc, &sizingRect, thickframe ); + NC_DrawMovingFrame( hdc, &newRect, thickframe ); + } + capturePoint = pt; + sizingRect = newRect; + } + } + } + + ReleaseCapture(); + if( iconic ) + { + if( moved ) /* restore cursors, show icon title later on */ + { + ShowCursor( FALSE ); + SetCursor( hOldCursor ); + } + DestroyCursor( hDragCursor ); + } + else + NC_DrawMovingFrame( hdc, &sizingRect, thickframe ); + + if (wndPtr->dwStyle & WS_CHILD) + ReleaseDC( wndPtr->parent->hwndSelf, hdc ); + else + { + ReleaseDC( 0, hdc ); + } + +// wndPtr->pDriver->pPostSizeMove(wndPtr); + + if (HOOK_IsHooked( WH_CBT )) + { + if ( wndPtr->class->bUnicode == FALSE ) { + if( HOOK_CallHooksA( WH_CBT, HCBT_MOVESIZE, hwnd,(LPARAM)&sizingRect) ) + sizingRect = wndPtr->rectWindow; + } + else { + if( HOOK_CallHooksW( WH_CBT, HCBT_MOVESIZE, hwnd,(LPARAM)&sizingRect) ) + sizingRect = wndPtr->rectWindow; + } + } + SendMessageA( hwnd, WM_EXITSIZEMOVE, 0, (LPARAM)0 ); + SendMessageA( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), (LPARAM)0); + + if( moved && !((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) ) + { + /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */ + SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top, + sizingRect.right - sizingRect.left, + sizingRect.bottom - sizingRect.top, + ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 ); + } + + if( IsWindow(hwnd) ) + if( wndPtr->dwStyle & WS_MINIMIZE ) + { + /* Single click brings up the system menu when iconized */ + + if( !moved ) + { + if( wndPtr->dwStyle & WS_SYSMENU ) + SendMessageA( hwnd, WM_SYSCOMMAND, + SC_MOUSEMENU + HTSYSMENU, *((LPARAM*)&pt)); + } + else WINPOS_ShowIconTitle( wndPtr, TRUE ); + } +} + + +/*********************************************************************** + * NC_TrackMinMaxBox + * + * Track a mouse button press on the minimize or maximize box. + */ +static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam ) +{ + MSG msg; + HDC hdc = GetWindowDC( hwnd ); + WINBOOL pressed = TRUE; + void (*paintButton)(HWND, HDC, WINBOOL); + + SetCapture( hwnd ); + if (wParam == HTMINBUTTON) + paintButton = + (TWEAK_WineLook == WIN31_LOOK) ? &NC_DrawMinButton : &NC_DrawMinButton95; + else + paintButton = + (TWEAK_WineLook == WIN31_LOOK) ? &NC_DrawMaxButton : &NC_DrawMaxButton95; + + (*paintButton)( hwnd, hdc, TRUE ); + + do + { + WINBOOL oldstate = pressed; + MSG_InternalGetMessage( &msg, 0, 0, 0, PM_REMOVE, FALSE ); + + pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam); + if (pressed != oldstate) + (*paintButton)( hwnd, hdc, pressed ); + } while (msg.message != WM_LBUTTONUP); + + (*paintButton)( hwnd, hdc, FALSE ); + + ReleaseCapture(); + ReleaseDC( hwnd, hdc ); + if (!pressed) return; + + if (wParam == HTMINBUTTON) + SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, *(LONG*)&msg.pt ); + else + SendMessageA( hwnd, WM_SYSCOMMAND, + IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, *(LONG*)&msg.pt ); +} + + +/*********************************************************************** + * NC_TrackCloseButton95 + * + * Track a mouse button press on the Win95 close button. + */ +static void +NC_TrackCloseButton95 (HWND hwnd, WORD wParam) +{ + MSG msg; + HDC hdc = GetWindowDC( hwnd ); + WINBOOL pressed = TRUE; + + SetCapture( hwnd ); + + NC_DrawCloseButton95 (hwnd, hdc, TRUE); + + do + { + WINBOOL oldstate = pressed; + MSG_InternalGetMessage( &msg, 0, 0, 0, PM_REMOVE, FALSE ); + + pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam); + if (pressed != oldstate) + NC_DrawCloseButton95 (hwnd, hdc, pressed); + } while (msg.message != WM_LBUTTONUP); + + NC_DrawCloseButton95 (hwnd, hdc, FALSE); + + ReleaseCapture(); + ReleaseDC( hwnd, hdc ); + if (!pressed) return; + + SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, *(LONG*)&msg.pt ); +} + + +/*********************************************************************** + * NC_TrackScrollBar + * + * Track a mouse button press on the horizontal or vertical scroll-bar. + */ +static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt ) +{ + MSG *msg; + INT scrollbar; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + if ((wParam & 0xfff0) == SC_HSCROLL) + { + if ((wParam & 0x0f) != HTHSCROLL) return; + scrollbar = SB_HORZ; + } + else /* SC_VSCROLL */ + { + if ((wParam & 0x0f) != HTVSCROLL) return; + scrollbar = SB_VERT; + } + + if (!(msg = malloc(sizeof(MSG)))) return; + pt.x -= wndPtr->rectWindow.left; + pt.y -= wndPtr->rectWindow.top; + SetCapture( hwnd ); + SCROLL_HandleScrollEvent( hwnd, scrollbar, WM_LBUTTONDOWN, pt ); + + do + { + GetMessageA( (msg), 0, 0, 0 ); + switch(msg->message) + { + case WM_LBUTTONUP: + case WM_MOUSEMOVE: + case WM_SYSTIMER: + pt.x = LOWORD(msg->lParam) + wndPtr->rectClient.left - + wndPtr->rectWindow.left; + pt.y = HIWORD(msg->lParam) + wndPtr->rectClient.top - + wndPtr->rectWindow.top; + SCROLL_HandleScrollEvent( hwnd, scrollbar, msg->message, pt ); + break; + default: + TranslateMessage( msg ); + DispatchMessage( msg ); + break; + } + if (!IsWindow( hwnd )) + { + ReleaseCapture(); + break; + } + } while (msg->message != WM_LBUTTONUP); + free(msg); +} + +/*********************************************************************** + * NC_HandleNCLButtonDown + * + * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc(). + */ +LONG NC_HandleNCLButtonDown( WND* pWnd, WPARAM wParam, LPARAM lParam ) +{ + HWND hwnd = pWnd->hwndSelf; + + switch(wParam) /* Hit test */ + { + case HTCAPTION: + hwnd = WIN_GetTopParent(hwnd); + + if( WINPOS_SetActiveWindow(hwnd, TRUE, TRUE) || (GetActiveWindow() == hwnd) ) + SendMessageA( pWnd->hwndSelf, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam ); + break; + + case HTSYSMENU: + if( pWnd->dwStyle & WS_SYSMENU ) + { + if( !(pWnd->dwStyle & WS_MINIMIZE) ) + { + HDC hDC = GetWindowDC(hwnd); + if (TWEAK_WineLook == WIN31_LOOK) + NC_DrawSysButton( hwnd, hDC, TRUE ); + else + NC_DrawSysButton95( hwnd, hDC, TRUE ); + ReleaseDC( hwnd, hDC ); + } + SendMessageA( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam ); + } + break; + + case HTMENU: + SendMessageA( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam ); + break; + + case HTHSCROLL: + SendMessageA( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam ); + break; + + case HTVSCROLL: + SendMessageA( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam ); + break; + + case HTMINBUTTON: + case HTMAXBUTTON: + NC_TrackMinMaxBox( hwnd, wParam ); + break; + + case HTCLOSE: + if (TWEAK_WineLook >= WIN95_LOOK) + NC_TrackCloseButton95 (hwnd, wParam); + break; + + case HTLEFT: + case HTRIGHT: + case HTTOP: + case HTTOPLEFT: + case HTTOPRIGHT: + case HTBOTTOM: + case HTBOTTOMLEFT: + case HTBOTTOMRIGHT: + /* make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU */ + SendMessageA( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - 2, lParam); + break; + + case HTBORDER: + break; + } + return 0; +} + + +/*********************************************************************** + * NC_HandleNCLButtonDblClk + * + * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc(). + */ +LONG NC_HandleNCLButtonDblClk( WND *pWnd, WPARAM wParam, LPARAM lParam ) +{ + /* + * if this is an icon, send a restore since we are handling + * a double click + */ + if (pWnd->dwStyle & WS_MINIMIZE) + { + SendMessageA( pWnd->hwndSelf, WM_SYSCOMMAND, SC_RESTORE, lParam ); + return 0; + } + + switch(wParam) /* Hit test */ + { + case HTCAPTION: + /* stop processing if WS_MAXIMIZEBOX is missing */ + if (pWnd->dwStyle & WS_MAXIMIZEBOX) + SendMessageA( pWnd->hwndSelf, WM_SYSCOMMAND, + (pWnd->dwStyle & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE, + lParam ); + break; + + case HTSYSMENU: + if (!(pWnd->class->style & CS_NOCLOSE)) + SendMessageA( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, lParam ); + break; + + case HTHSCROLL: + SendMessageA( pWnd->hwndSelf, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, + lParam ); + break; + + case HTVSCROLL: + SendMessageA( pWnd->hwndSelf, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, + lParam ); + break; + } + return 0; +} + + +/*********************************************************************** + * NC_HandleSysCommand + * + * Handle a WM_SYSCOMMAND message. Called from DefWindowProc(). + */ +LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, POINT pt ) +{ + WND *wndPtr = WIN_FindWndPtr( hwnd ); + UINT uCommand = wParam & 0xFFF0; + + DPRINT( "Handling WM_SYSCOMMAND %x %d,%d\n", + wParam, pt.x, pt.y ); + + if (wndPtr->dwStyle & WS_CHILD && uCommand != SC_KEYMENU ) + ScreenToClient( wndPtr->parent->hwndSelf, &pt ); + + switch (uCommand) + { + case SC_SIZE: + case SC_MOVE: + NC_DoSizeMove( hwnd, wParam ); + break; + + case SC_MINIMIZE: + ShowWindow( hwnd, SW_MINIMIZE ); + break; + + case SC_MAXIMIZE: + ShowWindow( hwnd, SW_MAXIMIZE ); + break; + + case SC_RESTORE: + ShowWindow( hwnd, SW_RESTORE ); + break; + + case SC_CLOSE: + return SendMessageA( hwnd, WM_CLOSE, 0, 0 ); + + case SC_VSCROLL: + case SC_HSCROLL: + NC_TrackScrollBar( hwnd, wParam, pt ); + break; + + case SC_MOUSEMENU: + MENU_TrackMouseMenuBar( wndPtr, wParam & 0x000F, pt ); + break; + + case SC_KEYMENU: + MENU_TrackKbdMenuBar( wndPtr , wParam , pt.x ); + break; + + case SC_TASKLIST: + WinExec( "taskman.exe", SW_SHOWNORMAL ); + break; + + case SC_SCREENSAVE: + if (wParam == SC_ABOUTWINE) { + //ShellAboutA(hwnd,"Wine", WINE_RELEASE_INFO, 0); + } + else + if (wParam == SC_PUTMARK) + DPRINT("Mark requested by user\n"); + break; + + case SC_HOTKEY: + case SC_ARRANGE: + case SC_NEXTWINDOW: + case SC_PREVWINDOW: + DPRINT( "unimplemented!\n"); + break; + } + return 0; +} + + +/*********************************************************************** + * FastWindowFrame (GDI.400) + */ +WINBOOL STDCALL FastWindowFrame( HDC hdc, const RECT *rect, + INT width, INT height, DWORD rop ) +{ + HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) ); + PatBlt( hdc, rect->left, rect->top, + rect->right - rect->left - width, height, rop ); + PatBlt( hdc, rect->left, rect->top + height, width, + rect->bottom - rect->top - height, rop ); + PatBlt( hdc, rect->left + width, rect->bottom, + rect->right - rect->left - width, -height, rop ); + PatBlt( hdc, rect->right, rect->top, -width, + rect->bottom - rect->top - height, rop ); + SelectObject( hdc, hbrush ); + return TRUE; +} \ No newline at end of file diff --git a/reactos/lib/user32/internal/property.c b/reactos/lib/user32/internal/property.c new file mode 100644 index 00000000000..84744fe122d --- /dev/null +++ b/reactos/lib/user32/internal/property.c @@ -0,0 +1,138 @@ + /* + * Window properties + * + * Copyright 1995, 1996 Alexandre Julliard + */ + +#include +#include +#include + + +/*********************************************************************** + * PROP_FindProp + */ +HANDLE PROPERTY_FindProp( HWND hwnd, ATOM atom ) +{ + + PROPERTY *prop; + WND *pWnd = WIN_FindWndPtr( hwnd ); + + if (!pWnd) + return NULL; + + + for (prop = pWnd->pProp; (prop); prop = prop->next) + { + + if ( prop->atom == atom) + return prop->handle; + } + return NULL; +} + +WINBOOL PROPERTY_SetProp(HANDLE hwnd,ATOM atom,HANDLE hData) +{ + PROPERTY *prop; + if (!(prop = PROPERTY_FindProp( hwnd, atom ))) + { + /* We need to create it */ + WND *pWnd = WIN_FindWndPtr( hwnd ); + if (!pWnd) + return FALSE; + if (!(prop = HeapAlloc( GetProcessHeap(), 0, sizeof(PROPERTY) ))) + return FALSE; + + prop->next = pWnd->pProp; + pWnd->pProp = prop; + prop->atom = atom; + prop->handle = hData; + } + else { + prop->handle = hData; + } + return TRUE; + +} + + + +HANDLE PROPERTY_RemoveProp( HANDLE hwnd , ATOM atom ) +{ + HANDLE handle = NULL; + PROPERTY **pprop, *prop; + WND *pWnd = WIN_FindWndPtr( hwnd ); + + + if (!pWnd) + return (HANDLE)0; + + for (pprop=(PROPERTY**)&pWnd->pProp; (*pprop); pprop = &(*pprop)->next) + { + + if ( (*pprop)->atom == atom ) { + prop = *pprop; + handle = prop->handle; + *pprop = prop->next; + HeapFree( GetProcessHeap(), 0, prop ); + break; + + } + } + + + return handle; +} + +/*********************************************************************** + * PROPERTY_RemoveWindowProps + * + * Remove all properties of a window. + */ +void PROPERTY_RemoveWindowProps( HANDLE hwnd ) +{ + + PROPERTY *prop, *next; + WND *pWnd = WIN_FindWndPtr( hwnd ); + + + if (!pWnd) + return (HANDLE)0; + + + + for (prop = pWnd->pProp; (prop); prop = next) + { + next = prop->next; + HeapFree(GetProcessHeap(),0, prop ); + + } + pWnd->pProp = NULL; +} + + +WINBOOL PROPERTY_EnumPropEx(HWND hwnd, PROPVALUE **pv , int maxsize, int *size ) +{ + PROPERTY *prop, *next; + WND *pWnd; + INT ret = -1; + int i; + + if (!(pWnd = WIN_FindWndPtr( hwnd ))) + return FALSE; + for (prop = pWnd->pProp; (prop); prop = next) + { + /* Already get the next in case the callback */ + /* function removes the current property. */ + next = prop->next; + pv[i]->hwnd = hwnd; + pv[i]->handle = prop->handle; + pv[i]->atom = prop->atom; + i++; + if ( i > maxsize ) + return FALSE; + + } + return TRUE; +} + diff --git a/reactos/lib/user32/internal/queue.c b/reactos/lib/user32/internal/queue.c new file mode 100644 index 00000000000..9ccf3750fec --- /dev/null +++ b/reactos/lib/user32/internal/queue.c @@ -0,0 +1,706 @@ +/* + * Message queues related functions + * + * Copyright 1993, 1994 Alexandre Julliard + */ + +#include +#include +#include +#include + + +HWND GetSysModalWindow(void); + +#define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */ + +static HQUEUE hFirstQueue = 0; +static HQUEUE hExitingQueue = 0; +static HQUEUE hmemSysMsgQueue = 0; +static MESSAGEQUEUE *sysMsgQueue = NULL; + +static MESSAGEQUEUE *pMouseQueue = NULL; /* Queue for last mouse message */ +static MESSAGEQUEUE *pKbdQueue = NULL; /* Queue for last kbd message */ + +MESSAGEQUEUE *pCursorQueue = NULL; +MESSAGEQUEUE *pActiveQueue = NULL; + +/*********************************************************************** + * QUEUE_DumpQueue + */ +void QUEUE_DumpQueue( HQUEUE hQueue ) +{ + MESSAGEQUEUE *pq; + + if (!(pq = (MESSAGEQUEUE*) GlobalLock( hQueue )) || + GlobalSize(hQueue) < sizeof(MESSAGEQUEUE)+pq->queueSize*sizeof(QMSG)) + { + DPRINT( "%04x is not a queue handle\n", hQueue ); + return; + } + + DPRINT( "next: %12.4x Intertask SendMessage:\n" + "hTask: %11.4x ----------------------\n" + "msgSize: %9.4x hWnd: %10.4x\n" + "msgCount: %8.4x msg: %11.4x\n" + "msgNext: %9.4x wParam: %8.4x\n" + "msgFree: %9.4x lParam: %8.8x\n" + "qSize: %11.4x lRet: %10.8x\n" + "wWinVer: %9.4x ISMH: %10.4x\n" + "paints: %10.4x hSendTask: %5.4x\n" + "timers: %10.4x hPrevSend: %5.4x\n" + "wakeBits: %8.4x\n" + "wakeMask: %8.4x\n" + "hCurHook: %8.4x\n", + pq->next, pq->hTask, pq->msgSize, pq->hWnd, + pq->msgCount, pq->msg, pq->nextMessage, pq->wParam, + pq->nextFreeMessage, (unsigned)pq->lParam, pq->queueSize, + (unsigned)pq->SendMessageReturn, pq->wWinVersion, pq->InSendMessageHandle, + pq->wPaintCount, pq->hSendingTask, pq->wTimerCount, + pq->hPrevSendingTask, pq->wakeBits, pq->wakeMask, pq->hCurHook); +} + + +/*********************************************************************** + * QUEUE_WalkQueues + */ +void QUEUE_WalkQueues(void) +{ + char module[10]; + HQUEUE hQueue = hFirstQueue; + + DPRINT( "Queue Size Msgs Task\n" ); + while (hQueue) + { + MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock( hQueue ); + if (!queue) + { + DPRINT( "Bad queue handle %04x\n", hQueue ); + return; + } +// if (!GetModuleFileName( queue->hTask, module, sizeof(module ))) +// strcpy( module, "???" ); +// DPRINT( "%04x %5d %4d %04x %s\n", hQueue, queue->msgSize, +// queue->msgCount, queue->hTask, module ); + hQueue = queue->next; + } + DPRINT( "\n" ); +} + + +/*********************************************************************** + * QUEUE_IsExitingQueue + */ +WINBOOL QUEUE_IsExitingQueue( HQUEUE hQueue ) +{ + return (hExitingQueue && (hQueue == hExitingQueue)); +} + + +/*********************************************************************** + * QUEUE_SetExitingQueue + */ +void QUEUE_SetExitingQueue( HQUEUE hQueue ) +{ + hExitingQueue = hQueue; +} + + +/*********************************************************************** + * QUEUE_CreateMsgQueue + * + * Creates a message queue. Doesn't link it into queue list! + */ +HQUEUE QUEUE_CreateMsgQueue( int size ) +{ + HQUEUE hQueue; + MESSAGEQUEUE * msgQueue; + int queueSize; + //TDB *pTask = (TDB *)GlobalLock( GetCurrentTask() ); + + DPRINT("Creating message queue...\n"); + + queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG); + if (!(hQueue = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, queueSize ))) + return 0; + msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue ); + msgQueue->self = hQueue; + msgQueue->msgSize = sizeof(QMSG); + msgQueue->queueSize = size; + msgQueue->wakeBits = msgQueue->changeBits = QS_SMPARAMSFREE; + //msgQueue->wWinVersion = pTask ? pTask->version : 0; + GlobalUnlock( hQueue ); + return hQueue; +} + + +/*********************************************************************** + * QUEUE_DeleteMsgQueue + * + * Unlinks and deletes a message queue. + * + * Note: We need to mask asynchronous events to make sure PostMessage works + * even in the signal handler. + */ +WINBOOL QUEUE_DeleteMsgQueue( HQUEUE hQueue ) +{ + MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)GlobalLock(hQueue); + HQUEUE senderQ; + HQUEUE *pPrev; + + DPRINT("Deleting message queue %04x\n", hQueue); + + if (!hQueue || !msgQueue) + { + DPRINT( "invalid argument.\n"); + return 0; + } + if( pCursorQueue == msgQueue ) pCursorQueue = NULL; + if( pActiveQueue == msgQueue ) pActiveQueue = NULL; + + /* flush sent messages */ + senderQ = msgQueue->hSendingTask; + while( senderQ ) + { + MESSAGEQUEUE* sq = (MESSAGEQUEUE*)GlobalLock(senderQ); + if( !sq ) break; + sq->SendMessageReturn = 0L; + QUEUE_SetWakeBit( sq, QS_SMRESULT ); + senderQ = sq->hPrevSendingTask; + } + + SIGNAL_MaskAsyncEvents( TRUE ); + + pPrev = &hFirstQueue; + while (*pPrev && (*pPrev != hQueue)) + { + MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock(*pPrev); + pPrev = &msgQ->next; + } + if (*pPrev) *pPrev = msgQueue->next; + msgQueue->self = 0; + + SIGNAL_MaskAsyncEvents( FALSE ); + + GlobalFree( hQueue ); + return 1; +} + + +/*********************************************************************** + * QUEUE_CreateSysMsgQueue + * + * Create the system message queue, and set the double-click speed. + * Must be called only once. + */ +WINBOOL QUEUE_CreateSysMsgQueue( int size ) +{ + if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE; + else if (size <= 0) size = 1; + if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( size ))) return FALSE; + sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue ); + return TRUE; +} + + +/*********************************************************************** + * QUEUE_GetSysQueue + */ +MESSAGEQUEUE *QUEUE_GetSysQueue(void) +{ + return sysMsgQueue; +} + +/*********************************************************************** + * QUEUE_Signal + */ + +void QUEUE_Signal( HTASK hTask ) +{ +#if 0 + PDB32 *pdb; + THREAD_ENTRY *entry; + + TDB *pTask = (TDB *)GlobalLock( hTask ); + if ( !pTask ) return; + + /* Wake up thread waiting for message */ + SetEvent( pTask->thdb->event ); + + PostEvent( hTask ); +#endif +} + +/*********************************************************************** + * QUEUE_Wait + */ +static void QUEUE_Wait( DWORD wait_mask ) +{ +#if 0 + if ( THREAD_IsWin16( THREAD_Current() ) ) + WaitEvent( 0 ); + else + { + DPRINT( "current task is 32-bit, calling SYNC_DoWait\n"); + MsgWaitForMultipleObjects( 0, NULL, FALSE, INFINITE32, wait_mask ); + } +#endif +} + + +/*********************************************************************** + * QUEUE_SetWakeBit + * + * See "Windows Internals", p.449 + */ +void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit ) +{ + DPRINT("queue = %04x (wm=%04x), bit = %04x\n", + queue->self, queue->wakeMask, bit ); + + if (bit & QS_MOUSE) pMouseQueue = queue; + if (bit & QS_KEY) pKbdQueue = queue; + queue->changeBits |= bit; + queue->wakeBits |= bit; + if (queue->wakeMask & bit) + { + queue->wakeMask = 0; + QUEUE_Signal( queue->hTask ); + } +} + + +/*********************************************************************** + * QUEUE_ClearWakeBit + */ +void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit ) +{ + queue->changeBits &= ~bit; + queue->wakeBits &= ~bit; +} + + +/*********************************************************************** + * QUEUE_WaitBits + * + * See "Windows Internals", p.447 + */ +void QUEUE_WaitBits( WORD bits ) +{ + MESSAGEQUEUE *queue; + + DPRINT("q %04x waiting for %04x\n", GetFastQueue(), bits); + + for (;;) + { + if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetFastQueue() ))) return; + + if (queue->changeBits & bits) + { + /* One of the bits is set; we can return */ + queue->wakeMask = 0; + return; + } + if (queue->wakeBits & QS_SENDMESSAGE) + { + /* Process the sent message immediately */ + + queue->wakeMask = 0; + QUEUE_ReceiveMessage( queue ); + continue; /* nested sm crux */ + } + + queue->wakeMask = bits | QS_SENDMESSAGE; + if(queue->changeBits & bits) continue; + + DPRINT("%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask); + + QUEUE_Wait( queue->wakeMask ); + } +} + + +/*********************************************************************** + * QUEUE_ReceiveMessage + * + * This routine is called when a sent message is waiting for the queue. + */ +void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue ) +{ + MESSAGEQUEUE *senderQ = NULL; + HQUEUE prevSender = 0; + QSMCTRL* prevCtrlPtr = NULL; + LRESULT result = 0; + + DPRINT( "ReceiveMessage, queue %04x\n", queue->self ); + if (!(queue->wakeBits & QS_SENDMESSAGE) || + !(senderQ = (MESSAGEQUEUE*)GlobalLock( queue->hSendingTask))) + { DPRINT("\trcm: nothing to do\n"); return; } + + if( !senderQ->hPrevSendingTask ) + QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE ); /* no more sent messages */ + + /* Save current state on stack */ + prevSender = queue->InSendMessageHandle; + prevCtrlPtr = queue->smResultCurrent; + + /* Remove sending queue from the list */ + queue->InSendMessageHandle = queue->hSendingTask; + queue->smResultCurrent = senderQ->smResultInit; + queue->hSendingTask = senderQ->hPrevSendingTask; + + DPRINT( "\trcm: smResultCurrent = %08x, prevCtrl = %08x\n", + (unsigned)queue->smResultCurrent, (unsigned)prevCtrlPtr ); + QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE ); + + DPRINT( "\trcm: calling wndproc - %04x %04x %04x%04x %08x\n", + senderQ->hWnd, senderQ->msg, senderQ->wParamHigh, + senderQ->wParam, (unsigned)senderQ->lParam ); + + if (IsWindow( senderQ->hWnd )) + { + WND *wndPtr = WIN_FindWndPtr( senderQ->hWnd ); + DWORD extraInfo = queue->GetMessageExtraInfoVal; + queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal; + + if (senderQ->flags & QUEUE_SM_ASCII) + { + WPARAM wParam = MAKELONG( senderQ->wParam, senderQ->wParamHigh ); + DPRINT( "\trcm: msg is Win32\n" ); + if (senderQ->flags & QUEUE_SM_UNICODE) + result = CallWindowProcW( wndPtr->winproc, + senderQ->hWnd, senderQ->msg, + wParam, senderQ->lParam ); + else + result = CallWindowProcA( wndPtr->winproc, + senderQ->hWnd, senderQ->msg, + wParam, senderQ->lParam ); + } + else /* Win16 message */ + result = CallWindowProc( (WNDPROC)wndPtr->winproc, + senderQ->hWnd, senderQ->msg, + senderQ->wParam, senderQ->lParam ); + + queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */ + DPRINT("\trcm: result = %08x\n", (unsigned)result ); + } + else DPRINT( "\trcm: bad hWnd\n"); + + /* Return the result to the sender task */ + ReplyMessage( result ); + + queue->InSendMessageHandle = prevSender; + queue->smResultCurrent = prevCtrlPtr; + + DPRINT("done!\n"); +} + +/*********************************************************************** + * QUEUE_FlushMessage + * + * Try to reply to all pending sent messages on exit. + */ +void QUEUE_FlushMessages( HQUEUE hQueue ) +{ + MESSAGEQUEUE *queue = (MESSAGEQUEUE*)GlobalLock( hQueue ); + + if( queue ) + { + MESSAGEQUEUE *senderQ = (MESSAGEQUEUE*)GlobalLock( queue->hSendingTask); + QSMCTRL* CtrlPtr = queue->smResultCurrent; + + DPRINT("Flushing queue %04x:\n", hQueue ); + + while( senderQ ) + { + if( !CtrlPtr ) + CtrlPtr = senderQ->smResultInit; + + DPRINT("\tfrom queue %04x, smResult %08x\n", queue->hSendingTask, (unsigned)CtrlPtr ); + + if( !(queue->hSendingTask = senderQ->hPrevSendingTask) ) + QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE ); + + QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE ); + + queue->smResultCurrent = CtrlPtr; +// while( senderQ->wakeBits & QS_SMRESULT ) OldYield(); + + while( senderQ->wakeBits & QS_SMRESULT ) Sleep(100); + + senderQ->SendMessageReturn = 0; + senderQ->smResult = queue->smResultCurrent; + QUEUE_SetWakeBit( senderQ, QS_SMRESULT); + + senderQ = (MESSAGEQUEUE*)GlobalLock( queue->hSendingTask); + CtrlPtr = NULL; + } + queue->InSendMessageHandle = 0; + } +} + +/*********************************************************************** + * QUEUE_AddMsg + * + * Add a message to the queue. Return FALSE if queue is full. + */ +WINBOOL QUEUE_AddMsg( HQUEUE hQueue, MSG * msg, DWORD extraInfo ) +{ + int pos; + MESSAGEQUEUE *msgQueue; + + SIGNAL_MaskAsyncEvents( TRUE ); + + if (!(msgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return FALSE; + pos = msgQueue->nextFreeMessage; + + /* Check if queue is full */ + if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0)) + { + SIGNAL_MaskAsyncEvents( FALSE ); + DPRINT("Queue is full!\n" ); + return FALSE; + } + + /* Store message */ + msgQueue->messages[pos].msg = *msg; + msgQueue->messages[pos].extraInfo = extraInfo; + if (pos < msgQueue->queueSize-1) pos++; + else pos = 0; + msgQueue->nextFreeMessage = pos; + msgQueue->msgCount++; + + SIGNAL_MaskAsyncEvents( FALSE ); + + QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE ); + return TRUE; +} + + +/*********************************************************************** + * QUEUE_FindMsg + * + * Find a message matching the given parameters. Return -1 if none available. + */ +int QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last ) +{ + int i, pos = msgQueue->nextMessage; + + DPRINT("hwnd=%04x pos=%d\n", hwnd, pos ); + + if (!msgQueue->msgCount) return -1; + if (!hwnd && !first && !last) return pos; + + for (i = 0; i < msgQueue->msgCount; i++) + { + MSG * msg = &msgQueue->messages[pos].msg; + + if (!hwnd || (msg->hwnd == hwnd)) + { + if (!first && !last) return pos; + if ((msg->message >= first) && (msg->message <= last)) return pos; + } + if (pos < msgQueue->queueSize-1) pos++; + else pos = 0; + } + return -1; +} + + +/*********************************************************************** + * QUEUE_RemoveMsg + * + * Remove a message from the queue (pos must be a valid position). + */ +void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos ) +{ + SIGNAL_MaskAsyncEvents( TRUE ); + + if (pos >= msgQueue->nextMessage) + { + for ( ; pos > msgQueue->nextMessage; pos--) + msgQueue->messages[pos] = msgQueue->messages[pos-1]; + msgQueue->nextMessage++; + if (msgQueue->nextMessage >= msgQueue->queueSize) + msgQueue->nextMessage = 0; + } + else + { + for ( ; pos < msgQueue->nextFreeMessage; pos++) + msgQueue->messages[pos] = msgQueue->messages[pos+1]; + if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--; + else msgQueue->nextFreeMessage = msgQueue->queueSize-1; + } + msgQueue->msgCount--; + if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE; + + SIGNAL_MaskAsyncEvents( FALSE ); +} + + +/*********************************************************************** + * QUEUE_WakeSomeone + * + * Wake a queue upon reception of a hardware event. + */ +static void QUEUE_WakeSomeone( UINT message ) +{ + WND* wndPtr = NULL; + WORD wakeBit; + HWND hwnd; + MESSAGEQUEUE *queue = pCursorQueue; + + if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) ) + { + wakeBit = QS_KEY; + if( pActiveQueue ) queue = pActiveQueue; + } + else + { + wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON; + if( (hwnd = GetCapture()) ) + if( (wndPtr = WIN_FindWndPtr( hwnd )) ) + queue = (MESSAGEQUEUE *)GlobalLock( wndPtr->hmemTaskQ ); + } + + if( (hwnd = GetSysModalWindow()) ) + if( (wndPtr = WIN_FindWndPtr( hwnd )) ) + queue = (MESSAGEQUEUE *)GlobalLock( wndPtr->hmemTaskQ ); + + if( !queue ) + { + queue = GlobalLock( hFirstQueue ); + while( queue ) + { + if (queue->wakeMask & wakeBit) break; + queue = GlobalLock( queue->next ); + } + if( !queue ) + { + DPRINT( "couldn't find queue\n"); + return; + } + } + + QUEUE_SetWakeBit( queue, wakeBit ); +} + + +/*********************************************************************** + * hardware_event + * + * Add an event to the system message queue. + * Note: the position is relative to the desktop window. + */ +void hardware_event( WORD message, WORD wParam, LONG lParam, + int xPos, int yPos, DWORD time, DWORD extraInfo ) +{ + MSG *msg; + int pos; + + if (!sysMsgQueue) return; + pos = sysMsgQueue->nextFreeMessage; + + /* Merge with previous event if possible */ + + if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount) + { + if (pos > 0) pos--; + else pos = sysMsgQueue->queueSize - 1; + msg = &sysMsgQueue->messages[pos].msg; + if ((msg->message == message) && (msg->wParam == wParam)) + sysMsgQueue->msgCount--; /* Merge events */ + else + pos = sysMsgQueue->nextFreeMessage; /* Don't merge */ + } + + /* Check if queue is full */ + + if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount) + { + /* Queue is full, beep (but not on every mouse motion...) */ + if (message != WM_MOUSEMOVE) MessageBeep(0); + return; + } + + /* Store message */ + + msg = &sysMsgQueue->messages[pos].msg; + msg->hwnd = 0; + msg->message = message; + msg->wParam = wParam; + msg->lParam = lParam; + msg->time = time; + msg->pt.x = xPos & 0xffff; + msg->pt.y = yPos & 0xffff; + sysMsgQueue->messages[pos].extraInfo = extraInfo; + if (pos < sysMsgQueue->queueSize - 1) pos++; + else pos = 0; + sysMsgQueue->nextFreeMessage = pos; + sysMsgQueue->msgCount++; + QUEUE_WakeSomeone( message ); +} + + +/*********************************************************************** + * QUEUE_GetQueueTask + */ +HTASK QUEUE_GetQueueTask( HQUEUE hQueue ) +{ + MESSAGEQUEUE *queue = GlobalLock( hQueue ); + return (queue) ? queue->hTask : 0 ; +} + + +/*********************************************************************** + * QUEUE_IncPaintCount + */ +void QUEUE_IncPaintCount( HQUEUE hQueue ) +{ + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return; + queue->wPaintCount++; + QUEUE_SetWakeBit( queue, QS_PAINT ); +} + + +/*********************************************************************** + * QUEUE_DecPaintCount + */ +void QUEUE_DecPaintCount( HQUEUE hQueue ) +{ + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return; + queue->wPaintCount--; + if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT; +} + + +/*********************************************************************** + * QUEUE_IncTimerCount + */ +void QUEUE_IncTimerCount( HQUEUE hQueue ) +{ + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return; + queue->wTimerCount++; + QUEUE_SetWakeBit( queue, QS_TIMER ); +} + + +/*********************************************************************** + * QUEUE_DecTimerCount + */ +void QUEUE_DecTimerCount( HQUEUE hQueue ) +{ + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return; + queue->wTimerCount--; + if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER; +} + + diff --git a/reactos/lib/user32/internal/region.c b/reactos/lib/user32/internal/region.c new file mode 100644 index 00000000000..f323b16990e --- /dev/null +++ b/reactos/lib/user32/internal/region.c @@ -0,0 +1,37 @@ +#include + +INT SelectVisRgn(HDC hdc,HRGN hrgn) +{ + return SelectClipRgn(hdc,hrgn); +} + +INT RestoreVisRgn(HDC hdc) +{ + return SelectClipRgn(hdc,NULL); +} + +INT ExcludeVisRect(HDC hDC,INT nLeftRect,INT nTopRect,INT nRightRect,INT nBottomRect) +{ + return ExcludeClipRect(hDC, nLeftRect, nTopRect,nRightRect,nBottomRect ); +} + + +HRGN InquireVisRgn(HDC hdc) +{ + return hdc; +} +HRGN SaveVisRgn(HDC hdc) +{ + return NULL; +} + +/*********************************************************************** + * REGION_UnionRectWithRgn + * Adds a rectangle to a HRGN32 + * A helper used by scroll.c + */ +WINBOOL REGION_UnionRectWithRgn( HRGN hrgn, const RECT *lpRect ) +{ + + return TRUE; +} \ No newline at end of file diff --git a/reactos/lib/user32/internal/scroll.c b/reactos/lib/user32/internal/scroll.c new file mode 100644 index 00000000000..15354332450 --- /dev/null +++ b/reactos/lib/user32/internal/scroll.c @@ -0,0 +1,1068 @@ +/* + * Scrollbar control + * + * Copyright 1993 Martin Ayotte + * Copyright 1994, 1996 Alexandre Julliard + */ + +#include +#include +#include +#include +#include +#include + +#define MAKEINTRESOURCEA(x) "x" +#define MAX(x,y) x > y ? x : y + +static HBITMAP hUpArrow = 0; +static HBITMAP hDnArrow = 0; +static HBITMAP hLfArrow = 0; +static HBITMAP hRgArrow = 0; +static HBITMAP hUpArrowD = 0; +static HBITMAP hDnArrowD = 0; +static HBITMAP hLfArrowD = 0; +static HBITMAP hRgArrowD = 0; +static HBITMAP hUpArrowI = 0; +static HBITMAP hDnArrowI = 0; +static HBITMAP hLfArrowI = 0; +static HBITMAP hRgArrowI = 0; + +#define TOP_ARROW(flags,pressed) \ + (((flags)&ESB_DISABLE_UP) ? hUpArrowI : ((pressed) ? hUpArrowD:hUpArrow)) +#define BOTTOM_ARROW(flags,pressed) \ + (((flags)&ESB_DISABLE_DOWN) ? hDnArrowI : ((pressed) ? hDnArrowD:hDnArrow)) +#define LEFT_ARROW(flags,pressed) \ + (((flags)&ESB_DISABLE_LEFT) ? hLfArrowI : ((pressed) ? hLfArrowD:hLfArrow)) +#define RIGHT_ARROW(flags,pressed) \ + (((flags)&ESB_DISABLE_RIGHT) ? hRgArrowI : ((pressed) ? hRgArrowD:hRgArrow)) + + + /* Minimum size of the rectangle between the arrows */ +#define SCROLL_MIN_RECT 4 + + /* Minimum size of the thumb in pixels */ +#define SCROLL_MIN_THUMB 6 + + /* Overlap between arrows and thumb */ +#define SCROLL_ARROW_THUMB_OVERLAP 1 + + /* Delay (in ms) before first repetition when holding the button down */ +#define SCROLL_FIRST_DELAY 200 + + /* Delay (in ms) between scroll repetitions */ +#define SCROLL_REPEAT_DELAY 50 + + /* Scroll timer id */ +#define SCROLL_TIMER 0 + + /* Scroll-bar hit testing */ +enum SCROLL_HITTEST +{ + SCROLL_NOWHERE, /* Outside the scroll bar */ + SCROLL_TOP_ARROW, /* Top or left arrow */ + SCROLL_TOP_RECT, /* Rectangle between the top arrow and the thumb */ + SCROLL_THUMB, /* Thumb rectangle */ + SCROLL_BOTTOM_RECT, /* Rectangle between the thumb and the bottom arrow */ + SCROLL_BOTTOM_ARROW /* Bottom or right arrow */ +}; + + /* What to do after SCROLL_SetScrollInfo() */ +#define SA_SSI_HIDE 0x0001 +#define SA_SSI_SHOW 0x0002 +#define SA_SSI_REFRESH 0x0004 +#define SA_SSI_REPAINT_ARROWS 0x0008 + + /* Thumb-tracking info */ +static HWND SCROLL_TrackingWin = 0; +static INT SCROLL_TrackingBar = 0; +static INT SCROLL_TrackingPos = 0; +static INT SCROLL_TrackingVal = 0; + /* Hit test code of the last button-down event */ +static enum SCROLL_HITTEST SCROLL_trackHitTest; +static WINBOOL SCROLL_trackVertical; + + /* Is the moving thumb being displayed? */ +static WINBOOL SCROLL_MovingThumb = FALSE; + + /* Local functions */ +static WINBOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar, + WINBOOL fShowH, WINBOOL fShowV ); +INT SCROLL_SetScrollInfo( HWND hwnd, INT nBar, + const SCROLLINFO *info, INT *action ); + +/*********************************************************************** + * SCROLL_LoadBitmaps + */ +static void SCROLL_LoadBitmaps(void) +{ + hUpArrow = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_UPARROW) ); + hDnArrow = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_DNARROW) ); + hLfArrow = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_LFARROW) ); + hRgArrow = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_RGARROW) ); + hUpArrowD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_UPARROWD) ); + hDnArrowD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_DNARROWD) ); + hLfArrowD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_LFARROWD) ); + hRgArrowD = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_RGARROWD) ); + hUpArrowI = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_UPARROWI) ); + hDnArrowI = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_DNARROWI) ); + hLfArrowI = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_LFARROWI) ); + hRgArrowI = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_RGARROWI) ); +} + + +/*********************************************************************** + * SCROLL_GetPtrScrollInfo + */ +static SCROLLBAR_INFO *SCROLL_GetPtrScrollInfo( WND* wndPtr, INT nBar ) +{ + SCROLLBAR_INFO *infoPtr; + + if (!wndPtr) return NULL; + switch(nBar) + { + case SB_HORZ: infoPtr = (SCROLLBAR_INFO *)wndPtr->pHScroll; break; + case SB_VERT: infoPtr = (SCROLLBAR_INFO *)wndPtr->pVScroll; break; + case SB_CTL: infoPtr = (SCROLLBAR_INFO *)wndPtr->wExtra; break; + default: return NULL; + } + + if (!infoPtr) /* Create the info structure if needed */ + { + if ((infoPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(SCROLLBAR_INFO) ))) + { + infoPtr->MinVal = infoPtr->CurVal = infoPtr->Page = 0; + infoPtr->MaxVal = 100; + infoPtr->flags = ESB_ENABLE_BOTH; + if (nBar == SB_HORZ) wndPtr->pHScroll = infoPtr; + else wndPtr->pVScroll = infoPtr; + } + if (!hUpArrow) SCROLL_LoadBitmaps(); + } + return infoPtr; +} + + +/*********************************************************************** + * SCROLL_GetScrollInfo + */ +static SCROLLBAR_INFO *SCROLL_GetScrollInfo( HWND hwnd, INT nBar ) +{ + WND *wndPtr = WIN_FindWndPtr( hwnd ); + return SCROLL_GetPtrScrollInfo( wndPtr, nBar ); +} + + +/*********************************************************************** + * SCROLL_GetScrollBarRect + * + * Compute the scroll bar rectangle, in drawing coordinates (i.e. client + * coords for SB_CTL, window coords for SB_VERT and SB_HORZ). + * 'arrowSize' returns the width or height of an arrow (depending on + * the orientation of the scrollbar), 'thumbSize' returns the size of + * the thumb, and 'thumbPos' returns the position of the thumb + * relative to the left or to the top. + * Return TRUE if the scrollbar is vertical, FALSE if horizontal. + */ +static WINBOOL SCROLL_GetScrollBarRect( HWND hwnd, INT nBar, RECT *lprect, + INT *arrowSize, INT *thumbSize, + INT *thumbPos ) +{ + INT pixels; + WINBOOL vertical; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + switch(nBar) + { + case SB_HORZ: + lprect->left = wndPtr->rectClient.left - wndPtr->rectWindow.left; + lprect->top = wndPtr->rectClient.bottom - wndPtr->rectWindow.top; + lprect->right = wndPtr->rectClient.right - wndPtr->rectWindow.left; + lprect->bottom = lprect->top + SYSMETRICS_CYHSCROLL; + if(wndPtr->dwStyle & WS_BORDER) { + lprect->left--; + lprect->right++; + } else if(wndPtr->dwStyle & WS_VSCROLL) + lprect->right++; + vertical = FALSE; + break; + + case SB_VERT: + lprect->left = wndPtr->rectClient.right - wndPtr->rectWindow.left; + lprect->top = wndPtr->rectClient.top - wndPtr->rectWindow.top; + lprect->right = lprect->left + SYSMETRICS_CXVSCROLL; + lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top; + if(wndPtr->dwStyle & WS_BORDER) { + lprect->top--; + lprect->bottom++; + } else if(wndPtr->dwStyle & WS_HSCROLL) + lprect->bottom++; + vertical = TRUE; + break; + + case SB_CTL: + GetClientRect( hwnd, lprect ); + vertical = ((wndPtr->dwStyle & SBS_VERT) != 0); + break; + + default: + return FALSE; + } + + if (vertical) pixels = lprect->bottom - lprect->top; + else pixels = lprect->right - lprect->left; + + if (pixels <= 2*SYSMETRICS_CXVSCROLL + SCROLL_MIN_RECT) + { + if (pixels > SCROLL_MIN_RECT) + *arrowSize = (pixels - SCROLL_MIN_RECT) / 2; + else + *arrowSize = 0; + *thumbPos = *thumbSize = 0; + } + else + { + SCROLLBAR_INFO *info = SCROLL_GetPtrScrollInfo( wndPtr, nBar ); + + *arrowSize = SYSMETRICS_CXVSCROLL; + pixels -= (2 * (SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP)); + + if (info->Page) + { + *thumbSize = pixels * info->Page / (info->MaxVal-info->MinVal+1); + if (*thumbSize < SCROLL_MIN_THUMB) *thumbSize = SCROLL_MIN_THUMB; + } + else *thumbSize = SYSMETRICS_CXVSCROLL; + + if (((pixels -= *thumbSize ) < 0) || + ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)) + { + /* Rectangle too small or scrollbar disabled -> no thumb */ + *thumbPos = *thumbSize = 0; + } + else + { + INT maxVal = info->MaxVal - MAX( info->Page-1, 0 ); + if (info->MinVal >= maxVal) + *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP; + else + *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP + + pixels * (info->CurVal-info->MinVal) / (maxVal - info->MinVal); + } + } + return vertical; +} + + +/*********************************************************************** + * SCROLL_GetThumbVal + * + * Compute the current scroll position based on the thumb position in pixels + * from the top of the scroll-bar. + */ +static UINT SCROLL_GetThumbVal( SCROLLBAR_INFO *infoPtr, RECT *rect, + WINBOOL vertical, INT pos ) +{ + INT thumbSize; + INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left; + + if ((pixels -= 2*(SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP)) <= 0) + return infoPtr->MinVal; + + if (infoPtr->Page) + { + thumbSize = pixels * infoPtr->Page/(infoPtr->MaxVal-infoPtr->MinVal+1); + if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB; + } + else thumbSize = SYSMETRICS_CXVSCROLL; + + if ((pixels -= thumbSize) <= 0) return infoPtr->MinVal; + + pos = MAX( 0, pos - (SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP) ); + if (pos > pixels) pos = pixels; + + if (!infoPtr->Page) pos *= infoPtr->MaxVal - infoPtr->MinVal; + else pos *= infoPtr->MaxVal - infoPtr->MinVal - infoPtr->Page + 1; + return infoPtr->MinVal + ((pos + pixels / 2) / pixels); +} + +/*********************************************************************** + * SCROLL_PtInRectEx + */ +static WINBOOL SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, WINBOOL vertical ) +{ + RECT rect = *lpRect; + + if (vertical) + { + rect.left -= lpRect->right - lpRect->left; + rect.right += lpRect->right - lpRect->left; + } + else + { + rect.top -= lpRect->bottom - lpRect->top; + rect.bottom += lpRect->bottom - lpRect->top; + } + return PtInRect( &rect, pt ); +} + +/*********************************************************************** + * SCROLL_ClipPos + */ +static POINT SCROLL_ClipPos( LPRECT lpRect, POINT pt ) +{ + if( pt.x < lpRect->left ) + pt.x = lpRect->left; + else + if( pt.x > lpRect->right ) + pt.x = lpRect->right; + + if( pt.y < lpRect->top ) + pt.y = lpRect->top; + else + if( pt.y > lpRect->bottom ) + pt.y = lpRect->bottom; + + return pt; +} + + +/*********************************************************************** + * SCROLL_HitTest + * + * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!). + */ +static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, INT nBar, + POINT pt, WINBOOL bDragging ) +{ + INT arrowSize, thumbSize, thumbPos; + RECT rect; + + WINBOOL vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect, + &arrowSize, &thumbSize, &thumbPos ); + + if ( (bDragging && !SCROLL_PtInRectEx( &rect, pt, vertical )) || + (!PtInRect( &rect, pt )) ) return SCROLL_NOWHERE; + + if (vertical) + { + if (pt.y < rect.top + arrowSize) return SCROLL_TOP_ARROW; + if (pt.y >= rect.bottom - arrowSize) return SCROLL_BOTTOM_ARROW; + if (!thumbPos) return SCROLL_TOP_RECT; + pt.y -= rect.top; + if (pt.y < thumbPos) return SCROLL_TOP_RECT; + if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT; + } + else /* horizontal */ + { + if (pt.x < rect.left + arrowSize) return SCROLL_TOP_ARROW; + if (pt.x >= rect.right - arrowSize) return SCROLL_BOTTOM_ARROW; + if (!thumbPos) return SCROLL_TOP_RECT; + pt.x -= rect.left; + if (pt.x < thumbPos) return SCROLL_TOP_RECT; + if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT; + } + return SCROLL_THUMB; +} + + +/*********************************************************************** + * SCROLL_DrawArrows + * + * Draw the scroll bar arrows. + */ +static void SCROLL_DrawArrows( HDC hdc, SCROLLBAR_INFO *infoPtr, + RECT *rect, INT arrowSize, WINBOOL vertical, + WINBOOL top_pressed, WINBOOL bottom_pressed ) +{ + HDC hdcMem = CreateCompatibleDC( hdc ); + HBITMAP hbmpPrev = SelectObject( hdcMem, vertical ? + TOP_ARROW(infoPtr->flags, top_pressed) + : LEFT_ARROW(infoPtr->flags, top_pressed)); + + SetStretchBltMode( hdc, STRETCH_DELETESCANS ); + StretchBlt( hdc, rect->left, rect->top, + vertical ? rect->right-rect->left : arrowSize, + vertical ? arrowSize : rect->bottom-rect->top, + hdcMem, 0, 0, + SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL, + SRCCOPY ); + + SelectObject( hdcMem, vertical ? + BOTTOM_ARROW( infoPtr->flags, bottom_pressed ) + : RIGHT_ARROW( infoPtr->flags, bottom_pressed ) ); + if (vertical) + StretchBlt( hdc, rect->left, rect->bottom - arrowSize, + rect->right - rect->left, arrowSize, + hdcMem, 0, 0, + SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL, + SRCCOPY ); + else + StretchBlt( hdc, rect->right - arrowSize, rect->top, + arrowSize, rect->bottom - rect->top, + hdcMem, 0, 0, + SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL, + SRCCOPY ); + SelectObject( hdcMem, hbmpPrev ); + DeleteDC( hdcMem ); +} + + +/*********************************************************************** + * SCROLL_DrawMovingThumb + * + * Draw the moving thumb rectangle. + */ +static void SCROLL_DrawMovingThumb( HDC hdc, RECT *rect, WINBOOL vertical, + INT arrowSize, INT thumbSize ) +{ + RECT r = *rect; + if (vertical) + { + r.top += SCROLL_TrackingPos; + if (r.top < rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP) + r.top = rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP; + if (r.top + thumbSize > + rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP)) + r.top = rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) + - thumbSize; + r.bottom = r.top + thumbSize; + } + else + { + r.left += SCROLL_TrackingPos; + if (r.left < rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP) + r.left = rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP; + if (r.left + thumbSize > + rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP)) + r.left = rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) + - thumbSize; + r.right = r.left + thumbSize; + } + DrawFocusRect( hdc, &r ); + SCROLL_MovingThumb = !SCROLL_MovingThumb; +} + + +/*********************************************************************** + * SCROLL_DrawInterior + * + * Draw the scroll bar interior (everything except the arrows). + */ +static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, INT nBar, + RECT *rect, INT arrowSize, + INT thumbSize, INT thumbPos, + UINT flags, WINBOOL vertical, + WINBOOL top_selected, WINBOOL bottom_selected ) +{ + RECT r; + + /* Select the correct brush and pen */ + + + + SelectObject( hdc, GetSysColorBrush(COLOR_WINDOWFRAME) ); + if ((flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH) + { + /* This ought to be the color of the parent window */ + SelectObject( hdc, GetSysColorBrush(COLOR_WINDOW) ); + } + else + { + if (nBar == SB_CTL) /* Only scrollbar controls send WM_CTLCOLOR */ + { + HBRUSH hbrush = SendMessageA(GetParent(hwnd), + WM_CTLCOLORSCROLLBAR, (WPARAM)hdc, (LPARAM)hwnd ); + SelectObject( hdc, hbrush ); + } + else SelectObject( hdc, GetSysColorBrush(COLOR_SCROLLBAR) ); + } + + /* Calculate the scroll rectangle */ + + r = *rect; + if (vertical) + { + r.top += arrowSize - SCROLL_ARROW_THUMB_OVERLAP; + r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP); + } + else + { + r.left += arrowSize - SCROLL_ARROW_THUMB_OVERLAP; + r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP); + } + + /* Draw the scroll bar frame */ + + Rectangle( hdc, r.left, r.top, r.right, r.bottom ); + + /* Draw the scroll rectangles and thumb */ + + if (!thumbPos) /* No thumb to draw */ + { + PatBlt( hdc, r.left+1, r.top+1, r.right - r.left - 2, + r.bottom - r.top - 2, PATCOPY ); + return; + } + + if (vertical) + { + PatBlt( hdc, r.left + 1, r.top + 1, + r.right - r.left - 2, + thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - 1, + top_selected ? 0x0f0000 : PATCOPY ); + r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP); + PatBlt( hdc, r.left + 1, r.top + thumbSize, + r.right - r.left - 2, + r.bottom - r.top - thumbSize - 1, + bottom_selected ? 0x0f0000 : PATCOPY ); + r.bottom = r.top + thumbSize; + } + else /* horizontal */ + { + PatBlt( hdc, r.left + 1, r.top + 1, + thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - 1, + r.bottom - r.top - 2, + top_selected ? 0x0f0000 : PATCOPY ); + r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP); + PatBlt( hdc, r.left + thumbSize, r.top + 1, + r.right - r.left - thumbSize - 1, + r.bottom - r.top - 2, + bottom_selected ? 0x0f0000 : PATCOPY ); + r.right = r.left + thumbSize; + } + + /* Draw the thumb */ + + SelectObject( hdc, GetSysColorBrush(COLOR_BTNFACE) ); + Rectangle( hdc, r.left, r.top, r.right, r.bottom ); + r.top++, r.left++; + DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT ); + if (SCROLL_MovingThumb && + (SCROLL_TrackingWin == hwnd) && + (SCROLL_TrackingBar == nBar)) + { + SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, thumbSize ); + SCROLL_MovingThumb = TRUE; + } +} + + +/*********************************************************************** + * SCROLL_DrawScrollBar + * + * Redraw the whole scrollbar. + */ +void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, INT nBar, + WINBOOL arrows, WINBOOL interior ) +{ + INT arrowSize, thumbSize, thumbPos; + RECT rect; + WINBOOL vertical; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + SCROLLBAR_INFO *infoPtr = SCROLL_GetPtrScrollInfo( wndPtr, nBar ); + + if (!wndPtr || !infoPtr || + ((nBar == SB_VERT) && !(wndPtr->dwStyle & WS_VSCROLL)) || + ((nBar == SB_HORZ) && !(wndPtr->dwStyle & WS_HSCROLL))) return; + if (!WIN_IsWindowDrawable( wndPtr, FALSE )) return; + + vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect, + &arrowSize, &thumbSize, &thumbPos ); + + /* Draw the arrows */ + + if (arrows && arrowSize) + { + if( vertical == SCROLL_trackVertical && GetCapture() == hwnd ) + SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, + (SCROLL_trackHitTest == SCROLL_TOP_ARROW), + (SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW) ); + else + SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, + FALSE, FALSE ); + } + if( interior ) + SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize, + thumbPos, infoPtr->flags, vertical, FALSE, FALSE ); +} + + +/*********************************************************************** + * SCROLL_RefreshScrollBar + * + * Repaint the scroll bar interior after a SetScrollRange() or + * SetScrollPos() call. + */ +static void SCROLL_RefreshScrollBar( HWND hwnd, INT nBar, + WINBOOL arrows, WINBOOL interior ) +{ + HDC hdc = GetDCEx( hwnd, 0, + DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW) ); + if (!hdc) return; + + SCROLL_DrawScrollBar( hwnd, hdc, nBar, arrows, interior ); + ReleaseDC( hwnd, hdc ); +} + + +/*********************************************************************** + * SCROLL_HandleKbdEvent + * + * Handle a keyboard event (only for SB_CTL scrollbars). + */ +void SCROLL_HandleKbdEvent( HWND hwnd, WPARAM wParam ) +{ + WND *wndPtr = WIN_FindWndPtr( hwnd ); + WPARAM msg; + + switch(wParam) + { + case VK_PRIOR: msg = SB_PAGEUP; break; + case VK_NEXT: msg = SB_PAGEDOWN; break; + case VK_HOME: msg = SB_TOP; break; + case VK_END: msg = SB_BOTTOM; break; + case VK_UP: msg = SB_LINEUP; break; + case VK_DOWN: msg = SB_LINEDOWN; break; + default: + return; + } + SendMessageA( GetParent(hwnd), + (wndPtr->dwStyle & SBS_VERT) ? WM_VSCROLL : WM_HSCROLL, + msg, (LPARAM)hwnd ); +} + + +/*********************************************************************** + * SCROLL_HandleScrollEvent + * + * Handle a mouse or timer event for the scrollbar. + * 'pt' is the location of the mouse event in client (for SB_CTL) or + * windows coordinates. + */ +void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt) +{ + /* Previous mouse position for timer events */ + static POINT prevPt; + /* Thumb position when tracking started. */ + static UINT trackThumbPos; + /* Position in the scroll-bar of the last button-down event. */ + static INT lastClickPos; + /* Position in the scroll-bar of the last mouse event. */ + static INT lastMousePos; + + enum SCROLL_HITTEST hittest; + HWND hwndOwner, hwndCtl; + WINBOOL vertical; + INT arrowSize, thumbSize, thumbPos; + RECT rect; + HDC hdc; + + SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ); + if (!infoPtr) return; + if ((SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN)) + return; + + hdc = GetDCEx( hwnd, 0, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW)); + vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect, + &arrowSize, &thumbSize, &thumbPos ); + hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd; + hwndCtl = (nBar == SB_CTL) ? hwnd : 0; + + switch(msg) + { + case WM_LBUTTONDOWN: /* Initialise mouse tracking */ + SCROLL_trackVertical = vertical; + SCROLL_trackHitTest = hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE ); + lastClickPos = vertical ? (pt.y - rect.top) : (pt.x - rect.left); + lastMousePos = lastClickPos; + trackThumbPos = thumbPos; + prevPt = pt; + SetCapture( hwnd ); + if (nBar == SB_CTL) SetFocus( hwnd ); + break; + + case WM_MOUSEMOVE: + hittest = SCROLL_HitTest( hwnd, nBar, pt, TRUE ); + prevPt = pt; + break; + + case WM_LBUTTONUP: + hittest = SCROLL_NOWHERE; + ReleaseCapture(); + break; + + case WM_SYSTIMER: + pt = prevPt; + hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE ); + break; + + default: + return; /* Should never happen */ + } + + DPRINT( "Event: hwnd=%04x bar=%d msg=%x pt=%d,%d hit=%d\n", + hwnd, nBar, msg, pt.x, pt.y, hittest ); + + switch(SCROLL_trackHitTest) + { + case SCROLL_NOWHERE: /* No tracking in progress */ + break; + + case SCROLL_TOP_ARROW: + SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, + (hittest == SCROLL_trackHitTest), FALSE ); + if (hittest == SCROLL_trackHitTest) + { + if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)) + { + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + SB_LINEUP, (LPARAM)hwndCtl ); + SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? + SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, + (TIMERPROC)0 ); + } + } + else KillTimer( hwnd, SCROLL_TIMER ); + break; + + case SCROLL_TOP_RECT: + SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize, + thumbPos, infoPtr->flags, vertical, + (hittest == SCROLL_trackHitTest), FALSE ); + if (hittest == SCROLL_trackHitTest) + { + if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)) + { + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + SB_PAGEUP, (LPARAM)hwndCtl ); + SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? + SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, + (TIMERPROC)0 ); + } + } + else KillTimer( hwnd, SCROLL_TIMER ); + break; + + case SCROLL_THUMB: + if (msg == WM_LBUTTONDOWN) + { + SCROLL_TrackingWin = hwnd; + SCROLL_TrackingBar = nBar; + SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos; + SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize); + } + else if (msg == WM_LBUTTONUP) + { + SCROLL_TrackingWin = 0; + SCROLL_MovingThumb = FALSE; + SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize, + thumbPos, infoPtr->flags, vertical, + FALSE, FALSE ); + } + else /* WM_MOUSEMOVE */ + { + UINT pos; + + if (!SCROLL_PtInRectEx( &rect, pt, vertical )) pos = lastClickPos; + else + { + pt = SCROLL_ClipPos( &rect, pt ); + pos = vertical ? (pt.y - rect.top) : (pt.x - rect.left); + } + if (pos != lastMousePos) + { + SCROLL_DrawMovingThumb( hdc, &rect, vertical, + arrowSize, thumbSize ); + lastMousePos = pos; + SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos; + SCROLL_TrackingVal = SCROLL_GetThumbVal( infoPtr, &rect, + vertical, + SCROLL_TrackingPos ); + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + MAKEWPARAM( SB_THUMBTRACK, SCROLL_TrackingVal), + (LPARAM)hwndCtl ); + SCROLL_DrawMovingThumb( hdc, &rect, vertical, + arrowSize, thumbSize ); + } + } + break; + + case SCROLL_BOTTOM_RECT: + SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize, + thumbPos, infoPtr->flags, vertical, + FALSE, (hittest == SCROLL_trackHitTest) ); + if (hittest == SCROLL_trackHitTest) + { + if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)) + { + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + SB_PAGEDOWN, (LPARAM)hwndCtl ); + SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? + SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, + (TIMERPROC)0 ); + } + } + else KillTimer( hwnd, SCROLL_TIMER ); + break; + + case SCROLL_BOTTOM_ARROW: + SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, + FALSE, (hittest == SCROLL_trackHitTest) ); + if (hittest == SCROLL_trackHitTest) + { + if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)) + { + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + SB_LINEDOWN, (LPARAM)hwndCtl ); + SetTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? + SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, + (TIMERPROC)0 ); + } + } + else KillTimer( hwnd, SCROLL_TIMER ); + break; + } + + if (msg == WM_LBUTTONUP) + { + hittest = SCROLL_trackHitTest; + SCROLL_trackHitTest = SCROLL_NOWHERE; /* Terminate tracking */ + + if (hittest == SCROLL_THUMB) + { + UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical, + trackThumbPos + lastMousePos - lastClickPos ); + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + MAKEWPARAM( SB_THUMBPOSITION, val ), (LPARAM)hwndCtl ); + } + else + SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + SB_ENDSCROLL, (LPARAM)hwndCtl ); + } + + ReleaseDC( hwnd, hdc ); +} + + +/************************************************************************* + * SCROLL_ShowScrollBar() + * + * Back-end for ShowScrollBar(). Returns FALSE if no action was taken. + * NOTE: fShowV/fShowH must be zero when nBar is SB_HORZ/SB_VERT. + */ +WINBOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar, + WINBOOL fShowH, WINBOOL fShowV ) +{ + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + if (!wndPtr) return FALSE; + DPRINT( "hwnd=%04x bar=%d horz=%d, vert=%d\n", + hwnd, nBar, fShowH, fShowV ); + + switch(nBar) + { + case SB_CTL: + ShowWindow( hwnd, fShowH ? SW_SHOW : SW_HIDE ); + return TRUE; + + case SB_BOTH: + case SB_HORZ: + if (fShowH) + { + fShowH = !(wndPtr->dwStyle & WS_HSCROLL); + wndPtr->dwStyle |= WS_HSCROLL; + } + else /* hide it */ + { + fShowH = (wndPtr->dwStyle & WS_HSCROLL); + wndPtr->dwStyle &= ~WS_HSCROLL; + } + if( nBar == SB_HORZ ) break; + /* fall through */ + + case SB_VERT: + if (fShowV) + { + fShowV = !(wndPtr->dwStyle & WS_VSCROLL); + wndPtr->dwStyle |= WS_VSCROLL; + } + else /* hide it */ + { + fShowV = (wndPtr->dwStyle & WS_VSCROLL); + wndPtr->dwStyle &= ~WS_VSCROLL; + } + break; + + default: + return FALSE; /* Nothing to do! */ + } + + if( fShowH || fShowV ) /* frame has been changed, let the window redraw itself */ + { + SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE + | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); + return TRUE; + } + + return FALSE; /* no frame changes */ +} + +/************************************************************************* + * SCROLL_SetNCSbState + * + * Updates both scrollbars at the same time. Used by MDI CalcChildScroll(). + */ +INT SCROLL_SetNCSbState(WND* wndPtr, int vMin, int vMax, int vPos, + int hMin, int hMax, int hPos) +{ + INT vA, hA; + SCROLLINFO vInfo, hInfo; + + vInfo.cbSize = hInfo.cbSize = sizeof(SCROLLINFO); + vInfo.nMin = vMin; hInfo.nMin = hMin; + vInfo.nMax = vMax; hInfo.nMax = hMax; + vInfo.nPos = vPos; hInfo.nPos = hPos; + vInfo.fMask = hInfo.fMask = SIF_RANGE | SIF_POS; + + SCROLL_SetScrollInfo( wndPtr->hwndSelf, SB_VERT, &vInfo, &vA ); + SCROLL_SetScrollInfo( wndPtr->hwndSelf, SB_HORZ, &hInfo, &hA ); + + if( !SCROLL_ShowScrollBar( wndPtr->hwndSelf, SB_BOTH, + (hA & SA_SSI_SHOW),(vA & SA_SSI_SHOW) ) ) + { + /* SetWindowPos() wasn't called, just redraw the scrollbars if needed */ + if( vA & SA_SSI_REFRESH ) + SCROLL_RefreshScrollBar( wndPtr->hwndSelf, SB_VERT, FALSE, TRUE ); + + if( hA & SA_SSI_REFRESH ) + SCROLL_RefreshScrollBar( wndPtr->hwndSelf, SB_HORZ, FALSE, TRUE ); + } + return 0; +} + +INT SCROLL_SetScrollInfo( HWND hwnd, INT nBar, + const SCROLLINFO *info, INT *action ) +{ + /* Update the scrollbar state and set action flags according to + * what has to be done graphics wise. */ + + SCROLLBAR_INFO *infoPtr; + UINT new_flags; + + //dbg_decl_str(scroll, 256); + + *action = 0; + + if (!(infoPtr = SCROLL_GetScrollInfo(hwnd, nBar))) return 0; + if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return 0; + if ((info->cbSize != sizeof(*info)) && + (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return 0; + + /* Set the page size */ + + if (info->fMask & SIF_PAGE) + { + DPRINT( " page=%d", info->nPage ); + if( infoPtr->Page != info->nPage ) + { + infoPtr->Page = info->nPage; + *action |= SA_SSI_REFRESH; + } + } + + /* Set the scroll pos */ + + if (info->fMask & SIF_POS) + { + DPRINT( " pos=%d", info->nPos ); + if( infoPtr->CurVal != info->nPos ) + { + infoPtr->CurVal = info->nPos; + *action |= SA_SSI_REFRESH; + } + } + + /* Set the scroll range */ + + if (info->fMask & SIF_RANGE) + { + DPRINT( " min=%d max=%d", info->nMin, info->nMax ); + + /* Invalid range -> range is set to (0,0) */ + if ((info->nMin > info->nMax) || + ((UINT)(info->nMax - info->nMin) >= 0x80000000)) + { + infoPtr->MinVal = 0; + infoPtr->MaxVal = 0; + } + else + { + if( infoPtr->MinVal != info->nMin || + infoPtr->MaxVal != info->nMax ) + { + *action |= SA_SSI_REFRESH; + infoPtr->MinVal = info->nMin; + infoPtr->MaxVal = info->nMax; + } + } + } + + //DPRINT("hwnd=%04x bar=%d %s\n", + // hwnd, nBar, dbg_str(scroll)); + + /* Make sure the page size is valid */ + + if (infoPtr->Page < 0) infoPtr->Page = 0; + else if (infoPtr->Page > infoPtr->MaxVal - infoPtr->MinVal + 1 ) + infoPtr->Page = infoPtr->MaxVal - infoPtr->MinVal + 1; + + /* Make sure the pos is inside the range */ + + if (infoPtr->CurVal < infoPtr->MinVal) + infoPtr->CurVal = infoPtr->MinVal; + else if (infoPtr->CurVal > infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 )) + infoPtr->CurVal = infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 ); + + DPRINT(" new values: page=%d pos=%d min=%d max=%d\n", + infoPtr->Page, infoPtr->CurVal, + infoPtr->MinVal, infoPtr->MaxVal ); + + /* Check if the scrollbar should be hidden or disabled */ + + if (info->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL)) + { + new_flags = infoPtr->flags; + if (infoPtr->MinVal >= infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 )) + { + /* Hide or disable scroll-bar */ + if (info->fMask & SIF_DISABLENOSCROLL) + { + new_flags = ESB_DISABLE_BOTH; + *action |= SA_SSI_REFRESH; + } + else if (nBar != SB_CTL) + { + *action = SA_SSI_HIDE; + goto done; + } + } + else /* Show and enable scroll-bar */ + { + new_flags = 0; + if (nBar != SB_CTL) + *action |= SA_SSI_SHOW; + } + + if (infoPtr->flags != new_flags) /* check arrow flags */ + { + infoPtr->flags = new_flags; + *action |= SA_SSI_REPAINT_ARROWS; + } + } + +done: + /* Return current position */ + + return infoPtr->CurVal; +} \ No newline at end of file diff --git a/reactos/lib/user32/internal/signal.c b/reactos/lib/user32/internal/signal.c new file mode 100644 index 00000000000..413d9da6624 --- /dev/null +++ b/reactos/lib/user32/internal/signal.c @@ -0,0 +1,6 @@ +#include + +void SIGNAL_MaskAsyncEvents( WINBOOL flag ) +{ + // sigprocmask( (flag) ? SIG_BLOCK : SIG_UNBLOCK , &async_signal_set, NULL); +} \ No newline at end of file diff --git a/reactos/lib/user32/internal/text.c b/reactos/lib/user32/internal/text.c new file mode 100644 index 00000000000..81736213322 --- /dev/null +++ b/reactos/lib/user32/internal/text.c @@ -0,0 +1,719 @@ +/* + * text functions + * + * Copyright 1993, 1994 Alexandre Julliard + * + */ + +//#include +#include +#include + + + + +int tabstop; +int tabwidth; +int spacewidth; +int prefix_offset; +/* +typedef struct { + UINT cbSize; + int iTabLength; + int iLeftMargin; + int iRightMargin; + UINT uiLengthDrawn; +} DRAWTEXTPARAMS, FAR *LPDRAWTEXTPARAMS; +*/ + +int TEXT_DrawTextEx(HDC hDC,void *strPtr,int nCount,LPRECT lpRect,UINT uFormat,LPDRAWTEXTPARAMS dtp,WINBOOL Unicode ) +{ + SIZE size; + int line[1024]; + int len, lh, count=nCount; + int prefix_x = 0; + int prefix_end = 0; + TEXTMETRIC tm; + int x = lpRect->left, y = lpRect->top; + int width = lpRect->right - lpRect->left; + int max_width = 0; + + //TRACE(text,"%s, %d , [(%d,%d),(%d,%d)]\n", + // debugstr_an (lpString, count), count, + // lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + + if (count == -1) { + if ( Unicode ) + count = lstrlenW(strPtr); + else + count = lstrlenA(strPtr); + } + if ( Unicode ) + GetTextMetricsW(hDC, &tm); + else + GetTextMetricsA(hDC, &tm); + + if (uFormat & DT_EXTERNALLEADING) + lh = tm.tmHeight + tm.tmExternalLeading; + else + lh = tm.tmHeight; + + if (uFormat & DT_TABSTOP) + tabstop = uFormat >> 8; + + + if (uFormat & DT_EXPANDTABS) + { + GetTextExtentPointA(hDC, " ", 1, &size); + spacewidth = size.cx; + if ( dtp->iTabLength == 0 ) { + GetTextExtentPointA(hDC, "o", 1, &size); + tabwidth = size.cx * tabstop; + } + else + tabwidth = tabstop * dtp->iTabLength; + + } + + if (uFormat & DT_CALCRECT) uFormat |= DT_NOCLIP; + + do + { + prefix_offset = -1; + if ( Unicode ) + strPtr = TEXT_NextLineW(hDC, strPtr, &count, (LPWSTR)line, &len, width, uFormat); + else + strPtr = TEXT_NextLineA(hDC, strPtr, &count, (LPSTR)line, &len, width, uFormat); + + if ( Unicode ) { + if (prefix_offset != -1) + { + GetTextExtentPointW(hDC, (LPWSTR)line, prefix_offset, &size); + prefix_x = size.cx; + GetTextExtentPointW(hDC, (LPWSTR)line, prefix_offset + 1, &size); + prefix_end = size.cx - 1; + } + if (!GetTextExtentPointW(hDC, (LPWSTR)line, len, &size)) + return 0; + } + else { + if (prefix_offset != -1) + { + GetTextExtentPointA(hDC, (LPSTR)line, prefix_offset, &size); + prefix_x = size.cx; + GetTextExtentPointA(hDC, (LPSTR)line, prefix_offset + 1, &size); + prefix_end = size.cx - 1; + } + if (!GetTextExtentPointA(hDC, (LPSTR)line, len, &size)) + return 0; + } + + + + if (uFormat & DT_CENTER) + x = (lpRect->left + lpRect->right - size.cx) / 2; + else if (uFormat & DT_RIGHT) + x = lpRect->right - size.cx; + + if (uFormat & DT_SINGLELINE) + { + if (uFormat & DT_VCENTER) y = lpRect->top + + (lpRect->bottom - lpRect->top) / 2 - size.cy / 2; + else if (uFormat & DT_BOTTOM) y = lpRect->bottom - size.cy; + } + if (!(uFormat & DT_CALCRECT)) + { + if ( Unicode ) { + if (!ExtTextOutW(hDC, x, y, (uFormat & DT_NOCLIP) ? 0 : ETO_CLIPPED,lpRect, (LPWSTR)line, len, NULL )) + return 0; + } + else { + if (!ExtTextOutA(hDC, x, y, (uFormat & DT_NOCLIP) ? 0 : ETO_CLIPPED,lpRect, (LPSTR)line, len, NULL )) + return 0; + } + if (prefix_offset != -1) + { + HPEN hpen = CreatePen( PS_SOLID, 1, GetTextColor(hDC) ); + HPEN oldPen = SelectObject( hDC, hpen ); + MoveToEx(hDC, x + prefix_x, y + tm.tmAscent + 1,NULL ); + LineTo(hDC, x + prefix_end + 1, y + tm.tmAscent + 1 ); + SelectObject( hDC, oldPen ); + DeleteObject( hpen ); + } + } + else if (size.cx > max_width) + max_width = size.cx; + + y += lh; + if (strPtr) + { + if (!(uFormat & DT_NOCLIP)) + { + if (y > lpRect->bottom - lh) + break; + } + } + } + while (strPtr); + if (uFormat & DT_CALCRECT) + { + lpRect->right = lpRect->left + max_width; + lpRect->bottom = y; + } + return y - lpRect->top; +} + + +LPCSTR TEXT_NextLineA( HDC hdc, LPCSTR str, INT *count, + LPSTR dest, INT *len, INT width, WORD format) +{ + /* Return next line of text from a string. + * + * hdc - handle to DC. + * str - string to parse into lines. + * count - length of str. + * dest - destination in which to return line. + * len - length of resultant line in dest in chars. + * width - maximum width of line in pixels. + * format - format type passed to DrawText. + * + * Returns pointer to next char in str after end of the line + * or NULL if end of str reached. + */ + + int i = 0, j = 0, k; + int plen = 0; + int numspaces; + SIZE size; + int lasttab = 0; + int wb_i = 0, wb_j = 0, wb_count = 0; + + while (*count) + { + switch (str[i]) + { + case CR: + case LF: + if (!(format & DT_SINGLELINE)) + { + if ((*count > 1) && (str[i] == CR) && (str[i+1] == LF)) + { + (*count)--; + i++; + } + i++; + *len = j; + (*count)--; + return (&str[i]); + } + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || + (format & DT_WORDBREAK)) + { + if (!GetTextExtentPointA(hdc, &dest[j-1], 1, &size)) + return NULL; + plen += size.cx; + } + break; + + case PREFIX: + if (!(format & DT_NOPREFIX) && *count > 1) + { + if (str[++i] == PREFIX) + (*count)--; + else { + prefix_offset = j; + break; + } + } + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || + (format & DT_WORDBREAK)) + { + if (!GetTextExtentPointA(hdc, &dest[j-1], 1, &size)) + return NULL; + plen += size.cx; + } + break; + + case TAB: + if (format & DT_EXPANDTABS) + { + wb_i = ++i; + wb_j = j; + wb_count = *count; + + if (!GetTextExtentPointA(hdc, &dest[lasttab], j - lasttab, + &size)) + return NULL; + + numspaces = (tabwidth - size.cx) / spacewidth; + for (k = 0; k < numspaces; k++) + dest[j++] = SPACE; + plen += tabwidth - size.cx; + lasttab = wb_j + numspaces; + } + else + { + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || + (format & DT_WORDBREAK)) + { + if (!GetTextExtentPointA(hdc, &dest[j-1], 1, &size)) + return NULL; + plen += size.cx; + } + } + break; + + case SPACE: + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || + (format & DT_WORDBREAK)) + { + wb_i = i; + wb_j = j - 1; + wb_count = *count; + if (!GetTextExtentPointA(hdc, &dest[j-1], 1, &size)) + return NULL; + plen += size.cx; + } + break; + + default: + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || + (format & DT_WORDBREAK)) + { + if (!GetTextExtentPointA(hdc, &dest[j-1], 1, &size)) + return NULL; + plen += size.cx; + } + } + + (*count)--; + if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK)) + { + if (plen > width) + { + if (format & DT_WORDBREAK) + { + if (wb_j) + { + *len = wb_j; + *count = wb_count - 1; + return (&str[wb_i]); + } + } + else + { + *len = j; + return (&str[i]); + } + } + } + } + + *len = j; + return NULL; +} + +LPCWSTR TEXT_NextLineW( HDC hdc, LPCWSTR str, INT *count, + LPWSTR dest, INT *len, INT width, WORD format) +{ + /* Return next line of text from a string. + * + * hdc - handle to DC. + * str - string to parse into lines. + * count - length of str. + * dest - destination in which to return line. + * len - length of resultant line in dest in chars. + * width - maximum width of line in pixels. + * format - format type passed to DrawText. + * + * Returns pointer to next char in str after end of the line + * or NULL if end of str reached. + */ + + int i = 0, j = 0, k; + int plen = 0; + int numspaces; + SIZE size; + int lasttab = 0; + int wb_i = 0, wb_j = 0, wb_count = 0; + + while (*count) + { + switch (str[i]) + { + case CR: + case LF: + if (!(format & DT_SINGLELINE)) + { + if ((*count > 1) && (str[i] == CR) && (str[i+1] == LF)) + { + (*count)--; + i++; + } + i++; + *len = j; + (*count)--; + return (&str[i]); + } + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || + (format & DT_WORDBREAK)) + { + if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size)) + return NULL; + plen += size.cx; + } + break; + + case PREFIX: + if (!(format & DT_NOPREFIX) && *count > 1) + { + if (str[++i] == PREFIX) + (*count)--; + else { + prefix_offset = j; + break; + } + } + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || + (format & DT_WORDBREAK)) + { + if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size)) + return NULL; + plen += size.cx; + } + break; + + case TAB: + if (format & DT_EXPANDTABS) + { + wb_i = ++i; + wb_j = j; + wb_count = *count; + + if (!GetTextExtentPointW(hdc, &dest[lasttab], j - lasttab, + &size)) + return NULL; + + numspaces = (tabwidth - size.cx) / spacewidth; + for (k = 0; k < numspaces; k++) + dest[j++] = SPACE; + plen += tabwidth - size.cx; + lasttab = wb_j + numspaces; + } + else + { + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || + (format & DT_WORDBREAK)) + { + if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size)) + return NULL; + plen += size.cx; + } + } + break; + + case SPACE: + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || + (format & DT_WORDBREAK)) + { + wb_i = i; + wb_j = j - 1; + wb_count = *count; + if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size)) + return NULL; + plen += size.cx; + } + break; + + default: + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || + (format & DT_WORDBREAK)) + { + if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size)) + return NULL; + plen += size.cx; + } + } + + (*count)--; + if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK)) + { + if (plen > width) + { + if (format & DT_WORDBREAK) + { + if (wb_j) + { + *len = wb_j; + *count = wb_count - 1; + return (&str[wb_i]); + } + } + else + { + *len = j; + return (&str[i]); + } + } + } + } + + *len = j; + return NULL; +} + +#if 0 + + +WINBOOL TEXT_GrayString(HDC hdc, HBRUSH hb, + GRAYSTRINGPROC fn, LPARAM lp, INT len, + INT x, INT y, INT cx, INT cy, WINBOOL Unicode) +{ + HBITMAP hbm, hbmsave; + HBRUSH hbsave; + HFONT hfsave; + HDC memdc = CreateCompatibleDC(hdc); + int slen = len; + WINBOOL retval = TRUE; + RECT r; + COLORREF fg, bg; + + if(!hdc) return FALSE; + + if(len == 0) + { + if ( Unicode ) + slen = lstrlenW((LPCWSTR)lp); + else + slen = lstrlenA((LPCSTR)lp); + + } + + if((cx == 0 || cy == 0) && slen != -1) + { + SIZE s; + if ( Unicode ) + GetTextExtentPointW(hdc, (LPCWSTR)lp, slen, &s); + else + GetTextExtentPointA(hdc, (LPCSTR)lp, slen, &s); + + if(cx == 0) cx = s.cx; + if(cy == 0) cy = s.cy; + } + + r.left = r.top = 0; + r.right = cx; + r.bottom = cy; + + hbm = CreateBitmap(cx, cy, 1, 1, NULL); + hbmsave = (HBITMAP)SelectObject(memdc, hbm); + FillRect(memdc, &r, (HBRUSH)GetStockObject(BLACK_BRUSH)); + SetTextColor(memdc, RGB(255, 255, 255)); + SetBkColor(memdc, RGB(0, 0, 0)); + hfsave = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT)); + + if(fn) + retval = fn(memdc, lp, slen); + else { + if (Unicode ) + TextOutW(memdc, 0, 0, (LPCWSTR)lp, slen); + else + TextOutA(memdc, 0, 0, (LPCSTR)lp, slen); + } + + + SelectObject(memdc, hfsave); + +/* + * Windows doc says that the bitmap isn't grayed when len == -1 and + * the callback function returns FALSE. However, testing this on + * win95 showed otherwise... +*/ +#ifdef GRAYSTRING_USING_DOCUMENTED_BEHAVIOUR + if(retval || len != -1) +#endif + { + hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush()); + PatBlt(memdc, 0, 0, cx, cy, 0x000A0329); + SelectObject(memdc, hbsave); + } + + if(hb) hbsave = (HBRUSH)SelectObject(hdc, hb); + fg = SetTextColor(hdc, RGB(0, 0, 0)); + bg = SetBkColor(hdc, RGB(255, 255, 255)); + BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00E20746); + SetTextColor(hdc, fg); + SetBkColor(hdc, bg); + if(hb) SelectObject(hdc, hbsave); + + SelectObject(memdc, hbmsave); + DeleteObject(hbm); + DeleteDC(memdc); + return retval; +} + + +#endif + +/*********************************************************************** + * TEXT_TabbedTextOut + * + * Helper function for TabbedTextOut() and GetTabbedTextExtent(). + * Note: this doesn't work too well for text-alignment modes other + * than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-) + */ +LONG TEXT_TabbedTextOutA( HDC hdc, INT x, INT y, LPCSTR lpstr, + INT count, INT cTabStops, const INT *lpTabPos, + INT nTabOrg, WINBOOL fDisplayText ) +{ + INT defWidth; + DWORD extent = 0; + int i, tabPos = x; + int start = x; + SIZE szSize; + + if (cTabStops == 1) + { + defWidth = lpTabPos ? *lpTabPos : 0; + cTabStops = 0; + } + else + { + TEXTMETRIC tm; + GetTextMetricsA( hdc, &tm ); + defWidth = 8 * tm.tmAveCharWidth; + } + + while (count > 0) + { + for (i = 0; i < count; i++) + if (lpstr[i] == '\t') break; + GetTextExtentPoint32A( hdc, lpstr, i, &szSize ); + extent = szSize.cx; + if (lpTabPos) + { + while ((cTabStops > 0) && + (nTabOrg + *lpTabPos <= x + LOWORD(extent))) + { + lpTabPos++; + cTabStops--; + } + } + else + { + while ((cTabStops > 0) && + (nTabOrg + *lpTabPos <= x + LOWORD(extent))) + { + lpTabPos++; + cTabStops--; + } + } + if (i == count) + tabPos = x + LOWORD(extent); + else if (cTabStops > 0) + tabPos = nTabOrg + (lpTabPos ? *lpTabPos : 0); + else + tabPos = nTabOrg + ((x + LOWORD(extent) - nTabOrg) / defWidth + 1) * defWidth; + if (fDisplayText) + { + RECT r; + SetRect( &r, x, y, tabPos, y+HIWORD(extent) ); + ExtTextOutA( hdc, x, y, + GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0, + &r, lpstr, i, NULL ); + } + x = tabPos; + count -= i+1; + lpstr += i+1; + } + return MAKELONG(tabPos - start, HIWORD(extent)); +} + +/*********************************************************************** + * TEXT_TabbedTextOut + * + * Helper function for TabbedTextOut() and GetTabbedTextExtent(). + * Note: this doesn't work too well for text-alignment modes other + * than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-) + */ +LONG TEXT_TabbedTextOutW( HDC hdc, INT x, INT y, LPCWSTR lpstr, + INT count, INT cTabStops, const INT *lpTabPos, + INT nTabOrg, WINBOOL fDisplayText ) +{ + INT defWidth; + DWORD extent = 0; + int i, tabPos = x; + int start = x; + SIZE szSize; + + if (cTabStops == 1) + { + defWidth = lpTabPos ? *lpTabPos : 0; + cTabStops = 0; + } + else + { + TEXTMETRIC tm; + GetTextMetricsW( hdc, &tm ); + defWidth = 8 * tm.tmAveCharWidth; + } + + while (count > 0) + { + for (i = 0; i < count; i++) + if (lpstr[i] == '\t') break; + GetTextExtentPoint32W( hdc, lpstr, i, &szSize ); + extent = szSize.cx; + if (lpTabPos) + { + while ((cTabStops > 0) && + (nTabOrg + *lpTabPos <= x + LOWORD(extent))) + { + lpTabPos++; + cTabStops--; + } + } + else + { + while ((cTabStops > 0) && + (nTabOrg + *lpTabPos <= x + LOWORD(extent))) + { + lpTabPos++; + cTabStops--; + } + } + if (i == count) + tabPos = x + LOWORD(extent); + else if (cTabStops > 0) + tabPos = nTabOrg + (lpTabPos ? *lpTabPos : 0); + else + tabPos = nTabOrg + ((x + LOWORD(extent) - nTabOrg) / defWidth + 1) * defWidth; + if (fDisplayText) + { + RECT r; + SetRect( &r, x, y, tabPos, y+HIWORD(extent) ); + ExtTextOutW( hdc, x, y, + GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0, + &r, lpstr, i, NULL ); + } + x = tabPos; + count -= i+1; + lpstr += i+1; + } + return MAKELONG(tabPos - start, HIWORD(extent)); +} + +int _alloca(int x) +{ + return malloc(x); +} \ No newline at end of file diff --git a/reactos/lib/user32/internal/timer.c b/reactos/lib/user32/internal/timer.c new file mode 100644 index 00000000000..7784073ff72 --- /dev/null +++ b/reactos/lib/user32/internal/timer.c @@ -0,0 +1,293 @@ +/* + * Timer functions + * + * Copyright 1993 Alexandre Julliard + */ + +#include +#include +#include + + + + +static TIMER TimersArray[NB_TIMERS]; + +static TIMER * pNextTimer = NULL; /* Next timer to expire */ + + /* Duration from 'time' until expiration of the timer */ +#define EXPIRE_TIME(pTimer,time) \ + (((pTimer)->expires <= (time)) ? 0 : (pTimer)->expires - (time)) + + +/*********************************************************************** + * TIMER_InsertTimer + * + * Insert the timer at its place in the chain. + */ +void TIMER_InsertTimer( TIMER * pTimer ) +{ + if (!pNextTimer || (pTimer->expires < pNextTimer->expires)) + { + pTimer->next = pNextTimer; + pNextTimer = pTimer; + } + else + { + TIMER * ptr = pNextTimer; + while (ptr->next && (pTimer->expires >= ptr->next->expires)) + ptr = ptr->next; + pTimer->next = ptr->next; + ptr->next = pTimer; + } +} + + +/*********************************************************************** + * TIMER_RemoveTimer + * + * Remove the timer from the chain. + */ +void TIMER_RemoveTimer( TIMER * pTimer ) +{ + TIMER **ppTimer = &pNextTimer; + + while (*ppTimer && (*ppTimer != pTimer)) ppTimer = &(*ppTimer)->next; + if (*ppTimer) *ppTimer = pTimer->next; + pTimer->next = NULL; + if (!pTimer->expires) QUEUE_DecTimerCount( pTimer->hq ); +} + + +/*********************************************************************** + * TIMER_ClearTimer + * + * Clear and remove a timer. + */ +void TIMER_ClearTimer( TIMER * pTimer ) +{ + TIMER_RemoveTimer( pTimer ); + pTimer->hwnd = 0; + pTimer->msg = 0; + pTimer->id = 0; + pTimer->timeout = 0; + //WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER ); +} + + +/*********************************************************************** + * TIMER_SwitchQueue + */ +void TIMER_SwitchQueue( HQUEUE old, HQUEUE newQ ) +{ + TIMER * pT = pNextTimer; + + while (pT) + { + if (pT->hq == old) pT->hq = newQ; + pT = pT->next; + } +} + + +/*********************************************************************** + * TIMER_RemoveWindowTimers + * + * Remove all timers for a given window. + */ +void TIMER_RemoveWindowTimers( HWND hwnd ) +{ + int i; + TIMER *pTimer; + + for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++) + if ((pTimer->hwnd == hwnd) && pTimer->timeout) + TIMER_ClearTimer( pTimer ); +} + + +/*********************************************************************** + * TIMER_RemoveQueueTimers + * + * Remove all timers for a given queue. + */ +void TIMER_RemoveQueueTimers( HQUEUE hqueue ) +{ + int i; + TIMER *pTimer; + + for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++) + if ((pTimer->hq == hqueue) && pTimer->timeout) + TIMER_ClearTimer( pTimer ); +} + + +/*********************************************************************** + * TIMER_RestartTimers + * + * Restart an expired timer. + */ +void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime ) +{ + TIMER_RemoveTimer( pTimer ); + pTimer->expires = curTime + pTimer->timeout; + TIMER_InsertTimer( pTimer ); +} + + +/*********************************************************************** + * TIMER_GetNextExpiration + * + * Return next timer expiration time, or -1 if none. + */ +LONG TIMER_GetNextExpiration(void) +{ + return pNextTimer ? EXPIRE_TIME( pNextTimer, GetTickCount() ) : -1; +} + + +/*********************************************************************** + * TIMER_ExpireTimers + * + * Mark expired timers and wake the appropriate queues. + */ +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. + */ +WINBOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd, + HQUEUE hQueue,WINBOOL 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 || (pTimer->expires > curTime)) return FALSE; /* No timer */ + if (remove) TIMER_RestartTimer( pTimer, curTime ); /* Restart it */ + + DPRINT( "Timer expired: %04x, %04x, %04x, %08lx\n", + pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc); + + /* Build the message */ + msg->hwnd = (HWND)pTimer->hwnd; + msg->message = pTimer->msg; + msg->wParam = (UINT)pTimer->id; + msg->lParam = (LONG)pTimer->proc; + msg->time = curTime; + return TRUE; +} + + +/*********************************************************************** + * TIMER_SetTimer + */ +UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout, + TIMERPROC proc, WINBOOL sys ) +{ + int i; + TIMER * pTimer; + + int type = 0; + + if (!timeout) return 0; + + /* Check if there's already a timer with the same hwnd and id */ + + for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++) + if ((pTimer->hwnd == hwnd) && (pTimer->id == id) && + (pTimer->timeout != 0)) + { + /* Got one: set new values and return */ + TIMER_RemoveTimer( pTimer ); + pTimer->timeout = timeout; + // WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER ); + pTimer->proc = (HWINDOWPROC)0; + if (proc) { + pTimer->proc = proc; + //WINPROC_SetProc( &pTimer->proc, proc, type,WIN_PROC_TIMER ); + } + pTimer->expires = GetTickCount() + timeout; + TIMER_InsertTimer( pTimer ); + return id; + } + + /* Find a free timer */ + + for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++) + if (!pTimer->timeout) break; + + if (i >= NB_TIMERS) return 0; + if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return 0; + if (!hwnd) id = i + 1; + + /* Add the timer */ + + pTimer->hwnd = hwnd; + pTimer->hq = (hwnd) ? GetThreadQueue( GetWindowThreadProcessId( hwnd, NULL ) ) + : GetFastQueue( ); + pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER; + pTimer->id = id; + pTimer->timeout = timeout; + pTimer->expires = GetTickCount() + timeout; + pTimer->proc = (HWINDOWPROC)0; + if (proc) { + pTimer->proc = proc; + // WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER ); + } + DPRINT( "Timer added: %p, %04x, %04x, %04x, %08lx\n", + pTimer, pTimer->hwnd, pTimer->msg, pTimer->id, + (DWORD)pTimer->proc ); + TIMER_InsertTimer( pTimer ); + if (!id) return TRUE; + else return id; +} + + +/*********************************************************************** + * TIMER_KillTimer + */ +WINBOOL TIMER_KillTimer( HWND hwnd, UINT id,WINBOOL sys ) +{ + int i; + TIMER * pTimer; + + /* Find the timer */ + + for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++) + if ((pTimer->hwnd == hwnd) && (pTimer->id == id) && + (pTimer->timeout != 0)) break; + if (i >= NB_TIMERS) return FALSE; + if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return FALSE; + if (!sys && (pTimer->msg != WM_TIMER)) return FALSE; + else if (sys && (pTimer->msg != WM_SYSTIMER)) return FALSE; + + /* Delete the timer */ + + TIMER_ClearTimer( pTimer ); + return TRUE; +} + + + + diff --git a/reactos/lib/user32/internal/win.c b/reactos/lib/user32/internal/win.c new file mode 100644 index 00000000000..54a50954242 --- /dev/null +++ b/reactos/lib/user32/internal/win.c @@ -0,0 +1,893 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +WND *rootWnd; +////////////////////////////////////////////////////////////////////////////////// + +WND *pWndDesktop; + +HANDLE WIN_CreateWindowEx( CREATESTRUCTW *cs, ATOM classAtom) +{ + HANDLE hWnd; + WND *wndPtr; + STARTUPINFO StartupInfo; + CLASS *classPtr = NULL; + POINT maxSize, maxPos, minTrack, maxTrack; + HWND hWndLinkAfter = NULL; + /* Create the window structure */ + + + + classPtr = CLASS_FindClassByAtom(classAtom,cs->hInstance); + if ( classPtr == NULL ) + return NULL; + + + if (!(wndPtr = HeapAlloc(GetProcessHeap(),0, sizeof(WND) + classPtr->cbWndExtra + - sizeof(classPtr->wExtra) ))) + { + return NULL; + } + + + + wndPtr->next = rootWnd; + rootWnd = wndPtr; + + wndPtr->class = classPtr; + +// if ( CreatePipe(&(wndPtr->hmemTaskQ), &(wndPtr->hwndSelf),NULL,4096) == FALSE ) +// return -1; + + + wndPtr->hwndSelf = wndPtr; + hWnd = wndPtr->hwndSelf; + + /* Fill the window structure */ + + wndPtr->next = NULL; + wndPtr->child = NULL; + + if ((cs->style & WS_CHILD) && cs->hWndParent) + { + wndPtr->parent = WIN_FindWndPtr( cs->hWndParent ); + wndPtr->owner = NULL; + } + else + { + wndPtr->parent = pWndDesktop; + if (!cs->hWndParent || (cs->hWndParent == pWndDesktop->hwndSelf)) + wndPtr->owner = NULL; + else + wndPtr->owner = WIN_GetTopParentPtr(WIN_FindWndPtr(cs->hWndParent)); + } + + + wndPtr->winproc = classPtr->winproc; + wndPtr->dwMagic = WND_MAGIC; + //wndPtr->hwndSelf = hWnd; + wndPtr->hInstance = cs->hInstance; + wndPtr->text = NULL; + wndPtr->hmemTaskQ = GetFastQueue(); + wndPtr->hrgnUpdate = 0; + wndPtr->hwndLastActive = wndPtr->hwndSelf; + wndPtr->dwStyle = cs->style & ~WS_VISIBLE; + wndPtr->dwExStyle = cs->dwExStyle; + wndPtr->wIDmenu = 0; + wndPtr->helpContext = 0; + wndPtr->flags = 0; + wndPtr->pVScroll = NULL; + wndPtr->pHScroll = NULL; + wndPtr->pProp = NULL; + wndPtr->userdata = 0; + wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU) + ? MENU_GetSysMenu( hWnd, 0 ) : 0; + + if (classPtr->cbWndExtra) + memset( wndPtr->wExtra, 0, classPtr->cbWndExtra); + + + /* Call the WH_CBT hook */ + + hWndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) ? HWND_BOTTOM : HWND_TOP; + + if (HOOK_IsHooked( WH_CBT )) + { + CBT_CREATEWNDW cbtc; + LRESULT ret; + + cbtc.lpcs = cs; + cbtc.hwndInsertAfter = hWndLinkAfter; + ret = HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND, hWnd, (LPARAM)&cbtc); + if (ret) + { + + HeapFree( GetProcessHeap(),0,wndPtr ); + return NULL; + } + } + + /* Increment class window counter */ + + classPtr->cWindows++; + + /* Correct the window style */ + + if (!(cs->style & (WS_POPUP | WS_CHILD))) /* Overlapped window */ + { + wndPtr->dwStyle |= WS_CAPTION | WS_CLIPSIBLINGS; + wndPtr->flags |= WIN_NEED_SIZE; + } + if (cs->dwExStyle & WS_EX_DLGMODALFRAME) + wndPtr->dwStyle &= ~WS_THICKFRAME; + + + + /* Get class or window DC if needed */ + + if (classPtr->style & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hWnd,DCE_WINDOW_DC); + else if (classPtr->style & CS_CLASSDC) wndPtr->dce = classPtr->dce; + else wndPtr->dce = NULL; + + GetStartupInfoW((STARTUPINFO *)&StartupInfo); + if (cs->x == CW_USEDEFAULT) + { + if ( !(cs->style & (WS_CHILD | WS_POPUP)) + && (StartupInfo.dwFlags & STARTF_USEPOSITION) ) + { + cs->x = StartupInfo.dwX; + cs->y = StartupInfo.dwY; + } + else + { + cs->x = 0; + cs->y = 0; + } + } + if (cs->cx == CW_USEDEFAULT) + { + + if ( !(cs->style & (WS_CHILD | WS_POPUP)) + && (StartupInfo.dwFlags & STARTF_USESIZE) ) + { + cs->cx = StartupInfo.dwXSize; + cs->cy = StartupInfo.dwYSize; + } + else + { + cs->cx = 600; /* FIXME */ + cs->cy = 400; + } + } + + + + + /* Send the WM_GETMINMAXINFO message and fix the size if needed */ + + if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD))) + { + WINPOS_GetMinMaxInfo( wndPtr, &maxSize, &maxPos, &minTrack, &maxTrack); + if (maxSize.x < cs->cx) cs->cx = maxSize.x; + if (maxSize.y < cs->cy) cs->cy = maxSize.y; + if (cs->cx < minTrack.x ) cs->cx = minTrack.x; + if (cs->cy < minTrack.y ) cs->cy = minTrack.y; + } + + if(cs->style & WS_CHILD) + { + if(cs->cx < 0) cs->cx = 0; + if(cs->cy < 0) cs->cy = 0; + } + else + { + if (cs->cx <= 0) cs->cx = 1; + if (cs->cy <= 0) cs->cy = 1; + } + + wndPtr->rectWindow.left = cs->x; + wndPtr->rectWindow.top = cs->y; + wndPtr->rectWindow.right = cs->x + cs->cx; + wndPtr->rectWindow.bottom = cs->y + cs->cy; + wndPtr->rectClient = wndPtr->rectWindow; + + + /* Set the window menu */ + + if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION ) + { + if (cs->hMenu) + SetMenu(hWnd, cs->hMenu); + else + { + if (classPtr->menuName) { + if ( classPtr->bUnicode == FALSE ) + cs->hMenu = LoadMenuA(cs->hInstance,classPtr->menuName); + else + cs->hMenu = LoadMenuW(cs->hInstance,classPtr->menuName); + } + } + } + else + wndPtr->wIDmenu = (UINT)cs->hMenu; + + /* Send the WM_CREATE message + * Perhaps we shouldn't allow width/height changes as well. + * See p327 in "Internals". + */ + + maxPos.x = wndPtr->rectWindow.left; + maxPos.y = wndPtr->rectWindow.top; + + + if( SendMessageW( hWnd, WM_NCCREATE, 0, (LPARAM)cs) == 0) + { + /* Abort window creation */ + WIN_DestroyWindow( wndPtr ); + return NULL; + } + + /* Insert the window in the linked list */ + + WIN_LinkWindow( hWnd, hWndLinkAfter ); + + WINPOS_SendNCCalcSize( hWnd, FALSE, &wndPtr->rectWindow, + NULL, NULL, 0, &wndPtr->rectClient ); + OffsetRect(&wndPtr->rectWindow, maxPos.x - wndPtr->rectWindow.left, + maxPos.y - wndPtr->rectWindow.top); + if( (SendMessageW( hWnd, WM_CREATE, 0, (LPARAM)cs )) == -1 ) + { + WIN_UnlinkWindow( hWnd ); + WIN_DestroyWindow( wndPtr ); + return NULL; + } + /* Send the size messages */ + + if (!(wndPtr->flags & WIN_NEED_SIZE)) + { + /* send it anyway */ + if (((wndPtr->rectClient.right-wndPtr->rectClient.left) <0) + ||((wndPtr->rectClient.bottom-wndPtr->rectClient.top)<0)) + + SendMessageA( hWnd, WM_SIZE, SIZE_RESTORED, + MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left, + wndPtr->rectClient.bottom-wndPtr->rectClient.top)); + SendMessageA( hWnd, WM_MOVE, 0, + MAKELONG( wndPtr->rectClient.left, + wndPtr->rectClient.top ) ); + } + + /* Show the window, maximizing or minimizing if needed */ + + if (wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE)) + { + RECT newPos; + UINT swFlag = (wndPtr->dwStyle & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE; + wndPtr->dwStyle &= ~(WS_MAXIMIZE | WS_MINIMIZE); + WINPOS_MinMaximize( wndPtr, swFlag, &newPos ); + swFlag = ((wndPtr->dwStyle & WS_CHILD) || GetActiveWindow()) + ? SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED + : SWP_NOZORDER | SWP_FRAMECHANGED; + SetWindowPos( hWnd, 0, newPos.left, newPos.top, + newPos.right, newPos.bottom, swFlag ); + } + + if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) ) + { + /* Notify the parent window only */ + + SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY, + MAKEWPARAM(WM_CREATE, wndPtr->wIDmenu), (LPARAM)hWnd ); + if( !IsWindow(hWnd) ) return 0; + } + + if (cs->style & WS_VISIBLE) + ShowWindow( hWnd, SW_SHOW ); + + /* Call WH_SHELL hook */ + + if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner) + HOOK_CallHooksW( WH_SHELL, HSHELL_WINDOWCREATED, hWnd, 0L ); + + + return hWnd; + + +} + +/*********************************************************************** + * WIN_FindWinToRepaint + * + * Find a window that needs repaint. + */ +HWND WIN_FindWinToRepaint( HWND hwnd, HQUEUE hQueue ) +{ + HWND hwndRet; + WND *pWnd = pWndDesktop; + + /* Note: the desktop window never gets WM_PAINT messages + * The real reason why is because Windows DesktopWndProc + * does ValidateRgn inside WM_ERASEBKGND handler. + */ + + pWnd = hwnd ? WIN_FindWndPtr( hwnd ) : pWndDesktop->child; + + for ( ; pWnd ; pWnd = pWnd->next ) + { + if (!(pWnd->dwStyle & WS_VISIBLE)) + { + DPRINT( "skipping window %04x\n", + pWnd->hwndSelf ); + continue; + } + if ((pWnd->hmemTaskQ == hQueue) && + (pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT))) break; + + if (pWnd->child ) + if ((hwndRet = WIN_FindWinToRepaint( pWnd->child->hwndSelf, hQueue )) ) + return hwndRet; + } + + if (!pWnd) return 0; + + hwndRet = pWnd->hwndSelf; + + /* look among siblings if we got a transparent window */ + while (pWnd && ((pWnd->dwExStyle & WS_EX_TRANSPARENT) || + !(pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)))) + { + pWnd = pWnd->next; + } + if (pWnd) hwndRet = pWnd->hwndSelf; + DPRINT("found %04x\n",hwndRet); + return hwndRet; +} + +/********************************************************************** + * WIN_GetWindowLong + * + * Helper function for GetWindowLong(). + */ +LONG WIN_GetWindowLong( HWND hwnd, INT offset ) +{ + LONG retval; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return 0; + if (offset >= 0) + { + if (offset + sizeof(LONG) > wndPtr->class->cbWndExtra) + { + DPRINT( "Invalid offset %d\n", offset ); + return 0; + } + retval = *(LONG *)(((char *)wndPtr->wExtra) + offset); + + return retval; + } + switch(offset) + { + case GWL_USERDATA: return wndPtr->userdata; + case GWL_STYLE: return wndPtr->dwStyle; + case GWL_EXSTYLE: return wndPtr->dwExStyle; + case GWL_ID: return (LONG)wndPtr->wIDmenu; + case GWL_WNDPROC: return (LONG)wndPtr->winproc; + case GWL_HWNDPARENT: return wndPtr->parent ? (LONG)wndPtr->parent->hwndSelf : (LONG)0; + case GWL_HINSTANCE: return (LONG)wndPtr->hInstance; + default: + DPRINT( "Unknown offset %d\n", offset ); + } + return 0; +} + + +/********************************************************************** + * WIN_SetWindowLong + * + * Helper function for SetWindowLong(). + * + * 0 is the failure code. However, in the case of failure SetLastError + * must be set to distinguish between a 0 return value and a failure. + * + * FIXME: The error values for SetLastError may not be right. Can + * someone check with the real thing? + */ +LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval ) +{ + LONG *ptr, retval = 0; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + STYLESTRUCT style; + + //DPRINT("%x=%p %x %lx %x\n",hwnd, wndPtr, offset, newval, type); + + if (!wndPtr) + { + /* Is this the right error? */ + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return 0; + } + + if (offset >= 0) + { + if (offset + sizeof(LONG) > wndPtr->class->cbWndExtra) + { + DPRINT( "Invalid offset %d\n", offset ); + + /* Is this the right error? */ + SetLastError( ERROR_OUTOFMEMORY ); + + return 0; + } + ptr = (LONG *)(((char *)wndPtr->wExtra) + offset); + + + /* Special case for dialog window procedure */ + if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG)) + { + retval = ptr; + *ptr = newval; + return (LONG)retval; + } + } + else switch(offset) + { + case GWL_ID: + ptr = (DWORD*)&wndPtr->wIDmenu; + break; + case GWL_HINSTANCE: + return SetWindowWord( hwnd, offset, newval ); + case GWL_WNDPROC: + retval = wndPtr->winproc; + wndPtr->winproc = (WNDPROC)newval; + return retval; + case GWL_STYLE: + style.styleOld = wndPtr->dwStyle; + newval &= ~(WS_VISIBLE | WS_CHILD); /* Some bits can't be changed this way */ + style.styleNew = newval | (style.styleOld & (WS_VISIBLE | WS_CHILD)); + + //if (wndPtr->flags & WIN_ISWIN32) + SendMessageA(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style); + wndPtr->dwStyle = style.styleNew; + //if (wndPtr->flags & WIN_ISWIN32) + SendMessageA(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style); + return style.styleOld; + + case GWL_USERDATA: + ptr = &wndPtr->userdata; + break; + case GWL_EXSTYLE: + style.styleOld = wndPtr->dwExStyle; + style.styleNew = newval; + //if (wndPtr->flags & WIN_ISWIN32) + SendMessageA(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style); + wndPtr->dwExStyle = newval; + //if (wndPtr->flags & WIN_ISWIN32) + SendMessageA(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style); + return style.styleOld; + + default: + DPRINT( "Invalid offset %d\n", offset ); + + /* Don't think this is right error but it should do */ + SetLastError( ERROR_OUTOFMEMORY ); + + return 0; + } + retval = *ptr; + *ptr = newval; + return retval; +} + + +/*********************************************************************** + * WIN_DestroyWindow + * + * Destroy storage associated to a window. "Internals" p.358 + */ +WINBOOL WIN_DestroyWindow( WND* wndPtr ) +{ + HWND hWnd; + WND *pWnd; + + hWnd = wndPtr->hwndSelf; + +#ifdef CONFIG_IPC + if (main_block) + DDE_DestroyWindow(wndPtr->hwndSelf); +#endif /* CONFIG_IPC */ + + /* free child windows */ + + while ((pWnd = wndPtr->child)) + wndPtr->child = WIN_DestroyWindow( pWnd ); + + SendMessageA( wndPtr->hwndSelf, WM_NCDESTROY, 0, 0); + + /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */ + + WINPOS_CheckInternalPos( hWnd ); + if( hWnd == GetCapture()) ReleaseCapture(); + + /* free resources associated with the window */ + +// TIMER_RemoveWindowTimers( wndPtr->hwndSelf ); + PROPERTY_RemoveWindowProps( wndPtr ); + + wndPtr->dwMagic = 0; /* Mark it as invalid */ + + if ((wndPtr->hrgnUpdate) || (wndPtr->flags & WIN_INTERNAL_PAINT)) + { + if ((UINT)wndPtr->hrgnUpdate > 1) + DeleteObject( wndPtr->hrgnUpdate ); + //QUEUE_DecPaintCount( wndPtr->hmemTaskQ ); + } +// changed message queue implementation with pipes + /* toss stale messages from the queue */ +#if 0 + if( wndPtr->hmemTaskQ ) + { + int pos; + WINBOOL bPostQuit = FALSE; + WPARAM wQuitParam = 0; + MESSAGEQUEUE* msgQ = (MESSAGEQUEUE*) GlobalLock(wndPtr->hmemTaskQ); + + while( (pos = QUEUE_FindMsg(msgQ, hWnd, 0, 0)) != -1 ) + { + if( msgQ->messages[pos].msg.message == WM_QUIT ) + { + bPostQuit = TRUE; + wQuitParam = msgQ->messages[pos].msg.wParam; + } + QUEUE_RemoveMsg(msgQ, pos); + } + /* repost WM_QUIT to make sure this app exits its message loop */ + if( bPostQuit ) PostQuitMessage(wQuitParam); + wndPtr->hmemTaskQ = 0; + } +#endif + if (!(wndPtr->dwStyle & WS_CHILD)) + if (wndPtr->wIDmenu) DestroyMenu( (HMENU)wndPtr->wIDmenu ); + if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu ); + //wndPtr->pDriver->pDestroyWindow( wndPtr ); + + //DeleteDC(wndPtr->dc) /* Always do this to catch orphaned DCs */ + + wndPtr->winproc = NULL; + wndPtr->hwndSelf = NULL; + wndPtr->class->cWindows--; + wndPtr->class = NULL; + pWnd = wndPtr->next; + + //wndPtr->pDriver->pFinalize(wndPtr); + HeapFree( GetProcessHeap(),0,wndPtr ); + return 0; +} + +/*********************************************************************** + * WIN_ResetQueueWindows + * + * Reset the queue of all the children of a given window. + * Return TRUE if something was done. + */ +WINBOOL WIN_ResetQueueWindows( WND* wnd, HQUEUE hQueue, HQUEUE hNew ) +{ + WINBOOL ret = FALSE; + + if (hNew) /* Set a new queue */ + { + for (wnd = wnd->child; (wnd); wnd = wnd->next) + { + if (wnd->hmemTaskQ == hQueue) + { + wnd->hmemTaskQ = hNew; + ret = TRUE; + } + if (wnd->child) + ret |= WIN_ResetQueueWindows( wnd, hQueue, hNew ); + } + } + else /* Queue is being destroyed */ + { + while (wnd->child) + { + WND *tmp = wnd->child; + ret = FALSE; + while (tmp) + { + if (tmp->hmemTaskQ == hQueue) + { + DestroyWindow( tmp->hwndSelf ); + ret = TRUE; + break; + } + if (tmp->child && WIN_ResetQueueWindows(tmp->child,hQueue,0)) + ret = TRUE; + else + tmp = tmp->next; + } + if (!ret) break; + } + } + return ret; +} + +#if 0 + +WND * WIN_FindWndPtr( HWND hWnd ) +{ + WND *wndPtr = rootWnd; + + while ( wndPtr != NULL ) { + if ( wndPtr->hwndSelf == hWnd ) + return wndPtr; + wndPtr->next = wndPtr; + } + return NULL; +} + +#endif + +WND * WIN_FindWndPtr( HWND hwnd ) +{ + WND * ptr; + + if ( hwnd == NULL ) return NULL; + ptr = (WND *)( hwnd ); + if (ptr->dwMagic != WND_MAGIC) return NULL; + if (ptr->hwndSelf != hwnd) + { + DPRINT( "Can't happen: hwnd %04x self pointer is %04x\n", + hwnd, ptr->hwndSelf ); + return NULL; + } + return ptr; +} +WND* WIN_GetDesktop(void) +{ + return NULL; +} + +WND **WIN_BuildWinArray( WND *wndPtr, UINT bwaFlags, UINT* pTotal ) +{ + WND **list, **ppWnd; + WND *pWnd; + UINT count, skipOwned, skipHidden; + DWORD skipFlags; + + skipHidden = bwaFlags & BWA_SKIPHIDDEN; + skipOwned = bwaFlags & BWA_SKIPOWNED; + skipFlags = (bwaFlags & BWA_SKIPDISABLED) ? WS_DISABLED : 0; + if( bwaFlags & BWA_SKIPICONIC ) skipFlags |= WS_MINIMIZE; + + /* First count the windows */ + + if (!wndPtr) wndPtr = pWndDesktop; + for (pWnd = wndPtr->child, count = 0; pWnd; pWnd = pWnd->next) + { + if( (pWnd->dwStyle & skipFlags) || (skipOwned && pWnd->owner) ) continue; + if( !skipHidden || pWnd->dwStyle & WS_VISIBLE ) count++; + } + + if( count ) + { + /* Now build the list of all windows */ + + if ((list = (WND **)HeapAlloc( GetProcessHeap(), 0, sizeof(WND *) * (count + 1)))) + { + for (pWnd = wndPtr->child, ppWnd = list, count = 0; pWnd; pWnd = pWnd->next) + { + if( (pWnd->dwStyle & skipFlags) || (skipOwned && pWnd->owner) ) continue; + if( !skipHidden || pWnd->dwStyle & WS_VISIBLE ) + { + *ppWnd++ = pWnd; + count++; + } + } + *ppWnd = NULL; + } + else count = 0; + } else list = NULL; + + if( pTotal ) *pTotal = count; + return list; +} +void WIN_DestroyList( WND **list ) +{ + HeapFree(GetProcessHeap(),0,*list); +} + + + + + + +/*********************************************************************** + * WIN_UnlinkWindow + * + * Remove a window from the siblings linked list. + */ +WINBOOL WIN_UnlinkWindow( HWND hWnd ) +{ + WND *wndPtr, **ppWnd; + + if (!(wndPtr = WIN_FindWndPtr( hWnd )) || !wndPtr->parent) return FALSE; + ppWnd = &wndPtr->parent->child; + while (*ppWnd != wndPtr) ppWnd = &(*ppWnd)->next; + *ppWnd = wndPtr->next; + return TRUE; +} + + +/*********************************************************************** + * WIN_LinkWindow + * + * Insert a window into the siblings linked list. + * The window is inserted after the specified window, which can also + * be specified as HWND_TOP or HWND_BOTTOM. + */ +WINBOOL WIN_LinkWindow( HWND hWnd, HWND hWndInsertAfter ) +{ + WND *wndPtr, **ppWnd; + + if (!(wndPtr = WIN_FindWndPtr( hWnd )) || !wndPtr->parent) return FALSE; + + if ((hWndInsertAfter == HWND_TOP) || (hWndInsertAfter == HWND_BOTTOM)) + { + ppWnd = &wndPtr->parent->child; /* Point to first sibling hWnd */ + if (hWndInsertAfter == HWND_BOTTOM) /* Find last sibling hWnd */ + while (*ppWnd) ppWnd = &(*ppWnd)->next; + } + else /* Normal case */ + { + WND * afterPtr = WIN_FindWndPtr( hWndInsertAfter ); + if (!afterPtr) return FALSE; + ppWnd = &afterPtr->next; + } + wndPtr->next = *ppWnd; + *ppWnd = wndPtr; + return TRUE; +} + + + +void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate) +{ + POINT pt = {0, 0}; + HRGN hClip = 1; + + DPRINT("hwnd %04x, hrgnUpdate %04x\n", + wnd->hwndSelf, wnd->hrgnUpdate ); + + /* desktop window doesn't have nonclient area */ + if(wnd == WIN_GetDesktop()) + { + wnd->flags &= ~WIN_NEEDS_NCPAINT; + return; + } + + if( wnd->hrgnUpdate > 1 ) + { + ClientToScreen(wnd->hwndSelf, &pt); + + hClip = CreateRectRgn( 0, 0, 0, 0 ); + if (!CombineRgn( hClip, wnd->hrgnUpdate, 0, RGN_COPY )) + { + DeleteObject(hClip); + hClip = 1; + } + else + OffsetRgn( hClip, pt.x, pt.y ); + + if (bUpdate) + { + /* exclude non-client area from update region */ + HRGN hrgn = CreateRectRgn( 0, 0, + wnd->rectClient.right - wnd->rectClient.left, + wnd->rectClient.bottom - wnd->rectClient.top); + + if (hrgn && (CombineRgn( wnd->hrgnUpdate, wnd->hrgnUpdate, + hrgn, RGN_AND) == NULLREGION)) + { + DeleteObject( wnd->hrgnUpdate ); + wnd->hrgnUpdate = 1; + } + + DeleteObject( hrgn ); + } + } + + wnd->flags &= ~WIN_NEEDS_NCPAINT; + + if ((wnd->hwndSelf == GetActiveWindow()) && + !(wnd->flags & WIN_NCACTIVATED)) + { + wnd->flags |= WIN_NCACTIVATED; + if( hClip > 1) DeleteObject( hClip ); + hClip = 1; + } + + if (hClip) SendMessage( wnd->hwndSelf, WM_NCPAINT, hClip, 0L ); + + if (hClip > 1) DeleteObject( hClip ); +} + +/*********************************************************************** + * WIN_IsWindowDrawable + * + * hwnd is drawable when it is visible, all parents are not + * minimized, and it is itself not minimized unless we are + * trying to draw its default class icon. + */ +WINBOOL WIN_IsWindowDrawable( WND* wnd, WINBOOL icon ) +{ + if( (wnd->dwStyle & WS_MINIMIZE && + icon && wnd->class->hIcon) || + !(wnd->dwStyle & WS_VISIBLE) ) return FALSE; + for(wnd = wnd->parent; wnd; wnd = wnd->parent) + if( wnd->dwStyle & WS_MINIMIZE || + !(wnd->dwStyle & WS_VISIBLE) ) break; + return (wnd == NULL); +} + + + +WND* WIN_GetTopParentPtr( WND* pWnd ) +{ + while( pWnd && (pWnd->dwStyle & WS_CHILD)) pWnd = pWnd->parent; + return pWnd; +} + + +HWND WIN_GetTopParent( HWND hwnd ) +{ + WND *wndPtr = WIN_GetTopParentPtr ( WIN_FindWndPtr( hwnd ) ); + return wndPtr ? wndPtr->hwndSelf : 0; +} + + +void WIN_CheckFocus( WND* pWnd ) +{ + if( GetFocus() == pWnd->hwndSelf ) + SetFocus( (pWnd->dwStyle & WS_CHILD) ? pWnd->parent->hwndSelf : 0 ); +} + + +void WIN_SendDestroyMsg( WND* pWnd ) +{ + WIN_CheckFocus(pWnd); + + if( CARET_GetHwnd() == pWnd->hwndSelf ) DestroyCaret(); +// CLIPBOARD_GetDriver()->pResetOwner( pWnd, TRUE ); + + SendMessageA( pWnd->hwndSelf, WM_DESTROY, 0, 0); + + if( IsWindow(pWnd->hwndSelf) ) + { + WND* pChild = pWnd->child; + while( pChild ) + { + WIN_SendDestroyMsg( pChild ); + pChild = pChild->next; + } + WIN_CheckFocus(pWnd); + } + else + DPRINT( "\tdestroyed itself while in WM_DESTROY!\n"); +} + + +/******************************************************************* + * GetSysModalWindow16 (USER.52) + */ +HWND GetSysModalWindow(void) +{ + return NULL; +} diff --git a/reactos/lib/user32/makefile.main b/reactos/lib/user32/makefile.main new file mode 100644 index 00000000000..ccdcef24790 --- /dev/null +++ b/reactos/lib/user32/makefile.main @@ -0,0 +1,29 @@ +all: user32.exe + +INTERNAL_OBJECTS = internal/property.o internal/menu.o internal/heapdup.o internal/nc.o\ + internal/scroll.o internal/win.o internal/dce.o internal/msg.o internal/queue.o\ + internal/signal.o internal/event.o internal/timer.o internal/region.o\ + internal/text.o + +MISC_OBJECTS = misc/sprintf.o misc/dllmain.o misc/string.o misc/sysmetr.o\ + misc/main.o misc/bitmap.o misc/cursor.o misc/vk.o + + +WINDOWS_OBJECTS = windows/wndproc.o windows/win.o windows/hook.o windows/spy.o\ + windows/queue.o windows/winpos.o windows/class.o windows/menu.o windows/dc.o\ + windows/timer.o windows/rect.o windows/msg.o windows/input.o windows/property.o\ + windows/focus.o + +GRAPHICS_OBJECTS = graphics/rect.o graphics/caret.o graphics/text.o graphics/syscol.o graphics/fill.o\ + graphics/draw.o + +RESOURCE_OBJECTS = resources/sysres.o + +OBJECTS = $(MISC_OBJECTS) $(INTERNAL_OBJECTS) $(GRAPHICS_OBJECTS) $(RESOURCE_OBJECTS) $(WINDOWS_OBJECTS) + +user32.exe: $(OBJECTS) + $(LD) $(OBJECTS) F:/gnu/cygnus/cygwin-b20/H-i586-cygwin32/i586-cygwin32/lib/crt1.o F:/gnu/cygnus/cygwin-b20/H-i586-cygwin32/i586-cygwin32/lib/libgdi32.a F:/gnu/cygnus/cygwin-b20/H-i586-cygwin32/i586-cygwin32/lib/libkernel32.a F:/gnu/cygnus/cygwin-b20/H-i586-cygwin32/i586-cygwin32/lib/libcrtdll.a -o user32.exe + +dummy: + +include ../../Rules.mak \ No newline at end of file diff --git a/reactos/lib/user32/misc/bitmap.c b/reactos/lib/user32/misc/bitmap.c new file mode 100644 index 00000000000..4ff22c57e4b --- /dev/null +++ b/reactos/lib/user32/misc/bitmap.c @@ -0,0 +1,80 @@ +#include + +HBITMAP BITMAP_LoadBitmapW(HINSTANCE instance,LPCWSTR name, UINT loadflags); + +HBITMAP LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName) +{ + return BITMAP_LoadBitmapW(hInstance, lpBitmapName, 0); +} + +HBITMAP LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName) +{ + return NULL; +// return BITMAP_LoadBitmap32W(hInstance, lpBitmapName, 0); +} + +HBITMAP BITMAP_LoadBitmapW(HINSTANCE instance,LPCWSTR name, + UINT loadflags) +{ +#if 0 + HBITMAP hbitmap = 0; + HDC hdc; + HRSRC hRsrc; + HGLOBAL handle; + char *ptr = NULL; + BITMAPINFO *info, *fix_info=NULL; + HGLOBAL hFix; + int size; + + if (!(loadflags & LR_LOADFROMFILE)) { + if (!instance) /* OEM bitmap */ + { + HDC hdc; + DC *dc; + + if (HIWORD((int)name)) return 0; + hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL ); + dc = DC_GetDCPtr( hdc ); + if(dc->funcs->pLoadOEMResource) + hbitmap = dc->funcs->pLoadOEMResource( LOWORD((int)name), + OEM_BITMAP ); + GDI_HEAP_UNLOCK( hdc ); + DeleteDC( hdc ); + return hbitmap; + } + + if (!(hRsrc = FindResourceW( instance, name, RT_BITMAPW ))) return 0; + if (!(handle = LoadResource( instance, hRsrc ))) return 0; + + if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0; + } + else + { + if (!(ptr = (char *)VIRTUAL_MapFileW( name ))) return 0; + info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER)); + } + size = DIB_BitmapInfoSize(info, DIB_RGB_COLORS); + if ((hFix = GlobalAlloc(0, size))) fix_info=GlobalLock(hFix); + if (fix_info) { + BYTE pix; + + memcpy(fix_info, info, size); + pix = *((LPBYTE)info+DIB_BitmapInfoSize(info, DIB_RGB_COLORS)); + DIB_FixColorsToLoadflags(fix_info, loadflags, pix); + if ((hdc = GetDC(0)) != 0) { + if (loadflags & LR_CREATEDIBSECTION) + hbitmap = CreateDIBSection(hdc, fix_info, DIB_RGB_COLORS, NULL, 0, 0); + else { + char *bits = (char *)info + size;; + hbitmap = CreateDIBitmap( hdc, &fix_info->bmiHeader, CBM_INIT, + bits, fix_info, DIB_RGB_COLORS ); + } + ReleaseDC( 0, hdc ); + } + GlobalUnlock(hFix); + GlobalFree(hFix); + } + if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr ); + return hbitmap; +#endif +} diff --git a/reactos/lib/user32/misc/cursor.c b/reactos/lib/user32/misc/cursor.c new file mode 100644 index 00000000000..56059628caa --- /dev/null +++ b/reactos/lib/user32/misc/cursor.c @@ -0,0 +1,34 @@ +#include + +/*********************************************************************** + * SetCursor (USER32.472) + * RETURNS: + * A handle to the previous cursor shape. + */ +HCURSOR STDCALL SetCursor( HCURSOR hCursor ) +{ +} + + +int STDCALL ShowCursor(WINBOOL bShow ) +{ +} + +WINBOOL STDCALL SetCursorPos(int x, int y ) +{ +} + +HCURSOR STDCALL LoadCursorA(HINSTANCE hInstance, LPCSTR lpCursorName ) +{ +} + +HCURSOR STDCALL LoadCursorW(HINSTANCE hInstance, LPCWSTR lpCursorName ) +{ +} + +WINBOOL +STDCALL +DestroyCursor( + HCURSOR hCursor) +{ +} \ No newline at end of file diff --git a/reactos/lib/user32/misc/main.c b/reactos/lib/user32/misc/main.c new file mode 100644 index 00000000000..38eee2e19c5 --- /dev/null +++ b/reactos/lib/user32/misc/main.c @@ -0,0 +1,72 @@ +#include + +LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM, LPARAM); + +char szName[] = "Hallo"; + +int _CRT_fmode = 0; +int _CRT_glob = 0; + +int __main(int argc, char **argv) +{ +} + + +int main(int argc, char **argv) +{ + HWND hwnd; + MSG msg; + WNDCLASSEX wc1; + HINSTANCE hInst = 0; + int nWinMode = 0; + + wc1.hInstance = hInst; + wc1.lpszClassName = szName; + wc1.lpfnWndProc = WindowFunc; + wc1.style = 0; + wc1.cbSize = sizeof(WNDCLASSEX); + wc1.hIcon = NULL; + wc1.hIconSm = NULL; + + wc1.hCursor = NULL; + wc1.lpszMenuName = NULL; + + wc1.cbClsExtra = 0; + wc1.cbWndExtra = 0; + + wc1.hbrBackground = NULL; + + if ( !RegisterClassEx(&wc1)) return 0; + + hwnd = CreateWindowEx(0, szName, "test", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, + NULL,NULL,hInst, NULL); + + ShowWindow(hwnd,nWinMode); + UpdateWindow(hwnd); + + while(GetMessage(&msg,NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return msg.wParam; +} + + + //printf("hallo\n"); + + + +LRESULT CALLBACK WindowFunc(HWND hwnd,UINT message,WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } + return 0; +} diff --git a/reactos/lib/user32/misc/string.c b/reactos/lib/user32/misc/string.c new file mode 100644 index 00000000000..f38e6a0ff87 --- /dev/null +++ b/reactos/lib/user32/misc/string.c @@ -0,0 +1,813 @@ +/* + * String functions + * + * Copyright 1993 Yngvi Sigurjonsson (yngvi@hafro.is) + * Copyright 1996 Marcus Meissner + */ + +#include +#include +#include +#include +#include + +/* Funny to divide them between user and kernel. */ + +/* be careful: always use functions from wctype.h if character > 255 */ + +/* + * Unicode case conversion routines ... these should be used where + * toupper/tolower are used for ASCII. + */ + +// bugfix: mutual exclusiveness of +// FORMAT_MESSAGE_FROM_STRING, FORMAT_MESSAGE_FROM_SYSTEM and FORMAT_MESSAGE_FROM_HMODULE +// in FormatMessage + +#define IsDBCSLeadByte(c) FALSE +#define IsDBCSLeadByteEx(c,n) FALSE +#define CopyMemory memcpy +#define lstrlenA strlen +#define lstrlenW wcslen + +DWORD LoadMessageA(HMODULE hModule,DWORD dwMessageId, + DWORD dwLanguageId,LPSTR Buffer,UINT BufSize); +DWORD LoadMessageW(HMODULE hModule,DWORD dwMessageId, + DWORD dwLanguageId,LPWSTR Buffer,UINT BufSize); + + +LPWSTR lstrchrW(LPCWSTR s, INT c); +LPSTR lstrchrA(LPCSTR s, INT c); + + + +LPSTR STDCALL CharNextA(LPCSTR lpsz) +{ + LPSTR next = (LPSTR)lpsz; + if (!*lpsz) + return next; + if (IsDBCSLeadByte( *next )) + next++; + next++; + return next; +} + + +/*********************************************************************** + * CharNextExA (USER.30) + */ +LPSTR STDCALL CharNextExA( WORD codepage, LPCSTR ptr, DWORD flags ) +{ + LPSTR next = (LPSTR)ptr; + if (!*ptr) + return next; + if (IsDBCSLeadByteEx( codepage, *next )) + return next++; + next++; + return next; +} + + + +LPWSTR +STDCALL +CharNextW(LPCWSTR lpsz) +{ + LPWSTR next = (LPWSTR)lpsz; + if (!*lpsz) + return next; + next++; + return next; +} + + +LPSTR STDCALL CharPrevA( LPCSTR start, LPCSTR ptr ) +{ + LPCSTR next; + while (*start && (start < ptr)) + { + next = CharNextA( start ); + if (next >= ptr) + break; + start = next; + } + return (LPSTR)start; +} + + + +LPSTR STDCALL CharPrevExA( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags ) +{ + + LPCSTR next; + while (*start && (start < ptr)) + { + next = CharNextExA( codepage, start, flags ); + if (next > ptr) + break; + start = next; + } + return (LPSTR)start; +} + + + + + + +LPWSTR STDCALL CharPrevW(LPCWSTR start,LPCWSTR x) +{ + LPWSTR prev = (LPWSTR)x; + if (x<=start) + return prev; + prev--; + return prev; +} + + +LPSTR STDCALL CharLowerA(LPSTR x) +{ + LPSTR s; + UINT s2; + if (!HIWORD(x)) { + s2 = (UINT)x; + + if (!IsDBCSLeadByte( s2 )) { + if (!IsCharLowerA(s2)) + s2 = s2 - ( 'A' - 'a' ); + return (LPSTR)s2; + } + else { + // should do a multibyte toupper + if (s2 >= 'A' && s2 <= 'Z') + s2 = s2 - ( 'A' - 'a' ); + return (LPSTR)s2; + } + return (LPSTR)x; + } + + s=x; + while (*s) + { + if (!IsDBCSLeadByte( *s )) { + if (!IsCharLowerA(*s)) + *s = *s - ( 'A' - 'a' ); + } + else { + // should do a multibyte toupper + s++; + } + s++; + } + return x; + +} + + +DWORD STDCALL CharLowerBuffA(LPSTR s,DWORD buflen) +{ + DWORD done=0; + + if (!s) + return 0; /* YES */ + while (*s && (buflen--)) + { + if (!IsDBCSLeadByte( *s )) { + if (!IsCharLowerA(*s)) + *s = *s - ( 'A' - 'a' ); + } + else { + // should do a multibyte toupper + s++; + } + s++; + done++; + } + return done; +} + + +DWORD STDCALL CharLowerBuffW(LPWSTR s,DWORD buflen) +{ + DWORD done=0; + + if (!s) + return 0; /* YES */ + while (*s && (buflen--)) + { + if (!IsCharLowerW(*s)) + *s = *s - ( L'A' - L'a' ); + s++; + done++; + } + return done; +} + + +LPWSTR STDCALL CharLowerW(LPWSTR x) +{ + LPWSTR s; + UINT s2; + if (!HIWORD(x)) { + s2 = (UINT)x; + if (!IsCharLowerW(s2)) + s2 = s2 - ( L'A' - L'a' ); + return (LPWSTR)s2; + } + s = x; + while (*s) + { + if (!IsCharLowerW(*s)) + *s = *s - ( L'A' - L'a' ); + s++; + } + return x; +} + + + +LPSTR STDCALL CharUpperA(LPSTR x) +{ + LPSTR s; + UINT s2; + if (!HIWORD(x)) { + s2 = (UINT)x; + + + if (!IsDBCSLeadByte( s2 )) { + if (!IsCharUpperW(s2)) + s2 = s2 + ( 'A' - 'a' ); + return (LPSTR)s2; + } + else { + // should do a multibyte toupper + if (s2 >= 'a' && s2 <= 'z') + s2 = s2 + ( 'A' - 'a' ); + return (LPSTR)s2; + } + return x; + } + + + + s=x; + while (*s) + { + if (!IsDBCSLeadByte( *s )) { + if (!IsCharUpperW(*s)) + *s = *s + ( 'A' - 'a' ); + } + else { + // should do a multibyte toupper + s++; + } + s++; + } + return x; + +} + + +DWORD STDCALL CharUpperBuffA(LPSTR s,DWORD buflen) +{ + DWORD done=0; + + if (!s) + return 0; /* YES */ + while (*s && (buflen--)) + { + if (!IsDBCSLeadByte( *s )) { + if (!IsCharUpperW(*s)) + *s = *s + ( 'A' - 'a' ); + } + else { + // should do a multibyte toupper + s++; + } + s++; + done++; + } + return done; +} + + +DWORD STDCALL CharUpperBuffW(LPWSTR s,DWORD buflen) +{ + DWORD done=0; + + if (!s) + return 0; /* YES */ + while (*s && (buflen--)) + { + if (!IsCharUpperW(*s)) + *s = *s + ( L'A' - L'a' ); + s++; + done++; + } + return done; +} + + +LPWSTR STDCALL CharUpperW(LPWSTR x) +{ + LPWSTR s; + UINT s2; + if (!HIWORD(x)) { + s2 = (UINT)x; + if (!IsCharUpperW(s2)) + s2 = s2 + ( L'A' - L'a' ); + return (LPWSTR)s2; + } + s = x; + while (*s) + { + if (!IsCharUpperW(*s)) + *s = *s + ( L'A' - L'a' ); + s++; + } + return x; +} + + + +WINBOOL STDCALL IsCharAlphaNumericA(CHAR c) +{ + return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')); +} + + +WINBOOL STDCALL IsCharAlphaNumericW(WCHAR c) +{ + return ((c >= L'A' && c <= L'Z') || (c >= L'a' && c <= L'z') || (c >= L'0' && c <= L'9')); +} +WINBOOL STDCALL IsCharAlphaA(CHAR c) +{ + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +WINBOOL STDCALL IsCharAlphaW(WCHAR c) +{ + return (c >= L'A' && c <= L'Z') || (c >= L'a' && c <= L'z'); +} + + +WINBOOL STDCALL IsCharLowerA(CHAR c) +{ + return (c >= 'a' && c <= 'z'); +} + + +WINBOOL STDCALL IsCharLowerW(WCHAR c) +{ + return (c >= L'a' && c <= L'z'); +} + + +WINBOOL STDCALL IsCharUpperA(CHAR c) +{ + return (c >= 'A' && c <= 'Z' ); +} + + +WINBOOL STDCALL IsCharUpperW(WCHAR c) +{ + return (c >= L'A' && c <= L'Z' ); +} + + +DWORD STDCALL FormatMessageA( + DWORD dwFlags, + LPCVOID lpSource, + DWORD dwMessageId, + DWORD dwLanguageId, + LPSTR lpBuffer, + DWORD nSize, + va_list *Arguments +) { + LPSTR target,t; + DWORD talloced; + LPSTR from,f; + //DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK; + DWORD nolinefeed = 0; + DWORD len; + + ////TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", + // dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,Arguments); + //if (width) + // FIXME(resource,"line wrapping not supported.\n"); + from = NULL; + if (dwFlags & FORMAT_MESSAGE_FROM_STRING) { + len = lstrlenA((LPSTR)lpSource); + from = HeapAlloc( GetProcessHeap(),0, len+1 ); + CopyMemory(from,lpSource,len+1); + } + else if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) { + len = 200; + from = HeapAlloc( GetProcessHeap(),0,200 ); + wsprintfA(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId); + } + else if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) { + INT bufsize; + + dwMessageId &= 0xFFFF; + bufsize=LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,NULL,100); + if (bufsize) { + from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 ); + LoadMessageA((HMODULE)lpSource,dwMessageId,dwLanguageId,from,bufsize+1); + } + } + target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100); + t = target; + talloced= 100; + +#define ADD_TO_T(c) \ + *t++=c;\ + if (t-target == talloced) {\ + target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\ + t = target+talloced;\ + talloced*=2;\ + } + + if (from) { + f=from; + while (*f && !nolinefeed) { + if (*f=='%') { + int insertnr; + char *fmtstr,*sprintfbuf,*x,*lastf; + DWORD *argliststart; + + fmtstr = NULL; + lastf = f; + f++; + if (!*f) { + ADD_TO_T('%'); + continue; + } + switch (*f) { + case '1':case '2':case '3':case '4':case '5': + case '6':case '7':case '8':case '9': + insertnr=*f-'0'; + switch (f[1]) { + case '0':case '1':case '2':case '3': + case '4':case '5':case '6':case '7': + case '8':case '9': + f++; + insertnr=insertnr*10+*f-'0'; + f++; + break; + default: + f++; + break; + } + if (*f=='!') { + f++; + if (NULL!=(x=lstrchrA(f,'!'))) { + *x='\0'; + fmtstr=HeapAlloc(GetProcessHeap(),0,lstrlenA(f)+2); + wsprintfA(fmtstr,"%%%s",f); + f=x+1; + } else { + len = lstrlenA(f); + fmtstr=HeapAlloc(GetProcessHeap(),0,len + 1); + wsprintfA(fmtstr,"%%%s",f); + f+=lstrlenA(f); /*at \0*/ + } + } else + if(!Arguments) + break; + else { + fmtstr = HeapAlloc( GetProcessHeap(),0, 3 ); + fmtstr[0] = '%'; + fmtstr[1] = 's'; + fmtstr[2] = 0; + } + if (Arguments) { + if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) + argliststart=Arguments+insertnr-1; + else + argliststart=(*(DWORD**)Arguments)+insertnr-1; + + if (fmtstr[lstrlenA(fmtstr)-1]=='s') + sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlenA((LPSTR)argliststart[0])+1); + else + sprintfbuf=HeapAlloc(GetProcessHeap(),0,100); + + /* CMF - This makes a BIG assumption about va_list */ + wvsprintfA(sprintfbuf, fmtstr, (va_list) argliststart); + x=sprintfbuf; + while (*x) { + ADD_TO_T(*x++); + } + HeapFree(GetProcessHeap(),0,sprintfbuf); + } else { + /* NULL Arguments - copy formatstr + * (probably wrong) + */ + while ((lastf +#include +#include + +#undef SM_CMETRICS +#define SM_CMETRICS (83) + +short sysMetrics[SM_CMETRICS+1] = { + + 800, // [SM_CXSCREEN] /* 0 */ + 600, // [SM_CYSCREEN] /* 1 */ + 19, // [SM_CXVSCROLL] /* 2 */ + 17, // [SM_CYHSCROLL] /* 3 */ + 19, // [SM_CYCAPTION] /* 4 */ + 1, // [SM_CXBORDER] /* 5 */ + 1, // [SM_CYBORDER] /* 6 */ + 3, // [SM_CXDLGFRAME] /* 7 */ + 3, // [SM_CYDLGFRAME] /* 8 */ + 17, // [SM_CYVTHUMB] /* 9 */ sysMetrics[SM_CXVSCROLL] - 1; + 17, // [SM_CXHTHUMB] /* 10 */ sysMetrics[SM_CXVSCROLL] - 1; + 32, // [SM_CXICON] /* 11 */ + 32, // [SM_CYICON] /* 12 */ + 32, // [SM_CXCURSOR] /* 13 */ + 32, // [SM_CYCURSOR] /* 14 */ + 19, // [SM_CYMENU] /* 15 */ + 800, // [SM_CXFULLSCREEN] /* 16 */ + 0, // [SM_CYFULLSCREEN] /* 17 */ + 0, // [SM_CYKANJIWINDOW] /* 18 */ + 0, // [SM_MOUSEPRESENT] /* 19 */ + 0, // [SM_CYVSCROLL] /* 20 */ + 0, // [SM_CXHSCROLL] /* 21 */ + 0, // [SM_DEBUG] /* 22 */ + 0, // [SM_SWAPBUTTON] /* 23 */ + 0, // [SM_RESERVED1] /* 24 */ + 0, // [SM_RESERVED2] /* 25 */ + 0, // [SM_RESERVED3] /* 26 */ + 0, // [SM_RESERVED4] /* 27 */ + 0, // [SM_CXMIN] /* 28 */ + 0, // [SM_CYMIN] /* 29 */ + 0, // [SM_CXSIZE] /* 30 */ + 0, // [SM_CYSIZE] /* 31 */ + 0, // [SM_CXFRAME] /* 32 */ + 0, // [SM_CYFRAME] /* 33 */ + 0, // [SM_CXMINTRACK] /* 34 */ + 0, // [SM_CYMINTRACK] /* 35 */ + 0, // [SM_CXDOUBLECLK] /* 36 */ + 0, // [SM_CYDOUBLECLK] /* 37 */ + 0, // [SM_CXICONSPACING] /* 38 */ + 0, // [SM_CYICONSPACING] /* 39 */ + 0, // [SM_MENUDROPALIGNMENT] /* 40 */ + 0, // [SM_PENWINDOWS] /* 41 */ + 0, // [SM_DBCSENABLED] /* 42 */ + 0, // [SM_CMOUSEBUTTONS] /* 43 */ + // [SM_CXDLGFRAME] /* win40 name change */ + // [SM_CYDLGFRAME] /* win40 name change */ + // [SM_CXFRAME] /* win40 name change */ + // [SM_CYFRAME] /* win40 name change */ + 0, // [SM_SECURE] /* 44 */ + 0, // [SM_CXEDGE] /* 45 */ + 0, // [SM_CYEDGE] /* 46 */ + 0, // [SM_CXMINSPACING] /* 47 */ + 0, // [SM_CYMINSPACING] /* 48 */ + 0, // [SM_CXSMICON] /* 49 */ + 0, // [SM_CYSMICON] /* 50 */ + 0, // [SM_CYSMCAPTION] /* 51 */ + 0, // [SM_CXSMSIZE] /* 52 */ + 0, // [SM_CYSMSIZE] /* 53 */ + 0, // [SM_CXMENUSIZE] /* 54 */ + 0, // [SM_CYMENUSIZE] /* 55 */ + 8, // [SM_ARRANGE] /* 56 */ + 160, // [SM_CXMINIMIZED] /* 57 */ + 24, // [SM_CYMINIMIZED] /* 58 */ + 0, // [SM_CXMAXTRACK] /* 59 */ + 0, // [SM_CYMAXTRACK] /* 60 */ + 0, // [SM_CXMAXIMIZED] /* 61 */ + 0, // [SM_CYMAXIMIZED] /* 62 */ + 3, // [SM_NETWORK] /* 63 */ + 0, // [SM_CLEANBOOT] /* 67 */ + 2, // [SM_CXDRAG] /* 68 */ + 2, // [SM_CYDRAG] /* 69 */ + 0, // [SM_SHOWSOUNDS] /* 70 */ + 2, // [SM_CXMENUCHECK] /* 71 */ + 2, // [SM_CYMENUCHECK] /* 72 */ + 0, // [SM_SLOWMACHINE] /* 73 */ + 0, // [SM_MIDEASTENABLED] /* 74 */ + 0, // [SM_MOUSEWHEELPRESENT] /* 75 */ + 800, // [SM_CXVIRTUALSCREEN] /* 76 */ + 600, // [SM_CYVIRTUALSCREEN] /* 77 */ + 0, // [SM_YVIRTUALSCREEN] /* 78 */ + 0, // [SM_XVIRTUALSCREEN] /* 79 */ + 1, // [SM_CMONITORS] /* 81 */ + 1 // [SM_SAMEDISPLAYFORMAT] /* 82 */ + + }; + + + +int STDCALL GetSystemMetrics(int nIndex) +{ + if ( nIndex >= 0 && nIndex <= SM_CMETRICS+1 ) + return sysMetrics[nIndex]; + return 0; +} + + +WINBOOL STDCALL SystemParametersInfo(UINT uiAction, + UINT uiParam, PVOID pvParam, UINT fWinIni ) +{ + return FALSE; +} + +#if 0 + /*********************************************************************** + * SYSMETRICS_Init + * + * Initialisation of the system metrics array. + * + * Differences in return values between 3.1 and 95 apps under Win95 (FIXME ?): + * SM_CXVSCROLL x+1 x + * SM_CYHSCROLL x+1 x + * SM_CXDLGFRAME x-1 x + * SM_CYDLGFRAME x-1 x + * SM_CYCAPTION x+1 x + * SM_CYMENU x-1 x + * SM_CYFULLSCREEN x-1 x + * + * (collides with TWEAK_WineLook sometimes, + * so changing anything might be difficult) + */ + + + + void SYSMETRICS_Init(void) + { + sysMetrics[SM_CXCURSOR] = 32; + sysMetrics[SM_CYCURSOR] = 32; + sysMetrics[SM_CXSCREEN] = screenWidth; + sysMetrics[SM_CYSCREEN] = screenHeight; + sysMetrics[SM_CXVSCROLL] = + PROFILE_GetWineIniInt("Tweak.Layout", "ScrollBarWidth", 16) + 1; + sysMetrics[SM_CYHSCROLL] = sysMetrics[SM_CXVSCROLL]; + if (TWEAK_WineLook > WIN31_LOOK) + sysMetrics[SM_CYCAPTION] = + PROFILE_GetWineIniInt("Tweak.Layout", "CaptionHeight", 19); + else + sysMetrics[SM_CYCAPTION] = 2 + + PROFILE_GetWineIniInt("Tweak.Layout", "CaptionHeight", 18); + sysMetrics[SM_CXBORDER] = 1; + sysMetrics[SM_CYBORDER] = sysMetrics[SM_CXBORDER]; + sysMetrics[SM_CXDLGFRAME] = + PROFILE_GetWineIniInt("Tweak.Layout", "DialogFrameWidth", + (TWEAK_WineLook > WIN31_LOOK) ? 3 : 4); + sysMetrics[SM_CYDLGFRAME] = sysMetrics[SM_CXDLGFRAME]; + */ sysMetrics[SM_CYVTHUMB] = sysMetrics[SM_CXVSCROLL] - 1; + */ sysMetrics[SM_CXHTHUMB] = sysMetrics[SM_CYVTHUMB]; + */ sysMetrics[SM_CXICON] = 32; + */ sysMetrics[SM_CYICON] = 32; + if (TWEAK_WineLook > WIN31_LOOK) + sysMetrics[SM_CYMENU] = + PROFILE_GetWineIniInt("Tweak.Layout", "MenuHeight", 19); + else + sysMetrics[SM_CYMENU] = + PROFILE_GetWineIniInt("Tweak.Layout", "MenuHeight", 18); + sysMetrics[SM_CXFULLSCREEN] = sysMetrics[SM_CXSCREEN]; + sysMetrics[SM_CYFULLSCREEN] = + sysMetrics[SM_CYSCREEN] - sysMetrics[SM_CYCAPTION]; + sysMetrics[SM_CYKANJIWINDOW] = 0; + sysMetrics[SM_MOUSEPRESENT] = 1; + sysMetrics[SM_CYVSCROLL] = sysMetrics[SM_CYVTHUMB]; + sysMetrics[SM_CXHSCROLL] = sysMetrics[SM_CXHTHUMB]; + sysMetrics[SM_DEBUG] = 0; + + /* FIXME: The following should look for the registry key to see if the + buttons should be swapped. */ + sysMetrics[SM_SWAPBUTTON] = 0; + + sysMetrics[SM_RESERVED1] = 0; + sysMetrics[SM_RESERVED2] = 0; + sysMetrics[SM_RESERVED3] = 0; + sysMetrics[SM_RESERVED4] = 0; + + /* FIXME: The following two are calculated, but how? */ + sysMetrics[SM_CXMIN] = (TWEAK_WineLook > WIN31_LOOK) ? 112 : 100; + sysMetrics[SM_CYMIN] = (TWEAK_WineLook > WIN31_LOOK) ? 27 : 28; + + sysMetrics[SM_CXSIZE] = sysMetrics[SM_CYCAPTION] - 2; + sysMetrics[SM_CYSIZE] = sysMetrics[SM_CXSIZE]; + sysMetrics[SM_CXFRAME] = GetProfileInt32A("Windows", "BorderWidth", 4); + sysMetrics[SM_CYFRAME] = sysMetrics[SM_CXFRAME]; + sysMetrics[SM_CXMINTRACK] = sysMetrics[SM_CXMIN]; + sysMetrics[SM_CYMINTRACK] = sysMetrics[SM_CYMIN]; + sysMetrics[SM_CXDOUBLECLK] = +(GetProfileInt32A("Windows", "DoubleClickWidth", 4) + 1) & ~1; + sysMetrics[SM_CYDOUBLECLK] = +(GetProfileInt32A("Windows","DoubleClickHeight", 4) + 1) & ~1; + sysMetrics[SM_CXICONSPACING] = + GetProfileInt32A("Desktop","IconSpacing", 75); + sysMetrics[SM_CYICONSPACING] = + GetProfileInt32A("Desktop", "IconVerticalSpacing", 75); + sysMetrics[SM_MENUDROPALIGNMENT] = + GetProfileInt32A("Windows", "MenuDropAlignment", 0); + sysMetrics[SM_PENWINDOWS] = 0; + sysMetrics[SM_DBCSENABLED] = 0; + + /* FIXME: Need to query X for the following */ + sysMetrics[SM_CMOUSEBUTTONS] = 3; + + sysMetrics[SM_SECURE] = 0; + sysMetrics[SM_CXEDGE] = sysMetrics[SM_CXBORDER] + 1; + sysMetrics[SM_CYEDGE] = sysMetrics[SM_CXEDGE]; + sysMetrics[SM_CXMINSPACING] = 160; + sysMetrics[SM_CYMINSPACING] = 24; + sysMetrics[SM_CXSMICON] = + sysMetrics[SM_CYSIZE] - (sysMetrics[SM_CYSIZE] % 2) - 2; + sysMetrics[SM_CYSMICON] = sysMetrics[SM_CXSMICON]; + sysMetrics[SM_CYSMCAPTION] = 16; + sysMetrics[SM_CXSMSIZE] = 15; + sysMetrics[SM_CYSMSIZE] = sysMetrics[SM_CXSMSIZE]; + sysMetrics[SM_CXMENUSIZE] = sysMetrics[SM_CYMENU]; + sysMetrics[SM_CYMENUSIZE] = sysMetrics[SM_CXMENUSIZE]; + + /* FIXME: What do these mean? */ + sysMetrics[SM_ARRANGE] = 8; + sysMetrics[SM_CXMINIMIZED] = 160; + sysMetrics[SM_CYMINIMIZED] = 24; + + /* FIXME: How do I calculate these? */ + sysMetrics[SM_CXMAXTRACK] = + sysMetrics[SM_CXSCREEN] + 4 + 2 * sysMetrics[SM_CXFRAME]; + sysMetrics[SM_CYMAXTRACK] = + sysMetrics[SM_CYSCREEN] + 4 + 2 * sysMetrics[SM_CYFRAME]; + sysMetrics[SM_CXMAXIMIZED] = + sysMetrics[SM_CXSCREEN] + 2 * sysMetrics[SM_CXFRAME]; + sysMetrics[SM_CYMAXIMIZED] = + sysMetrics[SM_CYSCREEN] - 45; + sysMetrics[SM_NETWORK] = 3; + + /* For the following: 0 = ok, 1 = failsafe, 2 = failsafe + network */ + sysMetrics[SM_CLEANBOOT] = 0; + + sysMetrics[SM_CXDRAG] = 2; + sysMetrics[SM_CYDRAG] = 2; + sysMetrics[SM_SHOWSOUNDS] = 0; + sysMetrics[SM_CXMENUCHECK] = 2; + sysMetrics[SM_CYMENUCHECK] = 2; + + /* FIXME: Should check the type of processor for the following */ + sysMetrics[SM_SLOWMACHINE] = 0; + + /* FIXME: Should perform a check */ + sysMetrics[SM_MIDEASTENABLED] = 0; + + sysMetrics[SM_MOUSEWHEELPRESENT] = 0; + + sysMetrics[SM_CXVIRTUALSCREEN] = sysMetrics[SM_CXSCREEN]; + sysMetrics[SM_CYVIRTUALSCREEN] = sysMetrics[SM_CYSCREEN]; + sysMetrics[SM_XVIRTUALSCREEN] = 0; + sysMetrics[SM_YVIRTUALSCREEN] = 0; + sysMetrics[SM_CMONITORS] = 1; + sysMetrics[SM_SAMEDISPLAYFORMAT] = 1; + sysMetrics[SM_CMETRICS] = SM_CMETRICS; +} + + + +#endif + diff --git a/reactos/lib/user32/misc/vk.c b/reactos/lib/user32/misc/vk.c new file mode 100644 index 00000000000..be5e58c0f84 --- /dev/null +++ b/reactos/lib/user32/misc/vk.c @@ -0,0 +1,26 @@ +#include + +int +STDCALL +ToAscii( + UINT uVirtKey, + UINT uScanCode, + PBYTE lpKeyState, + LPWORD lpChar, + UINT uFlags) +{ + return ToAsciiEx(uVirtKey,uScanCode, lpKeyState, lpChar, uFlags, NULL); +} + + +int +STDCALL +ToAsciiEx( + UINT uVirtKey, + UINT uScanCode, + PBYTE lpKeyState, + LPWORD lpChar, + UINT uFlags, + HKL dwhkl) +{ +} \ No newline at end of file diff --git a/reactos/lib/user32/resources/sysres.c b/reactos/lib/user32/resources/sysres.c new file mode 100644 index 00000000000..de94d6046d8 --- /dev/null +++ b/reactos/lib/user32/resources/sysres.c @@ -0,0 +1,13 @@ + +#include + +/*********************************************************************** + * SYSRES_GetResourcePtr + * + * Return a pointer to a system resource. + */ +LPCVOID SYSRES_GetResPtr( int id ) +{ +// return SYSRES_Resources[Options.language][id]->data; + return NULL; +} \ No newline at end of file diff --git a/reactos/lib/user32/windows/class.c b/reactos/lib/user32/windows/class.c new file mode 100644 index 00000000000..c61787ad424 --- /dev/null +++ b/reactos/lib/user32/windows/class.c @@ -0,0 +1,467 @@ + +#include +#include +#include +#include + +CLASS *rootClass; + +ATOM STDCALL RegisterClassA(const WNDCLASS* wc) +{ + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = wc->style; + wcex.lpfnWndProc = wc->lpfnWndProc; + wcex.cbClsExtra = wc->cbClsExtra; + wcex.cbWndExtra = wc->cbWndExtra; + wcex.hInstance = wc->hInstance; + wcex.hIcon = wc->hIcon; + wcex.hCursor = wc->hCursor; + wcex.hbrBackground = wc->hbrBackground; + wcex.lpszMenuName = wc->lpszMenuName; + wcex.lpszClassName = wc->lpszClassName; + wcex.hIconSm = NULL; + return RegisterClassExA(&wcex); +} + +ATOM STDCALL RegisterClassW(const WNDCLASS* wc) +{ + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = wc->style; + wcex.lpfnWndProc = wc->lpfnWndProc; + wcex.cbClsExtra = wc->cbClsExtra; + wcex.cbWndExtra = wc->cbWndExtra; + wcex.hInstance = wc->hInstance; + wcex.hIcon = wc->hIcon; + wcex.hCursor = wc->hCursor; + wcex.hbrBackground = wc->hbrBackground; + wcex.lpszMenuName = wc->lpszMenuName; + wcex.lpszClassName = wc->lpszClassName; + wcex.hIconSm = NULL; + return RegisterClassExW(&wcex); +} + +ATOM STDCALL RegisterClassExA(const WNDCLASSEX* wc) +{ + ATOM atom; + CLASS *classPtr; + INT classExtra, winExtra; + int len; + + + if ( wc == NULL || wc->cbSize != sizeof(WNDCLASSEX)) { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + atom = GlobalAddAtomA( wc->lpszClassName ); + if (!atom) + { + SetLastError(ERROR_CLASS_ALREADY_EXISTS); + return FALSE; + } + + classExtra = wc->cbClsExtra; + if (classExtra < 0) + classExtra = 0; + else if (classExtra > 40) + classExtra = 40; + + winExtra = wc->cbClsExtra; + if (winExtra < 0) + winExtra = 0; + else if (winExtra > 40) + winExtra = 40; + + classPtr = (CLASS *)HeapAlloc( GetProcessHeap(), 0, sizeof(CLASS) + + classExtra - sizeof(classPtr->wExtra) ); + + + if (classExtra) + memset( classPtr->wExtra, 0, classExtra ); + + if (!classPtr) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + GlobalDeleteAtom( atom ); + return FALSE; + } + classPtr->magic = CLASS_MAGIC; + classPtr->cWindows = 0; + classPtr->style = wc->style; + classPtr->winproc = wc->lpfnWndProc; + classPtr->cbWndExtra = winExtra; + classPtr->cbClsExtra = classExtra; + classPtr->hInstance = wc->hInstance; + classPtr->atomName = atom; + classPtr->hIcon = (HICON)wc->hIcon; + classPtr->hIconSm = (HICON)wc->hIconSm; + classPtr->hCursor = (HCURSOR)wc->hCursor; + classPtr->hbrBackground = (HBRUSH)wc->hbrBackground; + classPtr->bUnicode = FALSE; + + classPtr->dce = (wc->style & CS_CLASSDC) ? + CreateDC( "DISPLAY", NULL,NULL,NULL ) : NULL; + + + if ( wc->lpszMenuName != NULL ) { + len = lstrlenA(wc->lpszMenuName); + classPtr->menuName = HeapAlloc(GetProcessHeap(),0,len+1); + lstrcpyA(classPtr->menuName,wc->lpszMenuName); + } + else + classPtr->menuName = NULL; + + + + len = lstrlenA(wc->lpszClassName); + classPtr->className = HeapAlloc(GetProcessHeap(),0,len+1); + lstrcpyA(classPtr->className,wc->lpszClassName); + + + + classPtr->next = rootClass; + rootClass = classPtr; + + return atom; +} + + +ATOM STDCALL RegisterClassExW( const WNDCLASSEX* wc ) +{ + ATOM atom; + CLASS *classPtr; + INT classExtra, winExtra; + + int i, len; + if ( wc == NULL || wc->cbSize != sizeof(WNDCLASSEX)) { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + if (!(atom = GlobalAddAtomW( (LPWSTR)wc->lpszClassName ))) + { + SetLastError(ERROR_CLASS_ALREADY_EXISTS); + return FALSE; + } + + classExtra = wc->cbClsExtra; + if (classExtra < 0) + classExtra = 0; + else if (classExtra > 40) + classExtra = 40; + + winExtra = wc->cbClsExtra; + if (winExtra < 0) + winExtra = 0; + else if (winExtra > 40) + winExtra = 40; + + classPtr = (CLASS *)HeapAlloc( GetProcessHeap(), 0, sizeof(CLASS) + + classExtra - sizeof(classPtr->wExtra) ); + + + if (classExtra) + memset( classPtr->wExtra, 0, classExtra ); + + if (!classPtr) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + GlobalDeleteAtom( atom ); + return FALSE; + } + classPtr->magic = CLASS_MAGIC; + classPtr->cWindows = 0; + classPtr->style = wc->style; + classPtr->winproc = wc->lpfnWndProc; + classPtr->cbWndExtra = winExtra; + classPtr->cbClsExtra = classExtra; + classPtr->hInstance = wc->hInstance; + classPtr->atomName = atom; + classPtr->hIcon = (HICON)wc->hIcon; + classPtr->hIconSm = (HICON)wc->hIconSm; + classPtr->hCursor = (HCURSOR)wc->hCursor; + classPtr->hbrBackground = (HBRUSH)wc->hbrBackground; + classPtr->bUnicode = FALSE; + + classPtr->dce = (wc->style & CS_CLASSDC) ? + CreateDC( "DISPLAY", NULL,NULL,NULL ) : NULL; + + len = lstrlenW((LPWSTR)wc->lpszMenuName); + classPtr->menuName = HeapAlloc(GetProcessHeap(),0,(len+1)*2); + lstrcpyW((LPWSTR)classPtr->menuName, (LPWSTR)wc->lpszMenuName); + + + len = lstrlenW((LPWSTR)wc->lpszClassName); + classPtr->className = HeapAlloc(GetProcessHeap(),0,(len+1)*2); + lstrcpyW((LPWSTR)classPtr->className,(LPWSTR) wc->lpszClassName ); + + classPtr->next = rootClass; + rootClass = classPtr; + + return atom; +} + +WINBOOL UnregisterClassA(LPCSTR lpClassName, HINSTANCE hInstance ) +{ + CLASS *classPtr; + classPtr = CLASS_FindClassByAtom( STRING2ATOMA(lpClassName), hInstance ); + if ( classPtr == NULL ) + return FALSE; + + + if ( CLASS_FreeClass(classPtr) == TRUE ) + GlobalDeleteAtom( classPtr->atomName ); + return TRUE; +} + + + + +WINBOOL UnregisterClassW(LPCWSTR lpClassName, HINSTANCE hInstance ) +{ + CLASS *classPtr; + classPtr = CLASS_FindClassByAtom( STRING2ATOMW(lpClassName), hInstance ); + if ( classPtr == NULL ) + return FALSE; + + + if ( CLASS_FreeClass(classPtr) == TRUE ) + GlobalDeleteAtom( classPtr->atomName ); + return TRUE; +} + + +WINBOOL GetClassInfoA( HINSTANCE hInstance, LPCSTR lpClassName, LPWNDCLASS lpWndClass ) +{ + + return FALSE; +} + + +WINBOOL GetClassInfoW( HINSTANCE hInstance, LPCWSTR lpClassName, LPWNDCLASS lpWndClass ) +{ + CLASS *classPtr; + ATOM a; + + if ( HIWORD(lpClassName) != 0 ) + a = FindAtomW(lpClassName); + else + a = lpClassName; + + classPtr = CLASS_FindClassByAtom( a, hInstance ); + if ( classPtr == NULL ) + return FALSE; + + + lpWndClass->style = classPtr->style; + lpWndClass->lpfnWndProc = classPtr->winproc; + lpWndClass->cbClsExtra = classPtr->cbWndExtra; + lpWndClass->cbClsExtra = classPtr->cbClsExtra; + lpWndClass->hInstance = classPtr->hInstance; + lpWndClass->hIcon = classPtr->hIcon; + lpWndClass->hCursor = classPtr->hCursor; + lpWndClass->hbrBackground = classPtr->hbrBackground; + return TRUE; + +} + +WINBOOL GetClassInfoExA( HINSTANCE hInstance, LPCSTR lpClassName, LPWNDCLASSEX lpWndClass ) +{ + + return FALSE; +} + +WINBOOL GetClassInfoExW( HINSTANCE hInstance, LPCWSTR lpClassName, LPWNDCLASSEX lpWndClassEx ) +{ + + CLASS *classPtr; + ATOM a; + + if ( HIWORD(lpClassName) != 0 ) + a = FindAtomW(lpClassName); + else + a = lpClassName; + + classPtr = CLASS_FindClassByAtom( a, hInstance ); + if ( classPtr == NULL ) + return FALSE; + + + if ( lpWndClassEx ->cbSize != sizeof(WNDCLASSEX) ) + return FALSE; + + + lpWndClassEx->style = classPtr->style; + lpWndClassEx->lpfnWndProc = classPtr->winproc; + lpWndClassEx->cbClsExtra = classPtr->cbWndExtra; + lpWndClassEx->cbClsExtra = classPtr->cbClsExtra; + lpWndClassEx->hInstance = classPtr->hInstance; + lpWndClassEx->hIcon = classPtr->hIcon; + lpWndClassEx->hCursor = classPtr->hCursor; + lpWndClassEx->hbrBackground = classPtr->hbrBackground; + + + return TRUE; +} + +int GetClassNameA(HWND hWnd, LPSTR lpClassName, int nMaxCount ) +{ + WND *wndPtr = WIN_FindWndPtr(hWnd); + + if ( wndPtr == NULL ) + return 0; + + if ( wndPtr->class->bUnicode == TRUE ) + return 0; + + return lpstrncpyA(lpClassName,wndPtr->class->className, nMaxCount); + +} + +int GetClassNameW(HWND hWnd, LPWSTR lpClassName, int nMaxCount ) +{ + WND *wndPtr = WIN_FindWndPtr(hWnd); + + if ( wndPtr == NULL ) + return 0; + + if ( wndPtr->class->bUnicode == FALSE ) + return 0; + + return lpstrncpyW(lpClassName,wndPtr->class->className, nMaxCount); + + +} + +DWORD GetClassLongA(HWND hWnd, int nIndex ) +{ + WND * wndPtr; + + if (!(wndPtr = WIN_FindWndPtr( hWnd ))) return 0; + if (nIndex >= 0) + { + if (nIndex <= wndPtr->class->cbClsExtra - sizeof(LONG)) + return (DWORD)((char *)wndPtr->class->wExtra) + nIndex; + } + switch(nIndex) + { + case GCL_STYLE: return (LONG)wndPtr->class->style; + case GCL_CBWNDEXTRA: return (LONG)wndPtr->class->cbWndExtra; + case GCL_CBCLSEXTRA: return (LONG)wndPtr->class->cbClsExtra; + case GCL_HMODULE: return (LONG)wndPtr->class->hInstance; + case GCL_WNDPROC: return (LONG)wndPtr->class->winproc; + case GCL_MENUNAME: return (LONG)wndPtr->class->menuName; + case GCW_ATOM: + case GCL_HBRBACKGROUND: + case GCL_HCURSOR: + case GCL_HICON: + case GCL_HICONSM: + return GetClassWord( hWnd, nIndex ); + default: + return -1; + } + + return 0; +} + +DWORD GetClassLongW(HWND hWnd, int nIndex ) +{ + WND * wndPtr; + + if (!(wndPtr = WIN_FindWndPtr( hWnd ))) return 0; + if (nIndex >= 0) + { + if (nIndex <= wndPtr->class->cbClsExtra - sizeof(LONG)) + return (DWORD)((char *)wndPtr->class->wExtra) + nIndex; + } + switch(nIndex) + { + case GCL_STYLE: return (LONG)wndPtr->class->style; + case GCL_CBWNDEXTRA: return (LONG)wndPtr->class->cbWndExtra; + case GCL_CBCLSEXTRA: return (LONG)wndPtr->class->cbClsExtra; + case GCL_HMODULE: return (LONG)wndPtr->class->hInstance; + case GCL_WNDPROC: return (LONG)wndPtr->class->winproc; + case GCL_MENUNAME: return (LONG)wndPtr->class->menuName; + case GCW_ATOM: + case GCL_HBRBACKGROUND: + case GCL_HCURSOR: + case GCL_HICON: + case GCL_HICONSM: + return GetClassWord( hWnd, nIndex ); + default: + return -1; + } + + return 0; +} + + + +WORD STDCALL GetClassWord( HWND hWnd, INT nIndex ) +{ + WND * wndPtr; + + if (!(wndPtr = WIN_FindWndPtr( hWnd ))) return 0; + if (nIndex >= 0) + { + if (nIndex <= wndPtr->class->cbClsExtra - sizeof(WORD)) + return (WORD)((char *)wndPtr->class->wExtra) + nIndex; + } + else switch(nIndex) + { + //case GCW_HBRBACKGROUND: return wndPtr->class->hbrBackground; + //case GCW_HCURSOR: return wndPtr->class->hCursor; + //case GCW_HICON: return wndPtr->class->hIcon; + // case GCW_HICONSM: return wndPtr->class->hIconSm; + case GCW_ATOM: return wndPtr->class->atomName; + //case GCW_STYLE: + //case GCW_CBWNDEXTRA: + //case GCW_CBCLSEXTRA: + //case GCW_HMODULE: + return (WORD)GetClassLongA( hWnd, nIndex ); + default: + return -1; + } + + + return 0; +} + + +CLASS *CLASS_FindClassByAtom( ATOM classAtom, HINSTANCE hInstance ) +{ + CLASS *p = rootClass; + while(p != NULL ) { + if ( p->atomName == classAtom ) + return p; + p = p->next; + } + return NULL; +} + + +WINBOOL CLASS_FreeClass(CLASS *classPtr) +{ + CLASS *p = rootClass; + if( classPtr->cWindows > 0 ) + return FALSE; + + if (classPtr->dce) + DeleteDC( classPtr->dce ); + if (classPtr->hbrBackground) + DeleteObject( classPtr->hbrBackground ); + + + classPtr->atomName = 0; + HeapFree(GetProcessHeap(),0,classPtr->className); + + while(p != NULL && p->next != classPtr ) + p = p->next; + + if ( p != NULL ) + p->next = classPtr->next; + + HeapFree(GetProcessHeap(),0,classPtr); + return TRUE; +} + \ No newline at end of file diff --git a/reactos/lib/user32/windows/dc.c b/reactos/lib/user32/windows/dc.c new file mode 100644 index 00000000000..b3e3487598b --- /dev/null +++ b/reactos/lib/user32/windows/dc.c @@ -0,0 +1,505 @@ +/* + * USER DCE functions + * + * Copyright 1993 Alexandre Julliard + * 1996,1997 Alex Korobka + * + * + * Note: Visible regions of CS_OWNDC/CS_CLASSDC window DCs + * have to be updated dynamically. + * + * Internal DCX flags: + * + * DCX_DCEEMPTY - dce is uninitialized + * DCX_DCEBUSY - dce is in use + * DCX_DCEDIRTY - ReleaseDC() should wipe instead of caching + * DCX_KEEPCLIPRGN - ReleaseDC() should not delete the clipping region + * DCX_WINDOWPAINT - BeginPaint() is in effect + */ + +/* GetDCEx flags */ + +#define DCX_USESTYLE 0x00010000 + + + +#include +#include +#include +#include +#include + + +extern DCE *firstDCE; + +INT SelectVisRgn(HDC hdc,HRGN hrgn); +INT ExcludeVisRect(HDC hDC,INT nLeftRect,INT nTopRect,INT nRightRect,INT nBottomRect); +INT RestoreVisRgn(HDC hdc); + + +HDC STDCALL GetDC( HWND hWnd ) +{ + if (!hWnd) + return GetDCEx( GetDesktopWindow(), 0, DCX_CACHE | DCX_WINDOW ); + return GetDCEx( hWnd, 0, DCX_USESTYLE ); +} + +/*********************************************************************** + * GetDCEx + * + * Unimplemented flags: DCX_LOCKWINDOWUPDATE + * + * FIXME: Full support for hrgnClip == 1 (alias for entire window). + */ +HDC WINAPI GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags ) +{ + HRGN hrgnVisible = 0; + HDC hdc = 0; + DCE * dce; + //HDC dc; + WND * wndPtr; + DWORD dcxFlags = 0; + BOOL bUpdateVisRgn = TRUE; + BOOL bUpdateClipOrigin = FALSE; + + DPRINT("hwnd %04x, hrgnClip %04x, flags %08x\n", + hwnd, hrgnClip, (unsigned)flags); + + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0; + + /* fixup flags */ + + if (!(wndPtr->class->style & (CS_OWNDC | CS_CLASSDC))) flags |= DCX_CACHE; + + if (flags & DCX_USESTYLE) + { + flags &= ~( DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP); + + if( wndPtr->dwStyle & WS_CLIPSIBLINGS ) + flags |= DCX_CLIPSIBLINGS; + + if ( !(flags & DCX_WINDOW) ) + { + if (wndPtr->class->style & CS_PARENTDC) flags |= DCX_PARENTCLIP; + + if (wndPtr->dwStyle & WS_CLIPCHILDREN && + !(wndPtr->dwStyle & WS_MINIMIZE) ) flags |= DCX_CLIPCHILDREN; + } + else flags |= DCX_CACHE; + } + + if( flags & DCX_NOCLIPCHILDREN ) + { + flags |= DCX_CACHE; + flags &= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN); + } + + if (flags & DCX_WINDOW) + flags = (flags & ~DCX_CLIPCHILDREN) | DCX_CACHE; + + if (!(wndPtr->dwStyle & WS_CHILD) || !wndPtr->parent ) + flags &= ~DCX_PARENTCLIP; + else if( flags & DCX_PARENTCLIP ) + { + flags |= DCX_CACHE; + if( !(flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) ) + if( (wndPtr->dwStyle & WS_VISIBLE) && (wndPtr->parent->dwStyle & WS_VISIBLE) ) + { + flags &= ~DCX_CLIPCHILDREN; + if( wndPtr->parent->dwStyle & WS_CLIPSIBLINGS ) + flags |= DCX_CLIPSIBLINGS; + } + } + + /* find a suitable DCE */ + + dcxFlags = flags & (DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | + DCX_CACHE | DCX_WINDOW); + + if (flags & DCX_CACHE) + { + DCE* dceEmpty; + DCE* dceUnused; + + dceEmpty = dceUnused = NULL; + + /* Strategy: First, we attempt to find a non-empty but unused DCE with + * compatible flags. Next, we look for an empty entry. If the cache is + * full we have to purge one of the unused entries. + */ + + for (dce = firstDCE; (dce); dce = dce->next) + { + if ((dce->DCXflags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE ) + { + dceUnused = dce; + + if (dce->DCXflags & DCX_DCEEMPTY) + dceEmpty = dce; + else + if ((dce->hwndCurrent == hwnd) && + ((dce->DCXflags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | + DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)) == dcxFlags)) + { + DPRINT("\tfound valid %08x dce [%04x], flags %08x\n", + (unsigned)dce, hwnd, (unsigned)dcxFlags ); + bUpdateVisRgn = FALSE; + bUpdateClipOrigin = TRUE; + break; + } + } + } + if (!dce) dce = (dceEmpty) ? dceEmpty : dceUnused; + } + else + { + dce = (wndPtr->class->style & CS_OWNDC) ? wndPtr->dce : wndPtr->class->dce; + if( dce->hwndCurrent == hwnd ) + { + DPRINT("\tskipping hVisRgn update\n"); + bUpdateVisRgn = FALSE; /* updated automatically, via DCHook() */ + + if( (dce->DCXflags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) && + (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) ) + { + /* This is likely to be a nested BeginPaint(). */ + + if( dce->hClipRgn != hrgnClip ) + { + DPRINT("fixme new hrgnClip[%04x] smashes the previous[%04x]\n", + hrgnClip, dce->hClipRgn ); + DCE_DeleteClipRgn( dce ); + } + else + RestoreVisRgn(dce->hDC); + } + } + } + if (!dce) return 0; + + dce->hwndCurrent = hwnd; + dce->hClipRgn = 0; + dce->DCXflags = dcxFlags | (flags & DCX_WINDOWPAINT) | DCX_DCEBUSY; + hdc = dce->hDC; + + //if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0; + //bUpdateVisRgn = bUpdateVisRgn || (dc->w.flags & DC_DIRTY); + + /* recompute visible region */ + + //wndPtr->pDriver->pSetDrawable( wndPtr, dc, flags, bUpdateClipOrigin ); + if( bUpdateVisRgn ) + { + DPRINT("updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce, hwnd); + + if (flags & DCX_PARENTCLIP) + { + WND *parentPtr = wndPtr->parent; + + if( wndPtr->dwStyle & WS_VISIBLE && !(parentPtr->dwStyle & WS_MINIMIZE) ) + { + if( parentPtr->dwStyle & WS_CLIPSIBLINGS ) + dcxFlags = DCX_CLIPSIBLINGS | (flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW)); + else + dcxFlags = flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW); + + hrgnVisible = DCE_GetVisRgn( parentPtr->hwndSelf, dcxFlags ); + if( flags & DCX_WINDOW ) + OffsetRgn( hrgnVisible, -wndPtr->rectWindow.left, + -wndPtr->rectWindow.top ); + else + OffsetRgn( hrgnVisible, -wndPtr->rectClient.left, + -wndPtr->rectClient.top ); + DCE_OffsetVisRgn( hdc, hrgnVisible ); + } + else + hrgnVisible = CreateRectRgn( 0, 0, 0, 0 ); + } + else + if ((hwnd == GetDesktopWindow())) { + hrgnVisible = CreateRectRgn( 0, 0, SYSMETRICS_CXSCREEN, + SYSMETRICS_CYSCREEN ); +// (rootWindow == DefaultRootWindow(display)) + } + else + { + hrgnVisible = DCE_GetVisRgn( hwnd, flags ); + DCE_OffsetVisRgn( hdc, hrgnVisible ); + } + + //dc->w.flags &= ~DC_DIRTY; + dce->DCXflags &= ~DCX_DCEDIRTY; + SelectVisRgn( hdc, hrgnVisible ); + } + else + DPRINT("no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce, hwnd); + + /* apply additional region operation (if any) */ + + if( flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) ) + { + if( !hrgnVisible ) hrgnVisible = CreateRectRgn( 0, 0, 0, 0 ); + + dce->DCXflags |= flags & (DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_EXCLUDERGN); + dce->hClipRgn = hrgnClip; + + DPRINT( "\tsaved VisRgn, clipRgn = %04x\n", hrgnClip); + + SaveVisRgn( hdc ); + CombineRgn( hrgnVisible, hrgnClip, 0, RGN_COPY ); + DCE_OffsetVisRgn( hdc, hrgnVisible ); + CombineRgn( hrgnVisible, InquireVisRgn( hdc ), hrgnVisible, + (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF ); + SelectVisRgn( hdc, hrgnVisible ); + } + + if( hrgnVisible ) DeleteObject( hrgnVisible ); + + DPRINT( "(%04x,%04x,0x%lx): returning %04x\n", + hwnd, hrgnClip, flags, hdc); + return hdc; +} + +int STDCALL ReleaseDC(HWND hWnd,HDC hDC ) +{ + return 0; +} + +HDC GetWindowDC(HWND hWnd ) +{ + if (!hWnd) hWnd = GetDesktopWindow(); + return GetDCEx( hWnd, 0, DCX_USESTYLE | DCX_WINDOW ); +} + + +/*********************************************************************** + * BeginPaint (USER.10) + */ +HDC +STDCALL +BeginPaint( + HWND hWnd, + LPPAINTSTRUCT lpPaint) +{ + WINBOOL bIcon; + HRGN hrgnUpdate; + WND *wndPtr = WIN_FindWndPtr( hWnd ); + if (!wndPtr) return 0; + + bIcon = (wndPtr->dwStyle & WS_MINIMIZE && wndPtr->class->hIcon); + + wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT; + + if (wndPtr->flags & WIN_NEEDS_NCPAINT) WIN_UpdateNCArea( wndPtr, TRUE ); + + if (((hrgnUpdate = wndPtr->hrgnUpdate) != 0) || + (wndPtr->flags & WIN_INTERNAL_PAINT)) + QUEUE_DecPaintCount( wndPtr->hmemTaskQ ); + + wndPtr->hrgnUpdate = 0; + wndPtr->flags &= ~WIN_INTERNAL_PAINT; + + HideCaret( hWnd ); + + DPRINT("hrgnUpdate = %04x, \n", hrgnUpdate); + + /* When bIcon is TRUE hrgnUpdate is automatically in window coordinates + * (because rectClient == rectWindow for WS_MINIMIZE windows). + */ + + if (wndPtr->class->style & CS_PARENTDC) + { + /* Don't clip the output to the update region for CS_PARENTDC window */ + if(hrgnUpdate > 1) + DeleteObject(hrgnUpdate); + lpPaint->hdc = GetDCEx( hWnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE | + (bIcon ? DCX_WINDOW : 0) ); + } + else + { + lpPaint->hdc = GetDCEx(hWnd, hrgnUpdate, DCX_INTERSECTRGN | + DCX_WINDOWPAINT | DCX_USESTYLE | + (bIcon ? DCX_WINDOW : 0) ); + } + + DPRINT("hdc = %04x\n", lpPaint->hdc); + + if (!lpPaint->hdc) + { + //WARN(win, "GetDCEx() failed in BeginPaint(), hWnd=%04x\n", hWnd); + return 0; + } + + GetClipBox( lpPaint->hdc, &lpPaint->rcPaint ); + + DPRINT("box = (%i,%i - %i,%i)\n", lpPaint->rcPaint.left, lpPaint->rcPaint.top, + lpPaint->rcPaint.right, lpPaint->rcPaint.bottom ); + + if (wndPtr->flags & WIN_NEEDS_ERASEBKGND) + { + wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND; + lpPaint->fErase = !SendMessageA(hWnd, (bIcon) ? WM_ICONERASEBKGND + : WM_ERASEBKGND, + (WPARAM)lpPaint->hdc, 0 ); + } + else lpPaint->fErase = TRUE; + + return lpPaint->hdc; + +} + + +WINBOOL STDCALL EndPaint( HWND hWnd, const PAINTSTRUCT *lpPaint ) +{ + ReleaseDC( hWnd, lpPaint->hdc ); + ShowCaret( hWnd ); + return TRUE; +} + +/*********************************************************************** + * RedrawWindow (USER32.426) + */ +WINBOOL STDCALL RedrawWindow( HWND hwnd, const RECT *rectUpdate, + HRGN hrgnUpdate, UINT flags ) +{ + return PAINT_RedrawWindow( hwnd, rectUpdate, hrgnUpdate, flags, 0 ); +} + +/*********************************************************************** + * UpdateWindow (USER32.567) + */ +WINBOOL +STDCALL +UpdateWindow( + HWND hWnd) +{ + return PAINT_RedrawWindow( hWnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 ); +} + +/*********************************************************************** + * InvalidateRgn (USER32.9) + */ +WINBOOL +STDCALL +InvalidateRgn( + HWND hWnd, + HRGN hRgn, + WINBOOL bErase) +{ + return PAINT_RedrawWindow(hWnd, NULL, hRgn, RDW_INVALIDATE | (bErase ? RDW_ERASE : 0), 0 ); +} + +/*********************************************************************** + * InvalidateRect (USER32.8) + */ +WINBOOL +STDCALL +InvalidateRect( + HWND hWnd , + CONST RECT *lpRect, + WINBOOL bErase) +{ + return PAINT_RedrawWindow( hWnd, lpRect, 0, + RDW_INVALIDATE | (bErase ? RDW_ERASE : 0), 0 ); +} + +/*********************************************************************** + * ValidateRgn (USER32.572) + */ +WINBOOL +STDCALL +ValidateRgn( + HWND hWnd, + HRGN hRgn) +{ + return PAINT_RedrawWindow( hWnd, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN, 0 ); +} + +/*********************************************************************** + * ValidateRect (USER32.571) + */ +WINBOOL +STDCALL +ValidateRect( + HWND hWnd , + CONST RECT *lpRect) +{ + return PAINT_RedrawWindow( hWnd, lpRect, 0, RDW_VALIDATE | RDW_NOCHILDREN, 0 ); +} + +/*********************************************************************** + * GetUpdateRect (USER32.297) + */ +WINBOOL STDCALL GetUpdateRect( HWND hwnd, LPRECT rect, WINBOOL erase ) +{ + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return FALSE; + + if (rect) + { + if (wndPtr->hrgnUpdate > 1) + { + HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 ); + if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR) return FALSE; + GetRgnBox( hrgn, rect ); + DeleteObject( hrgn ); + } + else SetRectEmpty( rect ); + } + return ((UINT)wndPtr->hrgnUpdate > 1); +} + +/*********************************************************************** + * GetUpdateRgn (USER32.298) + */ +INT STDCALL GetUpdateRgn( HWND hwnd, HRGN hrgn, WINBOOL erase ) +{ + INT retval; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return ERROR; + + if ((UINT)wndPtr->hrgnUpdate <= 1) + { + SetRectRgn( hrgn, 0, 0, 0, 0 ); + return NULLREGION; + } + retval = CombineRgn( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY ); + if (erase) RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN ); + return retval; +} + +/*********************************************************************** + * ExcludeUpdateRgn (USER32.195) + */ +INT STDCALL ExcludeUpdateRgn( HDC hdc, HWND hwnd ) +{ + RECT rect; + WND * wndPtr; + + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return ERROR; + + if (wndPtr->hrgnUpdate) + { + INT ret; + HRGN hrgn = CreateRectRgn(wndPtr->rectWindow.left - wndPtr->rectClient.left, + wndPtr->rectWindow.top - wndPtr->rectClient.top, + wndPtr->rectClient.right - wndPtr->rectClient.left, + wndPtr->rectClient.bottom - wndPtr->rectClient.top); + if( wndPtr->hrgnUpdate > 1 ) + CombineRgn(hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY); + + /* do ugly coordinate translations in dce.c */ + + ret = DCE_ExcludeRgn( hdc, wndPtr, hrgn ); + DeleteObject( hrgn ); + return ret; + } + return GetClipBox( hdc, &rect ); +} + + + +WINBOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate, + HRGN hrgnUpdate, UINT flags, UINT control ) +{ +} \ No newline at end of file diff --git a/reactos/lib/user32/windows/focus.c b/reactos/lib/user32/windows/focus.c new file mode 100644 index 00000000000..da129fbbb3d --- /dev/null +++ b/reactos/lib/user32/windows/focus.c @@ -0,0 +1,86 @@ +#include +#include + +HWND hwndFocus; + +//FIXME this a shared api by all procedures + +HWND STDCALL SetFocus( HWND hwnd ) +{ + HWND hWndPrevFocus, hwndTop = hwnd; + WND *wndPtr = WIN_FindWndPtr( hwnd ); + + if (wndPtr) + { + /* Check if we can set the focus to this window */ + + while ( (wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD ) + { + if ( wndPtr->dwStyle & ( WS_MINIMIZE | WS_DISABLED) ) + return 0; + if (!(wndPtr = wndPtr->parent)) return 0; + hwndTop = wndPtr->hwndSelf; + } + + if( hwnd == hwndFocus ) return hwnd; + + /* call hooks */ + if( HOOK_CallHooksA( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, + (LPARAM)hwndFocus) ) + return 0; + + /* activate hwndTop if needed. */ + if (hwndTop != GetActiveWindow()) + { + if (!WINPOS_SetActiveWindow(hwndTop, 0, 0)) return 0; + + if (!IsWindow( hwnd )) return 0; /* Abort if window destroyed */ + } + } + else if( HOOK_CallHooksA( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)hwndFocus ) ) + return 0; + + /* Change focus and send messages */ + hWndPrevFocus = hwndFocus; + + FOCUS_SwitchFocus( hwndFocus , hwnd ); + + return hWndPrevFocus; +} + + +HWND STDCALL GetFocus(void) +{ + return hwndFocus; +} + +/***************************************************************** + * FOCUS_SwitchFocus + */ +void FOCUS_SwitchFocus( HWND hFocusFrom, HWND hFocusTo ) +{ + WND *pFocusTo = WIN_FindWndPtr( hFocusTo ); + hwndFocus = hFocusTo; + +#if 0 + if (hFocusFrom) SendMessageA( hFocusFrom, WM_KILLFOCUS, hFocusTo, 0 ); +#else + /* FIXME: must be SendMessage16() because 32A doesn't do + * intertask at this time */ + if (hFocusFrom) SendMessage( hFocusFrom, WM_KILLFOCUS, hFocusTo, 0 ); +#endif + if( !pFocusTo || hFocusTo != hwndFocus ) + return; + + /* According to API docs, the WM_SETFOCUS message is sent AFTER the window + has received the keyboard focus. */ + +// pFocusTo->pDriver->pSetFocus(pFocusTo); + +#if 0 + SendMessageA( hFocusTo, WM_SETFOCUS, hFocusFrom, 0 ); +#else + SendMessageA( hFocusTo, WM_SETFOCUS, hFocusFrom, 0 ); +#endif +} + diff --git a/reactos/lib/user32/windows/hook.c b/reactos/lib/user32/windows/hook.c index 19d85c76131..9606a492311 100644 --- a/reactos/lib/user32/windows/hook.c +++ b/reactos/lib/user32/windows/hook.c @@ -7,24 +7,453 @@ * Based on investigations by Alex Korobka */ +#include +#include + +#define GetThreadQueue(x) NULL + +HANDLE HOOK_systemHooks[WH_NB_HOOKS] = { NULL, }; + /*********************************************************************** - * HOOK_CallHooks32W + * SetWindowsHookA + * + * FIXME: I don't know if this is correct + */ +HHOOK SetWindowsHookExA(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId ) +{ + return HOOK_SetHook( idHook, lpfn, HOOK_WINA, hMod, dwThreadId ); + +} + + +/*********************************************************************** + * SetWindowsHookExW + * + * FIXME: I don't know if this is correct + */ +HHOOK SetWindowsHookExW(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId ) +{ + return HOOK_SetHook( idHook, lpfn, HOOK_WIN32W, hMod, dwThreadId ); + +} + + + + + + +/*********************************************************************** + * UnhookWindowsHook + */ +WINBOOL STDCALL UnhookWindowsHook( INT id, HOOKPROC proc ) +{ + return FALSE; +} + + +/*********************************************************************** + * UnhookWindowHookEx (USER.558) + */ +WINBOOL STDCALL UnhookWindowsHookEx( HHOOK hhook ) +{ + return HOOK_RemoveHook( hhook ); +} + + + +/*********************************************************************** + * CallNextHookEx + * + * There aren't ANSI and UNICODE versions of this. + */ +LRESULT STDCALL CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam, + LPARAM lParam ) +{ + HHOOK next; + INT fromtype; /* figure out Ansi/Unicode */ + HOOKDATA *oldhook; + + + if (!(next = HOOK_GetNextHook(hhook ))) return 0; + + oldhook = (HOOKDATA *)hhook ; + fromtype = oldhook->flags & HOOK_MAPTYPE; + + + return HOOK_CallHook( next, fromtype, code, wParam, lParam ); +} + + + +/*********************************************************************** + * CallMsgFilterA (USER.15) + */ +/* + * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified + * version, plus USER (the bit one) has a CallMsgFilter function. + */ +WINBOOL STDCALL CallMsgFilterA( LPMSG msg, INT code ) +{ + + if (HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) + return TRUE; + return HOOK_CallHooksA( WH_MSGFILTER, code, 0, (LPARAM)msg ); +} + + +/*********************************************************************** + * CallMsgFilterW (USER.) + */ +WINBOOL STDCALL CallMsgFilterW( LPMSG msg, INT code ) +{ + if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) + return TRUE; + return HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)msg ); +} + + + + + +/*********************************************************************** + * Internal Functions + */ + +/*********************************************************************** + * HOOK_GetNextHook + * + * Get the next hook of a given hook. + */ +HANDLE HOOK_GetNextHook( HHOOK hhook ) +{ + + HOOKDATA *hook; + if (!hhook) return 0; + hook = (HOOKDATA *)hhook; + + if (hook->next) return hook->next; + if (!hook->ownerQueue) return 0; /* Already system hook */ + + /* Now start enumerating the system hooks */ + return HOOK_systemHooks[hook->id - WH_MINHOOK]; +} + + +/*********************************************************************** + * HOOK_GetHook + * + * Get the first hook for a given type. + */ +HANDLE HOOK_GetHook( INT id, HQUEUE hQueue ) +{ +// MESSAGEQUEUE *queue; + HHOOK hook = 0; + + // if ((queue = (MESSAGEQUEUE *)GlobalLock( hQueue )) != NULL) + // hook = queue->hooks[id - WH_MINHOOK]; + if (!hook) hook = HOOK_systemHooks[id - WH_MINHOOK]; + return hook; +} + + +/*********************************************************************** + * HOOK_SetHook + * + * Install a given hook. + */ +HANDLE HOOK_SetHook( INT id, LPVOID proc, INT type, + HINSTANCE hInst, DWORD dwThreadId ) +{ + HOOKDATA *data; + //HANDLE handle; + HQUEUE hQueue = 0; + + if ((id < WH_MINHOOK) || (id > WH_MAXHOOK)) return 0; + + + + + //if (id == WH_JOURNALPLAYBACK) EnableHardwareInput(FALSE); + +#if 0 + if (hTask) /* Task-specific hook */ + { + if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) || + (id == WH_SYSMSGFILTER)) return 0; /* System-only hooks */ + if (!(hQueue = GetTaskQueue( hTask ))) + { + /* FIXME: shouldn't this be done somewhere else? */ + if (hTask != GetCurrentTask()) return 0; + if (!(hQueue = GetFastQueue())) return 0; + } + } +#endif + + /* Create the hook structure */ + + if (!(data = HeapAlloc(GetProcessHeap(),0, sizeof(HOOKDATA) ))) return 0; + data->proc = proc; + data->id = id; + data->ownerQueue = hQueue; + data->ownerModule = hInst; + data->flags = type; + + /* Insert it in the correct linked list */ +#if 0 + if (hQueue) + { + MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ); + data->next = queue->hooks[id - WH_MINHOOK]; + queue->hooks[id - WH_MINHOOK] = data; + return data; + } +#endif + + data->next = HOOK_systemHooks[id - WH_MINHOOK]; + HOOK_systemHooks[id - WH_MINHOOK] = data; + + + return data; +} + +/*********************************************************************** + * HOOK_RemoveHook + * + * Remove a hook from the list. + */ +WINBOOL HOOK_RemoveHook( HANDLE hook ) +{ + HOOKDATA *data; + HANDLE *prevHook; + + + + if (!(data = (HOOKDATA *)(hook))) return FALSE; + if (data->flags & HOOK_INUSE) + { + /* Mark it for deletion later on */ + //WARN(hook, "Hook still running, deletion delayed\n" ); + data->proc = (HOOKPROC)0; + return TRUE; + } + +// if (data->id == WH_JOURNALPLAYBACK) EnableHardwareInput(TRUE); + + /* Remove it from the linked list */ + + if (data->ownerQueue) + { +#if 0 + MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock( data->ownerQueue ); + if (!queue) return FALSE; + prevHook = &queue->hooks[data->id - WH_MINHOOK]; +#endif + } + else + prevHook = &HOOK_systemHooks[data->id - WH_MINHOOK]; + + while (*prevHook && *prevHook != hook) + prevHook = &((HOOKDATA *)(*prevHook))->next; + + if (!*prevHook) return FALSE; + *prevHook = data->next; + HeapFree(GetProcessHeap(),0, hook ); + return TRUE; +} + + +/*********************************************************************** + * HOOK_FindValidHook + */ +static HANDLE HOOK_FindValidHook( HANDLE hook ) +{ + HOOKDATA *data; + + for (;;) + { + if (!(data = (HOOKDATA *)(hook))) return 0; + if (data->proc) return hook; + hook = data->next; + } +} + + +/*********************************************************************** + * HOOK_CallHook + * + * Call a hook procedure. + */ +LRESULT HOOK_CallHook( HHOOK hook, INT fromtype, INT code, + WPARAM wParam, LPARAM lParam ) +{ + // MESSAGEQUEUE *queue; + HANDLE prevHook; + HOOKDATA *data = (HOOKDATA *)(hook); + LRESULT ret; + + WPARAM wParamOrig = wParam; + LPARAM lParamOrig = lParam; + // HOOK_MapFunc MapFunc; + // HOOK_UnMapFunc UnMapFunc; + + // MapFunc = HOOK_MapFuncs[fromtype][data->flags & HOOK_MAPTYPE]; + // UnMapFunc = HOOK_UnMapFuncs[fromtype][data->flags & HOOK_MAPTYPE]; + + //if (MapFunc) + // MapFunc( data->id, code, &wParam, &lParam ); + + /* Now call it */ +#if 0 + if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetThreadQueue(0) ))) return 0; + prevHook = queue->hCurHook; + queue->hCurHook = hook; + data->flags |= HOOK_INUSE; +#endif + //TRACE(hook, "Calling hook %04x: %d %08x %08lx\n", + // hook, code, wParam, lParam ); + + ret = data->proc(code, wParam, lParam); + + //TRACE(hook, "Ret hook %04x = %08lx\n", hook, ret ); + + data->flags &= ~HOOK_INUSE; + //queue->hCurHook = prevHook; + + //if (UnMapFunc) + // UnMapFunc( data->id, code, wParamOrig, lParamOrig, wParam, lParam ); + + if (!data->proc) HOOK_RemoveHook( hook ); + + return ret; +} + +/*********************************************************************** + * HOOK_IsHooked + * + * Replacement for calling HOOK_GetHook from other modules. + */ +WINBOOL HOOK_IsHooked( INT id ) +{ + return HOOK_GetHook( id, GetThreadQueue(0) ) != 0; +} + + + +/*********************************************************************** + * HOOK_CallHooksA * * Call a hook chain. */ -#include - LRESULT HOOK_CallHooksA( INT id, INT code, WPARAM wParam, LPARAM lParam ) { + HANDLE hook; + + if (!(hook = HOOK_GetHook( id , GetThreadQueue(0) ))) return 0; + if (!(hook = HOOK_FindValidHook(hook))) return 0; + return HOOK_CallHook( hook, HOOK_WINA, code, wParam, lParam ); } +/*********************************************************************** + * HOOK_CallHooksW + * + * Call a hook chain. + */ LRESULT HOOK_CallHooksW( INT id, INT code, WPARAM wParam, LPARAM lParam ) { + HANDLE hook; + + if (!(hook = HOOK_GetHook( id , GetThreadQueue(0) ))) return 0; + if (!(hook = HOOK_FindValidHook(hook))) return 0; + return HOOK_CallHook( hook, HOOK_WINW, code, wParam, + lParam ); } -WINBOOL HOOK_IsHooked( INT id ) + +/*********************************************************************** + * HOOK_ResetQueueHooks + */ +void HOOK_ResetQueueHooks( HQUEUE hQueue ) { - return FALSE; -} \ No newline at end of file +#if 0 + MESSAGEQUEUE *queue; + + if ((queue = (MESSAGEQUEUE *)GlobalLock( hQueue )) != NULL) + { + HOOKDATA* data; + HHOOK hook; + int id; + for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ ) + { + hook = queue->hooks[id - WH_MINHOOK]; + while( hook ) + { + if( (data = (HOOKDATA *)(hook)) ) + { + data->ownerQueue = hQueue; + hook = data->next; + } else break; + } + } + } +#endif +} + +/*********************************************************************** + * HOOK_FreeModuleHooks + */ +void HOOK_FreeModuleHooks( HMODULE hModule ) +{ + /* remove all system hooks registered by this module */ + + HOOKDATA* hptr; + HHOOK hook, next; + int id; + + for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ ) + { + hook = HOOK_systemHooks[id - WH_MINHOOK]; + while( hook ) + if( (hptr = (HOOKDATA *)(hook)) ) + { + next = hptr->next; + if( hptr->ownerModule == hModule ) + { + hptr->flags &= HOOK_MAPTYPE; + HOOK_RemoveHook(hook); + } + hook = next; + } + else hook = 0; + } +} + +/*********************************************************************** + * HOOK_FreeQueueHooks + */ +void HOOK_FreeQueueHooks( HQUEUE hQueue ) +{ + /* remove all hooks registered by this queue */ + + HOOKDATA* hptr = NULL; + HHOOK hook, next; + int id; + + for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ ) + { + hook = HOOK_GetHook( id, hQueue ); + while( hook ) + { + next = HOOK_GetNextHook(hook); + + hptr = (HOOKDATA *)(hook); + if( hptr && hptr->ownerQueue == hQueue ) + { + hptr->flags &= HOOK_MAPTYPE; + HOOK_RemoveHook(hook); + } + hook = next; + } + } +} diff --git a/reactos/lib/user32/windows/input.c b/reactos/lib/user32/windows/input.c new file mode 100644 index 00000000000..924a88c477a --- /dev/null +++ b/reactos/lib/user32/windows/input.c @@ -0,0 +1,64 @@ + +#include +#include + +static INT captureHT = HTCLIENT; +static HWND captureWnd = 0; + +WINBOOL MouseButtonsStates[3]; +WINBOOL AsyncMouseButtonsStates[3]; +BYTE InputKeyStateTable[256]; +BYTE QueueKeyStateTable[256]; +BYTE AsyncKeyStateTable[256]; + +HWND EVENT_Capture(HWND hwnd, INT ht); + +HWND STDCALL SetCapture( HWND hwnd ) +{ + return EVENT_Capture( hwnd, HTCLIENT ); +} + + +WINBOOL STDCALL ReleaseCapture(void) +{ + if( captureWnd ) EVENT_Capture( 0, 0 ); +} + + +HWND STDCALL GetCapture(void) +{ + return captureWnd; +} + +/********************************************************************** + * EVENT_Capture + * + * We need this to be able to generate double click messages + * when menu code captures mouse in the window without CS_DBLCLK style. + */ +HWND EVENT_Capture(HWND hwnd, INT ht) +{ + HWND capturePrev = captureWnd; + + if (!hwnd) + { + captureWnd = 0L; + captureHT = 0; + } + else + { + if( IsWindow(hwnd) ) + { + DPRINT("(0x%04x)\n", hwnd ); + captureWnd = hwnd; + captureHT = ht; + } + } + + if( capturePrev && capturePrev != captureWnd ) + { + if( IsWindow(capturePrev) ) + SendMessageA( capturePrev, WM_CAPTURECHANGED, 0L, hwnd); + } + return capturePrev; +} \ No newline at end of file diff --git a/reactos/lib/user32/windows/menu.c b/reactos/lib/user32/windows/menu.c new file mode 100644 index 00000000000..c25327b057b --- /dev/null +++ b/reactos/lib/user32/windows/menu.c @@ -0,0 +1,1306 @@ +/* + * Menu functions + * + * Copyright 1993 Martin Ayotte + * Copyright 1994 Alexandre Julliard + * Copyright 1997 Morten Welinder + */ + +/* + * Note: the style MF_MOUSESELECT is used to mark popup items that + * have been selected, i.e. their popup menu is currently displayed. + * This is probably not the meaning this style has in MS-Windows. + */ + + + +#include +#include +#include +#include +#undef WIN32_LEAN_AND_MEAN +#include +#include +//#include +#include +#include +#include + +#include +#define DPRINT printf + + +/********************************************************************** + * CreateMenu (USER32.81) + */ +HMENU STDCALL CreateMenu(void) +{ + HMENU hMenu; + LPPOPUPMENU menu; + if (!(menu = HeapAlloc(GetProcessHeap(),0,sizeof(POPUPMENU) ) ) ) + return (HMENU)NULL; + hMenu = (HANDLE)menu; + menu->wFlags = 0; + menu->wMagic = MENU_MAGIC; + menu->hTaskQ = 0; + menu->Width = 0; + menu->Height = 0; + menu->nItems = 0; + menu->hWnd = 0; + menu->items = NULL; + menu->FocusedItem = NO_SELECTED_ITEM; + //TRACE(menu, "return %04x\n", hMenu ); + return hMenu; +} + + + + + +/********************************************************************** + * DestroyMenu (USER32.134) + */ +WINBOOL STDCALL DestroyMenu( HMENU hMenu ) +{ + DPRINT("menu (%04x)\n", (UINT)hMenu); + + /* Silently ignore attempts to destroy default system popup */ + + if (hMenu && hMenu != MENU_DefSysPopup) + { + LPPOPUPMENU lppop = (LPPOPUPMENU) (hMenu); + + if( pTopPopupWnd && (hMenu == *(HMENU*)pTopPopupWnd->wExtra) ) + *(UINT*)pTopPopupWnd->wExtra = 0; + + if (IS_A_MENU( lppop )) + { + lppop->wMagic = 0; /* Mark it as destroyed */ + + if ((lppop->wFlags & MF_POPUP) && lppop->hWnd && + (!pTopPopupWnd || (lppop->hWnd != pTopPopupWnd->hwndSelf))) + DestroyWindow( lppop->hWnd ); + + if (lppop->items) /* recursively destroy submenus */ + { + int i; + MENUITEM *item = lppop->items; + for (i = lppop->nItems; i > 0; i--, item++) + { + if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu); + MENU_FreeItemData( item ); + } + HeapFree( GetProcessHeap(), 0, lppop->items ); + } + HeapFree( GetProcessHeap(),0,hMenu ); + } + else return FALSE; + } + return (hMenu != MENU_DefSysPopup); +} + + + + + +/********************************************************************** + * GetSystemMenu (USER32.291) + */ +HMENU STDCALL GetSystemMenu( HWND hWnd, WINBOOL bRevert ) +{ + WND *wndPtr = WIN_FindWndPtr( hWnd ); + + if (wndPtr) + { + if( wndPtr->hSysMenu ) + { + if( bRevert ) + { + DestroyMenu(wndPtr->hSysMenu); + wndPtr->hSysMenu = 0; + } + else + { + POPUPMENU *menu = (POPUPMENU*)(wndPtr->hSysMenu); + if( menu->items[0].hSubMenu == MENU_DefSysPopup ) + menu->items[0].hSubMenu = MENU_CopySysPopup(); + } + } + + if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) ) + wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) ); + + if( wndPtr->hSysMenu ) + return GetSubMenu(wndPtr->hSysMenu, 0); + } + return 0; +} + + + + + +/******************************************************************* + * SetSystemMenu (USER32.508) + */ +WINBOOL STDCALL SetSystemMenu( HWND hwnd, HMENU hMenu ) +{ + WND *wndPtr = WIN_FindWndPtr(hwnd); + + if (wndPtr) + { + if (wndPtr->hSysMenu) + DestroyMenu( wndPtr->hSysMenu ); + wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu ); + return TRUE; + } + return FALSE; +} + + + + +/********************************************************************** + * GetMenu (USER32.257) + */ +HMENU STDCALL GetMenu( HWND hWnd ) +{ + WND * wndPtr = WIN_FindWndPtr(hWnd); + if (wndPtr && !(wndPtr->dwStyle & WS_CHILD)) + return (HMENU)wndPtr->wIDmenu; + return 0; +} + + + + +/********************************************************************** + * SetMenu (USER32.487) + */ +WINBOOL STDCALL SetMenu( HWND hWnd, HMENU hMenu ) +{ + WND * wndPtr = WIN_FindWndPtr(hWnd); + + DPRINT("menu (%04x, %04x);\n", (UINT)hWnd, (UINT)hMenu); + + if (wndPtr && !(wndPtr->dwStyle & WS_CHILD)) + { + if (GetCapture() == hWnd) ReleaseCapture(); + + wndPtr->wIDmenu = (UINT)hMenu; + if (hMenu != 0) + { + LPPOPUPMENU lpmenu; + + if (!(lpmenu = (LPPOPUPMENU)(hMenu))) + return FALSE; + lpmenu->hWnd = hWnd; + lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */ + lpmenu->Height = 0; /* Make sure we recalculate the size */ + } + if (IsWindowVisible(hWnd)) + SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | + SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); + return TRUE; + } + return FALSE; +} + + + +/********************************************************************** + * GetSubMenu (USER32.288) + */ +HMENU STDCALL GetSubMenu( HMENU hMenu, INT nPos ) +{ + LPPOPUPMENU lppop; + + if (!(lppop = (LPPOPUPMENU)(hMenu))) return 0; + if ((UINT)nPos >= lppop->nItems) return 0; + if (!(lppop->items[nPos].fType & MF_POPUP)) return 0; + return lppop->items[nPos].hSubMenu; +} + + + +/********************************************************************** + * DrawMenuBar (USER32.1) + */ +WINBOOL STDCALL DrawMenuBar( HWND hWnd ) +{ + LPPOPUPMENU lppop; + WND *wndPtr = WIN_FindWndPtr(hWnd); + if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu) + { + lppop = (LPPOPUPMENU)((HMENU)wndPtr->wIDmenu); + if (lppop == NULL) return FALSE; + + lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */ + SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | + SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); + return TRUE; + } + return FALSE; +} + + + + + + + +/***************************************************************** + * LoadMenuA (USER32.370) + */ +HMENU STDCALL LoadMenuA( HINSTANCE instance, LPCSTR name ) +{ +// instance should be a module handle GetModuleHandle(NULL) + HRSRC hrsrc = FindResourceA( instance, name, (LPCSTR)RT_MENU ); + if (!hrsrc) return 0; + return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc )); +} + + +/***************************************************************** + * LoadMenuW (USER32.373) + */ +HMENU STDCALL LoadMenuW( HINSTANCE hInstance, LPCWSTR name ) +{ + + HRSRC hrsrc = FindResourceW( hInstance, name, (LPCWSTR)RT_MENU ); + if (!hrsrc) + return 0; + return LoadMenuIndirectW( (LPCVOID)LoadResource( hInstance, hrsrc )); +} +/* + + +typedef struct { + WORD mtOption; + WORD mtID; + WCHAR mtString[1]; +} MENUITEMTEMPLATE; +*/ + +/********************************************************************** + * LoadMenuIndirectA (USER32.371) + */ +HMENU +STDCALL +LoadMenuIndirectA( + CONST MENUTEMPLATE *lpMenuTemplate) +{ + return NULL; +} + + +/********************************************************************** + * LoadMenuIndirectW (USER32.372) + */ +HMENU +STDCALL +LoadMenuIndirectW( + CONST MENUTEMPLATE *lpMenuTemplate) +{ + return NULL; +} + + + +/********************************************************************** + * IsMenu (USER32.346) + */ +WINBOOL STDCALL IsMenu(HMENU hMenu) +{ + POPUPMENU *pMenu = hMenu; + return ((pMenu) && (pMenu)->wMagic == MENU_MAGIC); +} + + +/********************************************************************** + * GetMenuItemInfoA (USER32.264) + */ +WINBOOL STDCALL GetMenuItemInfoA( HMENU hmenu, UINT item, WINBOOL bypos, + LPMENUITEMINFO lpmii) +{ + int len; + MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0); + // debug_print_menuitem("GetMenuItemInfo_common: ", menu, ""); + if (!menu) + return FALSE; + + if (lpmii->fMask & MIIM_TYPE) { + lpmii->fType = menu->fType; + switch (MENU_ITEM_TYPE(menu->fType)) { + case MF_STRING: + if (menu->text && lpmii->dwTypeData && lpmii->cch) { + len = min( lpmii->cch, wcslen(menu->text)); + lstrcpynWtoA((LPSTR) lpmii->dwTypeData,menu->text,len); + lpmii->cch = len; + } + break; + case MF_OWNERDRAW: + case MF_BITMAP: + lpmii->dwTypeData = (DWORD)menu->text; + break; + default: + break; + } + } + if (lpmii->fMask & MIIM_STATE) + lpmii->fState = menu->fState; + + if (lpmii->fMask & MIIM_ID) + lpmii->wID = menu->wID; + + if (lpmii->fMask & MIIM_SUBMENU) + lpmii->hSubMenu = menu->hSubMenu; + + if (lpmii->fMask & MIIM_CHECKMARKS) { + lpmii->hbmpChecked = menu->hCheckBit; + lpmii->hbmpUnchecked = menu->hUnCheckBit; + } + if (lpmii->fMask & MIIM_DATA) + lpmii->dwItemData = menu->dwItemData; + + return TRUE; + +} + +/********************************************************************** + * GetMenuItemInfoW (USER32.265) + */ +WINBOOL STDCALL GetMenuItemInfoW( HMENU hmenu, UINT item, WINBOOL bypos, + LPMENUITEMINFO lpmii) +{ + int len; + MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0); + // debug_print_menuitem("GetMenuItemInfo_common: ", menu, ""); + if (!menu) + return FALSE; + + if (lpmii->fMask & MIIM_TYPE) { + lpmii->fType = menu->fType; + switch (MENU_ITEM_TYPE(menu->fType)) { + case MF_STRING: + if (menu->text && lpmii->dwTypeData && lpmii->cch) { + len = min( lpmii->cch, wcslen(menu->text)); + lstrcpynW((LPWSTR) lpmii->dwTypeData,menu->text,len); + lpmii->cch = len; + } + break; + case MF_OWNERDRAW: + case MF_BITMAP: + lpmii->dwTypeData = (DWORD)menu->text; + break; + default: + break; + } + } + if (lpmii->fMask & MIIM_STATE) + lpmii->fState = menu->fState; + + if (lpmii->fMask & MIIM_ID) + lpmii->wID = menu->wID; + + if (lpmii->fMask & MIIM_SUBMENU) + lpmii->hSubMenu = menu->hSubMenu; + + if (lpmii->fMask & MIIM_CHECKMARKS) { + lpmii->hbmpChecked = menu->hCheckBit; + lpmii->hbmpUnchecked = menu->hUnCheckBit; + } + if (lpmii->fMask & MIIM_DATA) + lpmii->dwItemData = menu->dwItemData; + + return TRUE; +} + + + +/********************************************************************** + * SetMenuItemInfoA (USER32.491) + */ +WINBOOL STDCALL SetMenuItemInfoA(HMENU hmenu, UINT item, WINBOOL bypos, + const MENUITEMINFO *lpmiiBuf) +{ + LPMENUITEMINFO lpmii = (LPMENUITEMINFO)lpmiiBuf; + WCHAR MenuTextW[MAX_PATH]; + char *MenuTextA; + WINBOOL bRet; + int i = 0; + MenuTextA = lpmii->dwTypeData; + + lpmii->dwTypeData = MenuTextW; + while ( MenuTextA[i] != 0 && i < MAX_PATH ) + { + MenuTextW[i] = MenuTextA[i]; + i++; + } + MenuTextW[i] = 0; + lpmii->dwTypeData = MenuTextW; + bRet = SetMenuItemInfoW(hmenu, item, bypos, lpmii); + lpmii->dwTypeData = MenuTextA; + + return bRet; +} + +/********************************************************************** + * SetMenuItemInfoW (USER32.492) + */ +WINBOOL STDCALL SetMenuItemInfoW(HMENU hmenu, UINT item, WINBOOL bypos, + const MENUITEMINFO *lpmii) +{ + MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0); + if (!menu) return FALSE; + + if (lpmii->fMask & MIIM_TYPE) { + /* Get rid of old string. */ + if (IS_STRING_ITEM(menu->fType) && menu->text) + HeapFree(GetProcessHeap(), 0, menu->text); + + menu->fType = lpmii->fType; + menu->text = lpmii->dwTypeData; + if (IS_STRING_ITEM(menu->fType) && menu->text) { + menu->text = HeapAlloc(GetProcessHeap(), 0,(lpmii->cch + 1)*sizeof(WCHAR)); + lstrcpynW(menu->text,(LPWSTR) lpmii->dwTypeData,lpmii->cch); + } + + + } + if (lpmii->fMask & MIIM_STATE) + menu->fState = lpmii->fState; + + if (lpmii->fMask & MIIM_ID) + menu->wID = lpmii->wID; + + if (lpmii->fMask & MIIM_SUBMENU) { + menu->hSubMenu = lpmii->hSubMenu; + if (menu->hSubMenu) { + POPUPMENU *subMenu = (POPUPMENU *)((UINT)menu->hSubMenu); + if (IS_A_MENU(subMenu)) { + subMenu->wFlags |= MF_POPUP; + menu->fType |= MF_POPUP; + } + else + /* FIXME: Return an error ? */ + menu->fType &= ~MF_POPUP; + } + else + menu->fType &= ~MF_POPUP; + } + + if (lpmii->fMask & MIIM_CHECKMARKS) + { + menu->hCheckBit = lpmii->hbmpChecked; + menu->hUnCheckBit = lpmii->hbmpUnchecked; + } + if (lpmii->fMask & MIIM_DATA) + menu->dwItemData = lpmii->dwItemData; + + //debug_print_menuitem("SetMenuItemInfo_common: ", menu, ""); + return TRUE; +} + +/********************************************************************** + * SetMenuDefaultItem (USER32.489) + */ +WINBOOL STDCALL SetMenuDefaultItem(HMENU hmenu, UINT item, UINT bypos) +{ + MENUITEM *menuitem = MENU_FindItem(&hmenu, &item, bypos); + POPUPMENU *menu; + + if (!menuitem) return FALSE; + if (!(menu = (POPUPMENU *)(hmenu))) return FALSE; + + menu->defitem = item; /* position */ + + // debug_print_menuitem("SetMenuDefaultItem: ", menuitem, ""); + // FIXME(menu, "(0x%x,%d,%d), empty stub!\n", +// hmenu, item, bypos); + return TRUE; +} + +/********************************************************************** + * GetMenuDefaultItem (USER32.260) + */ +UINT STDCALL GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags) +{ + POPUPMENU *menu; + + if (!(menu = (POPUPMENU *)(hmenu))) + return -1; + + //FIXME(menu, "(0x%x,%d,%d), stub!\n", hmenu, bypos, flags); + +// bypos should be specified TRUE to return default item by position +// flags are ignored + + if (bypos & MF_BYPOSITION) + return menu->defitem; + else { + //FIXME (menu, "default item 0x%x\n", menu->defitem); + if ((menu->defitem > 0) && (menu->defitem < menu->nItems)) + return menu->items[menu->defitem].wID; + } + return -1; +} + + + +/********************************************************************** + * InsertMenuItemA + */ +WINBOOL STDCALL InsertMenuItemA(HMENU hMenu, UINT uItem, WINBOOL bypos, + const MENUITEMINFO *lpmiiBuf) +{ + + LPMENUITEMINFO lpmii = lpmiiBuf; + WCHAR MenuTextW[MAX_PATH]; + char *MenuTextA; + WINBOOL bRet; + int i=0; + MenuTextA = lpmii->dwTypeData; + lpmii->dwTypeData = MenuTextW; + while ( MenuTextA[i] != 0 && i < MAX_PATH ) + { + MenuTextW[i] = MenuTextA[i]; + i++; + } + MenuTextW[i] = 0; + lpmii->dwTypeData = (LPWSTR)MenuTextW; + bRet = InsertMenuItemW(hMenu, uItem, bypos, lpmii); + lpmii->dwTypeData = (LPWSTR)MenuTextA; + return bRet; + + +} + + +/********************************************************************** + * InsertMenuItemW + */ +WINBOOL STDCALL InsertMenuItemW(HMENU hMenu, UINT uItem, WINBOOL bypos, + const MENUITEMINFO *lpmii) +{ + return SetMenuItemInfoW(hMenu,uItem,bypos,lpmii); +} + +/********************************************************************** + * CheckMenuRadioItem + */ + +WINBOOL STDCALL CheckMenuRadioItem(HMENU hMenu, + UINT first, UINT last, UINT check, + UINT bypos) +{ + MENUITEM *mifirst, *milast, *micheck; + HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu; + + // TRACE(menu, "ox%x: %d-%d, check %d, bypos=%d\n", +// hMenu, first, last, check, bypos); + + mifirst = MENU_FindItem (&mfirst, &first, bypos); + milast = MENU_FindItem (&mlast, &last, bypos); + micheck = MENU_FindItem (&mcheck, &check, bypos); + + if (mifirst == NULL || milast == NULL || micheck == NULL || + mifirst > milast || mfirst != mlast || mfirst != mcheck || + micheck > milast || micheck < mifirst) + return FALSE; + + while (mifirst <= milast) + { + if (mifirst == micheck) + { + mifirst->fType |= MFT_RADIOCHECK; + mifirst->fState |= MFS_CHECKED; + } else { + mifirst->fType &= ~MFT_RADIOCHECK; + mifirst->fState &= ~MFS_CHECKED; + } + mifirst++; + } + + return TRUE; +} + + + +/********************************************************************** + * GetMenuItemRect + */ + +WINBOOL STDCALL GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem, + LPRECT rect) +{ + RECT saverect, clientrect; + WINBOOL barp; + HDC hdc; + WND *wndPtr; + MENUITEM *item; + HMENU orghMenu = hMenu; + + // TRACE(menu, "(0x%x,0x%x,%d,%p)\n", +// hwnd, hMenu, uItem, rect); + + item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION); + wndPtr = WIN_FindWndPtr (hwnd); + if (!rect || !item || !wndPtr) return FALSE; + + GetClientRect( hwnd, &clientrect ); + hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW ); + barp = (hMenu == orghMenu); + + saverect = item->rect; + MENU_CalcItemSize (hdc, item, hwnd, + clientrect.left, clientrect.top, barp); + *rect = item->rect; + item->rect = saverect; + + ReleaseDC( hwnd, hdc ); + return TRUE; +} + + + +/********************************************************************** + * SetMenuContextHelpId + */ +WINBOOL STDCALL SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpId) +{ + POPUPMENU *pMenu; + + if (!(pMenu = (POPUPMENU *)(hMenu))) + return FALSE; + pMenu->dwContextHelpId = dwContextHelpId; + return TRUE; +} + + + +/********************************************************************** + * GetMenuContextHelpId + */ +DWORD STDCALL GetMenuContextHelpId( HMENU hMenu ) +{ + POPUPMENU *pMenu; + + if (!(pMenu = (POPUPMENU *)(hMenu))) + return -1; + return pMenu->dwContextHelpId; +} + + + + + +/********************************************************************** + * CreatePopupMenu (USER32.82) + */ +HMENU STDCALL CreatePopupMenu(void) +{ + HMENU hmenu; + POPUPMENU *menu; + + if (!(hmenu = CreateMenu())) return 0; + menu = (POPUPMENU *)( hmenu ); + menu->wFlags |= MF_POPUP; + return hmenu; +} + +/********************************************************************** + * TrackPopupMenu (USER32.549) + */ +WINBOOL STDCALL TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y, + INT nReserved, HWND hWnd, const RECT *lpRect ) +{ + WINBOOL ret = FALSE; + + HideCaret(0); + SendMessageA( hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, 0); + if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 )) + ret = MENU_TrackMenu( hMenu, wFlags & ~TPM_INTERNAL, 0, 0, hWnd, lpRect ); + ShowCaret(0); + return ret; +} + +/********************************************************************** + * TrackPopupMenuEx (USER32.550) + */ +WINBOOL STDCALL TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y, + HWND hWnd, LPTPMPARAMS lpTpm ) +{ +// FIXME(menu, "not fully implemented\n" ); + return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd, + lpTpm ? &lpTpm->rcExclude : NULL ); +} + +/*********************************************************************** + * PopupMenuWndProc + * + * NOTE: Windows has totally different (and undocumented) popup wndproc. + */ +LRESULT STDCALL PopupMenuWndProcA( HWND hwnd, UINT message, WPARAM wParam, + LPARAM lParam ) +{ + WND* wndPtr = WIN_FindWndPtr(hwnd); + + switch(message) + { + case WM_CREATE: + { + CREATESTRUCT *cs = (CREATESTRUCT*)lParam; + SetWindowLong( hwnd, 0, (LONG)cs->lpCreateParams ); + return 0; + } + + case WM_MOUSEACTIVATE: /* We don't want to be activated */ + return MA_NOACTIVATE; + + case WM_PAINT: + { + PAINTSTRUCT ps; + BeginPaint( hwnd, &ps ); + MENU_DrawPopupMenu( hwnd, ps.hdc, (HMENU)GetWindowLong( hwnd, 0 ) ); + EndPaint( hwnd, &ps ); + return 0; + } + case WM_ERASEBKGND: + return 1; + + case WM_DESTROY: + + /* zero out global pointer in case resident popup window + * was somehow destroyed. */ + + if( pTopPopupWnd ) + { + if( hwnd == pTopPopupWnd->hwndSelf ) + { + DPRINT("menu resident popup destroyed!\n"); + + pTopPopupWnd = NULL; + uSubPWndLevel = 0; + } + else + uSubPWndLevel--; + } + break; + + case WM_SHOWWINDOW: + + if( wParam ) + { + if( !(*(HMENU*)wndPtr->wExtra) ) {} + DPRINT("menu no menu to display\n"); + } + else + (LRESULT)*(HMENU*)wndPtr->wExtra = 0; + break; + + case MM_SETMENUHANDLE: + + (LRESULT)*(HMENU*)wndPtr->wExtra = (HMENU)wParam; + break; + + case MM_GETMENUHANDLE: + + return (LRESULT)*(HMENU*)wndPtr->wExtra; + + default: + return (LRESULT)DefWindowProcA( hwnd, message, wParam, lParam ); + } + return (LRESULT)0; +} + +/*********************************************************************** + * PopupMenuWndProc + * + * NOTE: Windows has totally different (and undocumented) popup wndproc. + */ +LRESULT STDCALL PopupMenuWndProcW( HWND hwnd, UINT message, WPARAM wParam, + LPARAM lParam ) +{ + WND* wndPtr = WIN_FindWndPtr(hwnd); + + switch(message) + { + case WM_CREATE: + { + CREATESTRUCT *cs = (CREATESTRUCT*)lParam; + SetWindowLong( hwnd, 0, (LONG)cs->lpCreateParams ); + return 0; + } + + case WM_MOUSEACTIVATE: /* We don't want to be activated */ + return MA_NOACTIVATE; + + case WM_PAINT: + { + PAINTSTRUCT ps; + BeginPaint( hwnd, &ps ); + MENU_DrawPopupMenu( hwnd, ps.hdc, (HMENU)GetWindowLong( hwnd, 0 ) ); + EndPaint( hwnd, &ps ); + return 0; + } + case WM_ERASEBKGND: + return 1; + + case WM_DESTROY: + + /* zero out global pointer in case resident popup window + * was somehow destroyed. */ + + if( pTopPopupWnd ) + { + if( hwnd == pTopPopupWnd->hwndSelf ) + { + DPRINT("menu resident popup destroyed!\n"); + + pTopPopupWnd = NULL; + uSubPWndLevel = 0; + } + else + uSubPWndLevel--; + } + break; + + case WM_SHOWWINDOW: + + if( wParam ) + { + if( !(*(HMENU*)wndPtr->wExtra) ) + DPRINT("menu no menu to display\n"); + } + else + (LRESULT)*(HMENU*)wndPtr->wExtra = 0; + break; + + case MM_SETMENUHANDLE: + + (LRESULT)*(HMENU*)wndPtr->wExtra = (HMENU)wParam; + break; + + case MM_GETMENUHANDLE: + + return (LRESULT)*(HMENU*)wndPtr->wExtra; + + default: + return (LRESULT)DefWindowProcW( hwnd, message, wParam, lParam ); + } + return (LRESULT)0; +} + + + + +/******************************************************************* + * ChangeMenuA (USER32.23) + */ +WINBOOL STDCALL ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data, + UINT id, UINT flags ) +{ + //DPRINT("menu menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n", + // hMenu, pos, (DWORD)data, id, flags ); + if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND, + id, data ); + if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE); + if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE, + id, data ); + if (flags & MF_REMOVE) return RemoveMenu( hMenu, + flags & MF_BYPOSITION ? pos : id, + flags & ~MF_REMOVE ); + /* Default: MF_INSERT */ + return InsertMenuA( hMenu, pos, flags, id, data ); +} + + +/******************************************************************* + * ChangeMenuW (USER32.24) + */ +WINBOOL STDCALL ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data, + UINT id, UINT flags ) +{ + //DPRINT("menu menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n", + // hMenu, pos, (DWORD)data, id, flags ); + if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND, + id, data ); + if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE); + if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE, + id, data ); + if (flags & MF_REMOVE) return RemoveMenu( hMenu, + flags & MF_BYPOSITION ? pos : id, + flags & ~MF_REMOVE ); + /* Default: MF_INSERT */ + return InsertMenuW( hMenu, pos, flags, id, data ); +} + +/******************************************************************* + * CheckMenuItem (USER32.46) + */ +DWORD STDCALL CheckMenuItem( HMENU hMenu, UINT id, UINT flags ) +{ + MENUITEM *item; + DWORD ret; + + DPRINT("menu %04x %04x %04x\n", (UINT)hMenu, id, flags ); + + if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1; + ret = item->fState & MF_CHECKED; + if (flags & MF_CHECKED) item->fState |= MF_CHECKED; + else item->fState &= ~MF_CHECKED; + return ret; +} + + +/********************************************************************** + * EnableMenuItem (USER32.170) + */ +WINBOOL +STDCALL +EnableMenuItem( + HMENU hMenu, + UINT uIDEnableItem, + UINT uEnable) +{ + UINT oldflags; + MENUITEM *item; + + DPRINT("menu (%04x, %04X, %04X) !\n", (UINT) hMenu, uIDEnableItem, uEnable); + + if (!(item = MENU_FindItem( &hMenu, &uIDEnableItem, uEnable ))) + return (UINT)-1; + + oldflags = item->fState & (MF_GRAYED | MF_DISABLED); + item->fState ^= (oldflags ^ uEnable) & (MF_GRAYED | MF_DISABLED); + return oldflags; +} + +/******************************************************************* + * GetMenuStringA (USER32.268) + */ +INT STDCALL GetMenuStringA( HMENU hMenu, UINT wItemID, + LPSTR str, INT nMaxSiz, UINT wFlags ) +{ + MENUITEM *item; + int i; + int len; + //TRACE(menu, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n", + // hMenu, wItemID, str, nMaxSiz, wFlags ); + if (!str || !nMaxSiz) + return 0; + str[0] = '\0'; + + if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) + return 0; + if (!IS_STRING_ITEM(item->fType)) return 0; + + len = min(lstrlenW(item->text),nMaxSiz-1); + for(i=0;itext[i]; + + return len; +} + + +/******************************************************************* + * GetMenuStringW (USER32.269) + */ +INT STDCALL GetMenuStringW( HMENU hMenu, UINT wItemID, + LPWSTR str, INT nMaxSiz, UINT wFlags ) +{ + MENUITEM *item; + + //TRACE(menu, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n", + // hMenu, wItemID, str, nMaxSiz, wFlags ); + if (!str || !nMaxSiz) + return 0; + str[0] = '\0'; + if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) + return 0; + lstrcpynW( str, item->text, nMaxSiz ); + return lstrlenW(str); +} + +/********************************************************************** + * HiliteMenuItem (USER32.318) + */ +WINBOOL STDCALL HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID, + UINT wHilite ) +{ + LPPOPUPMENU menu; +// DPRINT("menu (%04x, %04x, %04x, %04x);\n", +// hWnd, hMenu, wItemID, wHilite); + if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE; + if (!(menu = (LPPOPUPMENU) (hMenu))) return FALSE; + if (menu->FocusedItem == wItemID) return TRUE; + MENU_HideSubPopups( hWnd, hMenu, FALSE ); + MENU_SelectItem( hWnd, hMenu, wItemID, TRUE ); + return TRUE; +} + +/********************************************************************** + * GetMenuState (USER32.267) + */ +UINT STDCALL GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags ) +{ + MENUITEM *item; + DPRINT("menu (%04x, %04x, %04x);\n", (UINT)hMenu, wItemID, wFlags); + if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1; + //debug_print_menuitem (" item: ", item, ""); + if (item->fType & MF_POPUP) + { + POPUPMENU *menu = (POPUPMENU *)( item->hSubMenu ); + if (!menu) return -1; + else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff); + } + else + { + /* We used to (from way back then) mask the result to 0xff. */ + /* I don't know why and it seems wrong as the documented */ + /* return flag MF_SEPARATOR is outside that mask. */ + return (item->fType | item->fState); + } +} + +/********************************************************************** + * GetMenuItemCount (USER32.262) + */ +INT STDCALL GetMenuItemCount( HMENU hMenu ) +{ + LPPOPUPMENU menu = (LPPOPUPMENU)(hMenu); + if (!IS_A_MENU(menu)) return -1; + DPRINT("menu (%04x) returning %d\n", (UINT)hMenu, menu->nItems ); + return menu->nItems; +} + +/********************************************************************** + * GetMenuItemID (USER32.263) + */ +UINT STDCALL GetMenuItemID( HMENU hMenu, INT nPos ) +{ + LPPOPUPMENU menu; + + if (!(menu = (LPPOPUPMENU)(hMenu))) return -1; + if ((nPos < 0) || (nPos >= menu->nItems)) return -1; + if (menu->items[nPos].fType & MF_POPUP) return -1; + return menu->items[nPos].wID; +} + + + + +/******************************************************************* + * InsertMenuA (USER32.2) + */ +WINBOOL STDCALL InsertMenuA( HMENU hMenu, UINT pos, UINT flags, + UINT id, LPCSTR str ) +{ + int i; + WCHAR MenuTextW[MAX_PATH]; + i = 0; + while ((*str)!=0 && i < MAX_PATH) + { + MenuTextW[i] = *str; + str++; + i++; + } + MenuTextW[i] = 0; + return InsertMenuW(hMenu,pos,flags,id,MenuTextW); + + +} + + +/******************************************************************* + * InsertMenuW (USER32.5) + */ +WINBOOL STDCALL InsertMenuW( HMENU hMenu, UINT pos, UINT flags, + UINT id, LPCWSTR str ) +{ + MENUITEM *item; + + + if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE; + + + + if (!(MENU_SetItemData( item, flags, id, str ))) + { + RemoveMenu( hMenu, pos, flags ); + return FALSE; + } + + if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */ + ((POPUPMENU *)((HMENU)id))->wFlags |= MF_POPUP; + + item->hCheckBit = item->hUnCheckBit = 0; + return TRUE; +} + + + + +/******************************************************************* + * AppendMenuA (USER32.5) + */ +WINBOOL STDCALL AppendMenuA( HMENU hMenu, UINT flags, + UINT id, LPCSTR data ) +{ + return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data ); +} + + +/******************************************************************* + * AppendMenuW (USER32.6) + */ +WINBOOL STDCALL AppendMenuW( HMENU hMenu, UINT flags, + UINT id, LPCWSTR data ) +{ + return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data ); +} + + + + +/********************************************************************** + * RemoveMenu (USER32.441) + */ +WINBOOL STDCALL RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags ) +{ + LPPOPUPMENU menu; + MENUITEM *item; + + DPRINT("menu (%04x, %04x, %04x)\n",(UINT)hMenu, nPos, wFlags); + if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE; + if (!(menu = (LPPOPUPMENU) (hMenu))) return FALSE; + + /* Remove item */ + + MENU_FreeItemData( item ); + + if (--menu->nItems == 0) + { + HeapFree( GetProcessHeap(), 0, menu->items ); + menu->items = NULL; + } + else + { + while(nPos < menu->nItems) + { + *item = *(item+1); + item++; + nPos++; + } + menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items, + menu->nItems * sizeof(MENUITEM) ); + } + return TRUE; +} + + +/********************************************************************** + * DeleteMenu (USER32.129) + */ +WINBOOL STDCALL DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags ) +{ + MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags ); + if (!item) + return FALSE; + if (item->fType & MF_POPUP) + DestroyMenu( item->hSubMenu ); + /* nPos is now the position of the item */ + RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION ); + return TRUE; +} + + + + +/******************************************************************* + * ModifyMenuA (USER32.397) + */ +WINBOOL STDCALL ModifyMenuA( HMENU hMenu, UINT pos, UINT flags, + UINT id, LPCSTR str ) +{ + int i; + WCHAR MenuTextW[MAX_PATH]; + i = 0; + while ((*str)!=0 && i < MAX_PATH) + { + MenuTextW[i] = *str; + str++; + i++; + } + MenuTextW[i] = 0; + return ModifyMenuW(hMenu,pos,flags,id,MenuTextW); +} + + +/******************************************************************* + * ModifyMenuW (USER32.398) + */ +WINBOOL +STDCALL +ModifyMenuW(HMENU hMnu,UINT uPosition, + UINT uFlags, UINT uIDNewItem, + LPCWSTR lpNewItem ) +{ + MENUITEM *mnItem; + + + if (!(mnItem = MENU_FindItem( &hMnu, &uPosition, uFlags ))) + return FALSE; + return MENU_SetItemData( mnItem, uFlags, uIDNewItem, lpNewItem ); +} + + + + + + + +/********************************************************************** + * GetMenuCheckMarkDimensions (USER32.258) + */ +LONG +STDCALL +GetMenuCheckMarkDimensions(VOID) +{ + + + return MAKELONG(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) ); +} + + + + + +/********************************************************************** + * SetMenuItemBitmaps (USER32.490) + */ +WINBOOL STDCALL SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags, + HBITMAP hNewUnCheck, HBITMAP hNewCheck) +{ + MENUITEM *item; + DPRINT("menu (%04x, %04x, %04x, %04x, %04x)\n", + (UINT)hMenu, nPos, wFlags, (UINT)hNewCheck, (UINT)hNewUnCheck); + if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE; + + if (!hNewCheck && !hNewUnCheck) + { + item->fState &= ~MF_USECHECKBITMAPS; + } + else /* Install new bitmaps */ + { + item->hCheckBit = hNewCheck; + item->hUnCheckBit = hNewUnCheck; + item->fState |= MF_USECHECKBITMAPS; + } + return TRUE; +} + + + + diff --git a/reactos/lib/user32/windows/message.c b/reactos/lib/user32/windows/message.c index 7590b6a9506..28185ccec36 100644 --- a/reactos/lib/user32/windows/message.c +++ b/reactos/lib/user32/windows/message.c @@ -26,106 +26,22 @@ * ECMA-234, Win */ + +#if 0 LRESULT STDCALL SendMessageA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { - WND * wndPtr; - WND **list, **ppWnd; - LRESULT ret; - - if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST) - { - if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) - return TRUE; - for (ppWnd = list; *ppWnd; ppWnd++) - { - wndPtr = *ppWnd; - if (!IsWindow(wndPtr->hwndSelf)) continue; - if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) - SendMessageA( wndPtr->hwndSelf, msg, wParam, lParam ); - } - HeapFree( GetProcessHeap(), 0, list ); - return TRUE; - } - - if (HOOK_IsHooked( WH_CALLWNDPROC )) - MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE); - - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) - { - //WARN(msg, "invalid hwnd %08x\n", hwnd ); - return 0; - } -#if 0 - if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ)) - return 0; /* Don't send anything if the task is dying */ -#endif - SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam ); - - if (wndPtr->hmemTaskQ != GetFastQueue()) - ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam, - QUEUE_SM_ASCII ); - else - ret = CallWindowProcA( (WNDPROC)wndPtr->winproc, - hwnd, msg, wParam, lParam ); - - SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret ); - return ret; + return MSG_SendMessage( hwnd, msg, wParam, lParam, FALSE ); } -LRESULT STDCALL SendMessageW( - HWND hwnd, /* Window to send message to. If HWND_BROADCAST, - the message will be sent to all top-level windows. */ - - UINT msg, /* message */ - WPARAM wParam, /* message parameter */ - LPARAM lParam /* additional message parameter */ -) { - WND * wndPtr; - WND **list, **ppWnd; - LRESULT ret; - - if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST) - { - if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) - return TRUE; - for (ppWnd = list; *ppWnd; ppWnd++) - { - wndPtr = *ppWnd; - if (!IsWindow(wndPtr->hwndSelf)) continue; - if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) - SendMessageW( wndPtr->hwndSelf, msg, wParam, lParam ); - } - HeapFree( GetProcessHeap(), 0, list ); - return TRUE; - } - - if (HOOK_IsHooked( WH_CALLWNDPROC )) - MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE); - - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) - { - //WARN(msg, "invalid hwnd %08x\n", hwnd ); - return 0; - } -#if 0 - if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ)) - return 0; /* Don't send anything if the task is dying */ -#endif - SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam ); - - if (wndPtr->hmemTaskQ != GetFastQueue()) - ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam, - QUEUE_SM_ASCII | QUEUE_SM_UNICODE ); - else - ret = CallWindowProcW( (WNDPROC)wndPtr->winproc, - hwnd, msg, wParam, lParam ); - - SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret ); - return ret; +LRESULT STDCALL SendMessageW( HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam ) +{ + return MSG_SendMessage( hwnd, msg, wParam, lParam, TRUE ); } +#endif /*********************************************************************** @@ -133,11 +49,57 @@ LRESULT STDCALL SendMessageW( * * Implementation of an inter-task SendMessage. */ -LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam, WORD flags ) +LRESULT MSG_SendMessage( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, WINBOOL bUnicode ) { - return 0; + WND * wndPtr; + LRESULT ret; + MSG msg; + + +// SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam ); +#if 0 + WND **list, **ppWnd; + if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST) + { + if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) + return TRUE; + for (ppWnd = list; *ppWnd; ppWnd++) + { + wndPtr = *ppWnd; + if (!WIN_IsWindow(wndPtr->hwndSelf)) + continue; + if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) + MSG_SendMessage( wndPtr->hwndSelf, message, wParam, lParam, bUnicode ); + } + WIN_DestroyList( list ); + return TRUE; + } +#endif + + if (HOOK_IsHooked( WH_CALLWNDPROC )) + MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE); + + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) + { + return 0; + } + + + msg.hwnd = hwnd; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = 0; + msg.pt.x = 0; + msg.pt.y = 0; + + + // SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret ); + return ret; } + + + /************************************************************************ * MSG_CallWndProcHook */ @@ -160,3 +122,17 @@ void MSG_CallWndProcHook( LPMSG pmsg, WINBOOL bUnicode ) pmsg->message = cwp.message; pmsg->hwnd = cwp.hwnd; } + + +/*********************************************************************** + * MSG_InternalGetMessage + * + * GetMessage() function for internal use. Behave like GetMessage(), + * but also call message filters and optionally send WM_ENTERIDLE messages. + * 'hwnd' must be the handle of the dialog or menu window. + * 'code' is the message filter value (MSGF_??? codes). + */ +WINBOOL MSG_InternalGetMessage( MSG *msg, HWND hwnd, HWND hwndOwner, + WPARAM code, WORD flags, WINBOOL sendIdle ) +{ +} \ No newline at end of file diff --git a/reactos/lib/user32/windows/msg.c b/reactos/lib/user32/windows/msg.c new file mode 100644 index 00000000000..8dd616a346e --- /dev/null +++ b/reactos/lib/user32/windows/msg.c @@ -0,0 +1,925 @@ +#include +#include +#include +#include +#include +#include +#include + +extern int doubleClickSpeed; + +HQUEUE hFirstQueue; +HQUEUE hNewQueue; + +/********************************************************************** + * SetDoubleClickTime (USER.480) + */ +WINBOOL STDCALL SetDoubleClickTime( UINT interval ) +{ + doubleClickSpeed = interval ? interval : 500; + return TRUE; +} + + +/********************************************************************** + * GetDoubleClickTime (USER.239) + */ +UINT STDCALL GetDoubleClickTime(void) +{ + return doubleClickSpeed; +} + +/*********************************************************************** + * PeekMessageW Check queue for messages + * + * Checks for a message in the thread's queue, filtered as for + * GetMessage(). Returns immediately whether a message is available + * or not. + * + * Whether a retrieved message is removed from the queue is set by the + * _wRemoveMsg_ flags, which should be one of the following values: + * + * PM_NOREMOVE Do not remove the message from the queue. + * + * PM_REMOVE Remove the message from the queue. + * + * In addition, PM_NOYIELD may be combined into _wRemoveMsg_ to + * request that the system not yield control during PeekMessage(); + * however applications may not rely on scheduling behavior. + * + * RETURNS + * + * Nonzero if a message is available and is retrieved, zero otherwise. + * + * CONFORMANCE + * + * ECMA-234, Win + * + */ +WINBOOL STDCALL PeekMessageA( LPMSG msg, HWND hwnd, UINT first, + UINT last, UINT flags ) +{ + return MSG_PeekMessage( msg, hwnd, first, last, flags, FALSE ); +} + + +WINBOOL STDCALL PeekMessageW( LPMSG msg, HWND hwnd, UINT first, + UINT last, UINT flags ) +{ + return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE ); +} + +/*********************************************************************** + * GetMessageW (USER.274) Retrieve next message + * + * GetMessage retrieves the next event from the calling thread's + * queue and deposits it in *lpmsg. + * + * If _hwnd_ is not NULL, only messages for window _hwnd_ and its + * children as specified by IsChild() are retrieved. If _hwnd_ is NULL + * all application messages are retrieved. + * + * _min_ and _max_ specify the range of messages of interest. If + * min==max==0, no filtering is performed. Useful examples are + * WM_KEYFIRST and WM_KEYLAST to retrieve keyboard input, and + * WM_MOUSEFIRST and WM_MOUSELAST to retrieve mouse input. + * + * WM_PAINT messages are not removed from the queue; they remain until + * processed. Other messages are removed from the queue. + * + * RETURNS + * + * -1 on error, 0 if message is WM_QUIT, nonzero otherwise. + * + * CONFORMANCE + * + * ECMA-234, Win + * + */ +WINBOOL +STDCALL +GetMessageA(LPMSG lpMsg, HWND hWnd , + UINT wMsgFilterMin, UINT wMsgFilterMax) +{ + + MSG_PeekMessage( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, PM_REMOVE, FALSE ); + + HOOK_CallHooksA( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)lpMsg ); + return (lpMsg->message != WM_QUIT); +} + + + + +WINBOOL +STDCALL +GetMessageW( + LPMSG lpMsg, + HWND hWnd , + UINT wMsgFilterMin, + UINT wMsgFilterMax) +{ + + MSG_PeekMessage( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, PM_REMOVE, FALSE ); + + HOOK_CallHooksW( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)lpMsg ); + return (lpMsg->message != WM_QUIT); +} + + +/*********************************************************************** + * PostMessageA (USER.419) + */ + +WINBOOL STDCALL PostMessageA( HWND hwnd, UINT message, WPARAM wParam, + LPARAM lParam ) +{ + MSG msg; + WND *wndPtr; + + + + + msg.hwnd = hwnd; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = GetTickCount(); + msg.pt.x = 0; + msg.pt.y = 0; + +#ifdef CONFIG_IPC + if (DDE_PostMessage(&msg)) + return TRUE; +#endif /* CONFIG_IPC */ + + if (hwnd == HWND_BROADCAST) + { + DPRINT("HWND_BROADCAST !\n"); + for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next) + { + if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) + { + DPRINT("BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n", + wndPtr->hwndSelf, message, wParam, lParam); + PostMessageA( wndPtr->hwndSelf, message, wParam, lParam ); + } + } + DPRINT("End of HWND_BROADCAST !\n"); + return TRUE; + } + + wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE; + + return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 ); +} + + + + + +/*********************************************************************** + * PostMessageW (USER.420) + */ +WINBOOL STDCALL PostMessageW( HWND hwnd, UINT message, WPARAM wParam, + LPARAM lParam ) +{ + MSG msg; + WND *wndPtr; + + + + + msg.hwnd = hwnd; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = GetTickCount(); + msg.pt.x = 0; + msg.pt.y = 0; + +#ifdef CONFIG_IPC + if (DDE_PostMessage(&msg)) + return TRUE; +#endif /* CONFIG_IPC */ + + if (hwnd == HWND_BROADCAST) + { + DPRINT("HWND_BROADCAST !\n"); + for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next) + { + if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) + { + DPRINT("BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n", + wndPtr->hwndSelf, message, wParam, lParam); + PostMessageA( wndPtr->hwndSelf, message, wParam, lParam ); + } + } + DPRINT("End of HWND_BROADCAST !\n"); + return TRUE; + } + + wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE; + + return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 ); +} + + + +/*********************************************************************** + * SendMessageW (USER.459) Send Window Message + * + * Sends a message to the window procedure of the specified window. + * SendMessage() will not return until the called window procedure + * either returns or calls ReplyMessage(). + * + * Use PostMessage() to send message and return immediately. A window + * procedure may use InSendMessage() to detect + * SendMessage()-originated messages. + * + * Applications which communicate via HWND_BROADCAST may use + * RegisterWindowMessage() to obtain a unique message to avoid conflicts + * with other applications. + * + * CONFORMANCE + * + * ECMA-234, Win + */ + +LRESULT STDCALL SendMessageA( HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam ) +{ + WND * wndPtr; + WND **list, **ppWnd; + LRESULT ret; + + if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST) + { + if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) + return TRUE; + for (ppWnd = list; *ppWnd; ppWnd++) + { + wndPtr = *ppWnd; + if (!IsWindow(wndPtr->hwndSelf)) continue; + if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) + SendMessageA( wndPtr->hwndSelf, msg, wParam, lParam ); + } + HeapFree( GetProcessHeap(), 0, list ); + return TRUE; + } + + if (HOOK_IsHooked( WH_CALLWNDPROC )) + MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE); + + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) + { + DPRINT( "invalid hwnd %08x\n", hwnd ); + return 0; + } + + if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ)) + return 0; /* Don't send anything if the task is dying */ + + SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam ); + + if (wndPtr->hmemTaskQ != GetFastQueue()) + ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam, + QUEUE_SM_ASCII ); + else + ret = CallWindowProcA( (WNDPROC)wndPtr->winproc, + hwnd, msg, wParam, lParam ); + + SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret ); + return ret; +} + + + +LRESULT STDCALL SendMessageW( + HWND hwnd, /* Window to send message to. If HWND_BROADCAST, + the message will be sent to all top-level windows. */ + + UINT msg, /* message */ + WPARAM wParam, /* message parameter */ + LPARAM lParam /* additional message parameter */ +) { + WND * wndPtr; + WND **list, **ppWnd; + LRESULT ret; + + if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST) + { + if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) + return TRUE; + for (ppWnd = list; *ppWnd; ppWnd++) + { + wndPtr = *ppWnd; + if (!IsWindow(wndPtr->hwndSelf)) continue; + if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) + SendMessageW( wndPtr->hwndSelf, msg, wParam, lParam ); + } + HeapFree( GetProcessHeap(), 0, list ); + return TRUE; + } + + if (HOOK_IsHooked( WH_CALLWNDPROC )) + MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE); + + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) + { + DPRINT( "invalid hwnd %08x\n", hwnd ); + return 0; + } + if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ)) + return 0; /* Don't send anything if the task is dying */ + + SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam ); + + if (wndPtr->hmemTaskQ != GetFastQueue()) + ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam, + QUEUE_SM_ASCII | QUEUE_SM_UNICODE ); + else + ret = CallWindowProcW( (WNDPROC)wndPtr->winproc, + hwnd, msg, wParam, lParam ); + + SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret ); + return ret; +} + +/*********************************************************************** + * TranslateMessage (USER.556) + */ +WINBOOL STDCALL TranslateMessage( const MSG *msg ) +{ + return MSG_DoTranslateMessage( msg->message, msg->hwnd, + msg->wParam, msg->lParam ); +} + +/*********************************************************************** + * DispatchMessageA (USER.141) + */ +LONG STDCALL DispatchMessageA( const MSG* msg ) +{ + WND * wndPtr; + LONG retval; + int painting; + + /* Process timer messages */ + if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER)) + { + if (msg->lParam) + { +/* HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */ + return CallWindowProcA( (WNDPROC)msg->lParam, msg->hwnd, + msg->message, msg->wParam, GetTickCount() ); + } + } + + if (!msg->hwnd) return 0; + if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0; + if (!wndPtr->winproc) return 0; + painting = (msg->message == WM_PAINT); + if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT; +/* HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */ + + SPY_EnterMessage( SPY_DISPATCHMESSAGE, msg->hwnd, msg->message, + msg->wParam, msg->lParam ); + retval = CallWindowProcA( (WNDPROC)wndPtr->winproc, + msg->hwnd, msg->message, + msg->wParam, msg->lParam ); + SPY_ExitMessage( SPY_RESULT_OK, msg->hwnd, msg->message, retval ); + + if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) && + (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate) + { + //ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", + // msg->hwnd); + wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT; + /* Validate the update region to avoid infinite WM_PAINT loop */ + ValidateRect( msg->hwnd, NULL ); + } + return retval; +} + + +/*********************************************************************** + * DispatchMessageW (USER.142) Process Message + * + * Process the message specified in the structure *_msg_. + * + * If the lpMsg parameter points to a WM_TIMER message and the + * parameter of the WM_TIMER message is not NULL, the lParam parameter + * points to the function that is called instead of the window + * procedure. + * + * The message must be valid. + * + * RETURNS + * + * DispatchMessage() returns the result of the window procedure invoked. + * + * CONFORMANCE + * + * ECMA-234, Win + * + */ +LONG STDCALL DispatchMessageW( const MSG* msg ) +{ + WND * wndPtr; + LONG retval; + int painting; + + /* Process timer messages */ + if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER)) + { + if (msg->lParam) + { +/* HOOK_CallHooksW( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */ + return CallWindowProcW( (WNDPROC)msg->lParam, msg->hwnd, + msg->message, msg->wParam, GetTickCount() ); + } + } + + if (!msg->hwnd) return 0; + if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0; + if (!wndPtr->winproc) return 0; + painting = (msg->message == WM_PAINT); + if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT; +/* HOOK_CallHooksW( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */ + + SPY_EnterMessage( SPY_DISPATCHMESSAGE, msg->hwnd, msg->message, + msg->wParam, msg->lParam ); + retval = CallWindowProcW( (WNDPROC)wndPtr->winproc, + msg->hwnd, msg->message, + msg->wParam, msg->lParam ); + SPY_ExitMessage( SPY_RESULT_OK, msg->hwnd, msg->message, retval ); + + if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) && + (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate) + { + //ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", + // msg->hwnd); + wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT; + /* Validate the update region to avoid infinite WM_PAINT loop */ + ValidateRect( msg->hwnd, NULL ); + } + return retval; +} + + + +/********************************************************************** + * PostThreadMessageA (USER.422) + * + * BUGS + * + * Thread-local message queues are not supported. + * + */ +WINBOOL STDCALL PostThreadMessageA(DWORD idThread , UINT message, + WPARAM wParam, LPARAM lParam ) +{ + return FALSE; +} + +/********************************************************************** + * PostThreadMessageW (USER.423) + * + * BUGS + * + * Thread-local message queues are not supported. + * + */ +WINBOOL STDCALL PostThreadMessageW(DWORD idThread , UINT message, + WPARAM wParam, LPARAM lParam ) +{ + return FALSE; +} + +/*********************************************************************** + * SendMessageTimeoutA (USER.457) + */ +LRESULT STDCALL SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam, UINT flags, + UINT timeout, LPDWORD resultp) +{ + // DPRINT( "(...): semistub\n"); + return SendMessageA (hwnd, msg, wParam, lParam); +} + + +/*********************************************************************** + * SendMessageTimeoutW (USER.458) + */ +LRESULT STDCALL SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam, UINT flags, + UINT timeout, LPDWORD resultp) +{ +// DPRINT( "(...): semistub\n"); + return SendMessageW (hwnd, msg, wParam, lParam); +} + + +/*********************************************************************** + * WaitMessage (USER.112) (USER.578) Suspend thread pending messages + * + * WaitMessage() suspends a thread until events appear in the thread's + * queue. + * + * BUGS + * + * Is supposed to return WINBOOL under Win. + * + * Thread-local message queues are not supported. + * + * CONFORMANCE + * + * ECMA-234, Win + * + */ +WINBOOL +STDCALL +WaitMessage(VOID) +{ + QUEUE_WaitBits( QS_ALLINPUT ); + return TRUE; +} + +/*********************************************************************** + * MsgWaitForMultipleObjects (USER.400) + */ +DWORD STDCALL MsgWaitForMultipleObjects( DWORD nCount, HANDLE *pHandles, + WINBOOL fWaitAll, DWORD dwMilliseconds, + DWORD dwWakeMask ) +{ + +} + + +/*********************************************************************** + * RegisterWindowMessageA (USER.437) + */ +UINT +STDCALL +RegisterWindowMessageA( + LPCSTR lpString) +{ + return GlobalAddAtomA( lpString ); +} + + +/*********************************************************************** + * RegisterWindowMessageW (USER.438) + */ +UINT +STDCALL +RegisterWindowMessageW( + LPCWSTR lpString) +{ + return GlobalAddAtomW( lpString ); +} + +/*********************************************************************** + * InSendMessage (USER.0) + */ +WINBOOL STDCALL InSendMessage(void) +{ + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetFastQueue() ))) + return 0; + return (WINBOOL)queue->InSendMessageHandle; +} + +/*********************************************************************** + * BroadcastSystemMessage (USER.12) + */ +LONG STDCALL BroadcastSystemMessage( + DWORD dwFlags,LPDWORD recipients,UINT uMessage,WPARAM wParam, + LPARAM lParam +) { + DPRINT("(%08lx,%08lx,%08x,%08x,%08lx): stub!\n", + dwFlags,*recipients,uMessage,wParam,lParam + ); + return 0; +} + +/*********************************************************************** + * SendNotifyMessageA (USER.460) + * FIXME + * The message sended with PostMessage has to be put in the queue + * with a higher priority as the other "Posted" messages. + * QUEUE_AddMsg has to be modifyed. + */ +WINBOOL STDCALL SendNotifyMessageA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ WINBOOL ret = TRUE; + DPRINT("(%04x,%08x,%08x,%08lx) not complete\n", + hwnd, msg, wParam, lParam); + + if ( GetCurrentThreadId() == GetWindowThreadProcessId ( hwnd, NULL)) + { ret=SendMessageA ( hwnd, msg, wParam, lParam ); + } + else + { PostMessageA ( hwnd, msg, wParam, lParam ); + } + return ret; +} + +/*********************************************************************** + * SendNotifyMessageW (USER.461) + * FIXME + * The message sended with PostMessage has to be put in the queue + * with a higher priority as the other "Posted" messages. + * QUEUE_AddMsg has to be modifyed. + */ +WINBOOL STDCALL SendNotifyMessageW(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ WINBOOL ret = TRUE; + DPRINT("(%04x,%08x,%08x,%08lx) not complete\n", + hwnd, msg, wParam, lParam); + + if ( GetCurrentThreadId() == GetWindowThreadProcessId ( hwnd, NULL)) + { ret=SendMessageW ( hwnd, msg, wParam, lParam ); + } + else + { PostMessageW ( hwnd, msg, wParam, lParam ); + } + return ret; +} + +/*********************************************************************** + * SendMessageCallBackA + * FIXME: It's like PostMessage. The callback gets called when the message + * is processed. We have to modify the message processing for a exact + * implementation... + */ +WINBOOL +STDCALL +SendMessageCallbackA( + HWND hWnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam, + SENDASYNCPROC lpResultCallBack, + DWORD dwData) +{ + + if ( hWnd == HWND_BROADCAST) + { PostMessageA( hWnd, Msg, wParam, lParam); + // DPRINT("Broadcast: Callback will not be called!\n"); + return TRUE; + } + (lpResultCallBack)( hWnd, Msg, dwData, SendMessageA ( hWnd, Msg, wParam, lParam )); + return TRUE; +} + +/*********************************************************************** + * ReplyMessage (USER.115) + */ +WINBOOL STDCALL ReplyMessage( LRESULT result ) +{ + MESSAGEQUEUE *senderQ; + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE*)GlobalLock( GetFastQueue() ))) return; + + DPRINT("ReplyMessage, queue %04x\n", queue->self); + + while( (senderQ = (MESSAGEQUEUE*)GlobalLock( queue->InSendMessageHandle))) + { + DPRINT("\trpm: replying to %04x (%04x -> %04x)\n", + queue->msg, queue->self, senderQ->self); + + if( queue->wakeBits & QS_SENDMESSAGE ) + { + QUEUE_ReceiveMessage( queue ); + continue; /* ReceiveMessage() already called us */ + } + + if(!(senderQ->wakeBits & QS_SMRESULT) ) break; +// if (THREAD_IsWinA(THREAD_Current())) OldYield(); + } + if( !senderQ ) { DPRINT("\trpm: done\n"); return; } + + senderQ->SendMessageReturn = result; + DPRINT("\trpm: smResult = %08x, result = %08lx\n", + (unsigned)queue->smResultCurrent, result ); + + senderQ->smResult = queue->smResultCurrent; + queue->InSendMessageHandle = 0; + + QUEUE_SetWakeBit( senderQ, QS_SMRESULT ); +// if (THREAD_IsWinA(THREAD_Current())) DirectedYield( senderQ->hTask ); +} + + + + +/*********************************************************************** + * PostQuitMessage (USER.421) + * + * PostQuitMessage() posts a message to the system requesting an + * application to terminate execution. As a result of this function, + * the WM_QUIT message is posted to the application, and + * PostQuitMessage() returns immediately. The exitCode parameter + * specifies an application-defined exit code, which appears in the + * _wParam_ parameter of the WM_QUIT message posted to the application. + * + * CONFORMANCE + * + * ECMA-234, Win + */ +void STDCALL PostQuitMessage( INT exitCode ) +{ + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetFastQueue() ))) return; + queue->wPostQMsg = TRUE; + queue->wExitCode = (WORD)exitCode; +} + + + + +/*********************************************************************** + * GetWindowThreadProcessId (USER.313) + */ +DWORD STDCALL GetWindowThreadProcessId( HWND hwnd, LPDWORD process ) +{ + return 0; +} + + + + + +/*********************************************************************** + * SetMessageQueue (USER.494) + */ +WINBOOL STDCALL SetMessageQueue( INT size ) +{ + + HQUEUE hQueue, hNewQueue; + MESSAGEQUEUE *queuePtr; + + DPRINT("task %04x size %i\n", GetCurrentTask(), size); + + if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return FALSE; + + if( !(hNewQueue = QUEUE_CreateMsgQueue( size ))) + { + DPRINT( "failed!\n"); + return FALSE; + } + queuePtr = (MESSAGEQUEUE *)GlobalLock( hNewQueue ); + + SIGNAL_MaskAsyncEvents( TRUE ); + + /* Copy data and free the old message queue */ + if ((hQueue = GetThreadQueue(0)) != 0) + { + MESSAGEQUEUE *oldQ = (MESSAGEQUEUE *)GlobalLock( hQueue ); + memcpy( &queuePtr->wParamHigh, &oldQ->wParamHigh, + (int)oldQ->messages - (int)(&oldQ->wParamHigh) ); + HOOK_ResetQueueHooks( hNewQueue ); + if( WIN_GetDesktop()->hmemTaskQ == hQueue ) + WIN_GetDesktop()->hmemTaskQ = hNewQueue; + WIN_ResetQueueWindows( WIN_GetDesktop(), hQueue, hNewQueue ); +// CLIPBOARD_ResetLock( hQueue, hNewQueue ); + QUEUE_DeleteMsgQueue( hQueue ); + } + + /* Link new queue into list */ + queuePtr->hTask = GetCurrentTask(); + queuePtr->next = hFirstQueue; + hFirstQueue = hNewQueue; + + if( !queuePtr->next ) pCursorQueue = queuePtr; + SetThreadQueue( 0, hNewQueue ); + + SIGNAL_MaskAsyncEvents( FALSE ); + return TRUE; + + +// win32 dynamically expands the message queue +} + + + +/*********************************************************************** + * GetQueueStatus (USER.283) + */ +DWORD STDCALL GetQueueStatus( UINT flags ) +{ + MESSAGEQUEUE *queue; + DWORD ret; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetFastQueue() ))) return 0; + ret = MAKELONG( queue->changeBits, queue->wakeBits ); + queue->changeBits = 0; + return ret & MAKELONG( flags, flags ); +} + + +/*********************************************************************** + * WaitForInputIdle (USER.577) + */ +DWORD STDCALL WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut) +{ + // FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut); + + return WAIT_TIMEOUT; +} + + +/*********************************************************************** + * GetInputState (USER.244) + */ +WINBOOL STDCALL GetInputState(void) +{ + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetFastQueue() ))) + return FALSE; + return queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON); +} + + + +/*********************************************************************** + * GetMessagePos (USER.272) + * + * The GetMessagePos() function returns a long value representing a + * cursor position, in screen coordinates, when the last message + * retrieved by the GetMessage() function occurs. The x-coordinate is + * in the low-order word of the return value, the y-coordinate is in + * the high-order word. The application can use the MAKEPOINT() + * macro to obtain a POINT structure from the return value. + * + * For the current cursor position, use GetCursorPos(). + * + * RETURNS + * + * Cursor position of last message on success, zero on failure. + * + * CONFORMANCE + * + * ECMA-234, Win + * + */ +DWORD STDCALL GetMessagePos(void) +{ + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetFastQueue() ))) return 0; + return queue->GetMessagePosVal; +} + + +/*********************************************************************** + * GetMessageTime (USER.273) + * + * GetMessageTime() returns the message time for the last message + * retrieved by the function. The time is measured in milliseconds with + * the same offset as GetTickCount(). + * + * Since the tick count wraps, this is only useful for moderately short + * relative time comparisons. + * + * RETURNS + * + * Time of last message on success, zero on failure. + * + * CONFORMANCE + * + * ECMA-234, Win + * + */ +LONG STDCALL GetMessageTime(void) +{ + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetFastQueue() ))) return 0; + return queue->GetMessageTimeVal; +} + + +/*********************************************************************** + * GetMessageExtraInfo (USER.271) + */ +LONG STDCALL GetMessageExtraInfo(void) +{ + MESSAGEQUEUE *queue; + + if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetFastQueue() ))) return 0; + return queue->GetMessageExtraInfoVal; +} + + +WINBOOL STDCALL MessageBeep( UINT uType ) +{ + return Beep(uType ,0); +} + + diff --git a/reactos/lib/user32/windows/property.c b/reactos/lib/user32/windows/property.c new file mode 100644 index 00000000000..f0b1ec68e14 --- /dev/null +++ b/reactos/lib/user32/windows/property.c @@ -0,0 +1,200 @@ +#include +#include +#include + +/*********************************************************************** + * GetPropA (USER.281) + */ +HANDLE STDCALL GetPropA( HWND hWnd, LPCSTR str ) +{ + PROPERTY *prop; + prop = PROPERTY_FindProp(hWnd,STRING2ATOMA(str)); + return prop ? prop->handle : NULL; + +} + + +/*********************************************************************** + * GetPropW (USER.282) + */ +HANDLE STDCALL GetPropW( HWND hWnd, LPCWSTR str) +{ + PROPERTY *prop; + prop = PROPERTY_FindProp(hWnd,STRING2ATOMW(str)); + return prop ? prop->handle : NULL; +} + + + + + +/*********************************************************************** + * SetPropA (USER.497) + */ +WINBOOL STDCALL SetPropA( HWND hwnd, LPCSTR str, HANDLE hdata ) +{ + + return PROPERTY_SetProp( hwnd,STRING2ATOMA(str),hdata); + +} + + +/*********************************************************************** + * SetPropW (USER.498) + */ +WINBOOL STDCALL SetPropW( HWND hwnd, LPCWSTR str, HANDLE hdata ) +{ + return PROPERTY_SetProp(hwnd,STRING2ATOMW(str),hdata); +} + + + + +/*********************************************************************** + * RemovePropA (USER.442) + */ +HANDLE STDCALL RemovePropA( HWND hwnd, LPCSTR str ) +{ + return PROPERTY_RemoveProp(hwnd, STRING2ATOMA(str)); +} + + +/*********************************************************************** + * RemovePropW (USER.443) + */ +HANDLE STDCALL RemovePropW( HWND hwnd, LPCWSTR str ) +{ + return PROPERTY_RemoveProp(hwnd, STRING2ATOMW(str)); +} + + + + + +#if 0 + +/*********************************************************************** + * EnumPropsA (USER.186) + */ +INT STDCALL EnumPropsA( HWND hwnd, PROPENUMPROCA func ) +{ + int size; + int i; + INT ret = -1; + LPWSTR string[MAX_PATH]; + PROPVALUE pv; + + pv = malloc(100*sizeof(PROPVALUE)); + + PROPERTY_EnumPropEx(hwnd, pv ,100, &size ); + for (i=0;inext; + + GlobalFindAtomNameA(pv[i]->atom,string,MAX_PATH-1); + ret = func( hwnd, string, pv[i]->handle); + if (!ret) + break; + } + + free(pv); + return ret; +} + + +/*********************************************************************** + * EnumPropsW (USER.189) + */ +INT STDCALL EnumPropsW( HWND hwnd, PROPENUMPROCW func ) +{ + int size; + int i; + INT ret = -1; + LPWSTR string[MAX_PATH]; + PROPVALUE *pv; + + pv = malloc(100*sizeof(PROPVALUE)); + + PROPERTY_EnumPropEx(hwnd, pv ,100, &size ); + for (i=0;inext; + + GlobalFindAtomNameW(pv[i]->atom,string,MAX_PATH-1); + ret = func( hwnd, string, pv[i]->handle); + if (!ret) + break; + } + + free(pv); + return ret; +} + + +/*********************************************************************** + * EnumPropsExA (USER.187) + */ +INT STDCALL EnumPropsExA(HWND hwnd, PROPENUMPROCEXA func, LPARAM lParam) +{ + int size; + int i; + INT ret = -1; + LPWSTR string[MAX_PATH]; + PROPVALUE *pv; + + pv = malloc(100*sizeof(PROPVALUE)); + + PROPERTY_EnumPropEx(hwnd, pv ,100, &size ); + for (i=0;inext; + + GlobalFindAtomNameW(pv[i]->atom,string,MAX_PATH-1); + ret = func( hwnd, string, pv[i]->handle, lParam); + if (!ret) + break; + } + + free(pv); + return ret; +} + + +/*********************************************************************** + * EnumPropsExW (USER.188) + */ +INT STDCALL EnumPropsExW(HWND hwnd, PROPENUMPROCEXW func, LPARAM lParam) +{ + int size; + int i; + INT ret = -1; + LPWSTR string[MAX_PATH]; + PROPVALUE *pv; + + pv = malloc(100*sizeof(PROPVALUE)); + + PROPERTY_EnumPropEx(hwnd, pv ,100, &size ); + for (i=0;inext; + + GlobalFindAtomNameW(pv[i]->atom,string,MAX_PATH-1); + ret = func( hwnd, string, pv[i]->handle, lParam); + if (!ret) + break; + } + + free(pv); + return ret; +} + + +#endif \ No newline at end of file diff --git a/reactos/lib/user32/windows/queue.c b/reactos/lib/user32/windows/queue.c new file mode 100644 index 00000000000..a123969f444 --- /dev/null +++ b/reactos/lib/user32/windows/queue.c @@ -0,0 +1,5 @@ +#include +#include + + + diff --git a/reactos/lib/user32/windows/rect.c b/reactos/lib/user32/windows/rect.c new file mode 100644 index 00000000000..7ed97a06dc1 --- /dev/null +++ b/reactos/lib/user32/windows/rect.c @@ -0,0 +1,63 @@ +#include +#include + +WINBOOL +STDCALL +AdjustWindowRect( LPRECT lpRect, DWORD dwStyle, WINBOOL bMenu ) +{ + return AdjustWindowRectEx( lpRect, dwStyle, bMenu, 0 ); +} + + + +WINBOOL +STDCALL AdjustWindowRectEx(LPRECT lpRect, DWORD dwStyle, WINBOOL bMenu, DWORD dwExStyle) +{ + /* Correct the window style */ + + if (!(dwStyle & (WS_POPUP | WS_CHILD))) /* Overlapped window */ + dwStyle |= WS_CAPTION; + dwStyle &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD); + dwExStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | + WS_EX_STATICEDGE | WS_EX_TOOLWINDOW); + if (dwExStyle & WS_EX_DLGMODALFRAME) dwStyle &= ~WS_THICKFRAME; + + if (TWEAK_WineLook == WIN31_LOOK) + NC_AdjustRect( lpRect, dwStyle, bMenu, dwExStyle ); + else { + NC_AdjustRectOuter95( lpRect, dwStyle, bMenu, dwExStyle ); + NC_AdjustRectInner95( lpRect, dwStyle, dwExStyle ); + } + + return TRUE; +} + + +WINBOOL STDCALL GetWindowRect( HWND hwnd, LPRECT rect ) +{ + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return FALSE; + + *rect = wndPtr->rectWindow; + if (wndPtr->dwStyle & WS_CHILD) + MapWindowPoints( wndPtr->parent->hwndSelf, 0, (POINT *)rect, 2 ); + return TRUE; +} + + +WINBOOL +STDCALL +GetClientRect(HWND hWnd, LPRECT lpRect) +{ + WND * wndPtr = WIN_FindWndPtr( hWnd ); + if ( wndPtr == NULL || lpRect == NULL ) + return FALSE; + + lpRect->left = lpRect->top = lpRect->right = lpRect->bottom = 0; + if (wndPtr) + { + lpRect->right = wndPtr->rectClient.right - wndPtr->rectClient.left; + lpRect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top; + } + return TRUE; +} diff --git a/reactos/lib/user32/windows/spy.c b/reactos/lib/user32/windows/spy.c index 63f8c099391..d76dd5c817c 100644 --- a/reactos/lib/user32/windows/spy.c +++ b/reactos/lib/user32/windows/spy.c @@ -6,4 +6,8 @@ int SPY_EnterMessage( UINT id, HWND hwnd, UINT msg, WPARAM wParam,LPARAM lParam int SPY_ExitMessage( UINT id, HWND hwnd, UINT msg, LRESULT res ) { +} + +const char *SPY_GetMsgName( UINT msg ) +{ } \ No newline at end of file diff --git a/reactos/lib/user32/windows/timer.c b/reactos/lib/user32/windows/timer.c new file mode 100644 index 00000000000..1fefab29184 --- /dev/null +++ b/reactos/lib/user32/windows/timer.c @@ -0,0 +1,13 @@ +#include + +UINT SetTimer( HWND hWnd,UINT nIDEvent, + UINT uElapse, TIMERPROC lpTimerFunc + ) +{ + return 0; +} + +WINBOOL STDCALL KillTimer(HWND hWnd, UINT uIDEvent ) +{ + return FALSE; +} \ No newline at end of file diff --git a/reactos/lib/user32/windows/win.c b/reactos/lib/user32/windows/win.c index c05488297d7..db48105412f 100644 --- a/reactos/lib/user32/windows/win.c +++ b/reactos/lib/user32/windows/win.c @@ -1,22 +1,681 @@ #include #include +#include +#include +#include +#include +#include +#include + + + +#undef CreateWindowA +HWND STDCALL CreateWindowA(LPCSTR lpClassName, LPCSTR lpWindowName, + DWORD dwStyle,int x, int y, + int nWidth, int nHeight, HWND hWndParent, + HMENU hMenu, HANDLE hInstance, + LPVOID lpParam ) +{ + return CreateWindowExA( 0, lpClassName, lpWindowName, dwStyle,x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam ); +} + +#undef CreateWindowW +HWND STDCALL CreateWindowW(LPCWSTR lpClassName, LPCWSTR lpWindowName, + DWORD dwStyle,int x, int y, + int nWidth, int nHeight, HWND hWndParent, + HMENU hMenu, HANDLE hInstance, + LPVOID lpParam ) +{ + return CreateWindowExW( 0, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam ); +} + +HWND STDCALL CreateWindowExA( DWORD exStyle, LPCSTR lpClassName, + LPCSTR lpWindowName, DWORD style, INT x, + INT y, INT width, INT height, + HWND parent, HMENU menu, + HINSTANCE hInstance, LPVOID data ) +{ + + CREATESTRUCTW cs; + CLASS *p; + DWORD status; + +// int i; + + + p = CLASS_FindClassByAtom( STRING2ATOMA(lpClassName), hInstance ); + if ( p == NULL ) + return NULL; + + + //if(exStyle & WS_EX_MDICHILD) + // return MDI_CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, data); + +#if 0 + while ((*lpWindowName)!=0 && i < MAX_PATH) + { + WindowNameW[i] = *lpWindowName; + lpWindowName++; + i++; + } + WindowNameW[i] = 0; +#endif + + + + + /* Create the window */ + + cs.lpCreateParams = data; + cs.hInstance = hInstance; + cs.hMenu = menu; + cs.hWndParent = parent; + cs.x = x; + cs.y = y; + cs.cx = width; + cs.cy = height; + cs.style = style; + cs.lpszName = (LPWSTR)lpWindowName; + cs.dwExStyle = exStyle; + + + + return WIN_CreateWindowEx( &cs, p->atomName ); + +} + + +HWND STDCALL CreateWindowExW( DWORD exStyle, LPCWSTR lpClassName, + LPCWSTR windowName, DWORD style, INT x, + INT y, INT width, INT height, + HWND parent, HMENU menu, + HINSTANCE hInstance, LPVOID data ) +{ +// WCHAR WindowNameW[MAX_PATH]; +// WCHAR ClassNameW[MAX_PATH]; + CLASS *p; + DWORD status; + CREATESTRUCTW cs; + + + + p = CLASS_FindClassByAtom( STRING2ATOMW(lpClassName), hInstance ); + if ( p == NULL ) + return NULL; + + + + /* Create the window */ + + cs.lpCreateParams = data; + cs.hInstance = hInstance; + cs.hMenu = menu; + cs.hWndParent = parent; + cs.x = x; + cs.y = y; + cs.cx = width; + cs.cy = height; + cs.style = style; + cs.lpszName = windowName; + cs.lpszClass = p->className; + cs.dwExStyle = exStyle; + + + return WIN_CreateWindowEx( &cs, p->atomName ); + +} + + +/*********************************************************************** + * DestroyWindow (USER.135) + */ +WINBOOL STDCALL DestroyWindow( HWND hwnd ) +{ + WND * wndPtr; + + DPRINT( "(%04x)\n", hwnd); + + /* Initialization */ + + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE; + //if (wndPtr == pWndDesktop) return FALSE; /* Can't destroy desktop */ + + /* Call hooks */ + + + if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, hwnd, 0L) ) + return FALSE; + + if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner) + { + HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L ); + /* FIXME: clean up palette - see "Internals" p.352 */ + } + + if( !QUEUE_IsExitingQueue(wndPtr->hmemTaskQ) ) + if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) ) + { + /* Notify the parent window only */ + SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY, + MAKEWPARAM(WM_DESTROY, wndPtr->wIDmenu), (LPARAM)hwnd ); + if( !IsWindow(hwnd) ) return TRUE; + } + + // CLIPBOARD_GetDriver()->pResetOwner( wndPtr, FALSE ); /* before the window is unmapped */ + + /* Hide the window */ + + if (wndPtr->dwStyle & WS_VISIBLE) + { + SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | + SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE| + ((QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))?SWP_DEFERERASE:0) ); + if (!IsWindow(hwnd)) return TRUE; + } + + /* Recursively destroy owned windows */ + + if( !(wndPtr->dwStyle & WS_CHILD) ) + { + /* make sure top menu popup doesn't get destroyed */ + MENU_PatchResidentPopup( (HQUEUE)0xFFFF, wndPtr ); + + for (;;) + { + WND *siblingPtr = wndPtr->parent->child; /* First sibling */ + while (siblingPtr) + { + if (siblingPtr->owner == wndPtr) + { + if (siblingPtr->hmemTaskQ == wndPtr->hmemTaskQ) + break; + else + siblingPtr->owner = NULL; + } + siblingPtr = siblingPtr->next; + } + if (siblingPtr) DestroyWindow( siblingPtr->hwndSelf ); + else break; + } +// !Options.managed || + if( EVENT_CheckFocus() ) + WINPOS_ActivateOtherWindow(wndPtr); + + if( wndPtr->owner && + wndPtr->owner->hwndLastActive == wndPtr->hwndSelf ) + wndPtr->owner->hwndLastActive = wndPtr->owner->hwndSelf; + } + + /* Send destroy messages */ + + WIN_SendDestroyMsg( wndPtr ); + if (!IsWindow(hwnd)) return TRUE; + + /* Unlink now so we won't bother with the children later on */ + + if( wndPtr->parent ) WIN_UnlinkWindow(hwnd); + + /* Destroy the window storage */ + + WIN_DestroyWindow( wndPtr ); + return TRUE; +} + + +/******************************************************************* + * EnableWindow + */ +WINBOOL STDCALL EnableWindow( HWND hWnd, WINBOOL enable ) +{ + WND *wndPtr; + + if (!(wndPtr = WIN_FindWndPtr( hWnd ))) return FALSE; + if (enable && (wndPtr->dwStyle & WS_DISABLED)) + { + /* Enable window */ + wndPtr->dwStyle &= ~WS_DISABLED; + SendMessageA( hWnd, WM_ENABLE, TRUE, 0 ); + return TRUE; + } + else if (!enable && !(wndPtr->dwStyle & WS_DISABLED)) + { + /* Disable window */ + wndPtr->dwStyle |= WS_DISABLED; + if ((hWnd == GetFocus()) || IsChild( hWnd, GetFocus() )) + SetFocus( 0 ); /* A disabled window can't have the focus */ + if ((hWnd == GetCapture()) || IsChild( hWnd, GetCapture() )) + ReleaseCapture(); /* A disabled window can't capture the mouse */ + SendMessageA( hWnd, WM_ENABLE, FALSE, 0 ); + return FALSE; + } + return ((wndPtr->dwStyle & WS_DISABLED) != 0); +} + + + +HWND STDCALL GetDesktopWindow(VOID) +{ + return NULL; +} + + + +HWND STDCALL GetWindow( HWND hwnd, UINT rel ) +{ + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return 0; + switch(rel) + { + case GW_HWNDFIRST: + if (wndPtr->parent) return wndPtr->parent->child->hwndSelf; + else return 0; + + case GW_HWNDLAST: + if (!wndPtr->parent) return 0; /* Desktop window */ + while (wndPtr->next) wndPtr = wndPtr->next; + return wndPtr->hwndSelf; + + case GW_HWNDNEXT: + if (!wndPtr->next) return 0; + return wndPtr->next->hwndSelf; + + case GW_HWNDPREV: + if (!wndPtr->parent) return 0; /* Desktop window */ + wndPtr = wndPtr->parent->child; /* First sibling */ + if (wndPtr->hwndSelf == hwnd) return 0; /* First in list */ + while (wndPtr->next) + { + if (wndPtr->next->hwndSelf == hwnd) return wndPtr->hwndSelf; + wndPtr = wndPtr->next; + } + return 0; + + case GW_OWNER: + return wndPtr->owner ? wndPtr->owner->hwndSelf : 0; + + case GW_CHILD: + return wndPtr->child ? wndPtr->child->hwndSelf : 0; + } + return 0; +} + + +WORD STDCALL SetWindowWord( HWND hwnd, INT offset, WORD newval ) +{ + WORD *ptr, retval; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return 0; + if (offset >= 0) + { + if (offset + sizeof(WORD) > wndPtr->class->cbWndExtra) + { + DPRINT( "Invalid offset %d\n", offset ); + return 0; + } + ptr = (WORD *)(((char *)wndPtr->wExtra) + offset); + } + else switch(offset) + { + case GWW_ID: ptr = (WORD *)&wndPtr->wIDmenu; break; + case GWW_HINSTANCE: ptr = (WORD *)&wndPtr->hInstance; break; + case GWW_HWNDPARENT: return SetParent( hwnd, newval ); + default: + DPRINT("Invalid offset %d\n", offset ); + return 0; + } + retval = *ptr; + *ptr = newval; + return retval; +} + +LONG STDCALL GetWindowLongA( HWND hwnd, INT offset ) +{ + return WIN_GetWindowLong( hwnd, offset ); +} + + +LONG STDCALL GetWindowLongW( HWND hwnd, INT offset ) +{ + return WIN_GetWindowLong( hwnd, offset ); +} + +/********************************************************************** + * SetWindowLongW (USER.518) Set window attribute + * + * SetWindowLong() alters one of a window's attributes or sets a -bit (long) + * value in a window's extra memory. + * + * The _hwnd_ parameter specifies the window. is the handle to a + * window that has extra memory. The _newval_ parameter contains the + * new attribute or extra memory value. If positive, the _offset_ + * parameter is the byte-addressed location in the window's extra + * memory to set. If negative, _offset_ specifies the window + * attribute to set, and should be one of the following values: + * + * GWL_EXSTYLE The window's extended window style + * + * GWL_STYLE The window's window style. + * + * GWL_WNDPROC Pointer to the window's window procedure. + * + * GWL_HINSTANCE The window's pplication instance handle. + * + * GWL_ID The window's identifier. + * + * GWL_USERDATA The window's user-specified data. + * + * If the window is a dialog box, the _offset_ parameter can be one of + * the following values: + * + * DWL_DLGPROC The address of the window's dialog box procedure. + * + * DWL_MSGRESULT The return value of a message + * that the dialog box procedure processed. + * + * DWL_USER Application specific information. + * + * RETURNS + * + * If successful, returns the previous value located at _offset_. Otherwise, + * returns 0. + * + * NOTES + * + * Extra memory for a window class is specified by a nonzero cbWndExtra + * parameter of the WNDCLASS structure passed to RegisterClass() at the + * time of class creation. + * + * Using GWL_WNDPROC to set a new window procedure effectively creates + * a window subclass. Use CallWindowProc() in the new windows procedure + * to pass messages to the superclass's window procedure. + * + * The user data is reserved for use by the application which created + * the window. + * + * Do not use GWL_STYLE to change the window's WS_DISABLE style; + * instead, call the EnableWindow() function to change the window's + * disabled state. + * + * Do not use GWL_HWNDPARENT to reset the window's parent, use + * SetParent() instead. + * + * Win95: + * When offset is GWL_STYLE and the calling app's ver is 4.0, + * it sends WM_STYLECHANGING before changing the settings + * and WM_STYLECHANGED afterwards. + * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST. + * + * BUGS + * + * GWL_STYLE does not dispatch WM_STYLE... messages. + * + * CONFORMANCE + * + * ECMA-234, Win + * + */ + +LONG STDCALL SetWindowLongA( HWND hwnd, INT offset, LONG newval ) +{ + return WIN_SetWindowLong( hwnd, offset, newval ); +} + + +LONG STDCALL SetWindowLongW( + HWND hwnd, + INT offset, + LONG newval +) { + return WIN_SetWindowLong( hwnd, offset, newval ); +} + + +HWND STDCALL GetTopWindow( HWND hwnd ) +{ + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (wndPtr && wndPtr->child) return wndPtr->child->hwndSelf; + else return 0; +} + +HWND STDCALL GetNextWindow( HWND hwnd, UINT flag ) +{ + if ((flag != GW_HWNDNEXT) && (flag != GW_HWNDPREV)) return 0; + return GetWindow( hwnd, flag ); +} + +/***************************************************************** + * GetParent (USER.278) + */ +HWND STDCALL GetParent( HWND hwnd ) +{ + WND *wndPtr = WIN_FindWndPtr(hwnd); + if ((!wndPtr) || (!(wndPtr->dwStyle & (WS_POPUP|WS_CHILD)))) return 0; + wndPtr = (wndPtr->dwStyle & WS_CHILD) ? wndPtr->parent : wndPtr->owner; + return wndPtr ? wndPtr->hwndSelf : NULL; +} + +/***************************************************************** + * SetParent (USER.495) + */ +HWND STDCALL SetParent( HWND hWndChild, HWND hWndNewParent ) +{ + WND *wndPtr = WIN_FindWndPtr( hWndChild ); + WND *pWndNewParent = + (hWndNewParent) ? WIN_FindWndPtr( hWndNewParent ) : WIN_FindWndPtr(GetDesktopWindow()); + WND *pWndOldParent; + + // (wndPtr)?(*wndPtr->pDriver->pSetParent)(wndPtr, pWndNewParent):NULL; + + return pWndOldParent?pWndOldParent->hwndSelf:NULL; +} + +/******************************************************************* + * GetWindowTextA (USER.309) + */ +INT STDCALL GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount ) +{ + return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, + (LPARAM)lpString ); +} + + + +/******************************************************************* + * GetWindowTextW (USER.312) + */ +INT STDCALL GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount ) +{ + return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, + (LPARAM)lpString ); +} + + +WINBOOL STDCALL SetWindowTextA( HWND hwnd, LPCSTR lpString ) +{ + return (WINBOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString ); +} + + +WINBOOL STDCALL SetWindowTextW( HWND hwnd, LPCWSTR lpString ) +{ + return (WINBOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString ); +} + + +INT STDCALL GetWindowTextLengthA( HWND hwnd ) +{ + return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 ); +} + + +INT STDCALL GetWindowTextLengthW( HWND hwnd ) +{ + return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 ); +} + + +WINBOOL STDCALL IsChild( HWND parent, HWND child ) +{ + WND * wndPtr = WIN_FindWndPtr( child ); + while (wndPtr && (wndPtr->dwStyle & WS_CHILD)) + { + wndPtr = wndPtr->parent; + if (wndPtr->hwndSelf == parent) return TRUE; + } + return FALSE; +} WINBOOL IsWindow(HANDLE hWnd) -{ +{ + if (WIN_FindWndPtr( hWnd ) == NULL) return FALSE; return TRUE; } -WND * WIN_FindWndPtr( HWND hwnd ) + +/*********************************************************************** + * IsWindowEnabled + */ +WINBOOL STDCALL IsWindowEnabled(HWND hWnd) { - return NULL; + WND * wndPtr; + + if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE; + return !(wndPtr->dwStyle & WS_DISABLED); } -WND* WIN_GetDesktop(void) + +/*********************************************************************** + * IsWindowUnicode + */ +WINBOOL STDCALL IsWindowUnicode( HWND hWnd ) { - return NULL; + WND * wndPtr; +// What if handle is invalid ?? + + if (!(wndPtr = WIN_FindWndPtr(hWnd))) + return FALSE; + return wndPtr->class->bUnicode; } -WND **WIN_BuildWinArray( WND *wndPtr, UINT bwaFlags, UINT* pTotal ) + +WINBOOL STDCALL IsWindowVisible( HWND hwnd ) { - return NULL; -} \ No newline at end of file + WND *wndPtr = WIN_FindWndPtr( hwnd ); + while (wndPtr && (wndPtr->dwStyle & WS_CHILD)) + { + if (!(wndPtr->dwStyle & WS_VISIBLE)) return FALSE; + wndPtr = wndPtr->parent; + } + return (wndPtr && (wndPtr->dwStyle & WS_VISIBLE)); +} + + +/*********************************************************************** + * ShowWindow32 (USER32.534) + */ +WINBOOL STDCALL ShowWindow( HWND hwnd, INT cmd ) +{ + WND* wndPtr = WIN_FindWndPtr( hwnd ); + WINBOOL wasVisible, showFlag; + RECT newPos = {0, 0, 0, 0}; + int swp = 0; + + if (!wndPtr) return FALSE; + +// DPRINT("hwnd=%04x, cmd=%d\n", hwnd, cmd); + + wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0; + + switch(cmd) + { + case SW_HIDE: + if (!wasVisible) return FALSE; + swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | + SWP_NOACTIVATE | SWP_NOZORDER; + break; + + case SW_SHOWMINNOACTIVE: + swp |= SWP_NOACTIVATE | SWP_NOZORDER; + /* fall through */ + case SW_SHOWMINIMIZED: + swp |= SWP_SHOWWINDOW; + /* fall through */ + case SW_MINIMIZE: + swp |= SWP_FRAMECHANGED; + if( !(wndPtr->dwStyle & WS_MINIMIZE) ) + swp |= WINPOS_MinMaximize( wndPtr, SW_MINIMIZE, &newPos ); + else swp |= SWP_NOSIZE | SWP_NOMOVE; + break; + + case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */ + swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED; + if( !(wndPtr->dwStyle & WS_MAXIMIZE) ) + swp |= WINPOS_MinMaximize( wndPtr, SW_MAXIMIZE, &newPos ); + else swp |= SWP_NOSIZE | SWP_NOMOVE; + break; + + case SW_SHOWNA: + swp |= SWP_NOACTIVATE | SWP_NOZORDER; + /* fall through */ + case SW_SHOW: + swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; + break; + + case SW_SHOWNOACTIVATE: + swp |= SWP_NOZORDER; + if (GetActiveWindow()) swp |= SWP_NOACTIVATE; + /* fall through */ + case SW_SHOWNORMAL: /* same as SW_NORMAL: */ + case SW_SHOWDEFAULT: /* FIXME: should have its own handler */ + case SW_RESTORE: + swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED; + + if( wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE) ) + swp |= WINPOS_MinMaximize( wndPtr, SW_RESTORE, &newPos ); + else swp |= SWP_NOSIZE | SWP_NOMOVE; + break; + } + + showFlag = (cmd != SW_HIDE); + if (showFlag != wasVisible) + { + SendMessageW( hwnd, WM_SHOWWINDOW, showFlag, 0 ); + if (!IsWindow( hwnd )) return wasVisible; + } + + if ((wndPtr->dwStyle & WS_CHILD) && + !IsWindowVisible( wndPtr->parent->hwndSelf ) && + (swp & (SWP_NOSIZE | SWP_NOMOVE)) == (SWP_NOSIZE | SWP_NOMOVE) ) + { + /* Don't call SetWindowPos() on invisible child windows */ + if (cmd == SW_HIDE) wndPtr->dwStyle &= ~WS_VISIBLE; + else wndPtr->dwStyle |= WS_VISIBLE; + } + else + { + /* We can't activate a child window */ + if (wndPtr->dwStyle & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER; + SetWindowPos( hwnd, HWND_TOP, + newPos.left, newPos.top, newPos.right, newPos.bottom, swp ); + if (!IsWindow( hwnd )) return wasVisible; + else if( wndPtr->dwStyle & WS_MINIMIZE ) WINPOS_ShowIconTitle( wndPtr, TRUE ); + } + + if (wndPtr->flags & WIN_NEED_SIZE) + { + /* should happen only in CreateWindowEx() */ + int wParam = SIZE_RESTORED; + + wndPtr->flags &= ~WIN_NEED_SIZE; + if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED; + else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED; + SendMessageW( hwnd, WM_SIZE, wParam, + MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left, + wndPtr->rectClient.bottom-wndPtr->rectClient.top)); + SendMessageW( hwnd, WM_MOVE, 0, + MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) ); + } + + return wasVisible; +} + diff --git a/reactos/lib/user32/windows/winpos.c b/reactos/lib/user32/windows/winpos.c new file mode 100644 index 00000000000..c1a28cd4f12 --- /dev/null +++ b/reactos/lib/user32/windows/winpos.c @@ -0,0 +1,1138 @@ +/* + * Window position related functions. + * + * Copyright 1993, 1994, 1995 Alexandre Julliard + * 1995, 1996 Alex Korobka + */ +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +#include + +HWND ICONTITLE_Create( WND *pWnd ); +HWND GetSysModalWindow(void); + + +/* ----- internal variables ----- */ + +static HWND hwndActive = 0; /* Currently active window */ +static HWND hwndPrevActive = 0; /* Previously active window */ +//static HWND hGlobalShellWindow=0; /*the shell*/ + +static LPCSTR atomInternalPos; + +extern MESSAGEQUEUE* pActiveQueue; + + +void STDCALL SwitchToThisWindow( HWND hwnd, WINBOOL restore ) +{ + ShowWindow( hwnd, restore ? SW_RESTORE : SW_SHOWMINIMIZED ); +} + + +WINBOOL STDCALL ClientToScreen( HWND hwnd, LPPOINT lppnt ) +{ + return MapWindowPoints( hwnd, 0, lppnt, 1 ); + +} + + +WINBOOL STDCALL ScreenToClient( HWND hwnd, LPPOINT lppnt ) +{ + return MapWindowPoints( 0, hwnd, lppnt, 1 ); +} + + +HWND STDCALL WindowFromPoint( POINT pt ) +{ + WND *pWnd; + + WINPOS_WindowFromPoint( WIN_GetDesktop(), pt, &pWnd ); + return (HWND)pWnd->hwndSelf; +} + + + +HWND STDCALL ChildWindowFromPoint( HWND hwndParent, POINT pt ) +{ + /* pt is in the client coordinates */ + + WND* wnd = WIN_FindWndPtr(hwndParent); + RECT rect; + + if( !wnd ) return 0; + + /* get client rect fast */ + rect.top = rect.left = 0; + rect.right = wnd->rectClient.right - wnd->rectClient.left; + rect.bottom = wnd->rectClient.bottom - wnd->rectClient.top; + + if (!PtInRect( &rect, pt )) return 0; + + wnd = wnd->child; + while ( wnd ) + { + if (PtInRect( &wnd->rectWindow, pt )) return wnd->hwndSelf; + wnd = wnd->next; + } + return hwndParent; +} + + + + +HWND STDCALL ChildWindowFromPointEx( HWND hwndParent, POINT pt, + UINT uFlags) +{ + /* pt is in the client coordinates */ + + WND* wnd = WIN_FindWndPtr(hwndParent); + RECT rect; + + if( !wnd ) return 0; + + /* get client rect fast */ + rect.top = rect.left = 0; + rect.right = wnd->rectClient.right - wnd->rectClient.left; + rect.bottom = wnd->rectClient.bottom - wnd->rectClient.top; + + if (!PtInRect( &rect, pt )) return 0; + + wnd = wnd->child; + while ( wnd ) + { + if (PtInRect( &wnd->rectWindow, pt )) { + if ( (uFlags & CWP_SKIPINVISIBLE) && + !(wnd->dwStyle & WS_VISIBLE) ) + wnd = wnd->next; + else if ( (uFlags & CWP_SKIPDISABLED) && + (wnd->dwStyle & WS_DISABLED) ) + wnd = wnd->next; + else if ( (uFlags & CWP_SKIPTRANSPARENT) && + (wnd->dwExStyle & WS_EX_TRANSPARENT) ) + wnd = wnd->next; + else + return wnd->hwndSelf; + } + } + return hwndParent; +} + + +WINBOOL STDCALL MapWindowPoints( HWND hwndFrom, HWND hwndTo, + LPPOINT lppt, UINT count ) +{ + POINT offset; + + WINPOS_GetWinOffset( hwndFrom, hwndTo, &offset ); + while (count--) + { + lppt->x += offset.x; + lppt->y += offset.y; + lppt++; + } + return TRUE; +} + + +WINBOOL STDCALL IsIconic(HWND hWnd) +{ + WND * wndPtr = WIN_FindWndPtr(hWnd); + if (wndPtr == NULL) return FALSE; + return (wndPtr->dwStyle & WS_MINIMIZE) != 0; +} + + +WINBOOL STDCALL IsZoomed(HWND hWnd) +{ + WND * wndPtr = WIN_FindWndPtr(hWnd); + if (wndPtr == NULL) return FALSE; + return (wndPtr->dwStyle & WS_MAXIMIZE) != 0; +} + + +HWND STDCALL GetActiveWindow(void) +{ + return hwndActive; +} + +HWND SetActiveWindow(HWND hWnd ) +{ + HWND hPrev; + hPrev = GetActiveWindow(); + if ( WINPOS_SetActiveWindow( hWnd, TRUE, TRUE) ) + return hPrev; + return NULL; +} + + +WINBOOL +STDCALL +SetWindowPos(HWND hWnd, HWND hWndInsertAfter , + int X, int Y, + int cx, int cy, UINT flags) +{ + return FALSE; +} + + + +/*********************************************************************** + * WINPOS_CreateInternalPosAtom + */ +WINBOOL WINPOS_CreateInternalPosAtom() +{ + LPSTR str = "SysIP"; + atomInternalPos = (LPCSTR)(DWORD)GlobalAddAtomA(str); + return (atomInternalPos) ? TRUE : FALSE; +} + +/*********************************************************************** + * WINPOS_CheckInternalPos + * + * Called when a window is destroyed. + */ +void WINPOS_CheckInternalPos( HWND hwnd ) +{ + LPINTERNALPOS lpPos = (LPINTERNALPOS) GetPropA( hwnd, atomInternalPos ); + + if( hwnd == hwndPrevActive ) hwndPrevActive = 0; + if( hwnd == hwndActive ) + { + hwndActive = 0; + //WARN(win, "\tattempt to activate destroyed window!\n"); + } + + if( lpPos ) + { + if( IsWindow(lpPos->hwndIconTitle) ) + DestroyWindow( lpPos->hwndIconTitle ); + HeapFree( GetProcessHeap(), 0, lpPos ); + } +} + +/*********************************************************************** + * WINPOS_FindIconPos + * + * Find a suitable place for an iconic window. + */ +static POINT WINPOS_FindIconPos( WND* wndPtr, POINT pt ) +{ + RECT rectParent; + short x, y, xspacing, yspacing; + + GetClientRect( wndPtr->parent->hwndSelf, &rectParent ); + if ((pt.x >= rectParent.left) && (pt.x + SYSMETRICS_CXICON < rectParent.right) && + (pt.y >= rectParent.top) && (pt.y + SYSMETRICS_CYICON < rectParent.bottom)) + return pt; /* The icon already has a suitable position */ + + xspacing = SYSMETRICS_CXICONSPACING; + yspacing = SYSMETRICS_CYICONSPACING; + + y = rectParent.bottom; + for (;;) + { + for (x = rectParent.left; x <= rectParent.right-xspacing; x += xspacing) + { + /* Check if another icon already occupies this spot */ + WND *childPtr = wndPtr->parent->child; + while (childPtr) + { + if ((childPtr->dwStyle & WS_MINIMIZE) && (childPtr != wndPtr)) + { + if ((childPtr->rectWindow.left < x + xspacing) && + (childPtr->rectWindow.right >= x) && + (childPtr->rectWindow.top <= y) && + (childPtr->rectWindow.bottom > y - yspacing)) + break; /* There's a window in there */ + } + childPtr = childPtr->next; + } + if (!childPtr) /* No window was found, so it's OK for us */ + { + pt.x = x + (xspacing - SYSMETRICS_CXICON) / 2; + pt.y = y - (yspacing + SYSMETRICS_CYICON) / 2; + return pt; + } + } + y -= yspacing; + } +} + +/*********************************************************************** + * WINPOS_WindowFromPoint + * + * Find the window and hittest for a given point. + */ +INT WINPOS_WindowFromPoint( WND* wndScope, POINT pt, WND **ppWnd ) +{ + WND *wndPtr; + INT hittest = HTERROR; + POINT xy = pt; + + *ppWnd = NULL; + wndPtr = wndScope->child; + if( wndScope->flags & WIN_MANAGED ) + { + /* this prevents mouse clicks from going "through" scrollbars in managed mode */ + if( pt.x < wndScope->rectClient.left || pt.x >= wndScope->rectClient.right || + pt.y < wndScope->rectClient.top || pt.y >= wndScope->rectClient.bottom ) + goto hittest; + } + MapWindowPoints( GetDesktopWindow(), wndScope->hwndSelf, &xy, 1 ); + + for (;;) + { + while (wndPtr) + { + /* If point is in window, and window is visible, and it */ + /* is enabled (or it's a top-level window), then explore */ + /* its children. Otherwise, go to the next window. */ + + if ((wndPtr->dwStyle & WS_VISIBLE) && + (!(wndPtr->dwStyle & WS_DISABLED) || + ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)) && + (xy.x >= wndPtr->rectWindow.left) && + (xy.x < wndPtr->rectWindow.right) && + (xy.y >= wndPtr->rectWindow.top) && + (xy.y < wndPtr->rectWindow.bottom)) + { + *ppWnd = wndPtr; /* Got a suitable window */ + + /* If window is minimized or disabled, return at once */ + if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION; + if (wndPtr->dwStyle & WS_DISABLED) return HTERROR; + + /* If point is not in client area, ignore the children */ + if ((xy.x < wndPtr->rectClient.left) || + (xy.x >= wndPtr->rectClient.right) || + (xy.y < wndPtr->rectClient.top) || + (xy.y >= wndPtr->rectClient.bottom)) break; + + xy.x -= wndPtr->rectClient.left; + xy.y -= wndPtr->rectClient.top; + wndPtr = wndPtr->child; + } + else wndPtr = wndPtr->next; + } + +hittest: + /* If nothing found, try the scope window */ + if (!*ppWnd) *ppWnd = wndScope; + + /* Send the WM_NCHITTEST message (only if to the same task) */ + if ((*ppWnd)->hmemTaskQ == GetFastQueue()) + { + hittest = (INT)SendMessageA( (*ppWnd)->hwndSelf, WM_NCHITTEST, + 0, MAKELONG( pt.x, pt.y ) ); + if (hittest != HTTRANSPARENT) return hittest; /* Found the window */ + } + else return HTCLIENT; + + /* If no children found in last search, make point relative to parent */ + if (!wndPtr) + { + xy.x += (*ppWnd)->rectClient.left; + xy.y += (*ppWnd)->rectClient.top; + } + + /* Restart the search from the next sibling */ + wndPtr = (*ppWnd)->next; + *ppWnd = (*ppWnd)->parent; + } +} + +/******************************************************************* + * WINPOS_GetWinOffset + * + * Calculate the offset between the origin of the two windows. Used + * to implement MapWindowPoints. + */ +void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, + POINT *offset ) +{ + WND * wndPtr; + + offset->x = offset->y = 0; + if (hwndFrom == hwndTo ) return; + + /* Translate source window origin to screen coords */ + if (hwndFrom) + { + if (!(wndPtr = WIN_FindWndPtr( hwndFrom ))) + { + //ERR(win,"bad hwndFrom = %04x\n",hwndFrom); + return; + } + while (wndPtr->parent) + { + offset->x += wndPtr->rectClient.left; + offset->y += wndPtr->rectClient.top; + wndPtr = wndPtr->parent; + } + } + + /* Translate origin to destination window coords */ + if (hwndTo) + { + if (!(wndPtr = WIN_FindWndPtr( hwndTo ))) + { + //ERR(win,"bad hwndTo = %04x\n", hwndTo ); + return; + } + while (wndPtr->parent) + { + offset->x -= wndPtr->rectClient.left; + offset->y -= wndPtr->rectClient.top; + wndPtr = wndPtr->parent; + } + } +} + +/******************************************************************* + * WINPOS_CanActivate + */ +WINBOOL WINPOS_CanActivate(WND* pWnd) +{ + if( pWnd && ((pWnd->dwStyle & (WS_DISABLED | WS_VISIBLE | WS_CHILD)) + == WS_VISIBLE) ) return TRUE; + return FALSE; +} + +/*********************************************************************** + * WINPOS_InitInternalPos + */ +LPINTERNALPOS WINPOS_InitInternalPos( WND* wnd, POINT pt, + LPRECT restoreRect ) +{ + LPINTERNALPOS lpPos = (LPINTERNALPOS) GetPropA( wnd->hwndSelf, + atomInternalPos ); + if( !lpPos ) + { + /* this happens when the window is minimized/maximized + * for the first time (rectWindow is not adjusted yet) */ + + lpPos = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNALPOS) ); + if( !lpPos ) return NULL; + + SetPropA( wnd->hwndSelf, atomInternalPos, (HANDLE)lpPos ); + lpPos->hwndIconTitle = 0; /* defer until needs to be shown */ + memcpy( &lpPos->rectNormal, &wnd->rectWindow ,sizeof(RECT)); + *(UINT*)&lpPos->ptIconPos = *(UINT*)&lpPos->ptMaxPos = 0xFFFFFFFF; + } + + if( wnd->dwStyle & WS_MINIMIZE ) + memcpy( &lpPos->ptIconPos, &pt,sizeof(POINT) ); + else if( wnd->dwStyle & WS_MAXIMIZE ) + memcpy( &lpPos->ptMaxPos, &pt,sizeof(POINT) ); + else if( restoreRect ) + memcpy( &lpPos->rectNormal, restoreRect, sizeof(RECT) ); + + return lpPos; +} + +/*********************************************************************** + * WINPOS_RedrawIconTitle + */ +WINBOOL WINPOS_RedrawIconTitle( HWND hWnd ) +{ + LPINTERNALPOS lpPos = (LPINTERNALPOS)GetPropA( hWnd, atomInternalPos ); + if( lpPos ) + { + if( lpPos->hwndIconTitle ) + { + SendMessageA( lpPos->hwndIconTitle, WM_SHOWWINDOW, TRUE, 0); + InvalidateRect( lpPos->hwndIconTitle, NULL, TRUE ); + return TRUE; + } + } + return FALSE; +} + +/*********************************************************************** + * WINPOS_ShowIconTitle + */ +WINBOOL WINPOS_ShowIconTitle( WND* pWnd, WINBOOL bShow ) +{ + LPINTERNALPOS lpPos = (LPINTERNALPOS)GetPropA( pWnd->hwndSelf, atomInternalPos ); + + if( lpPos && !(pWnd->flags & WIN_MANAGED)) + { + HWND hWnd = lpPos->hwndIconTitle; + + //TRACE(win,"0x%04x %i\n", pWnd->hwndSelf, (bShow != 0) ); + +// if( !hWnd ) +// lpPos->hwndIconTitle = hWnd = ICONTITLE_Create( pWnd ); + if( bShow ) + { + pWnd = WIN_FindWndPtr(hWnd); + + if( !(pWnd->dwStyle & WS_VISIBLE) ) + { + SendMessageA( hWnd, WM_SHOWWINDOW, TRUE, 0 ); + SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | + SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW ); + } + } + else ShowWindow( hWnd, SW_HIDE ); + } + return FALSE; +} + +/******************************************************************* + * WINPOS_GetMinMaxInfo + * + * Get the minimized and maximized information for a window. + */ +void WINPOS_GetMinMaxInfo( WND *wndPtr, POINT *maxSize, POINT *maxPos, + POINT *minTrack, POINT *maxTrack ) +{ + LPINTERNALPOS lpPos; + MINMAXINFO MinMax; + INT xinc, yinc; + + /* Compute default values */ + + MinMax.ptMaxSize.x = SYSMETRICS_CXSCREEN; + MinMax.ptMaxSize.y = SYSMETRICS_CYSCREEN; + MinMax.ptMinTrackSize.x = SYSMETRICS_CXMINTRACK; + MinMax.ptMinTrackSize.y = SYSMETRICS_CYMINTRACK; + MinMax.ptMaxTrackSize.x = SYSMETRICS_CXSCREEN; + MinMax.ptMaxTrackSize.y = SYSMETRICS_CYSCREEN; + + if (wndPtr->flags & WIN_MANAGED) xinc = yinc = 0; + else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle )) + { + xinc = SYSMETRICS_CXDLGFRAME; + yinc = SYSMETRICS_CYDLGFRAME; + } + else + { + xinc = yinc = 0; + if (HAS_THICKFRAME(wndPtr->dwStyle)) + { + xinc += SYSMETRICS_CXFRAME; + yinc += SYSMETRICS_CYFRAME; + } + if (wndPtr->dwStyle & WS_BORDER) + { + xinc += SYSMETRICS_CXBORDER; + yinc += SYSMETRICS_CYBORDER; + } + } + MinMax.ptMaxSize.x += 2 * xinc; + MinMax.ptMaxSize.y += 2 * yinc; + + lpPos = (LPINTERNALPOS)GetPropA( wndPtr->hwndSelf, atomInternalPos ); + if( lpPos && !EMPTYPOINT(lpPos->ptMaxPos) ) + memcpy( &MinMax.ptMaxPosition, &lpPos->ptMaxPos,sizeof(POINT) ); + else + { + MinMax.ptMaxPosition.x = -xinc; + MinMax.ptMaxPosition.y = -yinc; + } + + SendMessageA( wndPtr->hwndSelf, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax ); + + /* Some sanity checks */ + + + MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x, + MinMax.ptMinTrackSize.x ); + MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y, + MinMax.ptMinTrackSize.y ); + + if (maxSize) *maxSize = MinMax.ptMaxSize; + if (maxPos) *maxPos = MinMax.ptMaxPosition; + if (minTrack) *minTrack = MinMax.ptMinTrackSize; + if (maxTrack) *maxTrack = MinMax.ptMaxTrackSize; +} + +/*********************************************************************** + * WINPOS_MinMaximize + * + * Fill in lpRect and return additional flags to be used with SetWindowPos(). + * This function assumes that 'cmd' is different from the current window + * state. + */ +UINT WINPOS_MinMaximize( WND* wndPtr, UINT cmd, LPRECT lpRect ) +{ + UINT swpFlags = 0; + POINT size = { wndPtr->rectWindow.left, wndPtr->rectWindow.top }; + LPINTERNALPOS lpPos = WINPOS_InitInternalPos( wndPtr, size, + &wndPtr->rectWindow ); + + + //TRACE(win,"0x%04x %u\n", wndPtr->hwndSelf, cmd ); + + if ( wndPtr->class->bUnicode ) { + if (HOOK_CallHooksW(WH_CBT, HCBT_MINMAX, (INT)wndPtr->hwndSelf, cmd)) { + swpFlags |= SWP_NOSIZE | SWP_NOMOVE; + return swpFlags; + } + } + else { + if (HOOK_CallHooksA(WH_CBT, HCBT_MINMAX, (INT)wndPtr->hwndSelf, cmd)) { + swpFlags |= SWP_NOSIZE | SWP_NOMOVE; + return swpFlags; + } + } + + + if (lpPos) + { + if( wndPtr->dwStyle & WS_MINIMIZE ) + { + if( !SendMessageA( wndPtr->hwndSelf, WM_QUERYOPEN, 0, 0L ) ) + return (SWP_NOSIZE | SWP_NOMOVE); + swpFlags |= SWP_NOCOPYBITS; + } + switch( cmd ) + { + case SW_MINIMIZE: + if( wndPtr->dwStyle & WS_MAXIMIZE) + { + wndPtr->flags |= WIN_RESTORE_MAX; + wndPtr->dwStyle &= ~WS_MAXIMIZE; + } + else + wndPtr->flags &= ~WIN_RESTORE_MAX; + wndPtr->dwStyle |= WS_MINIMIZE; + + lpPos->ptIconPos = WINPOS_FindIconPos( wndPtr, lpPos->ptIconPos ); + + SetRect( lpRect, lpPos->ptIconPos.x, lpPos->ptIconPos.y, + SYSMETRICS_CXICON, SYSMETRICS_CYICON ); + swpFlags |= SWP_NOCOPYBITS; + break; + + case SW_MAXIMIZE: + + WINPOS_GetMinMaxInfo( wndPtr, &size, &lpPos->ptMaxPos, NULL, NULL ); + + if( wndPtr->dwStyle & WS_MINIMIZE ) + { + WINPOS_ShowIconTitle( wndPtr, FALSE ); + wndPtr->dwStyle &= ~WS_MINIMIZE; + } + wndPtr->dwStyle |= WS_MAXIMIZE; + + SetRect( lpRect, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y, + size.x, size.y ); + break; + + case SW_RESTORE: + if( wndPtr->dwStyle & WS_MINIMIZE ) + { + wndPtr->dwStyle &= ~WS_MINIMIZE; + WINPOS_ShowIconTitle( wndPtr, FALSE ); + if( wndPtr->flags & WIN_RESTORE_MAX) + { + /* Restore to maximized position */ + WINPOS_GetMinMaxInfo( wndPtr, &size,&lpPos->ptMaxPos, NULL, NULL); + wndPtr->dwStyle |= WS_MAXIMIZE; + SetRect( lpRect, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y, size.x, size.y ); + break; + } + } + else + if( !(wndPtr->dwStyle & WS_MAXIMIZE) ) return (UINT)(-1); + else wndPtr->dwStyle &= ~WS_MAXIMIZE; + + /* Restore to normal position */ + + *lpRect = lpPos->rectNormal; + lpRect->right -= lpRect->left; + lpRect->bottom -= lpRect->top; + + break; + } + } else swpFlags |= SWP_NOSIZE | SWP_NOMOVE; + return swpFlags; +} + +/*********************************************************************** + * WINPOS_SetPlacement + */ +WINBOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, + UINT flags ) +{ + WND *pWnd = WIN_FindWndPtr( hwnd ); + if( pWnd ) + { + LPINTERNALPOS lpPos = (LPINTERNALPOS)WINPOS_InitInternalPos( pWnd, + *(LPPOINT)&pWnd->rectWindow.left, &pWnd->rectWindow ); + + if( flags & PLACE_MIN ) lpPos->ptIconPos = wndpl->ptMinPosition; + if( flags & PLACE_MAX ) lpPos->ptMaxPos = wndpl->ptMaxPosition; + if( flags & PLACE_RECT) lpPos->rectNormal = wndpl->rcNormalPosition; + + if( pWnd->dwStyle & WS_MINIMIZE ) + { + WINPOS_ShowIconTitle( pWnd, FALSE ); + if( wndpl->flags & WPF_SETMINPOSITION && !EMPTYPOINT(lpPos->ptIconPos)) + SetWindowPos( hwnd, 0, lpPos->ptIconPos.x, lpPos->ptIconPos.y, + 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); + } + else if( pWnd->dwStyle & WS_MAXIMIZE ) + { + if( !EMPTYPOINT(lpPos->ptMaxPos) ) + SetWindowPos( hwnd, 0, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y, + 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); + } + else if( flags & PLACE_RECT ) + SetWindowPos( hwnd, 0, lpPos->rectNormal.left, lpPos->rectNormal.top, + lpPos->rectNormal.right - lpPos->rectNormal.left, + lpPos->rectNormal.bottom - lpPos->rectNormal.top, + SWP_NOZORDER | SWP_NOACTIVATE ); + + ShowWindow( hwnd, wndpl->showCmd ); + if( IsWindow(hwnd) && pWnd->dwStyle & WS_MINIMIZE ) + { + if( pWnd->dwStyle & WS_VISIBLE ) WINPOS_ShowIconTitle( pWnd, TRUE ); + + /* SDK: ...valid only the next time... */ + if( wndpl->flags & WPF_RESTORETOMAXIMIZED ) pWnd->flags |= WIN_RESTORE_MAX; + } + return TRUE; + } + return FALSE; +} + +/******************************************************************* + * WINPOS_SetActiveWindow + * + * SetActiveWindow() back-end. This is the only function that + * can assign active status to a window. It must be called only + * for the top level windows. + */ +WINBOOL WINPOS_SetActiveWindow( HWND hWnd, WINBOOL fMouse, WINBOOL fChangeFocus) +{ + return FALSE; +} + +/******************************************************************* + * WINPOS_ActivateOtherWindow + * + * Activates window other than pWnd. + */ +WINBOOL WINPOS_ActivateOtherWindow(WND* pWnd) +{ + WINBOOL bRet = 0; + WND* pWndTo = NULL; + + if( pWnd->hwndSelf == hwndPrevActive ) + hwndPrevActive = 0; + + if( hwndActive != pWnd->hwndSelf && + ( hwndActive || QUEUE_IsExitingQueue(pWnd->hmemTaskQ)) ) + return 0; + + if( !(pWnd->dwStyle & WS_POPUP) || !(pWnd->owner) || + !WINPOS_CanActivate((pWndTo = WIN_GetTopParentPtr(pWnd->owner))) ) + { + WND* pWndPtr = WIN_GetTopParentPtr(pWnd); + + pWndTo = WIN_FindWndPtr(hwndPrevActive); + + while( !WINPOS_CanActivate(pWndTo) ) + { + /* by now owned windows should've been taken care of */ + + pWndTo = pWndPtr->next; + pWndPtr = pWndTo; + if( !pWndTo ) break; + } + } + + bRet = WINPOS_SetActiveWindow( pWndTo ? pWndTo->hwndSelf : NULL, FALSE, TRUE ); + + /* switch desktop queue to current active */ + if( pWndTo ) WIN_GetDesktop()->hmemTaskQ = pWndTo->hmemTaskQ; + + hwndPrevActive = 0; + return bRet; +} + +/******************************************************************* + * WINPOS_ChangeActiveWindow + * + */ +WINBOOL WINPOS_ChangeActiveWindow( HWND hWnd, WINBOOL mouseMsg ) +{ + WND *wndPtr = WIN_FindWndPtr(hWnd); + + if (!hWnd) return WINPOS_SetActiveWindow( 0, mouseMsg, TRUE ); + + if( !wndPtr ) return FALSE; + + /* child windows get WM_CHILDACTIVATE message */ + if( (wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD ) + return SendMessageA(hWnd, WM_CHILDACTIVATE, 0, 0L); + + /* owned popups imply owner activation - not sure */ + if ((wndPtr->dwStyle & WS_POPUP) && wndPtr->owner && + (wndPtr->owner->dwStyle & WS_VISIBLE ) && + !(wndPtr->owner->dwStyle & WS_DISABLED )) + { + if (!(wndPtr = wndPtr->owner)) return FALSE; + hWnd = wndPtr->hwndSelf; + } + + if( hWnd == hwndActive ) return FALSE; + + if( !WINPOS_SetActiveWindow(hWnd ,mouseMsg ,TRUE) ) + return FALSE; + + /* switch desktop queue to current active */ + if( wndPtr->parent == WIN_GetDesktop()) + WIN_GetDesktop()->hmemTaskQ = wndPtr->hmemTaskQ; + + return TRUE; +} + + +/*********************************************************************** + * WINPOS_SendNCCalcSize + * + * Send a WM_NCCALCSIZE message to a window. + * All parameters are read-only except newClientRect. + * oldWindowRect, oldClientRect and winpos must be non-NULL only + * when calcValidRect is TRUE. + */ +LONG WINPOS_SendNCCalcSize( HWND hwnd, WINBOOL calcValidRect, + RECT *newWindowRect, RECT *oldWindowRect, + RECT *oldClientRect, WINDOWPOS *winpos, + RECT *newClientRect ) +{ + NCCALCSIZE_PARAMS params; + WINDOWPOS winposCopy; + LONG result; + + params.rgrc[0] = *newWindowRect; + if (calcValidRect) + { + winposCopy = *winpos; + params.rgrc[1] = *oldWindowRect; + params.rgrc[2] = *oldClientRect; + params.lppos = &winposCopy; + } + result = SendMessageA( hwnd, WM_NCCALCSIZE, calcValidRect, + (LPARAM)¶ms ); + + *newClientRect = params.rgrc[0]; + return result; +} + + +/*********************************************************************** + * WINPOS_HandleWindowPosChanging + * + * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc(). + */ +LONG WINPOS_HandleWindowPosChangingA( WND *wndPtr, WINDOWPOS *winpos ) +{ + POINT maxSize, minTrack; + if (winpos->flags & SWP_NOSIZE) return 0; + if ((wndPtr->dwStyle & WS_THICKFRAME) || + ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) == 0)) + { + WINPOS_GetMinMaxInfo( wndPtr, &maxSize, NULL, &minTrack, NULL ); + if (maxSize.x < winpos->cx) winpos->cx = maxSize.x; + if (maxSize.y < winpos->cy) winpos->cy = maxSize.y; + if (!(wndPtr->dwStyle & WS_MINIMIZE)) + { + if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x; + if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y; + } + } + return 0; +} + + +/*********************************************************************** + * WINPOS_HandleWindowPosChanging + * + * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc(). + */ +LONG WINPOS_HandleWindowPosChanging( WND *wndPtr, WINDOWPOS *winpos ) +{ + POINT maxSize; + if (winpos->flags & SWP_NOSIZE) return 0; + if ((wndPtr->dwStyle & WS_THICKFRAME) || + ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) == 0)) + { + WINPOS_GetMinMaxInfo( wndPtr, &maxSize, NULL, NULL, NULL ); + winpos->cx = min( winpos->cx, maxSize.x ); + winpos->cy = min( winpos->cy, maxSize.y ); + } + return 0; +} + + +/*********************************************************************** + * WINPOS_MoveWindowZOrder + * + * Move a window in Z order, invalidating everything that needs it. + * Only necessary for windows without associated X window. + */ +void WINPOS_MoveWindowZOrder( HWND hwnd, HWND hwndAfter ) +{ + WINBOOL movingUp; + WND *pWndAfter, *pWndCur, *wndPtr = WIN_FindWndPtr( hwnd ); + + /* We have two possible cases: + * - The window is moving up: we have to invalidate all areas + * of the window that were covered by other windows + * - The window is moving down: we have to invalidate areas + * of other windows covered by this one. + */ + + if (hwndAfter == HWND_TOP) + { + movingUp = TRUE; + } + else if (hwndAfter == HWND_BOTTOM) + { + if (!wndPtr->next) return; /* Already at the bottom */ + movingUp = FALSE; + } + else + { + if (!(pWndAfter = WIN_FindWndPtr( hwndAfter ))) return; + if (wndPtr->next == pWndAfter) return; /* Already placed right */ + + /* Determine which window we encounter first in Z-order */ + pWndCur = wndPtr->parent->child; + while ((pWndCur != wndPtr) && (pWndCur != pWndAfter)) + pWndCur = pWndCur->next; + movingUp = (pWndCur == pWndAfter); + } + + if (movingUp) + { + WND *pWndPrevAfter = wndPtr->next; + WIN_UnlinkWindow( hwnd ); + WIN_LinkWindow( hwnd, hwndAfter ); + pWndCur = wndPtr->next; + while (pWndCur != pWndPrevAfter) + { + RECT rect = { pWndCur->rectWindow.left, + pWndCur->rectWindow.top, + pWndCur->rectWindow.right, + pWndCur->rectWindow.bottom }; + OffsetRect( &rect, -wndPtr->rectClient.left, + -wndPtr->rectClient.top ); + PAINT_RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN | + RDW_FRAME | RDW_ERASE, 0 ); + pWndCur = pWndCur->next; + } + } + else /* Moving down */ + { + pWndCur = wndPtr->next; + WIN_UnlinkWindow( hwnd ); + WIN_LinkWindow( hwnd, hwndAfter ); + while (pWndCur != wndPtr) + { + RECT rect = { pWndCur->rectWindow.left, + pWndCur->rectWindow.top, + pWndCur->rectWindow.right, + pWndCur->rectWindow.bottom }; + OffsetRect( &rect, -pWndCur->rectClient.left, + -pWndCur->rectClient.top ); + PAINT_RedrawWindow( pWndCur->hwndSelf, &rect, 0, RDW_INVALIDATE | + RDW_ALLCHILDREN | RDW_FRAME | RDW_ERASE, 0 ); + pWndCur = pWndCur->next; + } + } +} + +/*********************************************************************** + * WINPOS_ReorderOwnedPopups + * + * fix Z order taking into account owned popups - + * basically we need to maintain them above the window that owns them + */ +HWND WINPOS_ReorderOwnedPopups(HWND hwndInsertAfter,WND* wndPtr,WORD flags) +{ + WND* w = WIN_GetDesktop()->child; + + if( wndPtr->dwStyle & WS_POPUP && wndPtr->owner ) + { + /* implement "local z-order" between the top and owner window */ + + HWND hwndLocalPrev = HWND_TOP; + + if( hwndInsertAfter != HWND_TOP ) + { + while( w != wndPtr->owner ) + { + if (w != wndPtr) hwndLocalPrev = w->hwndSelf; + if( hwndLocalPrev == hwndInsertAfter ) break; + w = w->next; + } + hwndInsertAfter = hwndLocalPrev; + } + + } + else if( wndPtr->dwStyle & WS_CHILD ) return hwndInsertAfter; + + w = WIN_GetDesktop()->child; + while( w ) + { + if( w == wndPtr ) break; + + if( w->dwStyle & WS_POPUP && w->owner == wndPtr ) + { + SetWindowPos(w->hwndSelf, hwndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | + SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE); + hwndInsertAfter = w->hwndSelf; + } + w = w->next; + } + + return hwndInsertAfter; +} + +/*********************************************************************** + * WINPOS_SizeMoveClean + * + * Make window look nice without excessive repainting + * + * the pain: + * + * visible regions are in window coordinates + * update regions are in window client coordinates + * client and window rectangles are in parent client coordinates + * + * FIXME: Move visible and update regions to the same coordinate system + * (either parent client or window). This is a lot of work though. + */ +UINT WINPOS_SizeMoveClean( WND* Wnd, HRGN oldVisRgn, + LPRECT lpOldWndRect, + LPRECT lpOldClientRect, UINT uFlags ) +{ + HRGN newVisRgn = DCE_GetVisRgn(Wnd->hwndSelf,DCX_WINDOW | DCX_CLIPSIBLINGS); + HRGN dirtyRgn = CreateRectRgn(0,0,0,0); + int other, my; + + + + if( (lpOldWndRect->right - lpOldWndRect->left) != (Wnd->rectWindow.right - Wnd->rectWindow.left) || + (lpOldWndRect->bottom - lpOldWndRect->top) != (Wnd->rectWindow.bottom - Wnd->rectWindow.top) ) + uFlags |= SMC_DRAWFRAME; + + CombineRgn( dirtyRgn, newVisRgn, 0, RGN_COPY); + + if( !(uFlags & SMC_NOCOPY) ) + CombineRgn( newVisRgn, newVisRgn, oldVisRgn, RGN_AND ); + + /* map regions to the parent client area */ + + OffsetRgn( dirtyRgn, Wnd->rectWindow.left, Wnd->rectWindow.top ); + OffsetRgn( oldVisRgn, lpOldWndRect->left, lpOldWndRect->top ); + + /* compute invalidated region outside Wnd - (in client coordinates of the parent window) */ + + other = CombineRgn(dirtyRgn, oldVisRgn, dirtyRgn, RGN_DIFF); + + /* map visible region to the Wnd client area */ + + OffsetRgn( newVisRgn, Wnd->rectWindow.left - Wnd->rectClient.left, + Wnd->rectWindow.top - Wnd->rectClient.top ); + + /* substract previously invalidated region from the Wnd visible region */ + + my = (Wnd->hrgnUpdate > 1) ? CombineRgn( newVisRgn, newVisRgn, + Wnd->hrgnUpdate, RGN_DIFF) + : COMPLEXREGION; + + if( uFlags & SMC_NOCOPY ) /* invalidate Wnd visible region */ + { + if (my != NULLREGION) + PAINT_RedrawWindow( Wnd->hwndSelf, NULL, newVisRgn, RDW_INVALIDATE | + RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE, RDW_C_USEHRGN ); + else if(uFlags & SMC_DRAWFRAME) + Wnd->flags |= WIN_NEEDS_NCPAINT; + } + else /* bitblt old client area */ + { + HDC hDC; + int update; + HRGN updateRgn; + int xfrom,yfrom,xto,yto,width,height; + + if( uFlags & SMC_DRAWFRAME ) + { + /* copy only client area, frame will be redrawn anyway */ + + xfrom = lpOldClientRect->left; yfrom = lpOldClientRect->top; + xto = Wnd->rectClient.left; yto = Wnd->rectClient.top; + width = lpOldClientRect->right - xfrom; height = lpOldClientRect->bottom - yfrom; + updateRgn = CreateRectRgn( 0, 0, width, height ); + CombineRgn( newVisRgn, newVisRgn, updateRgn, RGN_AND ); + SetRectRgn( updateRgn, 0, 0, Wnd->rectClient.right - xto, + Wnd->rectClient.bottom - yto ); + } + else + { + xfrom = lpOldWndRect->left; yfrom = lpOldWndRect->top; + xto = Wnd->rectWindow.left; yto = Wnd->rectWindow.top; + width = lpOldWndRect->right - xfrom; height = lpOldWndRect->bottom - yfrom; + updateRgn = CreateRectRgn( xto - Wnd->rectClient.left, + yto - Wnd->rectClient.top, + Wnd->rectWindow.right - Wnd->rectClient.left, + Wnd->rectWindow.bottom - Wnd->rectClient.top ); + } + + CombineRgn( newVisRgn, newVisRgn, updateRgn, RGN_AND ); + + /* substract new visRgn from target rect to get a region that won't be copied */ + + update = CombineRgn( updateRgn, updateRgn, newVisRgn, RGN_DIFF ); + + /* Blt valid bits using parent window DC */ + + if( my != NULLREGION && (xfrom != xto || yfrom != yto) ) + { + + /* compute clipping region in parent client coordinates */ + + OffsetRgn( newVisRgn, Wnd->rectClient.left, Wnd->rectClient.top ); + CombineRgn( oldVisRgn, oldVisRgn, newVisRgn, RGN_OR ); + +// REMOVED DCX_KEEPCLIPRGN + + hDC = GetDCEx( Wnd->parent->hwndSelf, oldVisRgn, + DCX_INTERSECTRGN | + DCX_CACHE | DCX_CLIPSIBLINGS); + + BitBlt( hDC, xto, yto, width, height, hDC, xfrom, yfrom, SRCCOPY ); + ReleaseDC( Wnd->parent->hwndSelf, hDC); + } + + if( update != NULLREGION ) + PAINT_RedrawWindow( Wnd->hwndSelf, NULL, updateRgn, RDW_INVALIDATE | + RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE, RDW_C_USEHRGN ); + else if( uFlags & SMC_DRAWFRAME ) Wnd->flags |= WIN_NEEDS_NCPAINT; + DeleteObject( updateRgn ); + } + + /* erase uncovered areas */ + + if( !(uFlags & SMC_NOPARENTERASE) && (other != NULLREGION ) ) + PAINT_RedrawWindow( Wnd->parent->hwndSelf, NULL, dirtyRgn, + RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE, RDW_C_USEHRGN ); + DeleteObject(dirtyRgn); + DeleteObject(newVisRgn); + return uFlags; +} + diff --git a/reactos/lib/user32/windows/wndproc.c b/reactos/lib/user32/windows/wndproc.c index 6245c683bee..0e5c48c6773 100644 --- a/reactos/lib/user32/windows/wndproc.c +++ b/reactos/lib/user32/windows/wndproc.c @@ -1,5 +1,10 @@ #include +#include #include +//#include + +#define MDICREATESTRUCTA MDICREATESTRUCT +#define MDICREATESTRUCTW MDICREATESTRUCT /********************************************************************** @@ -34,6 +39,29 @@ LRESULT WINAPI CallWindowProcA( LPARAM lParam ) { + INT ret; + WND *w; + LRESULT l; + w = WIN_FindWndPtr( hwnd ); + if ( w == NULL ) + return 0; + + if ( w->class->bUnicode == FALSE ) + return func(hwnd,msg,wParam,lParam); + + + //convert message + ret = WINPROC_MapMsg32WTo32A( hwnd, msg, wParam, &lParam ); + if ( ret == -1 ) + return 0; + l = func(hwnd,msg,wParam,lParam); + if ( ret == 1 ) + WINPROC_UnmapMsg32WTo32A( hwnd, msg, wParam, lParam ); + return l; + + + + } LRESULT WINAPI CallWindowProcW( @@ -44,6 +72,25 @@ LRESULT WINAPI CallWindowProcW( LPARAM lParam ) { + INT ret; + WND *w; + LRESULT l; + w = WIN_FindWndPtr( hwnd ); + if ( w == NULL ) + return 0; + + if ( w->class->bUnicode == TRUE ) + return func(hwnd,msg,wParam,lParam); + + + //convert message + ret = WINPROC_MapMsg32ATo32W( hwnd, msg, wParam, &lParam ); + if ( ret == -1 ) + return 0; + l = func(hwnd,msg,wParam,lParam); + if ( ret == 1 ) + WINPROC_UnmapMsg32ATo32W( hwnd, msg, wParam, lParam ); + return l; } /*********************************************************************** @@ -65,7 +112,7 @@ LRESULT WINAPI DefWindowProcA( WPARAM wParam, LPARAM lParam ) { - + return 0; } @@ -75,7 +122,478 @@ LRESULT WINAPI DefWindowProcW( WPARAM wParam, LPARAM lParam ) { - + return 0; +} + +/********************************************************************** + * WINPROC_TestCBForStr + * + * Return TRUE if the lparam is a string + */ +WINBOOL WINPROC_TestCBForStr ( HWND hwnd ) +{ WND * wnd = WIN_FindWndPtr(hwnd); + return ( !(LOWORD(wnd->dwStyle) & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || + (LOWORD(wnd->dwStyle) & CBS_HASSTRINGS) ); +} +/********************************************************************** + * WINPROC_TestLBForStr + * + * Return TRUE if the lparam is a string + */ +WINBOOL WINPROC_TestLBForStr ( HWND hwnd ) +{ WND * wnd = WIN_FindWndPtr(hwnd); + return ( !(LOWORD(wnd->dwStyle) & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || + (LOWORD(wnd->dwStyle) & LBS_HASSTRINGS) ); +} + + +/********************************************************************** + * WINPROC_MapMsg32ATo32W + * + * Map a message from Ansi to Unicode. + * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed. + * + * FIXME: + * WM_CHAR, WM_CHARTOITEM, WM_DEADCHAR, WM_MENUCHAR, WM_SYSCHAR, WM_SYSDEADCHAR + * + * FIXME: + * WM_GETTEXT/WM_SETTEXT and static control with SS_ICON style: + * the first four bytes are the handle of the icon + * when the WM_SETTEXT message has been used to set the icon + */ +INT WINPROC_MapMsg32ATo32W( HWND hwnd, UINT msg, WPARAM wParam, LPARAM *plparam ) +{ + switch(msg) + { + case WM_GETTEXT: + { + LPARAM *ptr = (LPARAM *)HeapAlloc( GetProcessHeap(), 0, + wParam * sizeof(WCHAR) + sizeof(LPARAM) ); + if (!ptr) + return -1; + *ptr++ = *plparam; /* Store previous lParam */ + *plparam = (LPARAM)ptr; + } + return 1; + + case WM_SETTEXT: + case CB_DIR: + case CB_FINDSTRING: + case CB_FINDSTRINGEXACT: + case CB_SELECTSTRING: + case LB_DIR: + case LB_ADDFILE: + case LB_FINDSTRING: + case LB_SELECTSTRING: + case EM_REPLACESEL: + *plparam = (LPARAM)HEAP_strdupAtoW( GetProcessHeap(), 0, (LPCSTR)*plparam ); + return (*plparam ? 1 : -1); + break; + + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTW *cs = (CREATESTRUCTW *)HeapAlloc( GetProcessHeap(), 0, + sizeof(*cs) ); + if (!cs) return -1; + *cs = *(CREATESTRUCTW *)*plparam; + if (HIWORD(cs->lpszName)) + cs->lpszName = HEAP_strdupAtoW( GetProcessHeap(), 0, + (LPCSTR)cs->lpszName ); + if (HIWORD(cs->lpszClass)) + cs->lpszClass = HEAP_strdupAtoW( GetProcessHeap(), 0, + (LPCSTR)cs->lpszClass ); + *plparam = (LPARAM)cs; + } + return 1; + case WM_MDICREATE: + { + MDICREATESTRUCTW *cs = HeapAlloc( GetProcessHeap(), 0, sizeof(MDICREATESTRUCT) ); + if (!cs) return -1; + *cs = *(MDICREATESTRUCT *)*plparam; + if (HIWORD(cs->szClass)) + cs->szClass = HEAP_strdupAtoW( GetProcessHeap(), 0, + (LPCSTR)cs->szClass ); + if (HIWORD(cs->szTitle)) + cs->szTitle = HEAP_strdupAtoW( GetProcessHeap(), 0, + (LPCSTR)cs->szTitle ); + *plparam = (LPARAM)cs; + } + return 1; + +/* Listbox */ + case LB_ADDSTRING: + case LB_INSERTSTRING: + if ( WINPROC_TestLBForStr( hwnd )) + *plparam = (LPARAM)HEAP_strdupAtoW( GetProcessHeap(), 0, (LPCSTR)*plparam ); + return (*plparam ? 1 : -1); + + case LB_GETTEXT: /* fixme: fixed sized buffer */ + { if ( WINPROC_TestLBForStr( hwnd )) + { LPARAM *ptr = (LPARAM *)HeapAlloc( GetProcessHeap(), 0, 256 * sizeof(WCHAR) + sizeof(LPARAM) ); + if (!ptr) return -1; + *ptr++ = *plparam; /* Store previous lParam */ + *plparam = (LPARAM)ptr; + } + } + return 1; + +/* Combobox */ + case CB_ADDSTRING: + case CB_INSERTSTRING: + if ( WINPROC_TestCBForStr( hwnd )) + *plparam = (LPARAM)HEAP_strdupAtoW( GetProcessHeap(), 0, (LPCSTR)*plparam ); + return (*plparam ? 1 : -1); + + case CB_GETLBTEXT: /* fixme: fixed sized buffer */ + { if ( WINPROC_TestCBForStr( hwnd )) + { LPARAM *ptr = (LPARAM *)HeapAlloc( GetProcessHeap(), 0, 256 * sizeof(WCHAR) + sizeof(LPARAM) ); + if (!ptr) return -1; + *ptr++ = *plparam; /* Store previous lParam */ + *plparam = (LPARAM)ptr; + } + } + return 1; + +/* Multiline edit */ + case EM_GETLINE: + { WORD len = (WORD)*plparam; + LPARAM *ptr = (LPARAM *) HeapAlloc( GetProcessHeap(), 0, sizeof(LPARAM) + sizeof (WORD) + len*sizeof(WCHAR) ); + if (!ptr) return -1; + *ptr++ = *plparam; /* Store previous lParam */ + (WORD)*ptr = len; /* Store the lenght */ + *plparam = (LPARAM)ptr; + } + return 1; + + case WM_ASKCBFORMATNAME: + case WM_DEVMODECHANGE: + case WM_PAINTCLIPBOARD: + case WM_SIZECLIPBOARD: + case WM_WININICHANGE: + case EM_SETPASSWORDCHAR: + // FIXME(msg, "message %s (0x%x) needs translation, please report\n", SPY_GetMsgName(msg), msg ); + return -1; + default: /* No translation needed */ + return 0; + } +} + + +/********************************************************************** + * WINPROC_UnmapMsg32ATo32W + * + * Unmap a message that was mapped from Ansi to Unicode. + */ +void WINPROC_UnmapMsg32ATo32W( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + switch(msg) + { + case WM_GETTEXT: + { + LPARAM *ptr = (LPARAM *)lParam - 1; + lstrcpynWtoA( (LPSTR)*ptr, (LPWSTR)lParam, wParam ); + HeapFree( GetProcessHeap(), 0, ptr ); + } + break; + + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTW *cs = (CREATESTRUCTW *)lParam; + if (HIWORD(cs->lpszName)) + HeapFree( GetProcessHeap(), 0, (LPVOID)cs->lpszName ); + if (HIWORD(cs->lpszClass)) + HeapFree( GetProcessHeap(), 0, (LPVOID)cs->lpszClass ); + HeapFree( GetProcessHeap(), 0, cs ); + } + break; + + case WM_MDICREATE: + { + MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)lParam; + if (HIWORD(cs->szTitle)) + HeapFree( GetProcessHeap(), 0, (LPVOID)cs->szTitle ); + if (HIWORD(cs->szClass)) + HeapFree( GetProcessHeap(), 0, (LPVOID)cs->szClass ); + HeapFree( GetProcessHeap(), 0, cs ); + } + break; + + case WM_SETTEXT: + case CB_DIR: + case CB_FINDSTRING: + case CB_FINDSTRINGEXACT: + case CB_SELECTSTRING: + case LB_DIR: + case LB_ADDFILE: + case LB_FINDSTRING: + case LB_SELECTSTRING: + case EM_REPLACESEL: + HeapFree( GetProcessHeap(), 0, (void *)lParam ); + break; + +/* Listbox */ + case LB_ADDSTRING: + case LB_INSERTSTRING: + if ( WINPROC_TestLBForStr( hwnd )) + HeapFree( GetProcessHeap(), 0, (void *)lParam ); + break; + + case LB_GETTEXT: + { if ( WINPROC_TestLBForStr( hwnd )) + { LPARAM *ptr = (LPARAM *)lParam - 1; + lstrcpyWtoA( (LPSTR)*ptr, (LPWSTR)(lParam) ); + HeapFree( GetProcessHeap(), 0, ptr ); + } + } + break; + +/* Combobox */ + case CB_ADDSTRING: + case CB_INSERTSTRING: + if ( WINPROC_TestCBForStr( hwnd )) + HeapFree( GetProcessHeap(), 0, (void *)lParam ); + break; + + case CB_GETLBTEXT: + { if ( WINPROC_TestCBForStr( hwnd )) + { LPARAM *ptr = (LPARAM *)lParam - 1; + lstrcpyWtoA( (LPSTR)*ptr, (LPWSTR)(lParam) ); + HeapFree( GetProcessHeap(), 0, ptr ); + } + } + break; + +/* Multiline edit */ + case EM_GETLINE: + { LPARAM *ptr = (LPARAM *)lParam - 1; /* get the old lParam */ + WORD len = *(WORD *)ptr; + lstrcpynWtoA( ((LPSTR)*ptr)+2, ((LPWSTR)(lParam + 1))+1, len ); + HeapFree( GetProcessHeap(), 0, ptr ); + } + break; + } +} + + +/********************************************************************** + * WINPROC_MapMsg32WTo32A + * + * Map a message from Unicode to Ansi. + * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed. + */ +INT WINPROC_MapMsg32WTo32A( HWND hwnd, UINT msg, WPARAM wParam, LPARAM *plparam ) +{ switch(msg) + { + case WM_GETTEXT: + { + LPARAM *ptr = (LPARAM *)HeapAlloc( GetProcessHeap(), 0, + wParam + sizeof(LPARAM) ); + if (!ptr) return -1; + *ptr++ = *plparam; /* Store previous lParam */ + *plparam = (LPARAM)ptr; + } + return 1; + + case WM_SETTEXT: + case CB_DIR: + case CB_FINDSTRING: + case CB_FINDSTRINGEXACT: + case CB_SELECTSTRING: + case LB_DIR: + case LB_ADDFILE: + case LB_FINDSTRING: + case LB_SELECTSTRING: + case EM_REPLACESEL: + *plparam = (LPARAM)HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)*plparam ); + return (*plparam ? 1 : -1); + + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTA *cs = (CREATESTRUCTA *)HeapAlloc( GetProcessHeap(), 0, + sizeof(*cs) ); + if (!cs) return -1; + *cs = *(CREATESTRUCTA *)*plparam; + if (HIWORD(cs->lpszName)) + cs->lpszName = HEAP_strdupWtoA( GetProcessHeap(), 0, + (LPCWSTR)cs->lpszName ); + if (HIWORD(cs->lpszClass)) + cs->lpszClass = HEAP_strdupWtoA( GetProcessHeap(), 0, + (LPCWSTR)cs->lpszClass); + *plparam = (LPARAM)cs; + } + return 1; + case WM_MDICREATE: + { + MDICREATESTRUCTA *cs = + (MDICREATESTRUCTA *)HeapAlloc( GetProcessHeap(), 0, sizeof(*cs) ); + if (!cs) return -1; + *cs = *(MDICREATESTRUCTA *)*plparam; + if (HIWORD(cs->szTitle)) + cs->szTitle = HEAP_strdupWtoA( GetProcessHeap(), 0, + (LPCWSTR)cs->szTitle ); + if (HIWORD(cs->szClass)) + cs->szClass = HEAP_strdupWtoA( GetProcessHeap(), 0, + (LPCWSTR)cs->szClass ); + *plparam = (LPARAM)cs; + } + return 1; + +/* Listbox */ + case LB_ADDSTRING: + case LB_INSERTSTRING: + if ( WINPROC_TestLBForStr( hwnd )) + *plparam = (LPARAM)HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)*plparam ); + return (*plparam ? 1 : -1); + + case LB_GETTEXT: /* fixme: fixed sized buffer */ + { if ( WINPROC_TestLBForStr( hwnd )) + { LPARAM *ptr = (LPARAM *)HeapAlloc( GetProcessHeap(), 0, 256 + sizeof(LPARAM) ); + if (!ptr) return -1; + *ptr++ = *plparam; /* Store previous lParam */ + *plparam = (LPARAM)ptr; + } + } + return 1; + +/* Combobox */ + case CB_ADDSTRING: + case CB_INSERTSTRING: + if ( WINPROC_TestCBForStr( hwnd )) + *plparam = (LPARAM)HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)*plparam ); + return (*plparam ? 1 : -1); + + case CB_GETLBTEXT: /* fixme: fixed sized buffer */ + { if ( WINPROC_TestCBForStr( hwnd )) + { LPARAM *ptr = (LPARAM *)HeapAlloc( GetProcessHeap(), 0, 256 + sizeof(LPARAM) ); + if (!ptr) return -1; + *ptr++ = *plparam; /* Store previous lParam */ + *plparam = (LPARAM)ptr; + } + } + return 1; + +/* Multiline edit */ + case EM_GETLINE: + { WORD len = (WORD)*plparam; + LPARAM *ptr = (LPARAM *) HeapAlloc( GetProcessHeap(), 0, sizeof(LPARAM) + sizeof (WORD) + len*sizeof(CHAR) ); + if (!ptr) return -1; + *ptr++ = *plparam; /* Store previous lParam */ + (WORD)*ptr = len; /* Store the lenght */ + *plparam = (LPARAM)ptr; + } + return 1; + + case WM_ASKCBFORMATNAME: + case WM_DEVMODECHANGE: + case WM_PAINTCLIPBOARD: + case WM_SIZECLIPBOARD: + case WM_WININICHANGE: + case EM_SETPASSWORDCHAR: +// FIXME(msg, "message %s (%04x) needs translation, please report\n",SPY_GetMsgName(msg),msg ); + return -1; + default: /* No translation needed */ + return 0; + } +} + + +/********************************************************************** + * WINPROC_UnmapMsg32WTo32A + * + * Unmap a message that was mapped from Unicode to Ansi. + */ +void WINPROC_UnmapMsg32WTo32A( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + switch(msg) + { + case WM_GETTEXT: + { + LPARAM *ptr = (LPARAM *)lParam - 1; + lstrcpynAtoW( (LPWSTR)*ptr, (LPSTR)lParam, wParam ); + HeapFree( GetProcessHeap(), 0, ptr ); + } + break; + + case WM_SETTEXT: + case CB_DIR: + case CB_FINDSTRING: + case CB_FINDSTRINGEXACT: + case CB_SELECTSTRING: + case LB_DIR: + case LB_ADDFILE: + case LB_FINDSTRING: + case LB_SELECTSTRING: + case EM_REPLACESEL: + HeapFree( GetProcessHeap(), 0, (void *)lParam ); + break; + + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTA *cs = (CREATESTRUCTA *)lParam; + if (HIWORD(cs->lpszName)) + HeapFree( GetProcessHeap(), 0, (LPVOID)cs->lpszName ); + if (HIWORD(cs->lpszClass)) + HeapFree( GetProcessHeap(), 0, (LPVOID)cs->lpszClass ); + HeapFree( GetProcessHeap(), 0, cs ); + } + break; + + case WM_MDICREATE: + { + MDICREATESTRUCTA *cs = (MDICREATESTRUCTA *)lParam; + if (HIWORD(cs->szTitle)) + HeapFree( GetProcessHeap(), 0, (LPVOID)cs->szTitle ); + if (HIWORD(cs->szClass)) + HeapFree( GetProcessHeap(), 0, (LPVOID)cs->szClass ); + HeapFree( GetProcessHeap(), 0, cs ); + } + break; + +/* Listbox */ + case LB_ADDSTRING: + case LB_INSERTSTRING: + if ( WINPROC_TestLBForStr( hwnd )) + HeapFree( GetProcessHeap(), 0, (void *)lParam ); + break; + + case LB_GETTEXT: + { if ( WINPROC_TestLBForStr( hwnd )) + { LPARAM *ptr = (LPARAM *)lParam - 1; + lstrcpyAtoW( (LPWSTR)*ptr, (LPSTR)(lParam) ); + HeapFree( GetProcessHeap(), 0, ptr ); + } + } + break; + +/* Combobox */ + case CB_ADDSTRING: + case CB_INSERTSTRING: + if ( WINPROC_TestCBForStr( hwnd )) + HeapFree( GetProcessHeap(), 0, (void *)lParam ); + break; + + case CB_GETLBTEXT: + { if ( WINPROC_TestCBForStr( hwnd )) + { LPARAM *ptr = (LPARAM *)lParam - 1; + lstrcpyAtoW( (LPWSTR)*ptr, (LPSTR)(lParam) ); + HeapFree( GetProcessHeap(), 0, ptr ); + } + } + break; + +/* Multiline edit */ + case EM_GETLINE: + { LPARAM *ptr = (LPARAM *)lParam - 1; /* get the old lParam */ + WORD len = *(WORD *)ptr; + lstrcpynAtoW( ((LPWSTR)*ptr)+1, ((LPSTR)(lParam + 1))+2, len ); + HeapFree( GetProcessHeap(), 0, ptr ); + } + break; + } }