/* $Id: win32wbase.cpp,v 1.390 2004-05-24 09:02:00 sandervl Exp $ */ /* * Win32 Window Base Class for OS/2 * * Copyright 1998-2002 Sander van Leeuwen (sandervl@xs4all.nl) * Copyright 1999 Daniela Engert (dani@ngrt.de) * Copyright 1999-2000 Christoph Bratschi (cbratschi@datacomm.ch) * * Parts based on Wine Windows code (windows\win.c) * Corel version: corel20000212 * * Copyright 1993, 1994, 1996 Alexandre Julliard * 1995 Alex Korobka * * TODO: Not thread/process safe * * NOTE: To access a window object, you must call GetWindowFromOS2Handle or * GetWindowFromHandle. Both these methods increase the reference count * of the object. When you're done with the object, you MUST call * the release method! * This mechanism prevents premature destruction of objects when there * are still clients using it. * * NOTE: Client rectangle always relative to frame window * Window rectangle in parent coordinates (relative to parent's client window) * (screen coord. if no parent) * * NOTE: Status of window: * Before a window has processed WM_NCCREATE: * - GetTopWindow can't return that window handle * - GetWindow(parent, GW_CHILD) can't return that window handle * - IsChild works * TODO: Does this affect more functions?? (other GetWindow ops) * (verified in NT4, SP6) * * Project Odin Software License can be found in LICENSE.TXT * */ #include #include #include #include #include #include #include #include #include #include #include "win32wbase.h" #include "win32wfake.h" #include "wndmsg.h" #include "oslibwin.h" #include "oslibmsg.h" #include "oslibutil.h" #include "oslibgdi.h" #include "oslibres.h" #include "oslibdos.h" #include "syscolor.h" #include "win32wndhandle.h" #include "dc.h" #include "win32wdesktop.h" #include "pmwindow.h" #include "controls.h" #include #include #include "menu.h" #define INCL_TIMERWIN32 #include "timer.h" #include "user32api.h" #include "callwrap.h" #define DBG_LOCALLOG DBG_win32wbase #include "dbglocal.h" /* bits in the dwKeyData */ #define KEYDATA_ALT 0x2000 #define KEYDATA_PREVSTATE 0x4000 void PrintWindowStyle(DWORD dwStyle, DWORD dwExStyle); static BOOL fDestroyAll = FALSE; //For quick lookup of current process id static ULONG currentProcessId = -1; static int iF10Key = 0; static int iMenuSysKey = 0; //****************************************************************************** //****************************************************************************** Win32BaseWindow::Win32BaseWindow() : GenericObject(&windows, &critsect), ChildWindow(&critsect) { Init(); } //****************************************************************************** //****************************************************************************** Win32BaseWindow::Win32BaseWindow(CREATESTRUCTA *lpCreateStructA, ATOM classAtom, BOOL isUnicode) : GenericObject(&windows, &critsect), ChildWindow(&critsect) { Init(); this->isUnicode = isUnicode; // call member function CreateWindowExA(lpCreateStructA, classAtom); } //****************************************************************************** //****************************************************************************** void Win32BaseWindow::Init() { isUnicode = FALSE; fFirstShow = TRUE; fIsDialog = FALSE; fIsModalDialogOwner = FALSE; OS2HwndModalDialog = 0; fParentChange = FALSE; fDestroyWindowCalled = FALSE; fChildDestructionInProgress = FALSE; fTaskList = FALSE; fParentDC = FALSE; fComingToTop = FALSE; fMinMaxChange = FALSE; fPMUpdateRegionChanged = FALSE; fEraseBkgndFlag = TRUE; fIsDragDropActive= FALSE; fDirtyUpdateRegion = FALSE; fWindowLocked = FALSE; state = STATE_INIT; windowNameA = NULL; windowNameW = NULL; windowNameLengthA = 0; windowNameLengthW = 0; userWindowBytes = NULL;; nrUserWindowBytes= 0; OS2Hwnd = 0; OS2HwndFrame = 0; hSysMenu = 0; Win32Hwnd = 0; // allocate a Win32 HWND, return it in Win32Hwnd and associate object // pointer with it if(HwAllocateWindowHandle(&Win32Hwnd, (ULONG)this) == FALSE) { dprintf(("Win32BaseWindow::Init HwAllocateWindowHandle failed!!")); DebugInt3(); } Win32HwndOrg = Win32Hwnd; posx = posy = 0; width = height = 0; dwExStyle = 0; dwStyle = 0; dwOldStyle = 0; win32wndproc = 0; hInstance = 0; dwIDMenu = 0; //0xFFFFFFFF; //default -1 userData = 0; contextHelpId = 0; hotkey = 0; hwndLinkAfter = HWND_BOTTOM; flags = 0; lastHitTestVal = HTCLIENT; owner = NULL; windowClass = 0; hIcon = 0; hIconSm = 0; horzScrollInfo = NULL; vertScrollInfo = NULL; propertyList = NULL; cbExtra = 0; pExtra = NULL; ownDC = 0; hWindowRegion = 0; hClipRegion = 0; hVisRegion = 0; hUpdateRegion = 0; hTaskList = 0; if(currentProcessId == -1) { currentProcessId = GetCurrentProcessId(); } dwThreadId = GetCurrentThreadId(); dwProcessId = currentProcessId; memset(&windowpos, 0, sizeof(windowpos)); //min and max position are initially -1 (verified in NT4, SP6) windowpos.ptMinPosition.x = -1; windowpos.ptMinPosition.y = -1; windowpos.ptMaxPosition.x = -1; windowpos.ptMaxPosition.y = -1; lpVisRgnNotifyProc = NULL; dwVisRgnNotifyParam = NULL; pfnOldPMWndProc = NULL; memset(hdcWindow, 0, sizeof(hdcWindow)); nrOpenDCs = 0; } //****************************************************************************** //todo get rid of resources (menu, icon etc) //****************************************************************************** Win32BaseWindow::~Win32BaseWindow() { if(getRefCount() < 0) { DebugInt3(); } if(hTaskList) { OSLibWinRemoveFromTasklist(hTaskList); } OSLibWinSetVisibleRegionNotify(OS2Hwnd, FALSE); OSLibWinSetWindowULong(OS2Hwnd, OFFSET_WIN32WNDPTR, 0); OSLibWinSetWindowULong(OS2Hwnd, OFFSET_WIN32PM_MAGIC, 0); if(fDestroyAll) { dprintf(("Destroying window %x %s", getWindowHandle(), windowNameA)); setParent(NULL); //or else we'll crash in the dtor of the ChildWindow class } else if(getParent() && getParent()->getFirstChild() == this && getNextChild() == NULL) { //if we're the last child that's being destroyed and our //parent window was also destroyed, then we if(getParent()->IsWindowDestroyed()) { Win32BaseWindow *wndparent = (Win32BaseWindow *)ChildWindow::getParentOfChild(); RELEASE_WNDOBJ(wndparent); setParent(NULL); //or else we'll crash in the dtor of the ChildWindow class } } else { Win32BaseWindow *wndparent = (Win32BaseWindow *)ChildWindow::getParentOfChild(); if(wndparent && !fDestroyAll) { RELEASE_WNDOBJ(wndparent); } } if(owner && !fDestroyAll) { RELEASE_WNDOBJ(owner); } // Decrement class window counter // NOTE: Must be done before ReleaseDC call for ownDC! if(windowClass) { RELEASE_CLASSOBJ(windowClass); } if(ownDC) ReleaseDC(Win32HwndOrg, ownDC); if(Win32Hwnd) HwFreeWindowHandle(Win32Hwnd); if(userWindowBytes) free(userWindowBytes); if(windowNameA) { free(windowNameA); windowNameA = NULL; } if(windowNameW) { free(windowNameW); windowNameW = NULL; } if(vertScrollInfo) { free(vertScrollInfo); vertScrollInfo = NULL; } if(horzScrollInfo) { free(horzScrollInfo); horzScrollInfo = NULL; } if(propertyList) { removeWindowProps(); } if(hUpdateRegion) { DeleteObject(hUpdateRegion); hUpdateRegion = NULL; } } //****************************************************************************** //****************************************************************************** void Win32BaseWindow::DestroyAll() { fDestroyAll = TRUE; GenericObject::DestroyAll(windows); } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::isChild() { return ((dwStyle & WS_CHILD) != 0); } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::IsWindowUnicode() { dprintf2(("IsWindowUnicode %x %d", getWindowHandle(), WINPROC_GetProcType((HWINDOWPROC)getWindowProc()) == WIN_PROC_32W)); return (WINPROC_GetProcType((HWINDOWPROC)getWindowProc()) == WIN_PROC_32W); } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::CreateWindowExA(CREATESTRUCTA *cs, ATOM classAtom) { char buffer[256]; #ifdef DEBUG PrintWindowStyle(cs->style, cs->dwExStyle); #endif //If window has no owner/parent window, then it will be added to the tasklist //(depending on visibility state) if (!cs->hwndParent) fTaskList = TRUE; sw = SW_SHOW; SetLastError(0); /* Find the parent window */ if (cs->hwndParent) { Win32BaseWindow *window = GetWindowFromHandle(cs->hwndParent); if(!window) { dprintf(("Bad parent %04x\n", cs->hwndParent )); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* Make sure parent is valid */ if (!window->IsWindow() ) { RELEASE_WNDOBJ(window); dprintf(("Bad parent %04x\n", cs->hwndParent )); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (window->getExStyle() & WS_EX_TOPMOST) cs->dwExStyle |= WS_EX_TOPMOST; RELEASE_WNDOBJ(window); /* Windows does this for overlapped windows * (I don't know about other styles.) */ if (cs->hwndParent == GetDesktopWindow() && (!(cs->style & WS_CHILD) || (cs->style & WS_POPUP))) { cs->hwndParent = 0; } } else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP)) { dprintf(("No parent for child window" )); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; /* WS_CHILD needs a parent, but WS_POPUP doesn't */ } /* Find the window class */ windowClass = Win32WndClass::FindClass(cs->hInstance, (LPSTR)classAtom); if (!windowClass) { GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ); dprintf(("Bad class '%s'", buffer )); SetLastError(ERROR_INVALID_PARAMETER); return 0; } #ifdef DEBUG if(HIWORD(cs->lpszClass)) { if(isUnicode) dprintf(("Window class %ls", cs->lpszClass)); else dprintf(("Window class %s", cs->lpszClass)); } else dprintf(("Window class %x", cs->lpszClass)); #endif /* Fix the lpszClass field: from existing programs, it seems ok to call a CreateWindowXXX * with an atom as the class name, put some programs expect to have a *REAL* string in * lpszClass when the CREATESTRUCT is sent with WM_CREATE */ if (!HIWORD(cs->lpszClass) ) { if (isUnicode) { GlobalGetAtomNameW( classAtom, (LPWSTR)buffer, sizeof(buffer) ); } else { GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ); } cs->lpszClass = buffer; } /* Fix the coordinates */ fXDefault = FALSE; fCXDefault = FALSE; FixCoordinates(cs, &sw); /* Correct the window style - stage 1 * * These are patches that appear to affect both the style loaded into the * WIN structure and passed in the CreateStruct to the WM_CREATE etc. * * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so * why does the user get to set it? */ /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been * tested for WS_POPUP */ if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) || ((!(cs->dwExStyle & WS_EX_STATICEDGE)) && (cs->style & (WS_DLGFRAME | WS_THICKFRAME)))) cs->dwExStyle |= WS_EX_WINDOWEDGE; else cs->dwExStyle &= ~WS_EX_WINDOWEDGE; //Allocate window words nrUserWindowBytes = windowClass->getExtraWndBytes(); if(nrUserWindowBytes) { userWindowBytes = (char *)_smalloc(nrUserWindowBytes); memset(userWindowBytes, 0, nrUserWindowBytes); } // check if it's the standard child window case if ((cs->style & WS_CHILD) && cs->hwndParent) { SetParent(cs->hwndParent); owner = NULL; //SvL: Shell positioning shouldn't be done for child windows! (breaks Notes) fXDefault = fCXDefault = FALSE; } else { // either no child window or a popup window SetParent(0); if (!cs->hwndParent || (cs->hwndParent == windowDesktop->getWindowHandle())) { owner = NULL; } else { // we're a popup window Win32BaseWindow *wndparent = GetWindowFromHandle(cs->hwndParent); if(wndparent) { owner = GetWindowFromHandle(wndparent->GetTopParent()); RELEASE_WNDOBJ(wndparent); } else owner = NULL; if(owner == NULL) { dprintf(("HwGetWindowHandleData couldn't find owner window %x!!!", cs->hwndParent)); SetLastError(ERROR_INVALID_WINDOW_HANDLE); return FALSE; } } } WINPROC_SetProc((HWINDOWPROC *)&win32wndproc, windowClass->getWindowProc((isUnicode) ? WNDPROC_UNICODE : WNDPROC_ASCII), WINPROC_GetProcType((HWINDOWPROC)windowClass->getWindowProc((isUnicode) ? WNDPROC_UNICODE : WNDPROC_ASCII)), WIN_PROC_WINDOW); hInstance = cs->hInstance; dwStyle = cs->style & ~WS_VISIBLE; dwOldStyle = dwStyle; dwExStyle = cs->dwExStyle; hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) ? HWND_BOTTOM : HWND_TOP; /* Correct the window style phase 2 */ if (!(cs->style & WS_CHILD)) { dwStyle |= WS_CLIPSIBLINGS; if (!(cs->style & WS_POPUP)) { dwStyle |= WS_CAPTION; flags |= WIN_NEED_SIZE; } } //WinZip 8.0 crashes when a dialog created after opening a zipfile receives //the WM_SIZE message (before WM_INITDIALOG) //Opera doesn't like this either. if(IsDialog()) { flags |= WIN_NEED_SIZE; } //copy pointer of CREATESTRUCT for usage in MsgCreate method tmpcs = cs; //Store our window object pointer in thread local memory, so PMWINDOW.CPP can retrieve it TEB *teb = GetThreadTEB(); if(teb == NULL) { dprintf(("Window creation failed - teb == NULL")); //this is VERY bad ExitProcess(666); return FALSE; } teb->o.odin.newWindow = (ULONG)this; DWORD dwOSWinStyle, dwOSFrameStyle; OSLibWinConvertStyle(dwStyle,dwExStyle,&dwOSWinStyle, &dwOSFrameStyle); // create PM windows - frame and client window HWND hwndOS2Frame = (getParent()) ? getParent()->getOS2WindowHandle() : OSLIB_HWND_DESKTOP; OS2Hwnd = OSLibWinCreateWindow(hwndOS2Frame, dwOSWinStyle, dwOSFrameStyle, (char *)windowNameA, (owner) ? owner->getOS2WindowHandle() : 0, (hwndLinkAfter == HWND_BOTTOM) ? TRUE : FALSE, 0, fTaskList, fXDefault | fCXDefault, windowClass->getStyle(), &OS2HwndFrame); if(OS2Hwnd == 0) { dprintf(("Window creation failed!! OS LastError %0x", OSLibWinGetLastError())); SetLastError(ERROR_OUTOFMEMORY); //TODO: Better error return FALSE; } OSLibWinSetVisibleRegionNotify(OS2Hwnd, TRUE); state = STATE_CREATED; SetLastError(0); return TRUE; } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::MsgCreate(HWND hwndOS2) { CREATESTRUCTA *cs = tmpcs; //pointer to CREATESTRUCT used in CreateWindowExA method POINT maxSize, maxPos, minTrack, maxTrack; HWND hwnd = getWindowHandle(); LRESULT (* CALLBACK localSend32)(HWND, UINT, WPARAM, LPARAM); OS2Hwnd = hwndOS2; if(OSLibWinSetWindowULong(OS2Hwnd, OFFSET_WIN32WNDPTR, getWindowHandle()) == FALSE) { dprintf(("WM_CREATE: WinSetWindowULong %X failed!!", OS2Hwnd)); SetLastError(ERROR_OUTOFMEMORY); //TODO: Better error return FALSE; } if(OSLibWinSetWindowULong(OS2Hwnd, OFFSET_WIN32PM_MAGIC, WIN32PM_MAGIC) == FALSE) { dprintf(("WM_CREATE: WinSetWindowULong2 %X failed!!", OS2Hwnd)); SetLastError(ERROR_OUTOFMEMORY); //TODO: Better error return FALSE; } if(OSLibWinSetWindowULong(OS2Hwnd, OFFSET_WIN32FLAGS, 0) == FALSE) { dprintf(("WM_CREATE: WinSetWindowULong2 %X failed!!", OS2Hwnd)); SetLastError(ERROR_OUTOFMEMORY); //TODO: Better error return FALSE; } if (HOOK_IsHooked( WH_CBT )) { CBT_CREATEWNDA cbtc; LRESULT ret; cbtc.lpcs = cs; cbtc.hwndInsertAfter = hwndLinkAfter; ret = (isUnicode) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND, getWindowHandle(), (LPARAM)&cbtc) : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND, getWindowHandle(), (LPARAM)&cbtc); if(ret) { dprintf(("CBT-hook returned non-0 !!")); SetLastError(ERROR_CAN_NOT_COMPLETE); //todo: wrong error return FALSE; } //todo: if hook changes parent, we need to do so too!!!!!!!!!! } if (cs->style & WS_HSCROLL) { horzScrollInfo = (SCROLLBAR_INFO*)malloc(sizeof(SCROLLBAR_INFO)); horzScrollInfo->MinVal = horzScrollInfo->CurVal = horzScrollInfo->Page = 0; horzScrollInfo->MaxVal = 100; horzScrollInfo->flags = ESB_ENABLE_BOTH; } if (cs->style & WS_VSCROLL) { vertScrollInfo = (SCROLLBAR_INFO*)malloc(sizeof(SCROLLBAR_INFO)); vertScrollInfo->MinVal = vertScrollInfo->CurVal = vertScrollInfo->Page = 0; vertScrollInfo->MaxVal = 100; vertScrollInfo->flags = ESB_ENABLE_BOTH; } // initially allocate the window name fields if(HIWORD(cs->lpszName)) { if (!isUnicode) { windowNameLengthA = strlen(cs->lpszName); windowNameA = (LPSTR)_smalloc(windowNameLengthA+1); strcpy(windowNameA,cs->lpszName); windowNameLengthW = lstrlenAtoW( windowNameA, -1 ); windowNameW = (LPWSTR)_smalloc(( windowNameLengthW + 1 ) * sizeof( WCHAR ) ); lstrcpyAtoW( windowNameW, windowNameA ); } else { // Wide windowNameLengthW = lstrlenW((LPWSTR)cs->lpszName); windowNameW = (LPWSTR)_smalloc((windowNameLengthW+1)*sizeof(WCHAR)); strcpyW(windowNameW,(LPWSTR)cs->lpszName); // windowNameW[lstrlenW((LPWSTR)cs->lpszName)] = 0; // need ? // Ascii windowNameLengthA = lstrlenWtoA( windowNameW, -1 ); windowNameA = (LPSTR)_smalloc( windowNameLengthA + 1 ); lstrcpyWtoA( windowNameA, windowNameW ); } dprintf(("windowNameA 0x%lx to 0x%lx windowNameW : 0x%lx to 0x%lx", windowNameA, windowNameA + windowNameLengthA, windowNameW, windowNameW + windowNameLengthW )); if(fOS2Look) { OSLibWinSetTitleBarText(OS2HwndFrame, windowNameA); } } //SvL: This completely messes up MS Word 97 (no button bar, no menu) #if 0 //adjust CW_USEDEFAULT position if (fXDefault | fCXDefault) { RECT rect; //SvL: Returns invalid rectangle (not the expected shell default size) OSLibWinQueryWindowRect(OS2Hwnd,&rect,RELATIVE_TO_SCREEN); if (getParent()) mapWin32Rect(OSLIB_HWND_DESKTOP,getParent()->getOS2WindowHandle(),&rect); if (fXDefault) { cs->x = rect.left; cs->y = rect.top; if (!fCXDefault) { //CB: todo: adjust pos to screen rect } } if (fCXDefault) { cs->cx = rect.right-rect.left; cs->cy = rect.bottom-rect.top; } } #endif //Set icon from window or class if (hIcon) OSLibWinSetIcon(OS2HwndFrame,hIcon); else if (windowClass->getIcon()) OSLibWinSetIcon(OS2HwndFrame,windowClass->getIcon()); /* Get class or window DC if needed */ if(windowClass->getStyle() & CS_OWNDC) { dprintf(("Class with CS_OWNDC style")); ownDC = GetDCEx(getWindowHandle(), NULL, DCX_USESTYLE); } else if (windowClass->getStyle() & CS_PARENTDC) { fParentDC = TRUE; ownDC = 0; } else if (windowClass->getStyle() & CS_CLASSDC) { dprintf(("WARNING: Class with CS_CLASSDC style!")); //not a good solution, but it's a bit difficult to share a single //DC among different windows... DevOpenDC apparently can't be used //for window DCs and WinOpenWindowDC must be associated with a window ownDC = GetDCEx(getWindowHandle(), NULL, DCX_USESTYLE); } /* Set the window menu */ if ((dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION ) { if (cs->hMenu) { ::SetMenu(getWindowHandle(), cs->hMenu); } else { if (windowClass->getMenuNameA()) { cs->hMenu = LoadMenuA(windowClass->getInstance(),windowClass->getMenuNameA()); #if 0 //CB: hack for treeview test cases bug if (!cs->hMenu) cs->hMenu = LoadMenuA(windowClass->getInstance(),"MYAPP"); #endif if (cs->hMenu) ::SetMenu(getWindowHandle(), cs->hMenu ); } } } else { setWindowId((DWORD)cs->hMenu); } hSysMenu = (dwStyle & WS_SYSMENU) ? MENU_GetSysMenu(Win32Hwnd,0):0; /* Send the WM_GETMINMAXINFO message and fix the size if needed */ if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD))) { GetMinMaxInfo(&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->cx < 0) cs->cx = 0; if (cs->cy < 0) cs->cy = 0; } //set client & window rectangles from CreateWindowEx CREATESTRUCT rectWindow.left = cs->x; rectWindow.right = cs->x+cs->cx; rectWindow.top = cs->y; rectWindow.bottom = cs->y+cs->cy; rectClient = rectWindow; OffsetRect(&rectClient, -rectClient.left, -rectClient.top); /* Send the WM_CREATE message * Perhaps we shouldn't allow width/height changes as well. * See p327 in "Internals". */ maxPos.x = rectWindow.left; maxPos.y = rectWindow.top; if(fTaskList) { hTaskList = OSLibWinAddToTaskList(OS2HwndFrame, windowNameA, (cs->style & WS_VISIBLE) ? 1 : 0); } localSend32 = (isUnicode) ? ::SendMessageW : ::SendMessageA; state = STATE_PRE_WMNCCREATE; if(localSend32(getWindowHandle(), WM_NCCREATE,0,(LPARAM)cs)) { RECT tmpRect; //CB: recheck flags if (cs->style & (WS_POPUP | WS_CHILD)) { fXDefault = FALSE; if (fCXDefault) { fCXDefault = FALSE; cs->cx = cs->cy = 0; rectWindow.right = rectWindow.left; rectWindow.bottom = rectWindow.top; } } tmpRect = rectWindow; state = STATE_POST_WMNCCREATE; //set the window size and update the client //@@PF Popup children of inactive windows can thus bring inactive window //on top, this is not correct, popup windows can be on top only if their owner //is in foreground, otherwise they are linked after owner. if (((dwStyle & (WS_CHILD|WS_POPUP)) == WS_POPUP) && getOwner() && (getOwner()->getWindowHandle() != GetForegroundWindow())) { hwndLinkAfter = getOwner()->getWindowHandle(); } SetWindowPos(hwndLinkAfter, tmpRect.left, tmpRect.top, tmpRect.right-tmpRect.left, tmpRect.bottom-tmpRect.top,SWP_NOACTIVATE | SWP_NOREDRAW | SWP_FRAMECHANGED); state = STATE_PRE_WMCREATE; if (cs->style & WS_VISIBLE) dwStyle |= WS_VISIBLE; //program could change position in WM_CREATE if( (localSend32(getWindowHandle(), WM_CREATE, 0, (LPARAM)cs )) != -1 ) { state = STATE_POST_WMCREATE; if(!(flags & WIN_NEED_SIZE)) { SendMessageA(getWindowHandle(), WM_SIZE, SIZE_RESTORED, MAKELONG(rectClient.right-rectClient.left, rectClient.bottom-rectClient.top)); if(!::IsWindow(hwnd)) { dprintf(("Createwindow: WM_SIZE destroyed window")); goto end; } SendMessageA(getWindowHandle(), WM_MOVE,0,MAKELONG(rectClient.left,rectClient.top)); if(!::IsWindow(hwnd)) { dprintf(("Createwindow: WM_MOVE destroyed window")); goto end; } } if (getStyle() & (WS_MINIMIZE | WS_MAXIMIZE)) { RECT newPos; UINT swFlag = (getStyle() & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE; setStyle(getStyle() & ~(WS_MAXIMIZE | WS_MINIMIZE)); MinMaximize(swFlag, &newPos); swFlag = ((getStyle() & WS_CHILD) || GetActiveWindow()) ? SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED : SWP_NOZORDER | SWP_FRAMECHANGED; SetWindowPos(0, newPos.left, newPos.top, newPos.right, newPos.bottom, swFlag); if(!::IsWindow(hwnd)) { dprintf(("Createwindow: min/max destroyed window")); goto end; } } if( (getStyle() & WS_CHILD) && !(getExStyle() & WS_EX_NOPARENTNOTIFY) ) { /* Notify the parent window only */ if(getParent() && getParent()->IsWindowDestroyed() == FALSE) { SendMessageA(getParent()->getWindowHandle(), WM_PARENTNOTIFY, MAKEWPARAM(WM_CREATE, getWindowId()), (LPARAM)getWindowHandle()); } if(!::IsWindow(hwnd)) { dprintf(("Createwindow: WM_PARENTNOTIFY destroyed window")); goto end; } } if(cs->style & WS_VISIBLE) { dwStyle &= ~WS_VISIBLE; ShowWindow(sw); } /* Call WH_SHELL hook */ if (!(getStyle() & WS_CHILD) && !owner) HOOK_CallHooksA(WH_SHELL, HSHELL_WINDOWCREATED, getWindowHandle(), 0); //Call custom Odin hook for window creation (for all windows) HOOK_CallOdinHookA(HODIN_WINDOWCREATED, hwnd, 0); SetLastError(0); return TRUE; } } dprintf(("Window creation FAILED (NCCREATE cancelled creation)")); SetLastError(ERROR_OUTOFMEMORY); //TODO: Better error end: return FALSE; } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgQuit() { return SendMessageA(getWindowHandle(), WM_QUIT, 0, 0); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgClose() { return SendMessageA(getWindowHandle(), WM_CLOSE,0,0); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgDestroy() { ULONG rc; Win32BaseWindow *child; HWND hwnd = getWindowHandle(); state = STATE_DESTROYED; if(fDestroyWindowCalled == FALSE) {//this window was destroyed because DestroyWindow was called for its parent //so: send a WM_PARENTNOTIFY now as that hasn't happened yet if((getStyle() & WS_CHILD) && !(getExStyle() & WS_EX_NOPARENTNOTIFY)) { if(getParent() && getParent()->IsWindowDestroyed() == FALSE) { /* Notify the parent window only */ SendMessageA(getParent()->getWindowHandle(), WM_PARENTNOTIFY, MAKEWPARAM(WM_DESTROY, getWindowId()), (LPARAM)getWindowHandle()); } //// else DebugInt3(); } } // there may be no window proc already (reset to null with SetWindowLong by // the application), avoid the debug assertion if (win32wndproc) SendMessageA(getWindowHandle(),WM_DESTROY, 0, 0); if(::IsWindow(hwnd) == FALSE) { //object already destroyed, so return immediately return 1; } if (win32wndproc) SendMessageA(getWindowHandle(),WM_NCDESTROY, 0, 0); TIMER_KillTimerFromWindow(getWindowHandle()); if(getRefCount() == 0 && getFirstChild() == NULL && state == STATE_CREATED) { delete this; } else { //make sure no message can ever arrive for this window again (PM or from other win32 windows) dprintf(("Mark window %x (%x) as deleted; refcount %d", getWindowHandle(), this, getRefCount())); markDeleted(); OSLibWinSetWindowULong(OS2Hwnd, OFFSET_WIN32WNDPTR, 0); OSLibWinSetWindowULong(OS2Hwnd, OFFSET_WIN32PM_MAGIC, 0); if(Win32Hwnd) { HwFreeWindowHandle(Win32Hwnd); Win32Hwnd = 0; } // Decrement class window counter // NOTE: Must be done before ReleaseDC call for ownDC! if(windowClass) { RELEASE_CLASSOBJ(windowClass); } if(ownDC) { ReleaseDC(Win32Hwnd, ownDC); ownDC = 0; } } return 1; } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgEnable(BOOL fEnable) { if(fEnable) { dwStyle &= ~WS_DISABLED; } else dwStyle |= WS_DISABLED; return SendMessageA(getWindowHandle(),WM_ENABLE, fEnable, 0); } //****************************************************************************** //TODO: SW_PARENTCLOSING/OPENING flag (lParam) //****************************************************************************** ULONG Win32BaseWindow::MsgShow(BOOL fShow) { if(!CanReceiveSizeMsgs() || fDestroyWindowCalled) { return 1; } if(fShow) { setStyle(getStyle() | WS_VISIBLE); if(getStyle() & WS_MINIMIZE) { return ShowWindow(SW_RESTORE); } } else setStyle(getStyle() & ~WS_VISIBLE); //already sent from ShowWindow //// return SendMessageA(getWindowHandle(),WM_SHOWWINDOW, fShow, 0); return 0; } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgPosChanging(LPARAM lp) { //SvL: Notes crashes when switching views (calls DestroyWindow -> PM sends // a WM_WINDOWPOSCHANGED msg -> crash) if(!CanReceiveSizeMsgs() || fDestroyWindowCalled) return 0; return SendMessageA(getWindowHandle(),WM_WINDOWPOSCHANGING, 0, lp); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgPosChanged(LPARAM lp) { //SvL: Notes crashes when switching views (calls DestroyWindow -> PM sends // a WM_WINDOWPOSCHANGED msg -> crash) if(!CanReceiveSizeMsgs() || fDestroyWindowCalled) return 1; return SendMessageA(getWindowHandle(),WM_WINDOWPOSCHANGED, 0, lp); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgScroll(ULONG msg, ULONG scrollCode, ULONG scrollPos) { //According to the SDK docs, the scrollbar handle (lParam) is 0 when the standard //window scrollbars send these messages return SendMessageA(getWindowHandle(),msg, MAKELONG(scrollCode, scrollPos), 0); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgActivate(BOOL fActivate, BOOL fMinimized, HWND hwnd, HWND hwndOS2Win) { ULONG rc, procidhwnd = -1, threadidhwnd = 0; //SvL: Don't send WM_(NC)ACTIVATE messages when the window is being destroyed if(fDestroyWindowCalled) { return 0; } //According to SDK docs, if app returns FALSE & window is being deactivated, //default processing is cancelled //TODO: According to Wine we should proceed anyway if window is sysmodal if(SendMessageA(getWindowHandle(),WM_NCACTIVATE, fActivate, 0) == FALSE && !fActivate) { dprintf(("WARNING: WM_NCACTIVATE return code = FALSE -> cancel processing")); return 0; } /* child windows get a WM_CHILDACTIVATE message */ if((getStyle() & (WS_CHILD | WS_POPUP)) == WS_CHILD ) { if(fActivate) {//WM_CHILDACTIVE is for activation only SendMessageA(getWindowHandle(),WM_CHILDACTIVATE, 0, 0L); } return 0; } return SendMessageA(getWindowHandle(),WM_ACTIVATE, MAKELONG((fActivate) ? WA_ACTIVE : WA_INACTIVE, fMinimized), hwnd); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgChildActivate(BOOL fActivate) { //SvL: Don't send WM_(NC)ACTIVATE messages when the window is being destroyed if(fDestroyWindowCalled) { return 0; } //According to SDK docs, if app returns FALSE & window is being deactivated, //default processing is cancelled //TODO: According to Wine we should proceed anyway if window is sysmodal if(SendMessageA(getWindowHandle(),WM_NCACTIVATE, fActivate, 0) == FALSE && !fActivate) { dprintf(("WARNING: WM_NCACTIVATE return code = FALSE -> cancel processing")); return 0; } /* child windows get a WM_CHILDACTIVATE message */ if((getStyle() & (WS_CHILD | WS_POPUP)) == WS_CHILD ) { if(fActivate) {//WM_CHILDACTIVE is for activation only SendMessageA(getWindowHandle(),WM_CHILDACTIVATE, 0, 0L); } return 0; } DebugInt3(); return 0; } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::DispatchMsgA(MSG *msg) { return SendMessageA(getWindowHandle(),msg->message, msg->wParam, msg->lParam); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::DispatchMsgW(MSG *msg) { return SendMessageW(getWindowHandle(), msg->message, msg->wParam, msg->lParam); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgSetFocus(HWND hwnd) { //Notify that focus has changed (necessary for SetFocus(0) handling) SetFocusChanged(); //SvL: Don't send WM_(NC)ACTIVATE messages when the window is being destroyed if(fDestroyWindowCalled) { return 0; } // if in <= 8bpp mode, then we must send a WM_QUERYNEWPALETTE message here // this gives the app the chance to realize its palette if(ScreenBitsPerPel <= 8) { SendMessageA(getWindowHandle(),WM_QUERYNEWPALETTE, 0, 0); } return SendMessageA(getWindowHandle(),WM_SETFOCUS, hwnd, 0); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgKillFocus(HWND hwnd) { //Notify that focus has changed (necessary for SetFocus(0) handling) SetFocusChanged(); //SvL: Don't send WM_(NC)ACTIVATE messages when the window is being destroyed if(fDestroyWindowCalled) { return 0; } return SendMessageA(getWindowHandle(),WM_KILLFOCUS, hwnd, 0); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgButton(MSG *msg) { BOOL eatMsg = FALSE; BOOL fClick = FALSE; dprintf(("MsgButton %d at (%d,%d) %X %X", msg->message, msg->pt.x, msg->pt.y, msg->wParam, msg->lParam)); switch(msg->message) { case WM_LBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_MBUTTONDBLCLK: if (!(windowClass && windowClass->getClassLongA(GCL_STYLE) & CS_DBLCLKS)) { msg->message = msg->message - (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN); //dblclick -> down return MsgButton(msg); } break; case WM_NCLBUTTONDBLCLK: case WM_NCRBUTTONDBLCLK: case WM_NCMBUTTONDBLCLK: //Docs say CS_DBLCLKS style doesn't matter for non-client double clicks fClick = TRUE; break; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: if (getParent()) { dprintf(("notifying parent: %X %X", msg->wParam, msg->lParam)); NotifyParent(msg->message, msg->wParam, /*0*/msg->lParam); } // fall through to set fClick case WM_NCLBUTTONDOWN: case WM_NCRBUTTONDOWN: case WM_NCMBUTTONDOWN: fClick = TRUE; break; } if(fClick) { HWND hwndTop; /* Activate the window if needed */ hwndTop = GetTopParent(); HWND hwndActive = GetActiveWindow(); if (hwndTop && (getWindowHandle() != hwndActive)) { LONG ret = SendMessageA(getWindowHandle(),WM_MOUSEACTIVATE, hwndTop, MAKELONG( lastHitTestVal, msg->message) ); //SendMessageA(getWindowHandle(), msg->message, msg->wParam, msg->lParam); dprintf2(("WM_MOUSEACTIVATE returned %d foreground %x top %x", ret, GetForegroundWindow(), hwndTop)); if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT)) eatMsg = TRUE; //SvL: 0 is not documented, but experiments in NT4 show that // the window will get activated when it returns this. // (FreeCell is an example) if(((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT) || (ret == 0)) && (hwndTop != GetForegroundWindow()) ) { Win32BaseWindow *win32top = Win32BaseWindow::GetWindowFromHandle(hwndTop); //SvL: Calling OSLibSetActiveWindow(hwndTop); causes focus problems if (win32top) { //Must use client window handle (not frame!!) SetFocus(win32top->getWindowHandle()); RELEASE_WNDOBJ(win32top); } } } } SendMessageA(getWindowHandle(),WM_SETCURSOR, getWindowHandle(), MAKELONG(lastHitTestVal, msg->message)); return eatMsg ? 0 : SendMessageA(getWindowHandle(),msg->message, msg->wParam, msg->lParam); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgPaint(ULONG tmp, ULONG select) { if (select && IsWindowIconic()) return SendMessageA(getWindowHandle(),WM_PAINTICON, 1, 0); else return SendMessageA(getWindowHandle(),WM_PAINT, 0, 0); } //****************************************************************************** // // Win32BaseWindow::saveAndValidateUpdateRegion // // If an application doesn't validate the update region while processing // WM_PAINT, then we must remember it for the next time. Also validates // the current update region. // // Parameters: // Returns: // // NOTE: // Windows will only send a WM_PAINT once until another part of the // window is invalidated. Unfortunately PM keeps on sending // WM_PAINT messages until we validate the update region. // // This affects UpdateWindow, RedrawWindow, GetUpdateRgn, GetUpdateRect, // BeginPaint and the next WM_PAINT message. // //****************************************************************************** void Win32BaseWindow::saveAndValidateUpdateRegion() { if(hUpdateRegion == NULL) { hUpdateRegion = ::CreateRectRgn(0, 0, 1, 1); } dprintf(("Win32BaseWindow::saveAndValidateUpdateRegion; marked dirty!")); //save update region ::GetUpdateRgn(getWindowHandle(), hUpdateRegion, FALSE); //and validate it so PM won't bother us again ::ValidateRgn(getWindowHandle(), hUpdateRegion); //we just pretend the entire window is invalid. easier this way fDirtyUpdateRegion = TRUE; } //****************************************************************************** // // Win32BaseWindow::checkForDirtyUpdateRegion // // If an application doesn't validate the update region while processing // WM_PAINT, then we must remember it for the next time. If the window has // a dirty update region, then invalidate that region. // // Parameters: // Returns: // // NOTE: // //****************************************************************************** void Win32BaseWindow::checkForDirtyUpdateRegion() { if(fDirtyUpdateRegion) { dprintf(("Win32BaseWindow::checkForDirtyUpdateRegion; marked dirty -> invalidate whole window!")); fDirtyUpdateRegion = FALSE; ::InvalidateRgn(getWindowHandle(), hUpdateRegion, TRUE); } } //****************************************************************************** //TODO: Is the clipper region of the window DC equal to the invalidated rectangle? // (or are we simply erasing too much here) //****************************************************************************** ULONG Win32BaseWindow::MsgEraseBackGround(HDC hdc) { ULONG rc; HDC hdcErase = hdc; if (hdcErase == 0) { DebugInt3(); return 0; } if(IsWindowIconic()) rc = SendMessageA(getWindowHandle(),WM_ICONERASEBKGND, hdcErase, 0); else rc = SendMessageA(getWindowHandle(),WM_ERASEBKGND, hdcErase, 0); return (rc); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgMouseMove(MSG *msg) { //TODO: hiword should be 0 if window enters menu mode (SDK docs) //SDK: WM_SETCURSOR is not sent if the mouse is captured if(GetCapture() == 0) { SendMessageA(getWindowHandle(),WM_SETCURSOR, Win32Hwnd, MAKELONG(lastHitTestVal, msg->message)); } //translated message == WM_(NC)MOUSEMOVE return SendMessageA(getWindowHandle(),msg->message, msg->wParam, msg->lParam); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgChar(MSG *msg) { if (IsWindowUnicode()) { // Unicode windows expect the character code in UTF-16 while we save it // in ascii format, so we need to convert before sending to the window if (msg->message == WINWM_CHAR) { CHAR charA; WCHAR charW; charA = msg->wParam; MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1); msg->wParam= charW; dprintf(("MsgChar: Convert to Unicode src=%x res=%x", charA, charW)); } return DispatchMsgW(msg); } return DispatchMsgA(msg); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgNCPaint(PRECT pUpdateRect, HRGN hrgnUpdate) { ULONG rc; RECT client = rectClient; if ((pUpdateRect->left >= client.left) && (pUpdateRect->left < client.right) && (pUpdateRect->right >= client.left) && (pUpdateRect->right < client.right) && (pUpdateRect->top >= client.top) && (pUpdateRect->top < client.bottom) && (pUpdateRect->bottom >= client.top) && (pUpdateRect->bottom < client.bottom) && (!(getStyle() & WS_MINIMIZE))) { return 0; } rc = SendMessageA(getWindowHandle(),WM_NCPAINT, hrgnUpdate, 0); //Send WM_PAINTICON here if minimized, because client window will //not receive a (valid) WM_PAINT message if (getStyle() & WS_MINIMIZE) { rc = SendMessageA(getWindowHandle(),WM_PAINTICON, 1, 0); } return rc; } //****************************************************************************** //Called when either the frame's size or position has changed (lpWndPos != NULL) //or when the frame layout has changed (i.e. scrollbars added/removed) (lpWndPos == NULL) //****************************************************************************** ULONG Win32BaseWindow::MsgFormatFrame(WINDOWPOS *lpWndPos) { RECT oldWindowRect = rectWindow, client = rectClient, newWindowRect; RECT newClientRect; WINDOWPOS wndPos; ULONG rc; if(lpWndPos) { //set new window rectangle setWindowRect(lpWndPos->x, lpWndPos->y, lpWndPos->x+lpWndPos->cx, lpWndPos->y+lpWndPos->cy); newWindowRect = rectWindow; } else { wndPos.hwnd = getWindowHandle(); wndPos.hwndInsertAfter = 0; newWindowRect= rectWindow; wndPos.x = newWindowRect.left; wndPos.y = newWindowRect.top; wndPos.cx = newWindowRect.right - newWindowRect.left; wndPos.cy = newWindowRect.bottom - newWindowRect.top; wndPos.flags = SWP_FRAMECHANGED; lpWndPos = &wndPos; } newClientRect = rectClient; rc = SendNCCalcSize(TRUE, &newWindowRect, &oldWindowRect, &client, lpWndPos, &newClientRect); rectClient = newClientRect; //must update rectClient here dprintf(("MsgFormatFrame: old client rect (%d,%d)(%d,%d), new client (%d,%d)(%d,%d)", client.left, client.top, client.right, client.bottom, rectClient.left, rectClient.top, rectClient.right, rectClient.bottom)); dprintf(("MsgFormatFrame: old window rect (%d,%d)(%d,%d), new window (%d,%d)(%d,%d)", oldWindowRect.left, oldWindowRect.top, oldWindowRect.right, oldWindowRect.bottom, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom)); if(!CanReceiveSizeMsgs() || !EqualRect(&client, &rectClient)) { OSLibWinSetClientPos(getOS2WindowHandle(), rectClient.left, rectClient.top, getClientWidth(), getClientHeight(), getWindowHeight()); } #if 1 //this doesn't always work // if(CanReceiveSizeMsgs() && (client.left != rectClient.left || client.top != rectClient.top)) if(CanReceiveSizeMsgs() && ((oldWindowRect.right - oldWindowRect.left < rectClient.left || oldWindowRect.bottom - oldWindowRect.top < rectClient.top) || (EqualRect(&oldWindowRect, &rectWindow) && (client.left != rectClient.left || client.top != rectClient.top)))) { Win32BaseWindow *child = (Win32BaseWindow *)getFirstChild(); //client rectangle has moved -> inform children dprintf(("MsgFormatFrame -> client rectangle has changed, move children")); while(child) { ::SetWindowPos(child->getWindowHandle(), HWND_TOP, child->getWindowRect()->left, child->getWindowRect()->top, 0, 0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER); child = (Win32BaseWindow *)child->getNextChild(); } } #endif //WS_EX_TOOLWINDOW is incompatible with the OS2Look (titlebar thinner + smaller font) if(fOS2Look && ((dwStyle & WS_CAPTION) == WS_CAPTION) && !(dwExStyle & WS_EX_TOOLWINDOW)) { RECT rect = {0}; BOOL fCloseButton; fCloseButton = !(windowClass && (windowClass->getClassLongA(GCL_STYLE) & CS_NOCLOSE)); int height = getWindowHeight(); RECTLOS2 rectOS2; AdjustRectOuter(&rect, FALSE); rect.left = -rect.left; rect.top = rect.bottom - rect.top; rect.right = rectWindow.right - rectWindow.left - rect.right; rectOS2.xLeft = rect.left; rectOS2.xRight = rect.right; rectOS2.yBottom = height - rect.top; rectOS2.yTop = height - rect.bottom; //@@PF Disable close button as well when needed by application OSLibChangeCloseButtonState(getOS2FrameWindowHandle(), fCloseButton); OSLibWinPositionFrameControls(getOS2FrameWindowHandle(), &rectOS2, dwStyle, dwExStyle, IconForWindow(ICON_SMALL), fCloseButton, windowClass->getIcon() != NULL); } return rc; } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgSetText(LPSTR lpsz, LONG cch) { return SendMessageA(getWindowHandle(),WM_SETTEXT, 0, (LPARAM)lpsz); } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::MsgGetTextLength() { return SendMessageA(getWindowHandle(),WM_GETTEXTLENGTH, 0, 0); } //****************************************************************************** //****************************************************************************** void Win32BaseWindow::MsgGetText(char *wndtext, ULONG textlength) { SendMessageA(getWindowHandle(),WM_GETTEXT, textlength, (LPARAM)wndtext); } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::isMDIClient() { return FALSE; } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::isMDIChild() { return FALSE; } //****************************************************************************** //TODO: Not complete //****************************************************************************** BOOL Win32BaseWindow::isFrameWindow() { if(getParent() == NULL) return TRUE; return FALSE; } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::isDesktopWindow() { return FALSE; } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::isFakeWindow() { return FALSE; } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::IsWindowIconic() { return ((getStyle() & WS_MINIMIZE) && windowClass->getIcon()); } //****************************************************************************** //****************************************************************************** SCROLLBAR_INFO *Win32BaseWindow::getScrollInfo(int nBar) { switch(nBar) { case SB_HORZ: if (!horzScrollInfo) { horzScrollInfo = (SCROLLBAR_INFO*)malloc(sizeof(SCROLLBAR_INFO)); if (!horzScrollInfo) break; horzScrollInfo->MinVal = horzScrollInfo->CurVal = horzScrollInfo->Page = 0; horzScrollInfo->MaxVal = 100; horzScrollInfo->flags = ESB_ENABLE_BOTH; } return horzScrollInfo; case SB_VERT: if (!vertScrollInfo) { vertScrollInfo = (SCROLLBAR_INFO*)malloc(sizeof(SCROLLBAR_INFO)); if (!vertScrollInfo) break; vertScrollInfo->MinVal = vertScrollInfo->CurVal = vertScrollInfo->Page = 0; vertScrollInfo->MaxVal = 100; vertScrollInfo->flags = ESB_ENABLE_BOTH; } return vertScrollInfo; } return NULL; } //****************************************************************************** //****************************************************************************** LRESULT Win32BaseWindow::DefWndControlColor(UINT ctlType, HDC hdc) { //SvL: Set background color to default button color (not window (white)) if(ctlType == CTLCOLOR_BTN) { SetBkColor(hdc, GetSysColor(COLOR_BTNFACE)); SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); return GetSysColorBrush(COLOR_BTNFACE); } //SvL: Set background color to default dialog color if window is dialog if((ctlType == CTLCOLOR_DLG || ctlType == CTLCOLOR_STATIC) && IsDialog()) { SetBkColor(hdc, GetSysColor(COLOR_BTNFACE)); SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); return GetSysColorBrush(COLOR_BTNFACE); } if( ctlType == CTLCOLOR_SCROLLBAR) { HBRUSH hb = GetSysColorBrush(COLOR_SCROLLBAR); COLORREF bk = GetSysColor(COLOR_3DHILIGHT); SetTextColor( hdc, GetSysColor(COLOR_3DFACE)); SetBkColor( hdc, bk); /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT * we better use 0x55aa bitmap brush to make scrollbar's background * look different from the window background. */ if (bk == GetSysColor(COLOR_WINDOW)) { return GetPattern55AABrush(); } UnrealizeObject( hb ); return (LRESULT)hb; } SetTextColor( hdc, GetSysColor(COLOR_WINDOWTEXT)); if ((ctlType == CTLCOLOR_EDIT) || (ctlType == CTLCOLOR_LISTBOX)) { SetBkColor( hdc, GetSysColor(COLOR_WINDOW) ); } else { SetBkColor( hdc, GetSysColor(COLOR_3DFACE) ); return (LRESULT)GetSysColorBrush(COLOR_3DFACE); } return (LRESULT)GetSysColorBrush(COLOR_WINDOW); } //****************************************************************************** //****************************************************************************** LRESULT Win32BaseWindow::DefWndPrint(HDC hdc,ULONG uFlags) { /* * Visibility flag. */ if ( (uFlags & PRF_CHECKVISIBLE) && !IsWindowVisible(getWindowHandle()) ) return 0; /* * Unimplemented flags. */ if ( (uFlags & PRF_CHILDREN) || (uFlags & PRF_OWNED) || (uFlags & PRF_NONCLIENT) ) { dprintf(("WM_PRINT message with unsupported flags\n")); } /* * Background */ if ( uFlags & PRF_ERASEBKGND) SendMessageA(getWindowHandle(),WM_ERASEBKGND, (WPARAM)hdc, 0); /* * Client area */ if ( uFlags & PRF_CLIENT) SendMessageA(getWindowHandle(),WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT); return 0; } //****************************************************************************** //****************************************************************************** LRESULT Win32BaseWindow::DefWindowProcA(UINT Msg, WPARAM wParam, LPARAM lParam) { dprintf(("DefWndProc: winmsg: %x for %x Msg %s", Msg, Win32Hwnd, GetMsgText(/*HIWORD(lParam)*/Msg))); switch(Msg) { case WM_CLOSE: dprintf(("DefWindowProcA: WM_CLOSE %x", getWindowHandle())); DestroyWindow(); return 0; case WM_GETTEXTLENGTH: return windowNameLengthA; case WM_GETTEXT: if (!lParam || !wParam) return 0; if (!windowNameA) ((LPSTR)lParam)[0] = 0; else lstrcpynA(( LPSTR )lParam, windowNameA, wParam ); return strlen(( LPSTR )lParam ); case WM_SETTEXT: { LPCSTR lpsz = (LPCSTR)lParam; // reallocate if new buffer is larger if (!lParam) { free(windowNameA); free(windowNameW); windowNameLengthA = 0; windowNameLengthW = 0; windowNameA = NULL; windowNameW = NULL; } else { if (windowNameA) { free(windowNameA); windowNameA = NULL; } if (windowNameW) { free(windowNameW); windowNameW = NULL; } windowNameLengthA = strlen( lpsz ); windowNameA = (LPSTR)_smalloc(windowNameLengthA+1); strcpy(windowNameA, lpsz); windowNameLengthW = lstrlenAtoW( lpsz, -1 ); windowNameW = (LPWSTR)_smalloc(( windowNameLengthW + 1 )*sizeof(WCHAR)); lstrcpyAtoW( windowNameW, windowNameA ); } dprintf(("WM_SETTEXT of %x to %s\n", Win32Hwnd, lParam)); if ((dwStyle & WS_CAPTION) == WS_CAPTION) { HandleNCPaint((HRGN)1); if(hTaskList) { OSLibWinChangeTaskList(hTaskList, OS2HwndFrame, getWindowNameA(), (getStyle() & WS_VISIBLE) ? 1 : 0); } if(fOS2Look) { OSLibWinSetTitleBarText(OS2HwndFrame, getWindowNameA()); } } return TRUE; } case WM_SETREDRAW: { if (wParam) { setStyle(getStyle() | WS_VISIBLE); dprintf(("Enable window update for %x", getWindowHandle())); OSLibWinEnableWindowUpdate(OS2HwndFrame, OS2Hwnd, TRUE); } else { if (getStyle() & WS_VISIBLE) { setStyle(getStyle() & ~WS_VISIBLE); dprintf(("Disable window update for %x", getWindowHandle())); OSLibWinEnableWindowUpdate(OS2HwndFrame, OS2Hwnd, FALSE); } } return 0; } case WM_CTLCOLORMSGBOX: case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: case WM_CTLCOLORBTN: case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: case WM_CTLCOLORSCROLLBAR: return DefWndControlColor(Msg - WM_CTLCOLORMSGBOX, (HDC)wParam); case WM_CTLCOLOR: return DefWndControlColor(HIWORD(lParam), (HDC)wParam); case WM_VKEYTOITEM: case WM_CHARTOITEM: return -1; case WM_PARENTNOTIFY: return 0; case WM_MOUSEACTIVATE: { HWND hwnd = getWindowHandle(); dprintf(("DefWndProc: WM_MOUSEACTIVATE for %x Msg %s", Win32Hwnd, GetMsgText(HIWORD(lParam)))); if (::GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) { LONG ret = ::SendMessageW( ::GetParent(hwnd), WM_MOUSEACTIVATE, wParam, lParam ); if (ret) return ret; } /* Caption clicks are handled by the NC_HandleNCLButtonDown() */ return (LOWORD(lParam) >= HTCLIENT) ? MA_ACTIVATE : MA_NOACTIVATE; } case WM_ACTIVATE: /* The default action in Windows is to set the keyboard focus to * the window, if it's being activated and not minimized */ if (LOWORD(wParam) != WA_INACTIVE) { if(!(getStyle() & WS_MINIMIZE)) SetFocus(getWindowHandle()); } return 0; case WM_SETCURSOR: { dprintf(("DefWndProc: WM_SETCURSOR for %x Msg %s", Win32Hwnd, GetMsgText(HIWORD(lParam)))); if((getStyle() & WS_CHILD)) { if(getParent()) { LRESULT rc = SendMessageA(getParent()->getWindowHandle(), WM_SETCURSOR, wParam, lParam); if(rc) return rc; } } if (wParam == getWindowHandle()) { HCURSOR hCursor; switch(LOWORD(lParam)) { case HTCLIENT: hCursor = windowClass ? windowClass->getCursor():LoadCursorA(0,IDC_ARROWA); break; case HTLEFT: case HTRIGHT: hCursor = LoadCursorA(0,IDC_SIZEWEA); break; case HTTOP: case HTBOTTOM: hCursor = LoadCursorA(0,IDC_SIZENSA); break; case HTTOPLEFT: case HTBOTTOMRIGHT: hCursor = LoadCursorA(0,IDC_SIZENWSEA); break; case HTTOPRIGHT: case HTBOTTOMLEFT: hCursor = LoadCursorA(0,IDC_SIZENESWA); break; default: hCursor = LoadCursorA(0,IDC_ARROWA); break; } if (hCursor) { SetCursor(hCursor); return 1; } else return 0; } else return 0; } case WM_MOUSEMOVE: return 0; case WM_MOUSEWHEEL: if (::GetWindowLongA( getWindowHandle(), GWL_STYLE ) & WS_CHILD) return ::SendMessageA( ::GetParent(getWindowHandle()), WM_MOUSEWHEEL, wParam, lParam ); break; case WM_WINDOWPOSCHANGED: { PWINDOWPOS wpos = (PWINDOWPOS)lParam; WPARAM wp = SIZE_RESTORED; //According to Wine these are always sent, but experiments in Windows NT4, SP6 //show otherwise if (!(wpos->flags & SWP_NOMOVE) && !(wpos->flags & SWP_NOCLIENTMOVE)) { SendMessageA(getWindowHandle(),WM_MOVE, 0, MAKELONG(rectClient.left,rectClient.top)); } //According to Wine these are always sent, but experiments in Windows NT4, SP6 //show otherwise if (!(wpos->flags & SWP_NOSIZE) && !(wpos->flags & SWP_NOCLIENTSIZE)) { if (dwStyle & WS_MAXIMIZE) wp = SIZE_MAXIMIZED; else if (dwStyle & WS_MINIMIZE) wp = SIZE_MINIMIZED; SendMessageA(getWindowHandle(),WM_SIZE, wp, MAKELONG(rectClient.right - rectClient.left, rectClient.bottom - rectClient.top)); } return 0; } case WM_WINDOWPOSCHANGING: return HandleWindowPosChanging((WINDOWPOS *)lParam); case WM_ERASEBKGND: case WM_ICONERASEBKGND: { HBRUSH hBrush; RECT rect; int rc; if (!windowClass || (!windowClass->getBackgroundBrush() && !(getStyle() & WS_MINIMIZE))) return 0; //PF For PM desktop/MDI icons allocate brush as well to avoid //garbage in icons if (!windowClass->getBackgroundBrush()) hBrush = GetStockObject(GRAY_BRUSH); else { hBrush = windowClass->getBackgroundBrush(); if (hBrush <= (HBRUSH)(SYSCOLOR_GetLastColor()+1)) hBrush = GetSysColorBrush(hBrush-1); } rc = GetClipBox( (HDC)wParam, &rect ); if ((rc == SIMPLEREGION) || (rc == COMPLEXREGION)) FillRect( (HDC)wParam, &rect, hBrush); return 1; } case WM_PRINT: return DefWndPrint(wParam,lParam); case WM_SYNCPAINT: RedrawWindow(getWindowHandle(), NULL, 0, RDW_ERASENOW | RDW_ERASE | RDW_ALLCHILDREN); return 0; case WM_PAINTICON: case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(getWindowHandle(), &ps ); if( hdc ) { if( (getStyle() & WS_MINIMIZE) && (getWindowClass()->getIcon() || hIcon)) { int x = (rectWindow.right - rectWindow.left - GetSystemMetrics(SM_CXICON))/2; int y = (rectWindow.bottom - rectWindow.top - GetSystemMetrics(SM_CYICON))/2; dprintf(("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, hIcon ? hIcon:getWindowClass()->getIcon() ); } EndPaint(getWindowHandle(), &ps ); } return 0; } case WM_GETDLGCODE: return 0; case WM_NCPAINT: return HandleNCPaint((HRGN)wParam); case WM_NCACTIVATE: return HandleNCActivate(wParam); case WM_NCCREATE: return(TRUE); case WM_NCDESTROY: return 0; case WM_NCCALCSIZE: return HandleNCCalcSize((BOOL)wParam,(RECT*)lParam); case WM_NCLBUTTONDOWN: return HandleNCLButtonDown(wParam,lParam); case WM_LBUTTONDBLCLK: case WM_NCLBUTTONDBLCLK: return HandleNCLButtonDblClk(wParam,lParam); case WM_NCRBUTTONDOWN: case WM_NCRBUTTONDBLCLK: case WM_NCMBUTTONDOWN: case WM_NCMBUTTONDBLCLK: if (lastHitTestVal == HTERROR) MessageBeep(MB_ICONEXCLAMATION); return 0; case WM_NCRBUTTONUP: return HandleNCRButtonUp(wParam,lParam); case WM_NCMBUTTONUP: return 0; case WM_NCHITTEST: { POINT point; LRESULT retvalue; point.x = (SHORT)LOWORD(lParam); point.y = (SHORT)HIWORD(lParam); retvalue = HandleNCHitTest(point); #if 0 //CB: let the Corel people fix the bugs first if(retvalue == HTMENU) MENU_TrackMouseMenuBar_MouseMove(Win32Hwnd,point,TRUE); else MENU_TrackMouseMenuBar_MouseMove(Win32Hwnd,point,FALSE); #endif dprintf(("Hittest: %X", retvalue)); return retvalue; } case WM_SYSCOMMAND: { POINT point; point.x = LOWORD(lParam); point.y = HIWORD(lParam); return HandleSysCommand(wParam,&point); } 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 top = GetTopParent(); if (!(GetClassLongW( top, GCL_STYLE ) & CS_NOCLOSE)) PostMessageW( top, WM_SYSCOMMAND, SC_CLOSE, 0 ); } //Default OS/2 app behaviour for system keys if(fOS2Look) { if( wParam == VK_F5 ) /* try to restore the window */ { HWND top = GetTopParent(); /* No checks needed SC_RESTORE handler does them */ PostMessageW( top, WM_SYSCOMMAND, SC_RESTORE, 0 ); } if( wParam == VK_F7 ) /* size the window */ { HWND top = GetTopParent(); PostMessageW( top, WM_SYSCOMMAND, SC_MOVE, 0 ); } if( wParam == VK_F8 ) /* move the window */ { HWND top = GetTopParent(); if ( GetWindowLongA(top, GWL_STYLE) & WS_SIZEBOX) PostMessageW( top, WM_SYSCOMMAND, SC_SIZE, 0 ); } if( wParam == VK_F9 ) /* try to minimize the window */ { HWND top = GetTopParent(); if ( GetWindowLongA(top, GWL_STYLE) & WS_MINIMIZEBOX) PostMessageW( top, WM_SYSCOMMAND, SC_MINIMIZE, 0 ); } if( wParam == VK_F10 ) /* try to maximize the window */ { HWND top = GetTopParent(); if ( GetWindowLongA(top, GWL_STYLE) & WS_MAXIMIZEBOX) PostMessageW( top, WM_SYSCOMMAND, SC_MAXIMIZE, 0 ); } } } else if( wParam == VK_F10 ) iF10Key = 1; else if( wParam == VK_ESCAPE && (GetKeyState(VK_SHIFT) & 0x8000)) SendMessageW(getWindowHandle(), WM_SYSCOMMAND, SC_KEYMENU, VK_SPACE ); return 0; } case WM_KEYUP: //Single Alt down + up always generates WM_SYSKEYUP iMenuSysKey = 0; // no break; case WM_SYSKEYUP: /* Press and release F10 or ALT */ if (((wParam == VK_MENU) && iMenuSysKey) || ((wParam == VK_F10) && iF10Key)) ::SendMessageW( GetTopParent(), WM_SYSCOMMAND, SC_KEYMENU, 0L ); iMenuSysKey = iF10Key = 0; break; case WM_SYSCHAR: { iMenuSysKey = 0; if (wParam == VK_RETURN && (getStyle() & WS_MINIMIZE)) { PostMessageA(getWindowHandle(), WM_SYSCOMMAND, (WPARAM)SC_RESTORE, 0L ); break; } if((HIWORD(lParam) & KEYDATA_ALT) && wParam) { if (wParam == VK_TAB || wParam == VK_ESCAPE || wParam == VK_F4) break; if (wParam == VK_SPACE && (getStyle() & WS_CHILD)) { ::SendMessageW(GetParent(), Msg, wParam, lParam ); } else ::SendMessageA(getWindowHandle(), WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)wParam ); } #if 0 else /* check for Ctrl-Esc */ if (wParam != VK_ESCAPE) MessageBeep(0); break; #endif } case WM_SETHOTKEY: hotkey = wParam; return 1; //CB: always successful case WM_GETHOTKEY: return hotkey; case WM_RBUTTONUP: { POINT pt; pt.x = SLOWORD(lParam); pt.y = SHIWORD(lParam); ClientToScreen(getWindowHandle(), &pt); SendMessageA( getWindowHandle(), WM_CONTEXTMENU, getWindowHandle(),MAKELPARAM(pt.x, pt.y) ); } break; case WM_CONTEXTMENU: if ((dwStyle & WS_CHILD) && getParent()) SendMessageA(getParent()->getWindowHandle(), WM_CONTEXTMENU,wParam,lParam); else { LONG hitcode; POINT pt; if (!GetSysMenu()) return 0; pt.x = SLOWORD(lParam); pt.y = SHIWORD(lParam); hitcode = HandleNCHitTest(pt); /* Track system popup if click was in the caption area. */ if (hitcode==HTCAPTION || hitcode==HTSYSMENU) TrackPopupMenu(GetSysMenu(), TPM_LEFTBUTTON | TPM_RIGHTBUTTON, pt.x, pt.y, 0, getWindowHandle(), NULL); } return 0; case WM_SHOWWINDOW: if (!lParam) return 0; /* sent from ShowWindow */ if (!(dwStyle & WS_POPUP) || !owner) return 0; if ((dwStyle & WS_VISIBLE) && wParam) return 0; else if (!(dwStyle & WS_VISIBLE) && !wParam) return 0; ShowWindow(wParam ? SW_SHOW:SW_HIDE); return 0; case WM_CANCELMODE: if (getParent() == windowDesktop) EndMenu(); if (GetCapture() == Win32Hwnd) ReleaseCapture(); return 0; case WM_DROPOBJECT: return DRAG_FILE; case WM_QUERYDROPOBJECT: return (dwExStyle & WS_EX_ACCEPTFILES) ? 1:0; case WM_QUERYDRAGICON: { HICON hDragIcon = windowClass->getCursor(); UINT len; if(hDragIcon) return (LRESULT)hDragIcon; for(len = 1; len < 64; len++) { hDragIcon = LoadIconA(hInstance,MAKEINTRESOURCEA(len)); if(hDragIcon) return (LRESULT)hDragIcon; } return (LRESULT)LoadIconA(0,IDI_APPLICATIONA); } case WM_QUERYOPEN: case WM_QUERYENDSESSION: return 1; case WM_NOTIFYFORMAT: return IsWindowUnicode() ? NFR_UNICODE:NFR_ANSI; case WM_SETICON: case WM_GETICON: { LRESULT result = 0; /* Set the appropriate icon members in the window structure. */ if (wParam == ICON_SMALL) { result = hIconSm; if (Msg == WM_SETICON) hIconSm = (HICON)lParam; } else { result = hIcon; if (Msg == WM_SETICON) { hIcon = (HICON)lParam; if ((dwStyle & WS_CAPTION) == WS_CAPTION) OSLibWinSetIcon(OS2HwndFrame,hIcon); } } if ((Msg == WM_SETICON) && ((dwStyle & WS_CAPTION) == WS_CAPTION)) HandleNCPaint((HRGN)1); return result; } case WM_HELP: if (getParent()) SendMessageA(getParent()->getWindowHandle(), Msg,wParam,lParam); break; case WM_NOTIFY: return 0; //comctl32 controls expect this case WM_IME_CHAR: if( wParam & 0xFF00 ) // DBCS ? SendMessageA( getWindowHandle(), WM_CHAR, ( WPARAM )( BYTE )( wParam >> 8 ), lParam ); SendMessageA( getWindowHandle(), WM_CHAR, ( WPARAM )( BYTE )( wParam & 0xFF ), lParam ); break; default: return 0; } return 0; } //****************************************************************************** //****************************************************************************** LRESULT Win32BaseWindow::DefWindowProcW(UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_GETTEXTLENGTH: return windowNameLengthW; case WM_GETTEXT: if (!lParam || !wParam) return 0; if (!windowNameW) ((LPWSTR)lParam)[0] = 0; else lstrcpynW(( LPWSTR )lParam, windowNameW, wParam ); return strlenW(( LPWSTR )lParam ); case WM_SETTEXT: { LPWSTR lpsz = (LPWSTR)lParam; // reallocate if new buffer is larger if (!lParam) { free(windowNameA); free(windowNameW); windowNameLengthA = 0; windowNameLengthW = 0; windowNameA = NULL; windowNameW = NULL; } else { if (windowNameA) { free(windowNameA); windowNameA = NULL; } if (windowNameW) { free(windowNameW); windowNameW = NULL; } windowNameLengthW = lstrlenW( lpsz ); windowNameW = (LPWSTR)_smalloc((windowNameLengthW+1)*sizeof(WCHAR)); strcpyW(windowNameW, lpsz); windowNameLengthA = lstrlenWtoA( lpsz, -1 ); windowNameA = (LPSTR)_smalloc( windowNameLengthA + 1 ); lstrcpyWtoA( windowNameA, windowNameW ); } dprintf(("WM_SETTEXT of %x to %s\n", Win32Hwnd, windowNameA)); if ((dwStyle & WS_CAPTION) == WS_CAPTION) { HandleNCPaint((HRGN)1); if(hTaskList) { OSLibWinChangeTaskList(hTaskList, OS2HwndFrame, getWindowNameA(), (getStyle() & WS_VISIBLE) ? 1 : 0); } if(fOS2Look) { OSLibWinSetTitleBarText(OS2HwndFrame, getWindowNameA()); } } return TRUE; } case WM_IME_CHAR: SendMessageW( getWindowHandle(), WM_CHAR, wParam, lParam ); return 0; default: return DefWindowProcA(Msg, wParam, lParam); } } //****************************************************************************** //****************************************************************************** void Win32BaseWindow::NotifyParent(UINT Msg, WPARAM wParam, LPARAM lParam) { Win32BaseWindow *window = this; Win32BaseWindow *parentwindow; while(window) { if(window->getStyle() & WS_CHILD && !(window->getExStyle() & WS_EX_NOPARENTNOTIFY) ) { /* Notify the parent window only */ parentwindow = window->getParent(); if(parentwindow) { /* PF We should map points for each window accordingly! */ if (Msg == WM_LBUTTONDOWN || Msg == WM_MBUTTONDOWN || Msg == WM_RBUTTONDOWN || Msg == WM_LBUTTONUP || Msg == WM_MBUTTONUP || Msg == WM_RBUTTONUP) { POINTS pt = MAKEPOINTS(lParam); POINT point; point.x = pt.x; point.y = pt.y; MapWindowPoints(getWindowHandle(),parentwindow->getWindowHandle(), &point, 1); lParam = MAKELPARAM(point.x, point.y); wParam = MAKEWPARAM(Msg, 0 /* undefined according to MSDN, 0 under XP */); } else { lParam = getWindowHandle(); wParam = MAKEWPARAM(Msg, getWindowId()); } SendMessageA(parentwindow->getWindowHandle(), WM_PARENTNOTIFY, wParam, lParam); } } else break; window = parentwindow; } } //****************************************************************************** // Returns the big or small icon for the window, falling back to the // class as windows does. //****************************************************************************** HICON Win32BaseWindow::IconForWindow(WPARAM fType) { HICON hWndIcon; if (fType == ICON_BIG) { if (hIcon) hWndIcon = hIcon; else if (windowClass && windowClass->getIcon()) hWndIcon = windowClass->getIcon(); else if (!(dwStyle & DS_MODALFRAME)) {//SvL: load it as shared or else we'll leak icons hWndIcon = LoadImageA(0,MAKEINTRESOURCEA(OIC_ODINICON),IMAGE_ICON,0,0,LR_DEFAULTCOLOR|LR_SHARED); } else hWndIcon = 0; } else { if (hIconSm) hWndIcon = hIconSm; else if (hIcon) hWndIcon = hIcon; else if (windowClass && windowClass->getIconSm()) hWndIcon = windowClass->getIconSm(); else if (windowClass && windowClass->getIcon()) hWndIcon = windowClass->getIcon(); else if (!(dwStyle & DS_MODALFRAME)) {//SvL: load it as shared or else we'll leak icons hWndIcon = LoadImageA(0,MAKEINTRESOURCEA(OIC_ODINICON),IMAGE_ICON,0,0,LR_DEFAULTCOLOR|LR_SHARED); } else hWndIcon = 0; } return hWndIcon; } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::ShowWindow(ULONG nCmdShow) { ULONG swp = 0; HWND hWinAfter; BOOL rc,wasVisible,showFlag; RECT newPos = {0, 0, 0, 0}; dprintf(("ShowWindow %x %x", getWindowHandle(), nCmdShow)); wasVisible = (getStyle() & WS_VISIBLE) != 0; dwOldStyle = getStyle(); /* * SW_SHOWDEFAULT is an reference to the startup info wShowWindow member. */ if (nCmdShow == SW_SHOWDEFAULT) { nCmdShow = GetProcessDword(0, GPD_STARTF_SHOWWINDOW); dprintf(("ShowWindow: GetProcessDword(0, GPD_STARTF_SHOWWINDOW) -> %x", nCmdShow)); } switch(nCmdShow) { case SW_HIDE: if (!wasVisible) goto END; 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( !(getStyle() & WS_MINIMIZE) ) { swp |= MinMaximize(SW_MINIMIZE, &newPos ); fMinMaxChange = TRUE; //-> invalidate entire window in WM_CALCINVALIDRECT } else swp |= SWP_NOSIZE | SWP_NOMOVE; break; case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */ swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED; if( !(getStyle() & WS_MAXIMIZE) ) { swp |= MinMaximize(SW_MAXIMIZE, &newPos ); fMinMaxChange = TRUE; //-> invalidate entire window in WM_CALCINVALIDRECT } 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; /* * ShowWindow has a little peculiar behavior that if the * window is already the topmost window, it will not * activate it. */ if (::GetTopWindow((HWND)0)==getWindowHandle() && (wasVisible || GetActiveWindow() == getWindowHandle())) swp |= SWP_NOACTIVATE; break; case SW_SHOWNOACTIVATE: swp |= SWP_NOZORDER | SWP_NOACTIVATE; /* fall through */ case SW_SHOWNORMAL: /* same as SW_NORMAL: */ case SW_SHOWDEFAULT: /* FIXME: should have its own handler */ case SW_RESTORE: dprintf(("ShowWindow:restoring window")); swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED; if( getStyle() & (WS_MINIMIZE | WS_MAXIMIZE) ) { swp |= MinMaximize(SW_RESTORE, &newPos ); fMinMaxChange = TRUE; //-> invalidate entire window in WM_CALCINVALIDRECT } else swp |= SWP_NOSIZE | SWP_NOMOVE; break; } showFlag = (nCmdShow != SW_HIDE); if (showFlag != wasVisible) { SendMessageA(getWindowHandle(),WM_SHOWWINDOW, showFlag, 0 ); if (!::IsWindow( getWindowHandle() )) goto END; } /* We can't activate a child window */ if((getStyle() & WS_CHILD) && !(getExStyle() & WS_EX_MDICHILD)) swp |= SWP_NOACTIVATE | SWP_NOZORDER; if (!(getStyle() & WS_MINIMIZE)) { SetWindowPos(HWND_TOP, newPos.left, newPos.top, newPos.right, newPos.bottom, LOWORD(swp), TRUE); } else OSLibWinMinimizeWindow(getOS2FrameWindowHandle()); if(!(swp & SWP_NOACTIVATE) && (!(getStyle() & WS_MINIMIZE))) { OSLibWinSetActiveWindow(OS2HwndFrame); } if (flags & WIN_NEED_SIZE) { /* should happen only in CreateWindowEx() */ int wParam = SIZE_RESTORED; flags &= ~WIN_NEED_SIZE; if (dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED; else if (dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED; SendMessageA(getWindowHandle(),WM_SIZE, wParam, MAKELONG(rectClient.right-rectClient.left, rectClient.bottom-rectClient.top)); SendMessageA(getWindowHandle(),WM_MOVE,0,MAKELONG(rectClient.left,rectClient.top)); } //testestest //temporary workaround for file dialogs with template dialog child //they don't redraw when switching directories //For some reason the new child's (syslistview32) update rectangle stays //empty after its parent is made visible with ShowWindow //TODO: find real cause if(!wasVisible) { InvalidateRect(getWindowHandle(), NULL, TRUE); } //testestest END: fMinMaxChange = FALSE; return wasVisible; } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::SetWindowPos(HWND hwndInsertAfter, int x, int y, int cx, int cy, UINT fuFlags, BOOL fShowWindow) { BOOL rc = FALSE; Win32BaseWindow *window; HWND hParent = 0; RECT oldClientRect = rectClient; if (fuFlags & ~(SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_DEFERERASE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_ASYNCWINDOWPOS)) { dprintf(("ERROR: SetWindowPos; UNKNOWN flag")); return FALSE; } if( fuFlags & (SWP_DEFERERASE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_ASYNCWINDOWPOS)) { dprintf(("WARNING: SetWindowPos; unsupported flag")); } if(IsWindowDestroyed()) { //changing the position of a window that's being destroyed can cause crashes in PMMERGE dprintf(("SetWindowPos; window already destroyed")); return TRUE; } if(state >= STATE_CREATED) { /* Fix redundant flags */ if(getStyle() & WS_VISIBLE) { fuFlags &= ~SWP_SHOWWINDOW; } else { if (!(fuFlags & SWP_SHOWWINDOW)) fuFlags |= SWP_NOREDRAW; fuFlags &= ~SWP_HIDEWINDOW; } //SvL: These checks are causing problems in Lotus Notes 6 // It's not entirely clear why, but child windows are not placed // correctly when enabling them. #if 0 if((rectWindow.right - rectWindow.left == cx) && (rectWindow.bottom - rectWindow.top == cy)) { fuFlags |= SWP_NOSIZE; /* Already the right size */ } if((rectWindow.left == x) && (rectWindow.top == y)) { fuFlags |= SWP_NOMOVE; /* Already the right position */ } #endif if(getWindowHandle() == GetActiveWindow()) { fuFlags |= SWP_NOACTIVATE; /* Already active */ } else if((getStyle() & (WS_POPUP | WS_CHILD)) != WS_CHILD ) { if(!(fuFlags & SWP_NOACTIVATE)) /* Bring to the top when activating */ { fuFlags &= ~SWP_NOZORDER; hwndInsertAfter = HWND_TOP; } } } /* TODO: Check hwndInsertAfter */ //Note: Solitaire crashes when receiving WM_SIZE messages before WM_CREATE if(state < STATE_POST_WMNCCREATE) {//don't change size; modify internal structures only //TODO: not 100% correct yet (activate) dprintf2(("state < STATE_POST_WMNCCREATE")); if(!(fuFlags & SWP_NOZORDER)) { hwndLinkAfter = hwndInsertAfter; } if(!(fuFlags & SWP_NOMOVE)) { rectWindow.bottom = (rectWindow.bottom - rectWindow.top) + y; rectWindow.top = y; rectWindow.right = (rectWindow.right - rectWindow.left) + x; rectWindow.left = x; } if(!(fuFlags & SWP_NOSIZE)) { rectWindow.bottom = rectWindow.top + cy; rectWindow.right = rectWindow.left + cx; } return TRUE; } WINDOWPOS wpos; SWP swp, swpOld; wpos.flags = fuFlags; wpos.cy = cy; wpos.cx = cx; wpos.x = x; wpos.y = y; wpos.hwndInsertAfter = hwndInsertAfter; wpos.hwnd = getWindowHandle(); if(~fuFlags & (SWP_NOMOVE | SWP_NOSIZE)) { if (isChild()) { if(!getParent()) { dprintf(("WARNING: Win32BaseWindow::SetWindowPos window %x is child but has no parent!!", getWindowHandle())); } } OSLibWinQueryWindowPos(OS2HwndFrame, &swpOld); } if((dwOldStyle & WS_MINIMIZE) && (getStyle() & WS_MINIMIZE)) {//don't allow size changes if the window is minimized //we will update the restore position at the end of this method if(!(wpos.flags & SWP_NOSIZE)) { //TODO: updating the window rectangle doesn't look right wpos.flags |= SWP_NOSIZE; rectWindow.right = rectWindow.left + wpos.cx; rectWindow.bottom = rectWindow.top + wpos.cy; dprintf(("WARNING: Don't allow size change for minimized window; only save new restore position")); dprintf(("new window rectangle (%d,%d)(%d,%d)", rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom)); } } // Hack alert: This makes sure the tooltips windows in OpenOffice don't // activate the owner windows too. // First condition takes care of SetWindowPos during window // creation. The 2nd one for calls made by OpenOffice if(((getStyle() & WS_POPUP) && (getExStyle() & WS_EX_TOPMOST)) || (fuFlags & SWP_NOOWNERZORDER)) { //SWP_NOOWNERZORDER means only the z-order of this window changes; it //should not affect the owner //PM doesn't support this feature, so this hack might work wpos.flags |= SWP_NOZORDER; } if(getParent()) { OSLibMapWINDOWPOStoSWP(&wpos, &swp, &swpOld, getParent()->getClientHeight(), OS2HwndFrame); } else OSLibMapWINDOWPOStoSWP(&wpos, &swp, &swpOld, OSLibQueryScreenHeight(), OS2HwndFrame); if (swp.fl == 0) { dprintf2(("swp.fl == 0")); if(fuFlags & SWP_FRAMECHANGED) { NotifyFrameChanged(&wpos, &oldClientRect); } if(!fShowWindow && !(getStyle() & (WS_MINIMIZE|WS_MAXIMIZE)) && !(fuFlags & (SWP_NOSIZE | SWP_NOMOVE))) { //Restore position always changes when the window position is changed dprintf(("Save new restore position %x (%d,%d)(%d,%d)", getWindowHandle(), rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom)); windowpos.rcNormalPosition = rectWindow; } return TRUE; } // if ((swp.fl & SWPOS_ZORDER) && (swp.hwndInsertBehind > HWNDOS_BOTTOM)) if ((swp.hwndInsertBehind > HWNDOS_BOTTOM)) { Win32BaseWindow *wndBehind = Win32BaseWindow::GetWindowFromHandle(swp.hwndInsertBehind); if(wndBehind) { swp.hwndInsertBehind = wndBehind->getOS2FrameWindowHandle(); RELEASE_WNDOBJ(wndBehind); } else { dprintf(("ERROR: SetWindowPos: hwndInsertBehind %x invalid!",swp.hwndInsertBehind)); swp.hwndInsertBehind = 0; } } swp.hwnd = OS2HwndFrame; //SvL: Must also deactivate the window when hiding it or else focus won't // change. (NOTE: make sure this doesn't cause regressions (01-02-2003) if((swp.fl & (SWPOS_HIDE|SWPOS_DEACTIVATE)) == (SWPOS_HIDE|SWPOS_DEACTIVATE)) { //we must make sure the owner is not disabled or else the focus will //be switched to the wrong window Win32BaseWindow *topOwner; if(getOwner() == NULL) { windowDesktop->addRef(); topOwner = windowDesktop; } else topOwner = GetWindowFromHandle(getOwner()->GetTopParent()); if(topOwner != NULL) { DWORD dwStyle = topOwner->GetWindowLong(GWL_STYLE, FALSE); if(dwStyle & WS_DISABLED) { swp.fl &= ~SWPOS_DEACTIVATE; } } else DebugInt3(); } if(fuFlags & SWP_SHOWWINDOW && !IsWindowVisible(getWindowHandle())) { setStyle(getStyle() | WS_VISIBLE); if(hTaskList) { dprintf(("Adding window %x to tasklist", getWindowHandle())); OSLibWinChangeTaskList(hTaskList, OS2HwndFrame, getWindowNameA(), 1); } } else if((fuFlags & SWP_HIDEWINDOW) && IsWindowVisible(getWindowHandle())) { setStyle(getStyle() & ~WS_VISIBLE); if(hTaskList && !(getStyle() & WS_MINIMIZE)) { dprintf(("Removing window %x from tasklist", getWindowHandle())); OSLibWinChangeTaskList(hTaskList, OS2HwndFrame, getWindowNameA(), 0); } } dprintf (("WinSetWindowPos %x %x (%d,%d)(%d,%d) %x", swp.hwnd, swp.hwndInsertBehind, swp.x, swp.y, swp.cx, swp.cy, swp.fl)); rc = OSLibWinSetMultWindowPos(&swp, 1); if(rc == FALSE) { dprintf(("OSLibWinSetMultWindowPos failed! Error %x",OSLibWinGetLastError())); return 0; } if((fuFlags & SWP_FRAMECHANGED) && (fuFlags & (SWP_NOMOVE | SWP_NOSIZE) == (SWP_NOMOVE | SWP_NOSIZE))) { NotifyFrameChanged(&wpos, &oldClientRect); } if(!fShowWindow && !(getStyle() & (WS_MINIMIZE|WS_MAXIMIZE))) { //Restore position always changes when the window position is changed dprintf(("Save new restore position %x (%d,%d)(%d,%d)", getWindowHandle(), rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom)); windowpos.rcNormalPosition = rectWindow; } //MSDN says the entire client area will be invalidated when SWP_NOCOPYBITS //is specified (fixes repaint issues when window is made smaller) if((fuFlags & (SWP_NOCOPYBITS|SWP_NOREDRAW)) == SWP_NOCOPYBITS) { InvalidateRect(getWindowHandle(), NULL, TRUE); } if(!(fuFlags & SWP_NOSIZE)) { // We must call this function or open DC will get out of sync // (PM will not always send us a WM_VRNENABLED message) RecalcVisibleRegion(this); } return (rc); } //****************************************************************************** //Called by ScrollWindowEx (dc.cpp) to notify child window that it has moved //****************************************************************************** BOOL Win32BaseWindow::ScrollWindow(int dx, int dy) { rectWindow.left += dx; rectWindow.right += dx; rectWindow.top += dy; rectWindow.bottom += dy; SendMessageA(getWindowHandle(),WM_MOVE, 0, MAKELONG(rectClient.left, rectClient.top)); return TRUE; } //****************************************************************************** //****************************************************************************** void Win32BaseWindow::NotifyFrameChanged(WINDOWPOS *wpos, RECT *oldClientRect) { HRGN hrgn, hrgnClient; RECT rect; MsgFormatFrame(NULL); if(RECT_WIDTH(rectClient) != RECT_WIDTH(*oldClientRect) || RECT_HEIGHT(rectClient) != RECT_HEIGHT(*oldClientRect)) { wpos->flags &= ~(SWP_NOSIZE|SWP_NOCLIENTSIZE); wpos->cx = RECT_WIDTH(rectWindow); wpos->cy = RECT_HEIGHT(rectWindow); } if(rectClient.left != oldClientRect->left || rectClient.top != oldClientRect->top) { wpos->flags &= ~(SWP_NOMOVE|SWP_NOCLIENTMOVE); wpos->x = rectWindow.left; wpos->y = rectWindow.top; } WINDOWPOS wpOld = *wpos; if(!(wpos->flags & SWP_NOSENDCHANGING)) SendMessageA(getWindowHandle(),WM_WINDOWPOSCHANGING, 0, (LPARAM)wpos); if ((wpos->hwndInsertAfter != wpOld.hwndInsertAfter) || (wpos->x != wpOld.x) || (wpos->y != wpOld.y) || (wpos->cx != wpOld.cx) || (wpos->cy != wpOld.cy) || (wpos->flags != wpOld.flags)) { dprintf(("WARNING, NotifyFrameChanged: TODO -> adjust flags!!!!")); SetWindowPos(wpos->hwndInsertAfter, wpos->x, wpos->y, wpos->cx, wpos->cy, wpos->flags | SWP_NOSENDCHANGING); } else SendMessageA(getWindowHandle(),WM_WINDOWPOSCHANGED, 0, (LPARAM)wpos); //Calculate invalid areas rect = rectWindow; OffsetRect(&rect, -rectWindow.left, -rectWindow.top); hrgn = CreateRectRgnIndirect(&rect); if (!hrgn) { dprintf(("ERROR: NotifyFrameChanged, CreateRectRgnIndirect failed!!")); return; } rect = rectClient; hrgnClient = CreateRectRgnIndirect(&rect); if (!hrgn) { dprintf(("ERROR: NotifyFrameChanged, CreateRectRgnIndirect failed!!")); return; } CombineRgn(hrgn, hrgn, hrgnClient, RGN_DIFF); DeleteObject(hrgnClient); if(!EqualRect(oldClientRect, &rectClient)) { UnionRect(oldClientRect, oldClientRect, &rectClient); hrgnClient = CreateRectRgnIndirect(oldClientRect); if (!hrgn) { dprintf(("ERROR: NotifyFrameChanged, CreateRectRgnIndirect failed!!")); return; } CombineRgn(hrgn, hrgn, hrgnClient, RGN_OR); DeleteObject(hrgnClient); } RedrawWindow(getWindowHandle(), NULL, hrgn, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_FRAME); DeleteObject(hrgn); } //****************************************************************************** //TODO: Check how this api really works in NT //****************************************************************************** BOOL Win32BaseWindow::SetWindowPlacement(WINDOWPLACEMENT *wndpl) { dprintf(("SetWindowPlacement %x min (%d,%d)", getWindowHandle(), wndpl->ptMinPosition.x, wndpl->ptMinPosition.y)); dprintf(("SetWindowPlacement %x max (%d,%d)", getWindowHandle(), wndpl->ptMaxPosition.x, wndpl->ptMaxPosition.y)); dprintf(("SetWindowPlacement %x norm (%d,%d)(%d,%d)", getWindowHandle(), wndpl->rcNormalPosition.left, wndpl->rcNormalPosition.top, wndpl->rcNormalPosition.right, wndpl->rcNormalPosition.bottom)); windowpos.ptMinPosition = wndpl->ptMinPosition; windowpos.ptMaxPosition = wndpl->ptMaxPosition; windowpos.rcNormalPosition = wndpl->rcNormalPosition; if(getStyle() & WS_MINIMIZE ) { //TODO: Why can't this be (0,0)? if(wndpl->flags & WPF_SETMINPOSITION && !(!windowpos.ptMinPosition.x && !windowpos.ptMinPosition.y)) { SetWindowPos(0, windowpos.ptMinPosition.x, windowpos.ptMinPosition.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } } else if(getStyle() & WS_MAXIMIZE ) { //TODO: Why can't this be (0,0)? if(windowpos.ptMaxPosition.x != 0 || windowpos.ptMaxPosition.y != 0 ) SetWindowPos(0, windowpos.ptMaxPosition.x, windowpos.ptMaxPosition.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } else { SetWindowPos(0, windowpos.rcNormalPosition.left, windowpos.rcNormalPosition.top, windowpos.rcNormalPosition.right - windowpos.rcNormalPosition.left, windowpos.rcNormalPosition.bottom - windowpos.rcNormalPosition.top, SWP_NOZORDER | SWP_NOACTIVATE ); } ShowWindow(wndpl->showCmd); if( ::IsWindow(getWindowHandle()) && getStyle() & WS_MINIMIZE ) { /* SDK: ...valid only the next time... */ if(wndpl->flags & WPF_RESTORETOMAXIMIZED) setFlags(getFlags() | WIN_RESTORE_MAX); } return TRUE; } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::GetWindowPlacement(LPWINDOWPLACEMENT wndpl) { wndpl->length = sizeof(*wndpl); if(getStyle() & WS_MINIMIZE ) wndpl->showCmd = SW_SHOWMINIMIZED; else wndpl->showCmd = (getStyle() & WS_MAXIMIZE) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL; //TODO: Verify if this is correct -> SDK docs claim this flag must always be set to 0 if(getFlags() & WIN_RESTORE_MAX ) wndpl->flags = WPF_RESTORETOMAXIMIZED; else wndpl->flags = 0; wndpl->ptMinPosition = windowpos.ptMinPosition; wndpl->ptMaxPosition = windowpos.ptMaxPosition; //Must be in parent coordinates (or screen if no parent); verified in NT4, SP6 wndpl->rcNormalPosition = windowpos.rcNormalPosition; return TRUE; } //****************************************************************************** //Also destroys all the child windows (destroy children first, parent last) //TODO: Don't rely on PM to do the right thing. Send WM_(NC)DESTROY & // destroy children ourselves (see Wine) //****************************************************************************** BOOL Win32BaseWindow::DestroyWindow() { HWND hwnd = getWindowHandle(); dprintf(("DestroyWindow %x", hwnd)); #if 0 /* Look whether the focus is within the tree of windows we will * be destroying. */ HWND hwndFocus = GetFocus(); if (hwndFocus == hwnd || ::IsChild( hwnd, hwndFocus )) { HWND parent = GetAncestor( hwnd, GA_PARENT ); if (parent == GetDesktopWindow()) parent = 0; SetFocus( parent ); } #endif /* Call hooks */ if(HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, getWindowHandle(), 0L)) { return FALSE; } if(!(getStyle() & WS_CHILD) && getOwner() == NULL) { HOOK_CallHooksA(WH_SHELL, HSHELL_WINDOWDESTROYED, getWindowHandle(), 0L); /* FIXME: clean up palette - see "Internals" p.352 */ } if((getStyle() & WS_CHILD) && !(getExStyle() & WS_EX_NOPARENTNOTIFY)) { if(getParent() && getParent()->IsWindowDestroyed() == FALSE) { /* Notify the parent window only */ SendMessageA(getParent()->getWindowHandle(), WM_PARENTNOTIFY, MAKEWPARAM(WM_DESTROY, getWindowId()), (LPARAM)getWindowHandle()); if(!::IsWindow(hwnd) ) { return TRUE; } } //// else DebugInt3(); } //Must remove the switch entry here to avoid problems with XWorkPlace if(hTaskList) { OSLibWinRemoveFromTasklist(hTaskList); hTaskList = 0; } /* Hide the window */ if(IsWindowVisible(getWindowHandle())) { SetWindowPos(0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE); if(!::IsWindow(hwnd)) { return TRUE; } } dprintf(("DestroyWindow %x -> HIDDEN", hwnd)); // check the handle for the last active popup window Win32BaseWindow* owner = getOwner(); if (NULL != owner) { if (owner->getLastActive() == hwnd) owner->setLastActive( owner->getWindowHandle() ); //SvL: Not sure this is correct, but it solves the problem of reassigning // activation. A disabled window will never be activated -> // possible that the wrong window is chosen by PM. // PM chooses another window to be activated before WM_DESTROY is // sent. VPC enables the owner when it receives that message, // but by then it's too late. // (MFC created modeless dialog) //TODO: This might be the wrong place to do it. EndDialog is called, // so perhaps it should be done there. (although Wine only // enables the owner if the dialog is modal) ::EnableWindow(owner->getWindowHandle(), 1); } fDestroyWindowCalled = TRUE; //hack alert; PM crashes if child calls DestroyWindow for parent/owner in WM_DESTROY // handler; must postpone it if(fChildDestructionInProgress) { dprintf(("Postponing parent destruction because of dying child")); OSLibPostMessageDirect(OS2HwndFrame, WIN32APP_POSTPONEDESTROY, 0, 0); return TRUE; } BOOL fOldChildDestructionInProgress = FALSE; if(GetParent()) { Win32BaseWindow *window = Win32BaseWindow::GetWindowFromHandle(GetParent()); if(window) { fOldChildDestructionInProgress = window->IsChildDestructionInProgress(); window->SetChildDestructionInProgress(TRUE); RELEASE_WNDOBJ(window); } } //hack end BOOL ret = OSLibWinDestroyWindow(OS2HwndFrame); //hack alert; PM crashes if child calls DestroyWindow for parent/owner in WM_DESTROY // handler; must postpone it if(GetParent()) { Win32BaseWindow *window = Win32BaseWindow::GetWindowFromHandle(GetParent()); if(window) { window->SetChildDestructionInProgress(fOldChildDestructionInProgress); RELEASE_WNDOBJ(window); } } //hack end return ret; } //****************************************************************************** //****************************************************************************** Win32BaseWindow *Win32BaseWindow::getParent() { Win32BaseWindow *wndparent = (Win32BaseWindow *)ChildWindow::getParentOfChild(); //experiment #if 0 return ((ULONG)wndparent == (ULONG)windowDesktop) ? NULL : wndparent; #else return wndparent; #endif } //****************************************************************************** // Win32BaseWindow::GetParent // // If the window is a child window, then return the parent window handle. // If it's a popup window, then return the owner // // Returns window handle of parent or owner window // // Note: does not set last error if no parent (verified in NT4, SP6) //****************************************************************************** HWND Win32BaseWindow::GetParent() { Win32BaseWindow *wndparent = (Win32BaseWindow *)ChildWindow::getParentOfChild(); if(getStyle() & WS_CHILD) { if(wndparent) { return wndparent->getWindowHandle(); } dprintf(("WARNING: GetParent: WS_CHILD but no parent!!")); DebugInt3(); return 0; } else if(getStyle() & WS_POPUP) return (getOwner()) ? getOwner()->getWindowHandle() : 0; else return 0; } //****************************************************************************** //****************************************************************************** HWND Win32BaseWindow::SetParent(HWND hwndNewParent) { HWND oldhwnd; Win32BaseWindow *newparent; Win32BaseWindow *oldparent = (Win32BaseWindow *)ChildWindow::getParentOfChild(); BOOL fShow = FALSE; if(oldparent) { oldhwnd = oldparent->getWindowHandle(); oldparent->removeChild(this); } else oldhwnd = 0; /* Windows hides the window first, then shows it again * including the WM_SHOWWINDOW messages and all */ if(IsWindowCreated() && (getStyle() & WS_VISIBLE)) { ShowWindow(SW_HIDE); fShow = TRUE; } if(oldparent) { //release parent here (increased refcount during creation) RELEASE_WNDOBJ(oldparent); } newparent = GetWindowFromHandle(hwndNewParent); if(newparent && !newparent->isDesktopWindow()) { setParent(newparent); getParent()->addChild(this); fParentChange = TRUE; // in case we haven't finished creating the window whose parent we're // setting here, the OS/2 HWND might not exist yet and we call the PM // API with a NULLHANDLE - no problem // when we create the OS/2 window lateron, we will create it with the // right parent anyway. OSLibWinSetParent(getOS2FrameWindowHandle(), getParent()->getOS2WindowHandle()); if(!(getStyle() & WS_CHILD)) { if(getWindowId()) { DestroyMenu( (HMENU) getWindowId() ); setWindowId(0); } } //SvL: Even though the win32 coordinates might not change, the PM // coordinates can. We must make sure the control stays at the // same position (y) relative to the (new) parent. // TODO: shouldn't we check the state of the window and not do it in INIT state? SetWindowPos(HWND_TOPMOST, rectWindow.left, rectWindow.top, 0, 0, SWP_NOACTIVATE|SWP_NOSIZE); fParentChange = FALSE; } else { if(newparent) RELEASE_WNDOBJ(newparent); setParent(windowDesktop); windowDesktop->addRef(); windowDesktop->addChild(this); OSLibWinSetParent(getOS2FrameWindowHandle(), OSLIB_HWND_DESKTOP); //Do not change the window id! //// setWindowId(0); } /* SetParent additionally needs to make hwndChild the topmost window in the x-order and send the expected WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED notification messages. */ if(state >= STATE_PRE_WMNCCREATE) { SetWindowPos(HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|(fShow? SWP_SHOWWINDOW : 0)); /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */ } return oldhwnd; } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::IsChild(HWND hwndParent) { // PH: Optimizer won't unroll calls to getParent() even // in release build. Win32BaseWindow *_parent = getParent(); if(_parent) { if(_parent->getWindowHandle() == hwndParent) return TRUE; return _parent->IsChild(hwndParent); } else return 0; } //****************************************************************************** //****************************************************************************** HWND Win32BaseWindow::GetTopWindow() { HWND hwndTop; Win32BaseWindow *topwindow; hwndTop = OSLibWinQueryWindow(getOS2WindowHandle(), QWOS_TOP); if(!isDesktopWindow()) { topwindow = GetWindowFromOS2FrameHandle(hwndTop); //Note: GetTopWindow can't return a window that hasn't processed // WM_NCCREATE yet (verified in NT4, SP6) if(topwindow) { if(topwindow->state >= STATE_POST_WMNCCREATE) { hwndTop = topwindow->getWindowHandle(); } else hwndTop = topwindow->GetWindow(GW_HWNDNEXT); RELEASE_WNDOBJ(topwindow); return hwndTop; } if(topwindow) RELEASE_WNDOBJ(topwindow); return 0; } while(hwndTop) { topwindow = GetWindowFromOS2FrameHandle(hwndTop); //Note: GetTopWindow can't return a window that hasn't processed // WM_NCCREATE yet (verified in NT4, SP6) if(topwindow) { if(topwindow->state >= STATE_POST_WMNCCREATE) { hwndTop = topwindow->getWindowHandle(); } else hwndTop = topwindow->GetWindow(GW_HWNDNEXT); RELEASE_WNDOBJ(topwindow); return hwndTop; } if(topwindow) RELEASE_WNDOBJ(topwindow); hwndTop = OSLibWinQueryWindow(hwndTop, QWOS_NEXT); } return 0; } //****************************************************************************** // Get the top-level parent for a child window. //****************************************************************************** HWND Win32BaseWindow::GetTopParent() { Win32BaseWindow *window = this; HWND hwndTopParent = 0; lock(); while(window && (window->getStyle() & WS_CHILD)) { window = window->getParent(); } if(window) { hwndTopParent = window->getWindowHandle(); } unlock(); return hwndTopParent; } //****************************************************************************** //TODO: Should not enumerate children that are created during the enumeration! //TODO: Do this more efficiently //****************************************************************************** BOOL Win32BaseWindow::EnumChildWindows(WNDENUMPROC lpfn, LPARAM lParam) { BOOL rc = TRUE; HWND hwnd; Win32BaseWindow *prevchild = 0, *child = 0; dprintf(("EnumChildWindows of %x parameter %x %x (%x)", getWindowHandle(), lpfn, lParam, getFirstChild())); lock(); for (child = (Win32BaseWindow *)getFirstChild(); child != NULL; child = (Win32BaseWindow *)child->getNextChild()) { dprintf(("EnumChildWindows: enumerating child %x (owner %x; parent %x)", child->getWindowHandle(), (child->getOwner()) ? child->getOwner()->getWindowHandle() : 0, getWindowHandle())); hwnd = child->getWindowHandle(); if(child->IsWindowDestroyed() || child->getOwner()) { continue; //shouldn't have an owner (Wine) } child->addRef(); unlock(); if(WrapCallback2((WNDPROC)lpfn, hwnd, lParam) == FALSE) { child->release(); return FALSE; } child->release(); lock(); //check if the window still exists if(!::IsWindow(hwnd)) { child = prevchild; if(child == NULL) break; continue; } if(child->getFirstChild() != NULL) { dprintf(("EnumChildWindows: Enumerate children of %x", child->getWindowHandle())); child->addRef(); unlock(); if(child->EnumChildWindows(lpfn, lParam) == FALSE) { child->release(); return FALSE; } child->release(); lock(); } prevchild = child; } unlock(); return rc; } //****************************************************************************** //Enumerate first-level children only and check thread id //NOTE: NT4 returns first-level children in Z-order! //****************************************************************************** BOOL Win32BaseWindow::EnumThreadWindows(DWORD dwThreadId, WNDENUMPROC lpfn, LPARAM lParam) { Win32BaseWindow *wnd = NULL; HWND henum, hwnd, hwndWin32; ULONG tid, pid; BOOL rc; //Enumerate all top-level windows and check the process and thread ids henum = OSLibWinBeginEnumWindows(OSLIB_HWND_DESKTOP); hwnd = OSLibWinGetNextWindow(henum); while(hwnd) { wnd = GetWindowFromOS2FrameHandle(hwnd); if(wnd) { hwndWin32 = wnd->getWindowHandle(); } else hwndWin32 = 0; if(wnd) RELEASE_WNDOBJ(wnd); if(hwndWin32) { OSLibWinQueryWindowProcess(hwnd, &pid, &tid); if(dwThreadId == tid) { dprintf(("EnumThreadWindows: Found Window %x", hwndWin32)); if((rc = WrapCallback2((WNDPROC)lpfn, hwndWin32, lParam)) == FALSE) { break; } } } hwnd = OSLibWinGetNextWindow(henum); } OSLibWinEndEnumWindows(henum); return TRUE; } //****************************************************************************** //Enumerate first-level children only //****************************************************************************** BOOL Win32BaseWindow::EnumWindows(WNDENUMPROC lpfn, LPARAM lParam) { Win32BaseWindow *window; BOOL rc; HWND hwnd = WNDHANDLE_MAGIC_HIGHWORD; DWORD dwStyle; dprintf(("EnumWindows %x %x", lpfn, lParam)); for(int i=0;igetWindowHandle() != hwnd) { dprintf(("CORRUPT WINDOW %x %x", window, hwnd)); } RELEASE_WNDOBJ(window); dwStyle = ::GetWindowLongA(hwnd, GWL_STYLE); if ((dwStyle & WS_POPUP) || ((dwStyle & WS_CAPTION) == WS_CAPTION)) { dprintf2(("EnumWindows: Found Window %x", hwnd)); if((rc = WrapCallback2((WNDPROC)lpfn, hwnd, lParam)) == FALSE) { break; } } } hwnd++; } return TRUE; } //****************************************************************************** //****************************************************************************** HWND Win32BaseWindow::FindWindowById(int id) { HWND hwnd; lock(); for (Win32BaseWindow *child = (Win32BaseWindow *)getFirstChild(); child; child = (Win32BaseWindow *)child->getNextChild()) { if (child->getWindowId() == id) { hwnd = child->getWindowHandle(); unlock(); return hwnd; } } unlock(); return 0; } //****************************************************************************** //TODO: //We assume (for now) that if hwndParent or hwndChildAfter are real window handles, that //the current process owns them. //****************************************************************************** HWND Win32BaseWindow::FindWindowEx(HWND hwndParent, HWND hwndChildAfter, ATOM atom, LPSTR lpszWindow) { Win32BaseWindow *parent = GetWindowFromHandle(hwndParent); Win32BaseWindow *child = GetWindowFromHandle(hwndChildAfter); Win32BaseWindow *firstchild = child; dprintf(("FindWindowEx %x %x %x %s", hwndParent, hwndChildAfter, atom, lpszWindow)); if((hwndParent != 0 && !parent) || (hwndChildAfter != 0 && !child) || (hwndParent == 0 && hwndChildAfter != 0)) { if(parent) RELEASE_WNDOBJ(parent); if(firstchild) RELEASE_WNDOBJ(firstchild); dprintf(("Win32BaseWindow::FindWindowEx: parent or child not found %x %x", hwndParent, hwndChildAfter)); SetLastError(ERROR_INVALID_WINDOW_HANDLE); return 0; } SetLastError(0); if(hwndParent != 0) {//if the current process owns the window, just do a quick search lock(&critsect); child = (Win32BaseWindow *)parent->getFirstChild(); if(hwndChildAfter != 0) { while(child) { if(child->getWindowHandle() == hwndChildAfter) { child = (Win32BaseWindow *)child->getNextChild(); break; } child = (Win32BaseWindow *)child->getNextChild(); } } while(child) { //According to Wine, the class doesn't need to be specified if((!atom || child->getWindowClass()->getAtom() == atom) && (!lpszWindow || child->hasWindowName(lpszWindow))) { dprintf(("FindWindowEx: Found window %x", child->getWindowHandle())); HWND hwndChild = child->getWindowHandle(); unlock(&critsect); if(parent) RELEASE_WNDOBJ(parent); if(firstchild) RELEASE_WNDOBJ(firstchild); dprintf(("FindWindowEx: Found window %x", child->getWindowHandle())); return hwndChild; } child = (Win32BaseWindow *)child->getNextChild(); } unlock(&critsect); if(parent) RELEASE_WNDOBJ(parent); if(firstchild) RELEASE_WNDOBJ(firstchild); } else { Win32BaseWindow *wnd; HWND henum, hwnd; henum = OSLibWinBeginEnumWindows(OSLIB_HWND_DESKTOP); hwnd = OSLibWinGetNextWindow(henum); while(hwnd) { wnd = GetWindowFromOS2FrameHandle(hwnd); if(wnd) { //According to Wine, the class doesn't need to be specified if((!atom || wnd->getWindowClass()->getAtom() == atom) && (!lpszWindow || wnd->hasWindowName(lpszWindow))) { OSLibWinEndEnumWindows(henum); dprintf(("FindWindowEx: Found window %x", wnd->getWindowHandle())); HWND hwndret = wnd->getWindowHandle(); RELEASE_WNDOBJ(wnd); return hwndret; } RELEASE_WNDOBJ(wnd); } hwnd = OSLibWinGetNextWindow(henum); } OSLibWinEndEnumWindows(henum); if(parent) RELEASE_WNDOBJ(parent); if(firstchild) RELEASE_WNDOBJ(firstchild); } SetLastError(ERROR_CANNOT_FIND_WND_CLASS); //TODO: not always correct return 0; } //****************************************************************************** //****************************************************************************** HWND Win32BaseWindow::GetWindow(UINT uCmd) { HWND hwndRelated = 0; Win32BaseWindow *window; switch(uCmd) { case GW_HWNDFIRST: window = (Win32BaseWindow *)getParent(); if(window) { hwndRelated = OSLibWinQueryWindow(window->getOS2WindowHandle(), QWOS_TOP); window = GetWindowFromOS2FrameHandle(hwndRelated); if(window) { hwndRelated = window->getWindowHandle(); RELEASE_WNDOBJ(window); } else hwndRelated = 0; } else { dprintf(("WARNING: GW_HWNDFIRST not correctly implemented for toplevel/most windows!")); hwndRelated = 0; //TODO: not correct; should get first child in z-order of desktop } break; case GW_HWNDLAST: window = (Win32BaseWindow *)getParent(); if(window) { hwndRelated = OSLibWinQueryWindow(window->getOS2WindowHandle(), QWOS_BOTTOM); dprintf(("os2 handle %x", hwndRelated)); window = GetWindowFromOS2FrameHandle(hwndRelated); if(window) { hwndRelated = window->getWindowHandle(); RELEASE_WNDOBJ(window); } else hwndRelated = 0; } else { dprintf(("WARNING: GW_HWNDLAST not correctly implemented for toplevel/most windows!")); hwndRelated = 0; //TODO: not correct; should get first child in z-order of desktop } break; case GW_HWNDNEXT: if(getParent()) { hwndRelated = OSLibWinQueryWindow(getOS2FrameWindowHandle(), QWOS_NEXT); window = GetWindowFromOS2FrameHandle(hwndRelated); if(window) { hwndRelated = window->getWindowHandle(); RELEASE_WNDOBJ(window); } else hwndRelated = 0; } else { dprintf(("WARNING: GW_HWNDNEXT not correctly implemented for toplevel/most windows!")); hwndRelated = 0; //TODO: not correct; should get first child in z-order of desktop } break; case GW_HWNDPREV: if(getParent()) { hwndRelated = OSLibWinQueryWindow(getOS2FrameWindowHandle(), QWOS_PREV); window = GetWindowFromOS2FrameHandle(hwndRelated); if(window) { hwndRelated = window->getWindowHandle(); RELEASE_WNDOBJ(window); } else hwndRelated = 0; } else { dprintf(("WARNING: GW_HWNDPREV not correctly implemented for toplevel/most windows!")); hwndRelated = 0; //TODO: not correct; should get first child in z-order of desktop } break; case GW_OWNER: { Win32BaseWindow *owner = getOwner(); if(owner) { hwndRelated = owner->getWindowHandle(); } break; } case GW_CHILD: hwndRelated = OSLibWinQueryWindow(getOS2WindowHandle(), QWOS_TOP); window = GetWindowFromOS2FrameHandle(hwndRelated); //Before a window has processed WM_NCCREATE: //- GetWindow(parent, GW_CHILD) can't return that window handle //(verified in NT4, SP6) if(window) { if(window->state >= STATE_POST_WMNCCREATE) { hwndRelated = window->getWindowHandle(); RELEASE_WNDOBJ(window); } else { hwndRelated = window->GetWindow(GW_HWNDNEXT); RELEASE_WNDOBJ(window); } } else hwndRelated = 0; break; //for internal use only case GW_HWNDNEXTCHILD: lock(); window = (Win32BaseWindow *)getNextChild(); if(window) { hwndRelated = window->getWindowHandle(); } else hwndRelated = 0; unlock(); break; case GW_HWNDPREVCHILD: DebugInt3(); break; case GW_HWNDFIRSTCHILD: lock(); window = (Win32BaseWindow *)getFirstChild(); if(window) { hwndRelated = window->getWindowHandle(); } else hwndRelated = 0; unlock(); break; case GW_HWNDLASTCHILD: lock(); window = (Win32BaseWindow *)getFirstChild(); if(window) { while (window->getNextChild()) { window = (Win32BaseWindow *)window->getNextChild(); } hwndRelated = window->getWindowHandle(); } else hwndRelated = 0; unlock(); break; } end: dprintf(("GetWindow %x %d returned %x", getWindowHandle(), uCmd, hwndRelated)); return hwndRelated; } //****************************************************************************** //****************************************************************************** PRECT Win32BaseWindow::getWindowRect() { return &rectWindow; } //****************************************************************************** //****************************************************************************** HWND Win32BaseWindow::SetActiveWindow() { HWND hwndActive; dprintf(("SetActiveWindow %x", getWindowHandle())); if(getStyle() & WS_CHILD) { // if(getStyle() & (WS_DISABLED | WS_CHILD)) { dprintf(("WARNING: Window is a child or disabled")); return 0; } if(GetActiveWindow() == getWindowHandle()) { dprintf(("Window already active")); return getWindowHandle(); } if (HOOK_IsHooked( WH_CBT )) { CBTACTIVATESTRUCT cbta; LRESULT ret; cbta.fMouse = FALSE; cbta.hWndActive = GetActiveWindow(); ret = HOOK_CallHooksA(WH_CBT, HCBT_ACTIVATE, getWindowHandle(), (LPARAM)&cbta); if(ret) { dprintf(("SetActiveWindow %x, CBT hook cancelled operation", getWindowHandle())); return cbta.hWndActive; } } SetWindowPos(HWND_TOP, 0,0,0,0, SWP_NOSIZE | SWP_NOMOVE ); // if(OSLibWinSetActiveWindow(OS2Hwnd) == FALSE) { // dprintf(("OSLibWinSetActiveWindow %x returned FALSE!", OS2Hwnd)); // } hwndActive = GetActiveWindow(); return (hwndActive) ? hwndActive : windowDesktop->getWindowHandle(); //pretend the desktop was active } //****************************************************************************** //Used to change active status of an mdi window //****************************************************************************** BOOL Win32BaseWindow::DeactivateChildWindow() { /* child windows get a WM_CHILDACTIVATE message */ if((getStyle() & (WS_CHILD | WS_POPUP)) == WS_CHILD ) { ULONG flags = OSLibWinGetWindowULong(getOS2WindowHandle(), OFFSET_WIN32FLAGS); OSLibWinSetWindowULong(getOS2WindowHandle(), OFFSET_WIN32FLAGS, (flags & ~WINDOWFLAG_ACTIVE)); return TRUE; } DebugInt3(); //should not be called for non-child window return FALSE; } //****************************************************************************** //WM_ENABLE is sent to hwnd, but not to its children (as it should be) //****************************************************************************** BOOL Win32BaseWindow::EnableWindow(BOOL fEnable) { BOOL rc; dprintf(("Win32BaseWindow::EnableWindow %x %d", getWindowHandle(), fEnable)); //return true if previous state was disabled, else false (sdk docs) rc = (getStyle() & WS_DISABLED) != 0; if(rc && !fEnable) { SendMessageA(getWindowHandle(), WM_CANCELMODE, 0, 0); } OSLibWinEnableWindow(OS2HwndFrame, fEnable); if(fEnable == FALSE) { //SvL: No need to clear focus as PM already does this if(getWindowHandle() == GetCapture()) { ReleaseCapture(); /* A disabled window can't capture the mouse */ dprintf(("Released capture for window %x that is being disabled", getWindowHandle())); } } return rc; } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::CloseWindow() { if (::GetWindowLongW( getWindowHandle() , GWL_STYLE ) & WS_CHILD) return FALSE; ShowWindow( SW_MINIMIZE ); return TRUE; } //****************************************************************************** //TODO: Not be 100% correct; should return active window of current thread // or NULL when there is none -> WinQueryActiveWindow just returns // the current active window //****************************************************************************** HWND Win32BaseWindow::GetActiveWindow() { HWND hwndActive; hwndActive = OSLibWinQueryActiveWindow(); return OS2ToWin32Handle(hwndActive); } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::hasWindowName(LPSTR wndname, BOOL fUnicode) { INT len = GetWindowTextLength(fUnicode); BOOL res; if (wndname == NULL) return (len == 0); len++; if (fUnicode) { WCHAR *text = (WCHAR*)malloc(len*sizeof(WCHAR)); GetWindowTextW(text,len); res = (lstrcmpW(text,(LPWSTR)wndname) == 0); free(text); } else { CHAR *text = (CHAR*)malloc(len*sizeof(CHAR)); GetWindowTextA(text,len); res = (strcmp(text,wndname) == 0); free(text); } return res; } //****************************************************************************** //****************************************************************************** CHAR *Win32BaseWindow::getWindowNamePtrA() { INT len = GetWindowTextLength(FALSE); CHAR *text; if (len == 0) return NULL; len++; text = (CHAR*)malloc(len*sizeof(CHAR)); GetWindowTextA(text,len); return text; } //****************************************************************************** //****************************************************************************** WCHAR *Win32BaseWindow::getWindowNamePtrW() { INT len = GetWindowTextLength(TRUE); WCHAR *text; if (len == 0) return NULL; len++; text = (WCHAR*)malloc(len*sizeof(WCHAR)); GetWindowTextW(text,len); return text; } //****************************************************************************** //****************************************************************************** VOID Win32BaseWindow::freeWindowNamePtr(PVOID namePtr) { if (namePtr) free(namePtr); } //****************************************************************************** //When using this API for a window that was created by a different process, NT //does NOT send WM_GETTEXTLENGTH. //****************************************************************************** int Win32BaseWindow::GetWindowTextLength(BOOL fUnicode) { //if the destination window is created by this process, send message if(dwProcessId == currentProcessId) { if(fUnicode) { return SendMessageW(getWindowHandle(), WM_GETTEXTLENGTH,0,0); } else return SendMessageA(getWindowHandle(), WM_GETTEXTLENGTH,0,0); } //else get data directory from window structure //TODO: must lock window structure.... (TODO) return fUnicode ? windowNameLengthW : windowNameLengthA; } //****************************************************************************** //When using this API for a window that was created by a different process, NT //does NOT send WM_GETTEXT. //****************************************************************************** int Win32BaseWindow::GetWindowTextA(LPSTR lpsz, int cch) { //if the destination window is created by this process, send message if(dwProcessId == currentProcessId) { return SendMessageA(getWindowHandle(),WM_GETTEXT,(WPARAM)cch,(LPARAM)lpsz); } //else get data directory from window structure if (!lpsz || !cch) return 0; if (!windowNameA) lpsz[0] = 0; else lstrcpynA( lpsz, windowNameA, cch ); return strlen( lpsz ); } //****************************************************************************** //When using this API for a window that was created by a different process, NT //does NOT send WM_GETTEXT. //****************************************************************************** int Win32BaseWindow::GetWindowTextW(LPWSTR lpsz, int cch) { //if the destination window is created by this process, send message if(dwProcessId == currentProcessId) { return ::SendMessageW(getWindowHandle(), WM_GETTEXT,(WPARAM)cch,(LPARAM)lpsz); } //else get data directory from window structure if (!lpsz || !cch) return 0; if (!windowNameW) lpsz[0] = 0; else lstrcpynW( lpsz, windowNameW, cch ); return strlenW( lpsz ); } //****************************************************************************** //TODO: How does this work when the target window belongs to a different process??? //****************************************************************************** BOOL Win32BaseWindow::SetWindowTextA(LPSTR lpsz) { return SendMessageA(getWindowHandle(),WM_SETTEXT,0,(LPARAM)lpsz); } //****************************************************************************** //****************************************************************************** BOOL Win32BaseWindow::SetWindowTextW(LPWSTR lpsz) { return SendMessageW(getWindowHandle(), WM_SETTEXT,0,(LPARAM)lpsz); } //****************************************************************************** //****************************************************************************** LONG Win32BaseWindow::SetWindowLong(int index, ULONG value, BOOL fUnicode) { LONG oldval; switch(index) { case GWL_EXSTYLE: { STYLESTRUCT ss; if(dwExStyle == value) { oldval = value; break; } ss.styleOld = dwExStyle; ss.styleNew = value; dprintf(("SetWindowLong GWL_EXSTYLE %x old %x new style %x", getWindowHandle(), dwExStyle, value)); SendMessageA(getWindowHandle(),WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&ss); setExStyle(ss.styleNew); SendMessageA(getWindowHandle(),WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&ss); OSLibSetWindowStyle(getOS2FrameWindowHandle(), getOS2WindowHandle(), getStyle(), getExStyle(),ss.styleOld); oldval = ss.styleOld; break; } case GWL_STYLE: { STYLESTRUCT ss; //SvL: TODO: Can you change minimize or maximize status here too? if(dwStyle == value) { oldval = value; break; } dprintf(("SetWindowLong GWL_STYLE %x old %x new style %x (%x)", getWindowHandle(), dwStyle, value)); //Changing WS_CHILD style is allowed ss.styleOld = getStyle(); ss.styleNew = value; SendMessageA(getWindowHandle(),WM_STYLECHANGING,GWL_STYLE,(LPARAM)&ss); setStyle(ss.styleNew); SendMessageA(getWindowHandle(),WM_STYLECHANGED,GWL_STYLE,(LPARAM)&ss); OSLibSetWindowStyle(getOS2FrameWindowHandle(), getOS2WindowHandle(), getStyle(), getExStyle(),ss.styleOld); //TODO: Might not be correct to use ShowWindow here if((ss.styleOld & WS_VISIBLE) != (ss.styleNew & WS_VISIBLE)) { if(ss.styleNew & WS_VISIBLE) ShowWindow(SW_SHOWNOACTIVATE); else ShowWindow(SW_HIDE); } #ifdef DEBUG PrintWindowStyle(ss.styleNew, 0); #endif oldval = ss.styleOld; break; } case GWL_WNDPROC: { //Note: Type of SetWindowLong determines new window proc type // UNLESS the new window proc has already been registered // (use the old type in that case) // (VERIFIED in NT 4, SP6) WINDOWPROCTYPE type = WINPROC_GetProcType((HWINDOWPROC)value); if(type == WIN_PROC_INVALID) { type = (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A; } oldval = (LONG)WINPROC_GetProc((HWINDOWPROC)win32wndproc, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A); dprintf(("SetWindowLong%c GWL_WNDPROC %x old %x new wndproc %x", (fUnicode) ? 'W' : 'A', getWindowHandle(), oldval, value)); WINPROC_SetProc((HWINDOWPROC *)&win32wndproc, (WNDPROC)value, type, WIN_PROC_WINDOW); break; } case GWL_HINSTANCE: oldval = hInstance; hInstance = value; break; case GWL_HWNDPARENT: dprintf(("GWL_ID GWL_HWNDPARENT %x, new %x", GetParent(), value)); oldval = SetParent((HWND)value); break; case GWL_ID: dprintf(("GWL_ID old %x, new %x", getWindowId(), value)); oldval = getWindowId(); setWindowId(value); break; case GWL_USERDATA: oldval = userData; userData = value; break; default: if(index >= 0 && index + sizeof(ULONG) <= nrUserWindowBytes) { oldval = *(ULONG *)(userWindowBytes + index); *(ULONG *)(userWindowBytes + index) = value; break; } dprintf(("WARNING: SetWindowLong%c %x %d %x returned %x INVALID index!", (fUnicode) ? 'W' : 'A', getWindowHandle(), index, value)); SetLastError(ERROR_INVALID_INDEX); //verified in NT4, SP6 return 0; } //Note: NT4, SP6 does not set the last error to 0 SetLastError(ERROR_SUCCESS); dprintf2(("SetWindowLong%c %x %d %x returned %x", (fUnicode) ? 'W' : 'A', getWindowHandle(), index, value, oldval)); return oldval; } //****************************************************************************** //****************************************************************************** ULONG Win32BaseWindow::GetWindowLong(int index, BOOL fUnicode) { ULONG value; switch(index) { case GWL_EXSTYLE: value = dwExStyle; break; case GWL_STYLE: value = dwStyle; break; case GWL_WNDPROC: value = (LONG)WINPROC_GetProc((HWINDOWPROC)win32wndproc, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A); break; case GWL_HINSTANCE: value = hInstance; break; case GWL_HWNDPARENT: value = GetParent(); break; case GWL_ID: value = getWindowId(); break; case GWL_USERDATA: value = userData; break; default: if(index >= 0 && index + sizeof(ULONG) <= nrUserWindowBytes) { value = *(ULONG *)(userWindowBytes + index); break; } dprintf(("WARNING: GetWindowLong%c %x %d %x returned %x INVALID index!", (fUnicode) ? 'W' : 'A', getWindowHandle(), index, value)); SetLastError(ERROR_INVALID_INDEX); //verified in NT4, SP6 return 0; } dprintf2(("GetWindowLong%c %x %d %x", (fUnicode) ? 'W' : 'A', getWindowHandle(), index, value)); //Note: NT4, SP6 does not set the last error to 0 SetLastError(ERROR_SUCCESS); return value; } //****************************************************************************** //****************************************************************************** WORD Win32BaseWindow::SetWindowWord(int index, WORD value) { WORD oldval; if(index >= 0 && index + sizeof(WORD) <= nrUserWindowBytes) { oldval = *(WORD *)(userWindowBytes + index); *(WORD *)(userWindowBytes + index) = value; //Note: NT4, SP6 does not set the last error to 0 dprintf2(("SetWindowWord %x %d %x returned %x", getWindowHandle(), index, value, oldval)); SetLastError(ERROR_SUCCESS); return oldval; } switch(index) { case GWW_HINSTANCE: oldval = hInstance; hInstance = value; break; case GWW_HWNDPARENT: oldval = SetParent((HWND)(WNDHANDLE_MAGIC_HIGHWORD | value)); break; case GWW_ID: oldval = getWindowId(); setWindowId(value); break; default: dprintf(("WARNING: SetWindowWord %x %d %x returned %x INVALID index!", getWindowHandle(), index, value)); SetLastError(ERROR_INVALID_INDEX); //verified in NT4, SP6 return 0; } //Note: NT4, SP6 does not set the last error to 0 SetLastError(ERROR_SUCCESS); dprintf2(("SetWindowWord %x %d %x returned %x", getWindowHandle(), index, value, oldval)); return oldval; } //****************************************************************************** //****************************************************************************** WORD Win32BaseWindow::GetWindowWord(int index) { if(index >= 0 && index + sizeof(WORD) <= nrUserWindowBytes) { //Note: NT4, SP6 does not set the last error to 0 SetLastError(ERROR_SUCCESS); dprintf2(("GetWindowWord %x %d %x", getWindowHandle(), index, *(WORD *)(userWindowBytes + index))); return *(WORD *)(userWindowBytes + index); } switch(index) { case GWW_ID: if(HIWORD(getWindowId())) dprintf(("WARNING: GWW_ID: discards high bits of 0x%08x!\n", getWindowId())); return (WORD)getWindowId(); case GWW_HWNDPARENT: dprintf(("WARNING: GWW_HWNDPARENT: discards high bits of 0x%08x!\n", GetParent())); return (WORD) GetParent(); case GWW_HINSTANCE: if (HIWORD(hInstance)) dprintf(("WARNING: GWW_HINSTANCE: discards high bits of 0x%08x!\n", hInstance)); return (WORD)hInstance; } dprintf(("WARNING: GetWindowWord %x %d returned %x INVALID index!", getWindowHandle(), index)); SetLastError(ERROR_INVALID_INDEX); //verified in NT4, SP6 return 0; } //****************************************************************************** // Win32BaseWindow::setVisibleRgnNotifyProc // // Sets the visible region change notification handler. Called when // the window receives a WM_VRNDISABLED or WM_VRNENABLED message (PM). // // Parameters: // VISRGN_NOTIFY_PROC lpNotifyProc - notification handler // DWORD dwUserData - caller supplied parameter for handler invocations // // Returns: // TRUE - Success // FALSE - Failure // //****************************************************************************** BOOL Win32BaseWindow::setVisibleRgnNotifyProc(VISRGN_NOTIFY_PROC lpNotifyProc, DWORD dwUserData) { lpVisRgnNotifyProc = lpNotifyProc; dwVisRgnNotifyParam = dwUserData; return TRUE; } //****************************************************************************** // Win32BaseWindow::callVisibleRgnNotifyProc // // Call the visible region change notification handler. Called when // the window receives a WM_VRNDISABLED or WM_VRNENABLED message (PM). // // Parameters: // BOOL fDrawingAllowed - drawing is allowed or not // // Returns: // TRUE - Success // FALSE - Failure // //****************************************************************************** void Win32BaseWindow::callVisibleRgnNotifyProc(BOOL fDrawingAllowed) { if(fDrawingAllowed) { fWindowLocked = TRUE; } else { fWindowLocked = FALSE; } if(lpVisRgnNotifyProc) { lpVisRgnNotifyProc(getWindowHandle(), fDrawingAllowed, dwVisRgnNotifyParam); } } //****************************************************************************** // Win32BaseWindow::queryOpenDCs // // Return the DCs that are currently open for this window // // Parameters: // HDC *phdcWindow - pointer to HDC array (IN) // int chdcWindow - size of HDC array (IN) // int *pnrdcs - number of HDCs returned (OUT) // // Returns: // TRUE - Success // FALSE - Failure // //****************************************************************************** BOOL Win32BaseWindow::queryOpenDCs(HDC *phdcWindow, int chdcWindow, int *pnrdcs) { if(nrOpenDCs == 0) return FALSE; if(chdcWindow < nrOpenDCs) { DebugInt3(); return FALSE; } lock(&critsect); int j = 0; for(int i=0;igetRefCount()+1)); window->addRef(); } //// unlock(&critsect); return window; } //// unlock(&critsect); // dprintf2(("Win32BaseWindow::GetWindowFromHandle: not a win32 window %x", hwnd)); return NULL; } //****************************************************************************** //Locates window in linked list and increases reference count (if found) //Window object must be unreferenced after usage //****************************************************************************** Win32BaseWindow *Win32BaseWindow::GetWindowFromOS2Handle(HWND hwndOS2) { DWORD magic; HWND hwnd; if(hwndOS2 == OSLIB_HWND_DESKTOP) { windowDesktop->addRef(); return windowDesktop; } hwnd = (HWND)OSLibWinGetWindowULong(hwndOS2, OFFSET_WIN32WNDPTR); magic = OSLibWinGetWindowULong(hwndOS2, OFFSET_WIN32PM_MAGIC); if(hwnd && CheckMagicDword(magic)) { return GetWindowFromHandle(hwnd); } // dprintf2(("Win32BaseWindow::GetWindowFromOS2Handle: not an Odin os2 window %x", hwndOS2)); //Now check if it's a fake window Win32FakeWindow *window = Win32FakeWindow::GetWindowFromOS2Handle(hwndOS2); if(window) { return window; } return 0; } //****************************************************************************** //Locates window in linked list and increases reference count (if found) //Window object must be unreferenced after usage //****************************************************************************** Win32BaseWindow *Win32BaseWindow::GetWindowFromOS2FrameHandle(HWND hwnd) { return GetWindowFromOS2Handle(OSLibWinWindowFromID(hwnd,OSLIB_FID_CLIENT)); } //****************************************************************************** //****************************************************************************** HWND WIN32API Win32ToOS2Handle(HWND hwnd) { HWND hwndOS2; Win32BaseWindow *window = Win32BaseWindow::GetWindowFromHandle(hwnd); if(window) { hwndOS2 = window->getOS2WindowHandle(); RELEASE_WNDOBJ(window); return hwndOS2; } // dprintf2(("Win32BaseWindow::Win32ToOS2Handle: not a win32 window %x", hwnd)); return hwnd; } //****************************************************************************** //****************************************************************************** HWND WIN32API Win32ToOS2FrameHandle(HWND hwnd) { HWND hwndOS2; Win32BaseWindow *window = Win32BaseWindow::GetWindowFromHandle(hwnd); if(window) { hwndOS2 = window->getOS2FrameWindowHandle(); RELEASE_WNDOBJ(window); return hwndOS2; } // dprintf2(("Win32BaseWindow::Win32ToOS2Handle: not a win32 window %x", hwnd)); return hwnd; } //****************************************************************************** //****************************************************************************** HWND WIN32API OS2ToWin32Handle(HWND hwnd) { Win32BaseWindow *window = Win32BaseWindow::GetWindowFromOS2Handle(hwnd); HWND hwndWin32; if(window) { hwndWin32 = window->getWindowHandle(); RELEASE_WNDOBJ(window); return hwndWin32; } window = Win32BaseWindow::GetWindowFromOS2FrameHandle(hwnd); if(window) { hwndWin32 = window->getWindowHandle(); RELEASE_WNDOBJ(window); return hwndWin32; } // dprintf2(("Win32BaseWindow::OS2ToWin32Handle: not a win32 window %x", hwnd)); return 0; // else return hwnd; //OS/2 window handle } #ifdef DEBUG LONG Win32BaseWindow::addRef() { // dprintf2(("addRef %x %d", getWindowHandle(), getRefCount()+1)); return GenericObject::addRef(); } //****************************************************************************** //****************************************************************************** LONG Win32BaseWindow::release(const char *function, int line) { // dprintf2(("release %s %d %x %d", function, line, getWindowHandle(), getRefCount()-1)); return GenericObject::release(); } #endif //****************************************************************************** //****************************************************************************** GenericObject *Win32BaseWindow::windows = NULL; VMutex Win32BaseWindow::critsect; //****************************************************************************** //****************************************************************************** #ifdef DEBUG void PrintWindowStyle(DWORD dwStyle, DWORD dwExStyle) { char style[256] = ""; char exstyle[256] = ""; /* Window styles */ if(dwStyle & WS_CHILD) strcat(style, "WS_CHILD "); if(dwStyle & WS_POPUP) strcat(style, "WS_POPUP "); if(dwStyle & WS_VISIBLE) strcat(style, "WS_VISIBLE "); if(dwStyle & WS_DISABLED) strcat(style, "WS_DISABLED "); if(dwStyle & WS_CLIPSIBLINGS) strcat(style, "WS_CLIPSIBLINGS "); if(dwStyle & WS_CLIPCHILDREN) strcat(style, "WS_CLIPCHILDREN "); if(dwStyle & WS_MAXIMIZE) strcat(style, "WS_MAXIMIZE "); if(dwStyle & WS_MINIMIZE) strcat(style, "WS_MINIMIZE "); if(dwStyle & WS_GROUP) strcat(style, "WS_GROUP "); if(dwStyle & WS_TABSTOP) strcat(style, "WS_TABSTOP "); if((dwStyle & WS_CAPTION) == WS_CAPTION) strcat(style, "WS_CAPTION "); if(dwStyle & WS_DLGFRAME) strcat(style, "WS_DLGFRAME "); if(dwStyle & WS_BORDER) strcat(style, "WS_BORDER "); if(dwStyle & WS_VSCROLL) strcat(style, "WS_VSCROLL "); if(dwStyle & WS_HSCROLL) strcat(style, "WS_HSCROLL "); if(dwStyle & WS_SYSMENU) strcat(style, "WS_SYSMENU "); if(dwStyle & WS_THICKFRAME) strcat(style, "WS_THICKFRAME "); if(dwStyle & WS_MINIMIZEBOX) strcat(style, "WS_MINIMIZEBOX "); if(dwStyle & WS_MAXIMIZEBOX) strcat(style, "WS_MAXIMIZEBOX "); if(dwExStyle & WS_EX_DLGMODALFRAME) strcat(exstyle, "WS_EX_DLGMODALFRAME "); if(dwExStyle & WS_EX_ACCEPTFILES) strcat(exstyle, "WS_EX_ACCEPTFILES "); if(dwExStyle & WS_EX_NOPARENTNOTIFY) strcat(exstyle, "WS_EX_NOPARENTNOTIFY "); if(dwExStyle & WS_EX_TOPMOST) strcat(exstyle, "WS_EX_TOPMOST "); if(dwExStyle & WS_EX_TRANSPARENT) strcat(exstyle, "WS_EX_TRANSPARENT "); if(dwExStyle & WS_EX_MDICHILD) strcat(exstyle, "WS_EX_MDICHILD "); if(dwExStyle & WS_EX_TOOLWINDOW) strcat(exstyle, "WS_EX_TOOLWINDOW "); if(dwExStyle & WS_EX_WINDOWEDGE) strcat(exstyle, "WS_EX_WINDOWEDGE "); if(dwExStyle & WS_EX_CLIENTEDGE) strcat(exstyle, "WS_EX_CLIENTEDGE "); if(dwExStyle & WS_EX_CONTEXTHELP) strcat(exstyle, "WS_EX_CONTEXTHELP "); if(dwExStyle & WS_EX_RIGHT) strcat(exstyle, "WS_EX_RIGHT "); if(dwExStyle & WS_EX_LEFT) strcat(exstyle, "WS_EX_LEFT "); if(dwExStyle & WS_EX_RTLREADING) strcat(exstyle, "WS_EX_RTLREADING "); if(dwExStyle & WS_EX_LTRREADING) strcat(exstyle, "WS_EX_LTRREADING "); if(dwExStyle & WS_EX_LEFTSCROLLBAR) strcat(exstyle, "WS_EX_LEFTSCROLLBAR "); if(dwExStyle & WS_EX_RIGHTSCROLLBAR) strcat(exstyle, "WS_EX_RIGHTSCROLLBAR "); if(dwExStyle & WS_EX_CONTROLPARENT) strcat(exstyle, "WS_EX_CONTROLPARENT "); if(dwExStyle & WS_EX_STATICEDGE) strcat(exstyle, "WS_EX_STATICEDGE "); if(dwExStyle & WS_EX_APPWINDOW) strcat(exstyle, "WS_EX_APPWINDOW "); dprintf(("Window style: %x %s", dwStyle, style)); dprintf(("Window exStyle: %x %s", dwExStyle, exstyle)); } #endif //****************************************************************************** //******************************************************************************