diff options
Diffstat (limited to 'Src/Wasabi/api/wnd/basewnd.cpp')
-rw-r--r-- | Src/Wasabi/api/wnd/basewnd.cpp | 5743 |
1 files changed, 5743 insertions, 0 deletions
diff --git a/Src/Wasabi/api/wnd/basewnd.cpp b/Src/Wasabi/api/wnd/basewnd.cpp new file mode 100644 index 00000000..f24e4d6f --- /dev/null +++ b/Src/Wasabi/api/wnd/basewnd.cpp @@ -0,0 +1,5743 @@ +#include <precomp.h> + +#include <bfc/wasabi_std.h> +#include <bfc/wasabi_std_wnd.h> +#include <api/wnd/wndevent.h> + +#include <bfc/bfc_assert.h> +#include <api/wnd/wndclass/tooltip.h> +#include <api/wnd/cursor.h> +#include <api/wnd/accessible.h> +#include <api/service/svcs/svc_accessibility.h> +#include <api/wnd/paintsets.h> +#include <api/wnd/PaintCanvas.h> + +#ifdef _WIN32 +#include <shellapi.h> // for HDROP +#endif +#include <tataki/canvas/bltcanvas.h> + +#define DESKTOPALPHA +#define REFRESH_RATE 25 +#define DRAWTIMERID 125 + +#include <api/wnd/basewnd.h> +#include <api/wnd/usermsg.h> + +#include <api/wnd/paintcb.h> +#include <tataki/canvas/canvas.h> +#include <bfc/file/filename.h> +#include <tataki/region/region.h> +#include <api/wnd/wndclass/guiobjwnd.h> +#include <api/script/scriptguid.h> +#include <api/wnd/notifmsg.h> +#include <api/metrics/metricscb.h> + +#include <api/wndmgr/gc.h> +#include <api/wndmgr/layout.h> + +namespace Agave +{ + #include "../Agave/Config/api_config.h" +} + + + +//#define TIP_TIMER_ID 1601 +#define TIP_DESTROYTIMER_ID 1602 +#define TIP_AWAY_ID 1603 +#define TIP_AWAY_DELAY 100 + +#define TIP_TIMER_THRESHOLD 350 +#define TIP_LENGTH 3000 + +#define VCHILD_TIMER_ID_MIN 2000 +#define VCHILD_TIMER_ID_MAX 2100 + +#define BUFFEREDMSG_TIMER_ID 1604 + +#define DEFERREDCB_INVALIDATE 0x201 // move to .h +#define DEFERREDCB_FOCUSFIRST 0x202 // move to .h +#define DC_KILLGHOST 0x204 + +#ifdef _WIN32 +#define WM_DEFER_CALLBACK (WM_USER+0x333) +#endif +class DragSet : public PtrList<void>, public NamedW {}; + +//CUT? static void register_wndClass(HINSTANCE); + +//CUT? #define ROOTSTRING "RootWnd" + +//CUT? #define BASEWNDCLASSNAME "BaseWindow_" ROOTSTRING + +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x20A +#endif + +static ifc_window *stickyWnd; +static RECT sticky; + +static UINT WINAMP_WM_DIRECT_MOUSE_WHEEL = WM_NULL; + +/*api_window *api_window::rootwndFromPoint(POINT &point, int level) { + api_window *wnd; + wnd = WASABI_API_WND->rootWndFromPoint(&point); + return api_window::rootwndFromRootWnd(wnd, level, &point); +} + +api_window *api_window::rootwndFromRootWnd(api_window *wnd, int level, POINT *point) { + + for (;;) { + if (wnd == NULL || level < 0) return NULL; + if (point) { + RECT r; + wnd->getWindowRect(&r); + if (!PtInRect(&r, *point)) return NULL; // PORT ME + } + if (level == 0) return wnd; + wnd = wnd->getRootWndParent(); + level--; + } + // should never get here +}*/ + +static BOOL DisabledWindow_OnMouseClick(HWND hwnd) +{ + DWORD windowStyle = (DWORD)GetWindowLongPtrW(hwnd, GWL_STYLE); + if (WS_DISABLED != ((WS_CHILD | WS_DISABLED) & windowStyle)) + return FALSE; + + HWND hActive = GetActiveWindow(); + HWND hPopup = GetWindow(hwnd, GW_ENABLEDPOPUP); + + BOOL beepOk = (hPopup == hActive || hwnd == GetWindow(hActive, GW_OWNER)); + if (!beepOk && NULL == hPopup) + { + for (HWND hWalker = hwnd; ;) + { + hWalker = GetWindow(hWalker, GW_OWNER); + if (NULL == hWalker || (0 != (WS_CHILD & GetWindowLongPtrW(hWalker, GWL_STYLE)))) + break; + if (hActive == GetWindow(hWalker, GW_ENABLEDPOPUP)) + { + beepOk = TRUE; + break; + } + } + } + + if (beepOk) + { + static const GUID accessibilityConfigGroupGUID = + { 0xe2e7f4a, 0x7c51, 0x478f, { 0x87, 0x74, 0xab, 0xbc, 0xf6, 0xd5, 0xa8, 0x57 } }; + + #define GetBoolConfig(__group, __itemName, __default)\ + ((NULL != (__group)) && NULL != (item = group->GetItem(__itemName)) ? item->GetBool() : (__default)) + + waServiceFactory *serviceFactory = WASABI_API_SVC->service_getServiceByGuid(Agave::AgaveConfigGUID); + Agave::api_config *config = (NULL != serviceFactory) ? (Agave::api_config *)serviceFactory->getInterface() : NULL; + Agave::ifc_configgroup *group = (NULL != config) ? config->GetGroup(accessibilityConfigGroupGUID) : NULL; + Agave::ifc_configitem *item; + + if (GetBoolConfig(group, L"modalflash", true)) + { + FLASHWINFO flashInfo; + flashInfo.cbSize = sizeof(FLASHWINFO); + flashInfo.hwnd = hActive; + flashInfo.dwFlags = FLASHW_CAPTION; + flashInfo.uCount = 2; + flashInfo.dwTimeout = 100; + FlashWindowEx(&flashInfo); + } + + if (GetBoolConfig(group, L"modalbeep", false)) + MessageBeep(MB_OK); + + if (NULL != config) + serviceFactory->releaseInterface(config); + } + else + { + for (HWND hWalker = hwnd; NULL == hPopup;) + { + hWalker = GetWindow(hWalker, GW_OWNER); + if (NULL == hWalker || (0 != (WS_CHILD & GetWindowLongPtrW(hWalker, GWL_STYLE)))) + break; + hPopup = GetWindow(hWalker, GW_ENABLEDPOPUP); + } + + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE); + if (NULL != hPopup && hPopup != hwnd) + { + BringWindowToTop(hPopup); + SetActiveWindow(hPopup); + } + } + + return TRUE; +} +int WndWatcher::viewer_onItemDeleted(ifc_dependent *item) +{ + if (item == dep) + { + dep = NULL; + watcher->wndwatcher_onDeleteWindow(watched); + watched = NULL; + } + return 1; +} + +BaseWnd::BaseWnd() +{ + uiwaslocked = 0; + m_takenOver = 0; + rootfocus = NULL; + rootfocuswatcher.setWatcher(this); + alwaysontop = 0; + customdefaultcursor = NULL; + preventcancelcapture = 0; + ratiolinked = 1; + deleting = 0; + hinstance = NULL; + hwnd = NULL; + parentWnd = NULL; + dragging = 0; + prevtarg = NULL; + inputCaptured = 0; + btexture = NULL; + postoninit = 0; + inited = 0; + skipnextfocus = 0; + ncb = FALSE; + accessible = NULL; + + tooltip = NULL; + tip_done = FALSE; + tipshowtimer = FALSE; + tipawaytimer = FALSE; + tipdestroytimer = FALSE; + start_hidden = 0; + notifyWindow = NULL; + lastClick[0] = 0; + lastClick[1] = 0; + lastClickP[0].x = 0; + lastClickP[0].y = 0; + lastClickP[1].x = 0; + lastClickP[1].y = 0; + destroying = FALSE; + + curVirtualChildCaptured = NULL; + curVirtualChildFocus = NULL; + + virtualCanvas = NULL; virtualCanvasH = virtualCanvasW = 0; + deferedInvalidRgn = NULL; + + hasfocus = 0; + focus_on_click = 1; + lastnullregion = 0; + ratio = 1; + lastratio = 1; + rwidth = rheight = 0; + skin_id = -1; + wndalpha = 255; + activealpha = 255; + inactivealpha = 255; + w2k_alpha = 0; //FUCKO + scalecanvas = NULL; + clickthrough = 0; + + mustquit = 0; + returnvalue = 0; + notifyid = 0; + cloaked = 0; + disable_tooltip_til_recapture = 0; + + subtractorrgn = NULL; + composedrgn = NULL; + wndregioninvalid = 1; + regionop = REGIONOP_NONE; + rectrgn = 1; + need_flush_cascaderepaint = 0; + deferedCascadeRepaintRgn = NULL; + this_visible = 0; + this_enabled = 1; + renderbasetexture = 0; + oldCapture = NULL; + my_guiobject = NULL; + want_autoresize_after_init = 0; + resizecount = 0; + suggested_w = 320; + suggested_h = 200; + maximum_w = maximum_h = AUTOWH; + minimum_w = minimum_h = AUTOWH; + rx = 0; + ry = 0; + rwidth = 0; + rheight = 0; + allow_deactivate = 1; + minimized = 0; + inonresize = 0; +#ifndef WA3COMPATIBILITY + m_target = NULL; +#endif + + nodoubleclick = noleftclick = norightclick = nomousemove = nocontextmnu = 0; + focusEventsEnabled = 1; + maximized = 0; + MEMSET(&restore_rect, 0, sizeof(RECT)); + ghostbust = 0; + + lastActiveWnd = NULL; +} + +BaseWnd::~BaseWnd() +{ + //ASSERT(virtualChildren.getNumItems() == 0); + childtabs.deleteAll(); + if (WASABI_API_WND && WASABI_API_WND->getModalWnd() == this) WASABI_API_WND->popModalWnd(this); + destroying = TRUE; + curVirtualChildFocus = NULL; +#ifdef _WIN32 + if (inputCaptured && GetCapture() == getOsWindowHandle()) ReleaseCapture(); +#else +#warning port me +#endif + + for (int i = 0;i < ghosthwnd.getNumItems();i++) + Wasabi::Std::Wnd::destroyWnd(ghosthwnd.enumItem(i)); + + if (hwnd != NULL && !m_takenOver) + { +#ifdef URLDROPS + if (acceptExternalDrops()) Wasabi::Std::Wnd::revokeDragNDrop(hwnd /*, &m_target*/); +#else +#ifndef WA3COMPATIBILITY + if (m_target != NULL) + { + Wasabi::Std::Wnd::revokeDragNDrop(hwnd); + } +#endif +#endif + int popact = !wantActivation(); + if (popact) WASABI_API_WND->appdeactivation_push_disallow(this); + + Wasabi::Std::Wnd::destroyWnd(hwnd); + + if (popact) WASABI_API_WND->appdeactivation_pop_disallow(this); + } + + deleteFrameBuffer(virtualCanvas); + virtualCanvas = NULL; + delete scalecanvas; + scalecanvas = NULL; + + resetDragSet(); + + notifyParent(ChildNotify::DELETED); + if (tipdestroytimer) + killTimer(TIP_DESTROYTIMER_ID); + if (tipshowtimer) + { + // TODO: on the mac, use CreateMouseTrackingRegion + TRACKMOUSEEVENT tracker; + tracker.cbSize=sizeof(tracker); + tracker.dwFlags = TME_HOVER|TME_CANCEL; + tracker.hwndTrack = this->getOsWindowHandle(); + tracker.dwHoverTime = TIP_TIMER_THRESHOLD; + + TrackMouseEvent(&tracker); + + } + if (tipawaytimer) + killTimer(TIP_AWAY_ID); + + destroyTip(); + + delete tooltip; + + if (uiwaslocked) + killTimer(BUFFEREDMSG_TIMER_ID); + + if (deferedInvalidRgn) + delete deferedInvalidRgn; + + delete composedrgn; + delete subtractorrgn; + delete deferedCascadeRepaintRgn; + + if (parentWnd != NULL) + parentWnd->unregisterRootWndChild(this); + + if (!m_takenOver && WASABI_API_WND) WASABI_API_WND->unregisterRootWnd(this); + hwnd = NULL; +} + +int BaseWnd::init(ifc_window *parWnd, int nochild) +{ + if (parWnd == NULL) + return 0; + + OSWINDOWHANDLE phwnd = parWnd->getOsWindowHandle(); + ASSERT(phwnd != NULL); + + parentWnd = parWnd; // set default parent wnd + int ret = init(parWnd->getOsModuleHandle(), phwnd, nochild); + + if (!ret) + parentWnd = NULL; // abort + + return ret; +} + +int BaseWnd::init(OSMODULEHANDLE moduleHandle, OSWINDOWHANDLE parent, int nochild) +{ + RECT r; + int w, h; + + ASSERTPR(getOsWindowHandle() == NULL, "don't you double init you gaybag"); + + hinstance = moduleHandle; + +#ifdef _WIN32 + ASSERT(hinstance != NULL); +#endif + + //CUT register_wndClass(hinstance); + + if (parent != NULL) + { + Wasabi::Std::Wnd::getClientRect(parent, &r); + } + else + { + Wasabi::Std::setRect(&r, 0, 0, getPreferences(SUGGESTED_W), getPreferences(SUGGESTED_H)); + } + + w = (r.right - r.left); + h = (r.bottom - r.top); + + rwidth = w; + rheight = h; + rx = r.left; + ry = r.top; + + int popact = !wantActivation(); + if (popact) WASABI_API_WND->appdeactivation_push_disallow(this); + + //CUThwnd = createWindow(r.left, r.top, w, h, nochild, parent, hinstance); + hwnd = Wasabi::Std::Wnd::createWnd(&r, nochild, acceptExternalDrops(), parent, hinstance, static_cast<ifc_window*>(this)); +#ifdef __APPLE__ +#warning remove me + Wasabi::Std::Wnd::showWnd(hwnd); +#endif + + if (popact) WASABI_API_WND->appdeactivation_pop_disallow(this); + + //ASSERT(hwnd != NULL); // lets fail nicely, this could happen for some win32 reason, we don't want to fail the whole app for it, so lets just fail the wnd + if (hwnd == NULL) return 0; + + if (wantActivation()) bringToFront(); + + //CUT nreal++; + + //FUCKO +#ifdef _WIN32 // PORT ME +#ifdef URLDROPS + if (acceptExternalDrops()) RegisterDragDrop(hwnd, &m_target); +#else +#ifndef WA3COMPATIBILITY + if (!m_target && WASABI_API_WND != NULL) + m_target = WASABI_API_WND->getDefaultDropTarget(); + if (m_target != NULL) + { + RegisterDragDrop(hwnd, (IDropTarget *)m_target); + } +#endif +#endif +#endif + + this_visible = 0; + + onInit(); + + this_visible = !start_hidden; + + onPostOnInit(); + + return 1; +} + +#ifndef WA3COMPATIBILITY +void BaseWnd::setDropTarget(void *dt) +{ +#ifdef _WIN32 + if (isVirtual()) return ; + if (isInited() && m_target != NULL) + { + Wasabi::Std::Wnd::revokeDragNDrop(getOsWindowHandle()); + m_target = NULL; + } + m_target = dt; + if (m_target != NULL && isInited()) + { + RegisterDragDrop(gethWnd(), (IDropTarget *)m_target); + } +#else +#warning port me +#endif +} + +void *BaseWnd::getDropTarget() +{ + return m_target; +} +#endif + +int BaseWnd::onInit() +{ + + const wchar_t *s = getName(); + if (s != NULL) + setOSWndName(s); + + inited = 1; + + if (getParent()) + getParent()->registerRootWndChild(this); + + if (WASABI_API_WND != NULL) + WASABI_API_WND->registerRootWnd(this); + +#ifdef _WIN32 + if (!Wasabi::Std::Wnd::isDesktopAlphaAvailable()) + w2k_alpha = 0; //FUCKO + + if (w2k_alpha) + { + setLayeredWindow(1); + } + + if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL) + WINAMP_WM_DIRECT_MOUSE_WHEEL = RegisterWindowMessageW(L"WINAMP_WM_DIRECT_MOUSE_WHEEL"); + +#endif + + return 0; +} + +int BaseWnd::onPostOnInit() +{ + postoninit = 1; // from now on, isInited() returns 1; + if (want_autoresize_after_init) onResize(); + else invalidateWindowRegion(); + if (isVisible()) onSetVisible(1); + if (getTabOrder() == -1) setAutoTabOrder(); + ifc_window *dp = getDesktopParent(); + if ((dp == NULL || dp == this) && WASABI_API_TIMER != NULL) + postDeferredCallback(DEFERREDCB_FOCUSFIRST, 0, 500); + return 0; +} + +void BaseWnd::setLayeredWindow(int i) +{ + if (!Wasabi::Std::Wnd::isValidWnd(getOsWindowHandle())) return ; + if (!isInited()) return ; + Wasabi::Std::Wnd::setLayeredWnd(getOsWindowHandle(), i); +#if 0//CUT + if (i) + { + SetWindowLong(getOsWindowHandle(), GWL_EXSTYLE, GetWindowLong(getOsWindowHandle(), GWL_EXSTYLE) & ~WS_EX_LAYERED); + SetWindowLong(getOsWindowHandle(), GWL_EXSTYLE, GetWindowLong(getOsWindowHandle(), GWL_EXSTYLE) | WS_EX_LAYERED); + } + else + { + SetWindowLong(getOsWindowHandle(), GWL_EXSTYLE, GetWindowLong(getOsWindowHandle(), GWL_EXSTYLE) & ~WS_EX_LAYERED); + } +#endif + setTransparency(-1); +} + +int BaseWnd::getCursorType(int x, int y) +{ + if (!customdefaultcursor) + return BASEWND_CURSOR_POINTER; + return BASEWND_CURSOR_USERSET; +} + +void BaseWnd::onSetName() +{ + if (isInited() && !isVirtual()) + Wasabi::Std::Wnd::setWndName(getOsWindowHandle(), getNameSafe()); + notifyParent(ChildNotify::NAMECHANGED); + if (accessible) + accessible->onSetName(getName()); +} + +OSWINDOWHANDLE BaseWnd::getOsWindowHandle() +{ + OSWINDOWHANDLE handle; + + if ( isVirtual() ) + handle = getParent()->getOsWindowHandle(); + else + handle = hwnd; + + + return handle; +} + +OSMODULEHANDLE BaseWnd::getOsModuleHandle() +{ + return hinstance; +} + +void BaseWnd::onTip() +{ + tipshowtimer = FALSE; + tip_done = TRUE; + + POINT p; + Wasabi::Std::getMousePos(&p); + if (WASABI_API_WND->rootWndFromPoint(&p) == (ifc_window *)this) + { + createTip(); + setTimer(TIP_DESTROYTIMER_ID, TIP_LENGTH); + tipdestroytimer = TRUE; + } + setTimer(TIP_AWAY_ID, TIP_AWAY_DELAY); + tipawaytimer = TRUE; +} + +void BaseWnd::timerCallback(int id) +{ + switch (id) + { + case BUFFEREDMSG_TIMER_ID: + checkLockedUI(); + break; +// case TIP_TIMER_ID: + //onTip(); + //break; + case TIP_DESTROYTIMER_ID: + killTimer(TIP_DESTROYTIMER_ID); + killTimer(TIP_AWAY_ID); + tipawaytimer = FALSE; + tipdestroytimer = FALSE; + destroyTip(); + break; + case TIP_AWAY_ID: + onTipMouseMove(); + break; + } +} + +int BaseWnd::isInited() +{ + return inited; +} + +int BaseWnd::isDestroying() +{ + return destroying; +} + +int BaseWnd::wantSiblingInvalidations() +{ + return FALSE; +} + +void BaseWnd::setRSize(int x, int y, int w, int h) +{ + rwidth = w; + rheight = h; + rx = x; + ry = y; +} + +void BaseWnd::resize(int x, int y, int w, int h, int wantcb) +{ + inonresize = 1; + + if (x == AUTOWH) x = NOCHANGE; + if (y == AUTOWH) y = NOCHANGE; + if (w == AUTOWH) w = NOCHANGE; + if (h == AUTOWH) h = NOCHANGE; + + if (getNumMinMaxEnforcers() > 0) + { + int min_w = getPreferences(MINIMUM_W); + int min_h = getPreferences(MINIMUM_H); + int max_w = getPreferences(MAXIMUM_W); + int max_h = getPreferences(MAXIMUM_H); + if (min_w != AUTOWH && w != NOCHANGE && w < min_w) w = min_w; + if (max_w != AUTOWH && w != NOCHANGE && w > max_w) w = max_w; + if (min_h != AUTOWH && h != NOCHANGE && h < min_h) h = min_h; + if (max_h != AUTOWH && h != NOCHANGE && h > max_h) h = max_h; + } + + int noresize = (w == NOCHANGE && h == NOCHANGE); + int nomove = (x == NOCHANGE && y == NOCHANGE)/* || (x == rx && y == ry)*/; + if (x == NOCHANGE) x = rx; + if (y == NOCHANGE) y = ry; + if (w == NOCHANGE) w = rwidth; + if (h == NOCHANGE) h = rheight; + +#ifdef _DEBUG + ASSERT(x < 0xFFF0); + ASSERT(y < 0xFFF0); + ASSERT(w < 0xFFF0); + ASSERT(h < 0xFFF0); +#endif + + double thisratio = getRenderRatio(); + int different_ratio = (lastratio != thisratio); + lastratio = thisratio; + + int noevent = (resizecount > 1 && w == rwidth && h == rheight); + //ifc_window *dp = getDesktopParent(); + if (different_ratio == 1 && noevent == 1) + { + if (Wasabi::Std::Wnd::getTopmostChild(getOsWindowHandle()) != INVALIDOSWINDOWHANDLE) + noevent = 0; + invalidateWindowRegion(); + } + + RECT oldsize, newsize = Wasabi::Std::makeRect(x, y, w, h); + if (hwnd != NULL) + BaseWnd::getNonClientRect(&oldsize); + else + oldsize = newsize; + + setRSize(x, y, w, h); + + if (handleRatio() && renderRatioActive()) + { + multRatio(&w, &h); + if (getParent() != NULL) + { + multRatio(&x, &y); + } + } + + if (!noevent) + { + if (wantcb && isPostOnInit()) + { + resizecount = MIN(5, ++resizecount); + if (!isVirtual()) + invalidateWindowRegion(); + onResize(); + if (ensureWindowRegionValid()) + updateWindowRegion(); + } + } + + if (getOsWindowHandle() != NULL) + { + + RECT oldsizescaled; + getWindowRect(&oldsizescaled); + RECT newsizescaled = {x, y, x + w, y + h}; + if (MEMCMP(&newsizescaled, &oldsizescaled, sizeof(RECT))) + { + //CUT SetWindowPos(getOsWindowHandle(), NULL, x, y, w, h, + //CUT SWP_NOZORDER | + //CUT SWP_NOACTIVATE | + //CUT (!wantRedrawOnResize() ? SWP_NOCOPYBITS: 0) | + //CUT (ncb ? SWP_NOCOPYBITS : 0) | + //CUT ( nomove ? SWP_NOMOVE : 0) | + //CUT ( noresize ? SWP_NOSIZE : 0) | + //CUT 0); + Wasabi::Std::Wnd::setWndPos( getOsWindowHandle(), NULL, x, y, w, h, TRUE, TRUE, !wantRedrawOnResize() || ncb, nomove, noresize ); + } + //else + //{ + // DebugStringW(L"BaseWnd::resize optimized\n"); + //} + + onAfterResize(); + + if (ncb) + invalidate(); + else + { + RECT r; + if (hwnd != NULL) + { + if (newsize.left == oldsize.left && newsize.top == oldsize.top) + { + if (newsize.right > oldsize.right) + { + // growing in width + r.left = oldsize.right; + r.right = newsize.right; + r.top = newsize.top; + r.bottom = newsize.bottom; + invalidateRect(&r); + if (newsize.bottom > oldsize.bottom) + { + // growing in width & height + r.left = oldsize.left; + r.right = newsize.right; + r.top = oldsize.bottom; + r.bottom = newsize.bottom; + invalidateRect(&r); + } + } + else if (newsize.bottom > oldsize.bottom) + { + if (newsize.bottom > oldsize.bottom) + { + // growing in height + r.left = oldsize.left; + r.right = newsize.right; + r.top = oldsize.bottom; + r.bottom = newsize.bottom; + invalidateRect(&r); + } + } + } + } + } + } + inonresize = 0; +} + +void BaseWnd::forcedOnResizeChain(ifc_window *w) +{ + w->triggerEvent(TRIGGER_ONRESIZE); + int n = w->getNumRootWndChildren(); + for (int i = 0;i < n;i++) + { + forcedOnResizeChain(w->enumRootWndChildren(i)); + } +} + +int BaseWnd::forcedOnResize() +{ + forcedOnResizeChain(this); + return 1; +} + +int BaseWnd::onResize() +{ + if (!isVirtual() || (getRegionOp() != REGIONOP_NONE)) + invalidateWindowRegion(); + // you are not supposed to call onResize until after onInit has returned. If what you wanted was to generate + // an onResize event to do some custom client coordinates recalculations (ie: to apply on your children) + // then you don't need to do anything since onResize is going to be called after onInit() is done. If you still want to + // trigger it because your code might be called by onInit and after onInit, use isPostOnInit() as a test. + // if what you wanted was to signal a object that you just resized it, then you don't need to do anything beside + // resize(...), it will generate the event on its own if the window is inited, and will defer to until after onInit + // if it is not. + // shortly put: do not call onResize before or inside onInit() + // if you have any valid reason for doing that, i'd like to know about it so i can make it possible. -FG +#ifdef _DEBUG + if (!isPostOnInit()) + { + //__asm int 3; + ASSERTPR(isPostOnInit(), "do not call onResize before or inside onInit()"); + } +#endif + return FALSE; +} + +void BaseWnd::resizeToClient(BaseWnd *wnd) +{ + if (wnd != NULL) + wnd->resize(&clientRect()); +} + +int BaseWnd::onPostedMove() +{ + /* + if (w2k_alpha && Wasabi::Std::Wnd::isDesktopAlphaAvailable() && !cloaked) + { + RECT r; + getWindowRect(&r); + Wasabi::Std::Wnd::moveLayeredWnd(hwnd, r.left, r.top); + }*/ + return FALSE; +} + +void BaseWnd::resize(RECT *r, int wantcb) +{ + resize(r->left, r->top, r->right - r->left, r->bottom - r->top, wantcb); +} + +void BaseWnd::move(int x, int y) +{ + //DebugStringW( L"BaseWnd::move( x = %d, y = %d )\n", x, y ); + + setRSize(x, y, rwidth, rheight); + Wasabi::Std::Wnd::setWndPos( getOsWindowHandle(), NULL, x, y, 0, 0, TRUE, TRUE, ncb, FALSE, TRUE ); + //CUT if (!ncb) + //CUT SetWindowPos(getOsWindowHandle(), NULL, x, y, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_DEFERERASE); + //CUT else + //CUT SetWindowPos(getOsWindowHandle(), NULL, x, y, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOCOPYBITS|SWP_NOACTIVATE|SWP_DEFERERASE); +} + +#ifdef EXPERIMENTAL_INDEPENDENT_AOT +BOOL CALLBACK EnumOwnedTopMostWindows(HWND hwnd, LPARAM lParam) +{ + enumownedstruct *st = (enumownedstruct *)lParam; + if (hwnd != st->hthis && GetWindow(hwnd, GW_OWNER) == st->owner) + { + ifc_window *w = (ifc_window*)GetWindowLong(hwnd, GWL_USERDATA); + if (w != NULL && w->getAlwaysOnTop()) + st->hlist->addItem(w); + } + return TRUE; +} + +void BaseWnd::saveTopMosts() +{ + HWND owner = GetWindow(getOsWindowHandle(), GW_OWNER); + enumownedstruct st; + ontoplist.removeAll(); + if (owner != NULL) + { + st.owner = owner; + st.hlist = &ontoplist; + st.hthis = getOsWindowHandle(); + EnumWindows(EnumOwnedTopMostWindows, (long)&st); + } +} + +void BaseWnd::restoreTopMosts() +{ + HWND owner = GetWindow(getOsWindowHandle(), GW_OWNER); + if (owner != NULL) + { + for (int i = 0;i < ontoplist.getNumItems();i++) + { + ontoplist.enumItem(i)->setAlwaysOnTop(1); + } + } +} +#endif + +void BaseWnd::bringToFront() +{ + // when we set a window to the top of the zorder (not topmost), win32 finds the owner and removes any topmost flag its children may + // have because it assumes we want this window over these, which we definitly don't. so we need to first go thru all the owner's children, + // make a list of the ones with a topmost flag, set this window on top, and set the topmost flags back. yay + ASSERT(!isVirtual()); +#ifdef EXPERIMENTAL_INDEPENDENT_AOT + saveTopMosts(); +#endif + //CUT SetWindowPos(getOsWindowHandle(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE|SWP_DEFERERASE|SWP_NOOWNERZORDER); + Wasabi::Std::Wnd::bringToFront(getOsWindowHandle()); +#ifdef EXPERIMENTAL_INDEPENDENT_AOT + restoreTopMosts(); +#endif +} + +void BaseWnd::bringToBack() +{ + ASSERT(!isVirtual()); +#ifdef EXPERIMENTAL_INDEPENDENT_AOT + saveTopMosts(); +#endif + //CUT SetWindowPos(getOsWindowHandle(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE|SWP_DEFERERASE|SWP_NOOWNERZORDER); + Wasabi::Std::Wnd::sendToBack(getOsWindowHandle()); +#ifdef EXPERIMENTAL_INDEPENDENT_AOT + restoreTopMosts(); +#endif +} + +void BaseWnd::setVisible(int show) +{ + int visible = isVisible(1); + if (!!visible == !!show) return ; + invalidate(); + this_visible = !!show; + /*if (!getParent() || getParent() == WASABI_API_WND->main_getRootWnd() && IsWindow(getOsWindowHandle())) { + if (!show) { + setLayeredWindow(0); + if (setLayeredWindowAttributes) + setLayeredWindowAttributes(hwnd, RGB(0,0,0), 255, LWA_ALPHA); + } else { + setLayeredWindow(w2k_alpha); + } + }*/ + if (!getParent() || getParent() == WASABI_API_WND->main_getRootWnd() || getParent()->isVisible()) + { + onSetVisible(show); + } +} + +void BaseWnd::setCloaked(int cloak) +{ + if (cloaked == cloak) return ; + cloaked = cloak; + if (isVirtual()) return ; + if (cloaked) + { + //CUTif (IsWindowVisible(getOsWindowHandle())) + //CUT ShowWindow(getOsWindowHandle(), SW_HIDE); + if (Wasabi::Std::Wnd::isWndVisible(getOsWindowHandle())) + Wasabi::Std::Wnd::hideWnd(getOsWindowHandle()); + } + else + { + if (isVisible(1)) + //CUTShowWindow(getOsWindowHandle(), SW_NORMAL); + Wasabi::Std::Wnd::showWnd(getOsWindowHandle()); + } +} + + +void BaseWnd::onSetVisible(int show) +{ + /* for debug purposes - don't delete please + #include "../../../studio/container.h" + #include "../../../studio/layout.h" + if (!show && getGuiObject() && STRCASEEQLSAFE(getGuiObject()->guiobject_getId(), "normal")) { + Layout *l = (Layout *)getInterface(layoutGuid); + if (l) { + if (l->getParentContainer() && STRCASEEQLSAFE(l->getParentContainer()->getId(), "main")) { + DebugString("Hiding main player\n"); + } + } + }*/ + if (!isVirtual()) + if (hwnd != NULL) + if (!cloaked) + { + //CUT // SetWindowPos(getOsWindowHandle(),NULL,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_SHOWWINDOW); + //CUT ShowWindow(getOsWindowHandle(), show ? SW_SHOWNA : SW_HIDE); + if (show) + Wasabi::Std::Wnd::showWnd(getOsWindowHandle(), TRUE); + else + Wasabi::Std::Wnd::hideWnd(getOsWindowHandle()); + } + /* if (!show) + postDeferredCallback(0x7849); + else {*/ + foreach(rootwndchildren) + ifc_window *w = rootwndchildren.getfor(); + if (w && w->isVisible(1)) // check internal flag only + w->onSetVisible(show); + endfor; + dependent_sendEvent(BaseWnd::depend_getClassGuid(), Event_SETVISIBLE, show); + //} + /* if (getDesktopParent() == this) { + cascadeRepaint(0); + }*/ + + /*#ifdef WIN32 // os-specific non virtual child wnd support + if (!isVirtual()) { + HWND w = GetWindow(getOsWindowHandle(), GW_CHILD); + while (w != NULL) { + api_window *rootwnd = (api_window*)GetWindowLong(w, GWL_USERDATA); + if (rootwnd && rootwnd != this) + if (rootwnd->isInited()) + rootwnd->onSetVisible(show); + w = GetWindow(w, GW_HWNDNEXT); + } + } + #endif*/ + if (!isVirtual()) + { + if (!show) + { + deferedInvalidate(); + delete virtualCanvas; + virtualCanvas = NULL; + } + } + invalidateWindowRegion(); +} + +void BaseWnd::setEnabled(int en) +{ + int enabled = isEnabled(1); + if (!!enabled == !!en) return ; + invalidate(); + this_enabled = !!en; + if (!getParent() || getParent() == WASABI_API_WND->main_getRootWnd() || getParent()->isEnabled()) + { + onEnable(en); + } +} + +int BaseWnd::isEnabled(int within) +{ + if (!isVirtual() && !getOsWindowHandle()) return 0; + if (!this_enabled) return 0; + + if (within) return this_enabled; // whatever, local + + if (isVirtual()) // virtual, global + if (getParent()) + return getParent()->isEnabled(); + else + return 0; + + // non virtual, global + //CUT if (GetWindowLong(getOsWindowHandle(), GWL_STYLE) & WS_POPUP) return this_enabled; + if (Wasabi::Std::Wnd::isPopup(getOsWindowHandle())) return this_enabled; + //CUT if (!Wasabi::Std::Wnd::isValidWnd(GetParent(gethWnd()))) return this_enabled; + if (!Wasabi::Std::Wnd::isValidWnd(Wasabi::Std::Wnd::getParent(getOsWindowHandle()))) return this_enabled; + if (getParent()) return getParent()->isEnabled(); // not a popup, check its parent or fail + return this_enabled; +} + +int BaseWnd::onEnable(int en) +{ + if (!isVirtual()) + { + if (hwnd != NULL) + //CUT EnableWindow(getOsWindowHandle(), en); + Wasabi::Std::Wnd::setEnabled(getOsWindowHandle(), en); + foreach(rootwndchildren) + ifc_window *w = rootwndchildren.getfor(); + if (w->isEnabled(1)) // check internal flag only + w->onEnable(en); + endfor; + } + return 1; +} + +void BaseWnd::setFocus() +{ + if (curVirtualChildFocus != NULL) + { + curVirtualChildFocus->onKillFocus(); + curVirtualChildFocus = NULL; + } + onSetRootFocus(this); + //CUT SetFocus(getOsWindowHandle()); + Wasabi::Std::Wnd::setFocus(getOsWindowHandle()); +} + +void BaseWnd::setFocusOnClick(int f) +{ + focus_on_click = f; +} + +api_region *BaseWnd::getDeferedInvalidRgn() +{ + return deferedInvalidRgn; +} + +void BaseWnd::deferedInvalidate() +{ + if (!hasVirtualChildren() || !isVisible(1)) return ; + RECT r = Wasabi::Std::makeRect(0, 0, 0, 0); + getNonClientRect(&r); + deferedInvalidateRect(&r); +} + +void BaseWnd::deferedInvalidateRect(RECT *r) +{ + if (!hasVirtualChildren()) return ; + RegionI h(r); + deferedInvalidateRgn(&h); +} + +void BaseWnd::deferedInvalidateRgn(api_region *h) +{ + if (!hasVirtualChildren()) return ; + if (!deferedInvalidRgn) + { + deferedInvalidRgn = new RegionI(); + } + + deferedInvalidRgn->addRegion(h); +} + +void BaseWnd::deferedValidate() +{ + if (!hasVirtualChildren() || !isVisible(1)) return ; + RECT r = Wasabi::Std::makeRect(0,0,0,0); + getNonClientRect(&r); + deferedValidateRect(&r); +} + +void BaseWnd::deferedValidateRect(RECT *r) +{ + if (!hasVirtualChildren()) return ; + RegionI h(r); + deferedValidateRgn(&h); +} + +void BaseWnd::deferedValidateRgn(api_region *h) +{ + if (!hasVirtualChildren()) return ; + if (!deferedInvalidRgn) return ; + + deferedInvalidRgn->subtractRgn(h); +} + +int BaseWnd::hasVirtualChildren() +{ + return 1; //virtualChildren.getNumItems() > 0; +} + +void BaseWnd::invalidate() +{ + invalidateFrom(this); +} + +void BaseWnd::invalidateFrom(ifc_window *who) +{ + if (hasVirtualChildren()) deferedInvalidate(); + //CUT if (hwnd != NULL && isVisible(1)) InvalidateRect(getOsWindowHandle(), NULL, FALSE); + if (hwnd != NULL && isVisible(1)) + Wasabi::Std::Wnd::invalidateRect(getOsWindowHandle()); +} + +void BaseWnd::invalidateRectFrom(RECT *r, ifc_window *who) +{ + if (hasVirtualChildren()) deferedInvalidateRect(r); + RegionI rg(r); + invalidateRgnFrom(&rg, who); +} + +void BaseWnd::invalidateRgn(api_region *r) +{ + invalidateRgnFrom(r, this); +} + +void BaseWnd::invalidateRect(RECT *r) +{ + invalidateRectFrom(r, this); +} + +void BaseWnd::invalidateRgnFrom(api_region *r, ifc_window *who) +{ + if (parentWnd) parentWnd->onChildInvalidate(r, who); + PaintCallbackInfoI pc(NULL, r); + dependent_sendEvent(BaseWnd::depend_getClassGuid(), Event_ONINVALIDATE, 0, &pc); + if (hwnd != NULL && isVisible(1)) + { + if (hasVirtualChildren()) + { + api_region *_r = r->clone(); + int j = virtualChildren.searchItem(who); + for (int i = 0;i < virtualChildren.getNumItems();i++) + { + ifc_window *w = virtualChildren[i]; + if (w != who && w->wantSiblingInvalidations()) + w->onSiblingInvalidateRgn(_r, who, j, i); + } + + deferedInvalidateRgn(_r); + physicalInvalidateRgn(_r); + r->disposeClone(_r); + } + else + { + deferedInvalidateRgn(r); + physicalInvalidateRgn(r); + } + } +} + +void BaseWnd::physicalInvalidateRgn(api_region *r) +{ + if (hwnd != NULL && isVisible(1)) + { + if (renderRatioActive()) + { + api_region *clone = r->clone(); + clone->scale(getRenderRatio(), getRenderRatio(), TRUE); + //CUT InvalidateRgn(getOsWindowHandle(), clone->getOSHandle(), FALSE); + Wasabi::Std::Wnd::invalidateRegion(getOsWindowHandle(), clone->getOSHandle()); + r->disposeClone(clone); + } + else + //CUT InvalidateRgn(getOsWindowHandle(), r->getOSHandle(), FALSE); + Wasabi::Std::Wnd::invalidateRegion(getOsWindowHandle(), r->getOSHandle()); + } +} + +void BaseWnd::validate() +{ + //CUT if (hwnd != NULL) ValidateRect(getOsWindowHandle(), NULL); + if (hwnd != NULL) + Wasabi::Std::Wnd::validateRect(getOsWindowHandle()); +} + +void BaseWnd::validateRect(RECT *r) +{ + if (hwnd != NULL) + { + if (renderRatioActive()) + { + RECT r2 = *r; + Wasabi::Std::scaleRect(&r2, getRenderRatio()); + //CUT ValidateRect(getOsWindowHandle(), &r2); + Wasabi::Std::Wnd::validateRect(getOsWindowHandle(), &r2); + } + else + //CUT ValidateRect(getOsWindowHandle(), r); + Wasabi::Std::Wnd::validateRect(getOsWindowHandle(), r); + } +} + +void BaseWnd::validateRgn(api_region *reg) +{ + if (hwnd != NULL) + { + if (renderRatioActive()) + { + api_region *clone = reg->clone(); + clone->scale(getRenderRatio(), getRenderRatio(), TRUE); + //CUT ValidateRgn(getOsWindowHandle(), clone->getOSHandle()); + Wasabi::Std::Wnd::validateRegion(getOsWindowHandle(), clone->getOSHandle()); + reg->disposeClone(clone); + } + else + //CUT ValidateRgn(getOsWindowHandle(), reg->getOSHandle()); + Wasabi::Std::Wnd::validateRegion(getOsWindowHandle(), reg->getOSHandle()); + } +} + +void BaseWnd::repaint() +{ + /* if (hasVirtualChildren()) { + api_region *h = new api_region(); + int s = GetUpdateRgn(getOsWindowHandle(), h->getHRGN(), FALSE); + if (s != NULLREGION && s != ERROR) { + virtualDrawRgn(h); + } + delete h; + }*/ + //CUTif (hwnd != NULL) UpdateWindow(getOsWindowHandle()); + if (hwnd != NULL) + Wasabi::Std::Wnd::update(getOsWindowHandle()); +} + +void BaseWnd::getClientRect(RECT *rect) +{ + /* rect->left = rx; + rect->right = rx + rwidth; + rect->top = ry; + rect->bottom = ry + rheight;*/ + //ASSERT(hwnd != NULL); + if (!Wasabi::Std::Wnd::isValidWnd(hwnd)) + { + MEMSET(rect, 0, sizeof(RECT)); + return ; + } + + GetClientRect(getOsWindowHandle(), rect); + ////Wasabi::Std::Wnd::getClientRect(getOsWindowHandle(), rect); + rect->right = rect->left + rwidth; + rect->bottom = rect->top + rheight; +} + +RECT BaseWnd::clientRect() +{ + RECT ret; + getClientRect(&ret); + return ret; +} + +void BaseWnd::getNonClientRect(RECT *rect) +{ + // ASSERT(hwnd != NULL); + if (!hwnd) + getClientRect(rect); + else + { + Wasabi::Std::Wnd::getClientRect(getOsWindowHandle(), rect); + if (getRenderRatio() != 1.0) + { + rect->right = rect->left + rwidth; + rect->bottom = rect->left + rheight; + } + } + /* rect->left = rx; + rect->right = rx + rwidth; + rect->top = ry; + rect->bottom = ry + rheight;*/ +} + +RECT BaseWnd::nonClientRect() +{ + RECT ret; + getNonClientRect(&ret); + return ret; +} + +void BaseWnd::getWindowRect(RECT *rect) +{ + //CUT#ifdef WIN32 + //CUT ASSERT(hwnd != NULL); + //CUT GetWindowRect(getOsWindowHandle(), rect); + //CUT#else + //CUT#error port me + //CUT#endif + Wasabi::Std::Wnd::getWindowRect(getOsWindowHandle(), rect); +} + +// get position relative to parent (same coordinate system for basewnd & virtualwnd) +void BaseWnd::getPosition(POINT *pt) +{ + pt->x = rx; + pt->y = ry; +} + +void *BaseWnd::dependent_getInterface(const GUID *classguid) +{ + HANDLEGETINTERFACE(ifc_window); + //CUT HANDLEGETINTERFACE(api_window); + return NULL; +} + +RECT BaseWnd::windowRect() +{ + RECT ret; + getWindowRect(&ret); + return ret; +} + + +void BaseWnd::clientToScreen(int *x, int *y) +{ + int _x = x ? *x : 0; + int _y = y ? *y : 0; + if (renderRatioActive()) + { + _x = (int)((double)_x * getRenderRatio()); + _y = (int)((double)_y * getRenderRatio()); + } + Wasabi::Std::Wnd::clientToScreen(getOsWindowHandle(), &_x, &_y); + if (x) *x = _x; + if (y) *y = _y; +} + +void BaseWnd::clientToScreen(RECT *r) +{ + clientToScreen((int*)&r->left, (int*)&r->top); + clientToScreen((int*)&r->right, (int*)&r->bottom); +} + +void BaseWnd::clientToScreen(POINT *p) +{ + clientToScreen((int *)&p->x, (int *)&p->y); +} + +void BaseWnd::screenToClient(int *x, int *y) +{ + //CUT POINT p; + int _x = x ? *x : 0; + int _y = y ? *y : 0; + //CUT ScreenToClient(getOsWindowHandle(), &p); + Wasabi::Std::Wnd::screenToClient(getOsWindowHandle(), &_x, &_y); + if (renderRatioActive()) + { + _x = (int)((double)_x / getRenderRatio()); + _y = (int)((double)_y / getRenderRatio()); + } + if (x) *x = _x; + if (y) *y = _y; +} + +void BaseWnd::screenToClient(RECT *r) +{ + screenToClient((int*)&r->left, (int*)&r->top); + screenToClient((int*)&r->right, (int*)&r->bottom); +} + +void BaseWnd::screenToClient(POINT *p) +{ + screenToClient((int *)&p->x, (int *)&p->y); +} + +void BaseWnd::setParent(ifc_window *newparent) +{ + ASSERTPR(newparent != NULL, "quit being a weeny"); + ASSERTPR(parentWnd == NULL || newparent == parentWnd, "can't reset parent"); + parentWnd = newparent; + if (isInited()) + { + OSWINDOWHANDLE w1 = getOsWindowHandle(); + OSWINDOWHANDLE w2 = newparent->getOsWindowHandle(); + if (w1 != w2) + //CUT SetParent(w1, w2); + Wasabi::Std::Wnd::setParent(w1, w2); + } +} + +//FUCKO +int BaseWnd::reparent(ifc_window *newparent) +{ +#ifdef _WIN32 + if (!isVirtual()) + { + if (isInited()) + { + ifc_window *old = getParent(); + if (!old && newparent) + { + ::SetParent(getOsWindowHandle(), newparent->getOsWindowHandle()); + SetWindowLong(getOsWindowHandle() , GWL_STYLE, GetWindowLong(getOsWindowHandle(), GWL_STYLE) & ~WS_POPUP); + SetWindowLong(getOsWindowHandle() , GWL_STYLE, GetWindowLong(getOsWindowHandle(), GWL_STYLE) | WS_CHILD); + } + else if (old && !newparent) + { + SetWindowLong(getOsWindowHandle() , GWL_STYLE, GetWindowLong(getOsWindowHandle(), GWL_STYLE) & ~WS_CHILD); + SetWindowLong(getOsWindowHandle() , GWL_STYLE, GetWindowLong(getOsWindowHandle(), GWL_STYLE) | WS_POPUP); + ::SetParent(getOsWindowHandle(), NULL); + } + else + { + ::SetParent(getOsWindowHandle(), newparent ? newparent->getOsWindowHandle() : NULL); + } + } + } + + parentWnd = newparent; + onSetParent(newparent); + +#ifdef WASABI_ON_REPARENT + WASABI_ON_REPARENT(getOsWindowHandle()); +#endif +#else +#warning port me +#endif + return 1; +} + +ifc_window *BaseWnd::getParent() +{ + return parentWnd; +} + +ifc_window *BaseWnd::getRootParent() +{ + return this; +} + +//PORTME +ifc_window *BaseWnd::getDesktopParent() +{ +#ifdef _WIN32 + // NONPORTABLE + HWND w = getOsWindowHandle(); + HWND last = w; + if (!w) return NULL; + HWND p = w; + wchar_t cn[256] = {0}; + while (p && !(GetWindowLong(p, GWL_STYLE) & WS_POPUP)) + { + GetClassNameW(p, cn, 255); cn[255] = 0; + if (!wcscmp(cn, BASEWNDCLASSNAME)) + last = p; + p = GetParent(p); + } + if (p) + { + GetClassNameW(p, cn, 255); cn[255] = 0; + if (!wcscmp(cn, BASEWNDCLASSNAME)) + return (ifc_window*)GetWindowLongPtrW(p, GWLP_USERDATA); + else if (last != NULL) + return (ifc_window*)GetWindowLongPtrW(last, GWLP_USERDATA); + } +#else +#warning port me +#endif + return NULL; +} + +int BaseWnd::notifyParent(int msg, int param1, int param2) +{ + ifc_window *notifywnd = getNotifyWindow(); + if (getParent() == NULL && notifywnd == NULL) return 0; + if (notifywnd == NULL) notifywnd = getParent(); + ASSERT(notifywnd != NULL); + return notifywnd->childNotify(this, msg, param1, param2); +} + +int BaseWnd::passNotifyUp(ifc_window *child, int msg, int param1, int param2) +{ + // Same code as above to decide for whom we should notify. + ifc_window *notifywnd = getNotifyWindow(); + if (getParent() == NULL && notifywnd == NULL) return 0; + if (notifywnd == NULL) notifywnd = getParent(); + ASSERT(notifywnd != NULL); + // And here we just change the api_window pointer. + return notifywnd->childNotify(child, msg, param1, param2); +} + +void BaseWnd::setNotifyId(int id) +{ + notifyid = id; +} + +int BaseWnd::getNotifyId() +{ + return notifyid; +} + +DragInterface *BaseWnd::getDragInterface() +{ + return this; +} + +ifc_window *BaseWnd::rootWndFromPoint(POINT *pt) +{ + // pt is in client coordinates + int x = (int)((double)pt->x / getRenderRatio()); + int y = (int)((double)pt->y / getRenderRatio()); + + ifc_window *ret = findRootWndChild(x, y); + if (ret == NULL) ret = this; + return ret; +} + +int BaseWnd::rootwnd_paintTree(ifc_canvas *canvas, api_region *r) +{ + BaseCloneCanvas c(canvas); + return paintTree(&c, r); +} + +const wchar_t *BaseWnd::getRootWndName() +{ + return getName(); +} + +const wchar_t *BaseWnd::getId() +{ + return NULL; +} + +void BaseWnd::setSkinId(int id) +{ + skin_id = id; +} + +void BaseWnd::setPreferences(int what, int v) +{ + switch (what) + { + case MAXIMUM_W: maximum_w = v; break; + case MAXIMUM_H: maximum_h = v; break; + case MINIMUM_W: minimum_w = v; break; + case MINIMUM_H: minimum_h = v; break; + case SUGGESTED_W: suggested_w = v; break; + case SUGGESTED_H: suggested_h = v; break; + } +} + +int BaseWnd::getPreferences(int what) +{ + if (getNumMinMaxEnforcers() > 0) + { + + int min_x = minimum_w, min_y = minimum_h, max_x = maximum_w, max_y = maximum_h, sug_x = suggested_w, sug_y = suggested_h; + + for (int i = 0;i < getNumMinMaxEnforcers();i++) + { + + int tmin_x = MINIMUM_W, tmin_y = MINIMUM_H, tmax_x = MAXIMUM_W, tmax_y = MAXIMUM_H, tsug_x = SUGGESTED_W, tsug_y = SUGGESTED_H; + + ifc_window *w = enumMinMaxEnforcer(i); + + if (w) + { + + tmin_x = w->getPreferences(MINIMUM_W); + tmin_y = w->getPreferences(MINIMUM_H); + tmax_x = w->getPreferences(MAXIMUM_W); + tmax_y = w->getPreferences(MAXIMUM_H); + tsug_x = w->getPreferences(SUGGESTED_W); + tsug_y = w->getPreferences(SUGGESTED_H); + + if (tmin_x == -1) tmin_x = AUTOWH; + if (tmin_y == -1) tmin_y = AUTOWH; + if (tmax_x == -1) tmax_x = AUTOWH; + if (tmax_y == -1) tmax_y = AUTOWH; + if (tsug_x == -1) tsug_x = AUTOWH; + if (tsug_y == -1) tsug_y = AUTOWH; + +#ifndef DISABLE_SYSFONTSCALE + TextInfoCanvas textInfoCanvas(this); + double fontScale = textInfoCanvas.getSystemFontScale(); + GuiObject *o = static_cast<GuiObject *>(getInterface(guiObjectGuid)); + if (o != NULL) + { + if (o->guiobject_getAutoSysMetricsW()) + { + if (tmin_x != AUTOWH) tmin_x = (int)((float)tmin_x * fontScale); + if (tmax_x != AUTOWH) tmax_x = (int)((float)tmax_x * fontScale); + if (tsug_x != AUTOWH) tsug_x = (int)((float)tsug_x * fontScale); + } + if (o->guiobject_getAutoSysMetricsH()) + { + if (tmin_y != AUTOWH) tmin_y = (int)((float)tmin_y * fontScale); + if (tmax_y != AUTOWH) tmax_y = (int)((float)tmax_y * fontScale); + if (tsug_y != AUTOWH) tsug_y = (int)((float)tsug_y * fontScale); + } + } +#endif + + RECT cor; + w->getNonClientRect(&cor); + RECT wr; + getNonClientRect(&wr); + + int xdif = (wr.right - wr.left) - (cor.right - cor.left); + int ydif = (wr.bottom - wr.top) - (cor.bottom - cor.top); + if (tmin_x != AUTOWH) tmin_x += xdif; + if (tmin_y != AUTOWH) tmin_y += ydif; + if (tmax_x != AUTOWH) tmax_x += xdif; + if (tmax_y != AUTOWH) tmax_y += ydif; + if (tsug_x != AUTOWH) tsug_x += xdif; + if (tsug_y != AUTOWH) tsug_y += ydif; + } + + if (min_x != AUTOWH) min_x = (tmin_x != AUTOWH) ? MAX(min_x, tmin_x) : min_x; else min_x = tmin_x; + if (max_x != AUTOWH) max_x = (tmax_x != AUTOWH) ? MAX(max_x, tmax_x) : max_x; else max_x = tmax_x; + if (min_y != AUTOWH) min_y = (tmin_y != AUTOWH) ? MAX(min_y, tmin_y) : min_y; else min_y = tmin_y; + if (max_y != AUTOWH) max_y = (tmax_y != AUTOWH) ? MAX(max_y, tmax_y) : max_y; else max_y = tmax_y; + if (sug_x != AUTOWH) sug_x = (tsug_x != AUTOWH) ? MAX(sug_x, tsug_x) : sug_x; else sug_x = tsug_x; + if (sug_y != AUTOWH) sug_y = (tsug_y != AUTOWH) ? MAX(sug_y, tsug_y) : sug_y; else sug_y = tsug_y; + } + + if (min_x != AUTOWH && min_x == max_x) sug_x = min_x; + if (min_y != AUTOWH && min_y == max_y) sug_y = min_y; + + switch (what) + { + case MINIMUM_W: return min_x; + case MINIMUM_H: return min_y; + case MAXIMUM_W: return max_x; + case MAXIMUM_H: return max_y; + case SUGGESTED_W: return sug_x; + case SUGGESTED_H: return sug_y; + } + } + + switch (what) + { + case SUGGESTED_W: return suggested_w; + case SUGGESTED_H: return suggested_h; + case MAXIMUM_W: return maximum_w; + case MAXIMUM_H: return maximum_h; + case MINIMUM_W: return minimum_w; + case MINIMUM_H: return minimum_h; + } + + return AUTOWH; +} + +void BaseWnd::setStartHidden(int wtf) +{ + start_hidden = wtf; +} + +//PORTME +#ifdef _WIN32 + + + +#define EQUAL_CLSNAME(__name1, __name2)\ +(CSTR_EQUAL == CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),\ +NORM_IGNORECASE, (__name1), -1, (__name2), -1)) + +static BOOL BaseWnd_IsFrameWindow(HWND hwnd) +{ + WCHAR szClass[64] = {0}; + if (NULL == hwnd || !GetClassNameW(hwnd, szClass, ARRAYSIZE(szClass))) + return FALSE; + + return EQUAL_CLSNAME(szClass, L"Winamp v1.x") || + EQUAL_CLSNAME(szClass, L"BaseWindow_RootWnd"); +} + + +LRESULT BaseWnd::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (!isDestroying()) switch (uMsg) + { + case WM_DEFER_CALLBACK: + timerclient_onDeferredCallback(wParam, lParam); + break; + case WM_SYSCOMMAND: + { + if ((wParam & 0xfff0) == SC_SCREENSAVE || (wParam & 0xfff0) == SC_MONITORPOWER) + { + ifc_window *main = WASABI_API_WND->main_getRootWnd(); + if (main && main != this) + return SendMessageW(main->gethWnd(), uMsg, wParam, lParam); + } + break; + } + //CUT case WM_CREATE: + //CUT hwnd = hWnd; + //CUT break; + + //CUT case WM_CLOSE: + //CUT return 0; + + case WM_PAINT: + { + if (inonresize && !wantRedrawOnResize()) return 1; + ASSERT(hwnd != NULL); + if (!isVisible(1) || IsIconic(hWnd)) break; + RECT r; + if (GetUpdateRect(hWnd, &r, FALSE)) + { + if (virtualOnPaint()) + { + return 0; + } + } + } + break; + + case WM_PRINTCLIENT: + { + bool old_cloaked = (!!cloaked); + cloaked = true; + DCCanvas dc((HDC)wParam, this); + paint(&dc, 0); + cloaked = old_cloaked; + + if (lParam & PRF_CHILDREN) + { + RECT wnd_size; + GetWindowRect(hwnd, &wnd_size); + + HWND child = GetWindow(hwnd, GW_CHILD); + while (child != NULL) + { + if (GetWindowLongPtrW(child, GWL_STYLE) & WS_VISIBLE) + { + RECT child_size; + GetWindowRect(child, &child_size); + if (child_size.right && child_size.bottom) + { + BltCanvas bitmap(child_size.right, child_size.bottom, child);; + SendMessageW(child, WM_PRINT, (WPARAM)bitmap.getHDC(), PRF_CHILDREN | PRF_CLIENT | PRF_NONCLIENT/*| PRF_OWNED*/); + //bitmap->makeAlpha(255); + + //set alpha to 255 + int w, h; + bitmap.getDim(&w, &h, NULL); + ARGB32 *m_pBits = (ARGB32 *)bitmap.getBits(); + int nwords = w*h; + for (; nwords > 0; nwords--, m_pBits++) + { + unsigned char *pixel = (unsigned char *)m_pBits; + pixel[3] = 255; // alpha + } + + POINT offset; + offset.x = child_size.left - wnd_size.left; + offset.y = child_size.top - wnd_size.top; + + //BLENDFUNCTION blendFn; + //blendFn.BlendOp = AC_SRC_OVER; + //blendFn.BlendFlags = 0; + //blendFn.SourceConstantAlpha = 255; + //blendFn.AlphaFormat = 0; + //AlphaBlend((HDC)wParam, offset.x, offset.y, child_size.right-child_size.left, child_size.bottom-child_size.top, + // bitmap->getHDC(), 0, 0, child_size.right-child_size.left, child_size.bottom-child_size.top, blendFn); + StretchBlt((HDC)wParam, offset.x, offset.y, child_size.right-child_size.left, child_size.bottom-child_size.top, + bitmap.getHDC(), 0, 0, child_size.right-child_size.left, child_size.bottom-child_size.top, SRCCOPY); + } + } + child = GetWindow(child, GW_HWNDNEXT); + } + + } + } + return 0; + //CUT case WM_NCPAINT: return 0; + //CUT case WM_SYNCPAINT: return 0; + + case WM_SETCURSOR: + if (checkModal()) return TRUE; + if (hWnd == (HWND)wParam) + { + DWORD windowStyle = (DWORD)GetWindowLongPtrW(hWnd, GWL_STYLE); + switch(HIWORD(lParam)) + { + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case 0x020B/*WM_XBUTTONDOWN*/: + DisabledWindow_OnMouseClick(hWnd); + break; + } + int ct = BASEWND_CURSOR_POINTER; + int _x, _y; + Wasabi::Std::getMousePos(&_x, &_y); + screenToClient(&_x, &_y); + OSCURSORHANDLE c = NULL; + + if (0 == (WS_DISABLED & windowStyle)) + { + if (!handleVirtualChildMsg(WM_SETCURSOR, _x, _y, &ct, &c)) + { + ct = getCursorType(_x, _y); + } + } + wchar_t *wincursor = NULL; + switch (ct) + { + case BASEWND_CURSOR_USERSET: + + if (c == NULL) + c = getCustomCursor(_x, _y); + if (c != NULL) + { + SetCursor(c); + return TRUE; + } + else wincursor = IDC_ARROW; // Ensure to have at least a cursor + break; + case BASEWND_CURSOR_POINTER: + wincursor = IDC_ARROW; + break; + case BASEWND_CURSOR_NORTHSOUTH: + wincursor = IDC_SIZENS; + break; + case BASEWND_CURSOR_EASTWEST: + wincursor = IDC_SIZEWE; + break; + case BASEWND_CURSOR_NORTHWEST_SOUTHEAST: + wincursor = IDC_SIZENWSE; + break; + case BASEWND_CURSOR_NORTHEAST_SOUTHWEST: + wincursor = IDC_SIZENESW; + break; + case BASEWND_CURSOR_4WAY: + wincursor = IDC_SIZEALL; + break; + case BASEWND_CURSOR_EDIT: + wincursor = IDC_IBEAM; + break; + default: + wincursor = IDC_ARROW; + break; + } + if (wincursor != NULL) + { + SetCursor(LoadCursor(NULL, wincursor)); + return TRUE; + } + } + return FALSE; + + case WM_TIMER: + timerCallback((int)wParam); + return 0; + + case WM_GETOBJECT: + if (lParam == OBJID_CLIENT) + { + Accessible *acc = getAccessibleObject(); + if (acc != NULL) + { + LRESULT lAcc = acc->getOSHandle((int)wParam); + return lAcc; + } + } + break; // Fall through to DefWindowProc + + + case WM_SETFOCUS: + if (!focusEventsEnabled) break; + if (isInited()) + { + if (rootfocus != NULL && rootfocus != this) + { + if (rootfocus != curVirtualChildFocus) + rootfocus->setFocus(); + break; + } + else + { + if (wantFocus()) + { + onGetFocus(); + break; + } + else + { + ifc_window *w = getTab(TAB_GETFIRST); + if (w != NULL) + { + w->setFocus(); + } + } + } + } + break; + + case WM_KILLFOCUS: + { + ifc_window *rp = getRootParent(); + if (!WASABI_API_WND->rootwndIsValid(rp) || !Wasabi::Std::Wnd::isValidWnd(rp->getOsWindowHandle())) break; + if (!focusEventsEnabled) break; +#ifdef WASABI_COMPILE_WND + if (WASABI_API_WND) WASABI_API_WND->forwardOnKillFocus(); // resets the keyboard active keys buffer +#endif + if (!WASABI_API_WND->rootwndIsValid(curVirtualChildFocus)) curVirtualChildFocus = NULL; + if (curVirtualChildFocus) + { + curVirtualChildFocus->onKillFocus(); + curVirtualChildFocus = NULL; + } + else + if (hasfocus) onKillFocus(); + break; + } + + // dragging and dropping + + case WM_LBUTTONDOWN: + { + if (lParam == 0xdeadc0de) + return 1; + + if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) + return 0; + + WASABI_API_WND->popupexit_check(this); + + if (checkModal()) + return 0; + + abortTip(); + + int xPos = (signed short)LOWORD(lParam); + int yPos = (signed short)HIWORD(lParam); + + xPos = (int)((float)xPos / getRenderRatio()); + yPos = (int)((float)yPos / getRenderRatio()); + + if (!getCapture() && hasVirtualChildren() && handleVirtualChildMsg(WM_LBUTTONDOWN, xPos, yPos)) + return 0; + + if (isEnabled() && !dragging) + { + autoFocus(this); + + int r = 0; + + if (wantLeftClicks()) + r = onLeftButtonDown(xPos, yPos); + + if (checkDoubleClick(uMsg, xPos, yPos) && wantDoubleClicks() && onLeftButtonDblClk(xPos, yPos)) + return 0; + + return r; + } + } + break; + + case WM_RBUTTONDOWN: + { + if (lParam == 0xdeadc0de) return 1; + if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0; + WASABI_API_WND->popupexit_check(this); + if (checkModal()) return 0; + abortTip(); + int xPos = (signed short)LOWORD(lParam); + int yPos = (signed short)HIWORD(lParam); + xPos = (int)((float)xPos / getRenderRatio()); + yPos = (int)((float)yPos / getRenderRatio()); + if (!getCapture() && hasVirtualChildren()) + if (handleVirtualChildMsg(WM_RBUTTONDOWN, xPos, yPos)) + return 0; + if (isEnabled() && !dragging) + { + autoFocus(this); + int r = 0; + if (wantRightClicks()) + r = onRightButtonDown(xPos, yPos); + if (checkDoubleClick(uMsg, xPos, yPos) && wantDoubleClicks()) if (onRightButtonDblClk(xPos, yPos)) return 0; + return r; + } + } + break; + case WM_MOUSEHOVER: + if (checkModal()) return 0; + if (!getCapture() && hasVirtualChildren()) + if (handleVirtualChildMsg(WM_MOUSEHOVER, 0, 0)) + return 0; + break; + case WM_MOUSEMOVE: + { + /* static int mm=0; + DebugString("mousemove %d\n", mm++);*/ + if (checkModal()) return 0; + int xPos = (signed short)LOWORD(lParam); + int yPos = (signed short)HIWORD(lParam); + xPos = (int)((float)xPos / getRenderRatio()); + yPos = (int)((float)yPos / getRenderRatio()); + if (dragging) + { + POINT pt = {xPos, yPos}; + clientToScreen(&pt); + ifc_window *targ; + int candrop = 0; + // find the window the mouse is over + + targ = NULL; + if (stickyWnd) + { + RECT wr; + GetWindowRect(stickyWnd->getOsWindowHandle(), &wr); + if (pt.x >= wr.left - sticky.left && + pt.x <= wr.right + sticky.right && + pt.y >= wr.top - sticky.top && + pt.y <= wr.bottom + sticky.bottom) targ = stickyWnd; + else stickyWnd = NULL; + } + + if (targ == NULL && WASABI_API_WND) targ = WASABI_API_WND->rootWndFromPoint(&pt); // FG> not to self, check + + DI prevtargdi(prevtarg); + DI targdi(targ); + + if (prevtarg != targ) + { + // window switch + if (prevtarg != NULL) prevtargdi.dragLeave(this); + if (targ != NULL) targdi.dragEnter(this); + } + if (targ != NULL) + candrop = targdi.dragOver(pt.x, pt.y, this); + if (targ == NULL || !candrop) + SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_NO))); + else + SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_APPSTARTING))); + prevtarg = targ; + } + else if (isEnabled()) + { + tipbeenchecked = FALSE; + if (!getCapture() && hasVirtualChildren()) + { + if (handleVirtualChildMsg(WM_MOUSEMOVE, xPos, yPos)) + return 0; + } + if (getCapture()) + { + if (wantMouseMoves()) + if (onMouseMove(xPos, yPos)) + return 0; + } + if (!tipbeenchecked) onTipMouseMove(); + return 0; + } + } + break; + + case WM_LBUTTONUP: + { + if (lParam == 0xdeadc0de) return 1; + if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0; + if (checkModal()) return 0; + int xPos = (signed short)LOWORD(lParam); + int yPos = (signed short)HIWORD(lParam); + xPos = (int)((float)xPos / getRenderRatio()); + yPos = (int)((float)yPos / getRenderRatio()); + abortTip(); + if (!dragging && !getCapture() && hasVirtualChildren()) + { + if (handleVirtualChildMsg(WM_LBUTTONUP, xPos, yPos)) + return 0; + } + if (dragging) + { + clientToScreen(&xPos, &yPos); + int res = 0; + if (prevtarg != NULL) + { + res = DI(prevtarg).dragDrop(this, xPos, yPos); + } + + // inform source what happened + dragComplete(res); + + resetDragSet(); + prevtarg = NULL; + stickyWnd = NULL; + suggestedTitle = NULL; + SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); + Wasabi::Std::Wnd::releaseCapture(); + dragging = 0; + } + else if (isEnabled()) + { + if (wantLeftClicks()) + if (onLeftButtonUp(xPos, yPos)) return 0; + } + } + break; + + case WM_RBUTTONUP: + { + if (lParam == 0xdeadc0de) return 1; + if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0; + if (checkModal()) return 0; + abortTip(); + int xPos = (signed short)LOWORD(lParam); + int yPos = (signed short)HIWORD(lParam); + xPos = (int)((float)xPos / getRenderRatio()); + yPos = (int)((float)yPos / getRenderRatio()); + if (!getCapture() && hasVirtualChildren()) + { + if (handleVirtualChildMsg(WM_RBUTTONUP, xPos, yPos)) + return 0; + } + if (isEnabled() && !dragging) + { + if (wantRightClicks()) + if (onRightButtonUp(xPos, yPos)) return 0; + } + } + break; + + case WM_CONTEXTMENU: + { + if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0; + if (checkModal()) return 0; + ASSERT(hWnd != NULL); + int xPos = (signed short)LOWORD(lParam); + int yPos = (signed short)HIWORD(lParam); + if (hWnd == getOsWindowHandle()) + { + if (wantContextMenus()) + if (onContextMenu(xPos, yPos)) return 0; + } + else if (GetParent(hWnd) == getOsWindowHandle()) + { + if (wantContextMenus()) + if (onChildContextMenu(xPos, yPos)) return 0; + } + } + break; + + case WM_ERASEBKGND: + return (onEraseBkgnd((HDC)wParam)); + + case WM_MOUSEWHEEL: + { + abortTip(); + + int l, a; + l = (short)HIWORD(wParam) / 120; + a = (short)HIWORD(wParam); + if (!l) + if (a > 0) l = 1; + else if (a < 0)l = 0; + a = l >= 0 ? l : -l; + if (GetAsyncKeyState(VK_MBUTTON)&0x8000) + { + if (l >= 0) l = 0; // Fast Forward 5s + else l = 1; // Rewind 5s + } + else + { + if (l >= 0) l = 2; // Volume up + else l = 3; // Volume down + } + + int r = 0; + + if (l & 1) + r = onMouseWheelDown(!(BOOL)(l & 2), a); + else + r = onMouseWheelUp(!(BOOL)(l & 2), a); + if (r == 0) + { + r = WASABI_API_WND->forwardOnMouseWheel(l, a); + } + // if it wasn't handled by this wnd, nor by the api, send it to the main wnd, unless we're it + if (r == 0) + { + if (WASABI_API_WND->main_getRootWnd() != this) + r = (int)SendMessageW(WASABI_API_WND->main_getRootWnd()->gethWnd(), uMsg, wParam, lParam); + } + + return r; + } + + case WM_WA_RELOAD: + { + if (wParam == 0) + freeResources(); + else + reloadResources(); + return 0; + } + + case WM_WA_GETFBSIZE: + { + SIZE *s = (SIZE *)wParam; + s->cx = rwidth; + s->cy = rheight; + return 0; + } + + case WM_USER + 8976: // wheel in tip, delete tip + abortTip(); + return 0; + + case WM_CHAR: + if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0; + if (WASABI_API_WND->interceptOnChar((TCHAR) wParam)) return 0; + if (curVirtualChildFocus == NULL) + { + if (onChar(((TCHAR) wParam))) return 0; + } + else + { + if (curVirtualChildFocus->onChar(((TCHAR) wParam))) return 0; + } + if (WASABI_API_WND && WASABI_API_WND->forwardOnChar(this, (TCHAR) wParam, (int)lParam)) return 0; + break; + + case WM_KEYDOWN: + if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0; + if (WASABI_API_WND->interceptOnKeyDown((int) wParam)) return 0; + if (curVirtualChildFocus == NULL) + { + if (onKeyDown((int) wParam)) return 0; + } + else + { + if (curVirtualChildFocus->onKeyDown((int)wParam)) return 0; + } + if (WASABI_API_WND && WASABI_API_WND->forwardOnKeyDown(this, (int) wParam, (int)lParam)) return 0; + break; + + case WM_KEYUP: + if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0; + if (WASABI_API_WND->interceptOnKeyUp((int) wParam)) return 0; + if (curVirtualChildFocus == NULL) + { + if (onKeyUp((int) wParam)) return 0; + } + else + { + if (curVirtualChildFocus->onKeyUp((int)wParam)) return 0; + } + if (WASABI_API_WND && WASABI_API_WND->forwardOnKeyUp(this, (int) wParam, (int)lParam)) return 0; + break; + + case WM_SYSKEYDOWN: + if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0; + if (WASABI_API_WND->interceptOnSysKeyDown((int) wParam, (int)lParam)) return 0; + if (curVirtualChildFocus == NULL) + { + if (onSysKeyDown((int) wParam, (int)lParam)) return 0; + } + else + { + if (curVirtualChildFocus->onSysKeyDown((int)wParam, (int)lParam)) return 0; + } + if (WASABI_API_WND && WASABI_API_WND->forwardOnSysKeyDown(this, (int) wParam, (int)lParam)) return 0; + break; + + case WM_SYSKEYUP: + if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0; + if (WASABI_API_WND->interceptOnSysKeyUp((int) wParam, (int)lParam)) return 0; + if (curVirtualChildFocus == NULL) + { + if (onSysKeyUp((int) wParam, (int)lParam)) return 0; + } + else + { + if (curVirtualChildFocus->onSysKeyUp((int)wParam, (int)lParam)) return 0; + } + if (WASABI_API_WND && WASABI_API_WND->forwardOnSysKeyUp(this, (int) wParam, (int)lParam)) return 0; + break; + + case WM_MOUSEACTIVATE: + { + if (checkModal() || !wantActivation()) + return MA_NOACTIVATE; + //SetFocus(getOsWindowHandle()); + return MA_ACTIVATE; + } + + case WM_ACTIVATEAPP: + + if (wParam == FALSE) + { + + if (WASABI_API_WND != NULL) + { + WASABI_API_WND->popupexit_signal(); + WASABI_API_SYSCB->syscb_issueCallback(SysCallback::GC, GarbageCollectCallback::GARBAGECOLLECT); + WASABI_API_WND->kbdReset(); + if (ghosthwnd.getNumItems() > 0 && ghostbust) + { + ghostbust = 0; postDeferredCallback(DC_KILLGHOST); + } + return 0; + } + } + + break; + + case WM_ACTIVATE: + switch(LOWORD(wParam)) + { + case WA_ACTIVE: + case WA_CLICKACTIVE: + if (WASABI_API_WND != NULL) + WASABI_API_WND->popupexit_check(this); + + onActivate(); + + if (WA_CLICKACTIVE == LOWORD(wParam)) + { + POINT pt; + DWORD pts = GetMessagePos(); + POINTSTOPOINT(pt, pts); + MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1); + HWND hTarget = ChildWindowFromPointEx(hwnd, pt, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED | CWP_SKIPTRANSPARENT); + if (hTarget && hTarget != hwnd) lastActiveWnd = hTarget; + } + + if (lastActiveWnd != hwnd && NULL != lastActiveWnd && IsWindow(lastActiveWnd)) + { + SendMessageW(lastActiveWnd, uMsg, wParam, lParam); + return 0; + } + break; + default: + + onDeactivate(); + + lastActiveWnd = GetFocus(); + + if (NULL != lastActiveWnd && !IsChild(hwnd, lastActiveWnd)) + lastActiveWnd = NULL; + + { +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x)) +#endif + if (NULL != lastActiveWnd && !BaseWnd_IsFrameWindow(lastActiveWnd)) + { + while (lastActiveWnd) + { + if (BaseWnd_IsFrameWindow(GetWindow(lastActiveWnd, GW_OWNER))) + break; + lastActiveWnd = GetAncestor(lastActiveWnd, GA_PARENT); + } + } + } + + if (lastActiveWnd != hwnd && NULL != lastActiveWnd) + { + SendMessageW(lastActiveWnd, uMsg, wParam, lParam); + return 0; + } + + break; + } + break; + + case WM_NCACTIVATE: + if (allowDeactivation()) + return TRUE; + return FALSE; + + case WM_WINDOWPOSCHANGING: + { + if (!isVirtual() && Wasabi::Std::Wnd::isPopup(hwnd)) + { + WINDOWPOS *wp = (WINDOWPOS *)lParam; + if (wp->x != rx || wp->y != ry) wp->flags |= SWP_NOMOVE; + } + } + break; + + case WM_WINDOWPOSCHANGED: + { + + WINDOWPOS *lpwp = (WINDOWPOS *)lParam; // points to size and position data + if (lpwp->flags & SWP_HIDEWINDOW) + { + minimized = 1; + onMinimize(); + } + else if (lpwp->flags & SWP_SHOWWINDOW) + { + minimized = 0; + onRestore(); + } + + if (!inonresize) + { + int w = rwidth; + int h = rheight; + multRatio(&w, &h); + if (lpwp->cx != w || lpwp->cy != h) + { + DebugStringW(L"external onResize\n"); + w = lpwp->cx; + h = lpwp->cy; + divRatio(&w, &h); + setRSize(rx, ry, w, h); + if (isPostOnInit()) + onResize(); + } + } + + onPostedMove(); + return 0; + } + + case WM_DROPFILES: + { + if (checkModal()) break; + WASABI_API_WND->pushModalWnd(); + onExternalDropBegin(); + HDROP h = (HDROP)wParam; + POINT dp = {0}; + DragQueryPoint(h, &dp); + clientToScreen(&dp); + // build a file list + wchar_t buf[WA_MAX_PATH] = {0}; + PtrList<FilenamePS> keep; + + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + //CUT #if UTF8 + //CUT // doesn't really need UTF8, the "buf" is never written to. + //CUT // made to be NULL to enforce this concept. + int nfiles = DragQueryFile(h, 0xffffffff, NULL, 0); + //CUT #else + //CUT int nfiles = DragQueryFile(h, 0xffffffff, buf, sizeof(buf)); + //CUT #endif + + // convert them all to PlayItem *'s + for (int i = 0; i < nfiles; i++) + { + DragQueryFileW(h, i, buf, WA_MAX_PATH); + addDroppedFile(buf, &keep); // recursive + + } + SetCursor(LoadCursor(NULL, IDC_ARROW)); + dragging = 1; + if (dragEnter(this)) + { + if (dragOver(dp.x, dp.y, this)) dragDrop(this, dp.x, dp.y); + } + else + { + dragLeave(this); +#ifdef FORWARD_DRAGNDROP + HWND w = WASABI_API_WND->main_getRootWnd()->gethWnd(); + SendMessageW(w, WM_DROPFILES, wParam, lParam); +#endif + + } + dragging = 0; + + // remove data + keep.deleteAll(); + resetDragSet(); + + onExternalDropEnd(); + WASABI_API_WND->popModalWnd(); + } + return 0; // dropfiles + + case WM_CAPTURECHANGED: + /* static int cc=0; + DebugString("capture changed! %d\n", cc++);*/ + if (preventcancelcapture) return 0; + inputCaptured = 0; + if (curVirtualChildCaptured != NULL) + { + ifc_window *w = curVirtualChildCaptured; + curVirtualChildCaptured = NULL; + w->onCancelCapture(); + } + else + { + onCancelCapture(); + } + return 0; + + } //switch + + if (WINAMP_WM_DIRECT_MOUSE_WHEEL == uMsg && + WM_NULL != WINAMP_WM_DIRECT_MOUSE_WHEEL) + { + wndProc(hWnd, WM_MOUSEWHEEL, wParam, lParam); + return TRUE; + } + + if (uMsg >= WM_USER) + { + int ret; + if (onUserMessage(uMsg, (int)wParam, (int)lParam, &ret)) + return ret; + return 0; + } + + return DefWindowProcW(hWnd, uMsg, wParam, lParam); +} +#endif +int BaseWnd::onUserMessage(int msg, int w, int l, int *r) +{ + return 0; +} + +int BaseWnd::checkDoubleClick(int b, int x, int y) +{ +#ifdef _WIN32 + uint32_t now = Wasabi::Std::getTickCount(); + + switch (b) + { + case WM_LBUTTONDOWN: + if (lastClick[0] > now - Wasabi::Std::getDoubleClickDelay()) + { + lastClick[0] = 0; + if (ABS(lastClickP[0].x - x) > Wasabi::Std::getDoubleClickX() || ABS(lastClickP[0].y - y) > Wasabi::Std::getDoubleClickY()) return 0; + return 1; + } + lastClick[0] = now; + lastClickP[0].x = x; + lastClickP[0].y = y; + break; + + case WM_RBUTTONDOWN: + if (lastClick[1] > now - Wasabi::Std::getDoubleClickDelay()) + { + lastClick[1] = 0; + if (ABS(lastClickP[1].x - x) > Wasabi::Std::getDoubleClickX() || ABS(lastClickP[1].y - y) > Wasabi::Std::getDoubleClickY()) return 0; + return 1; + } + lastClick[1] = now; + lastClickP[1].x = x; + lastClickP[1].y = y; + break; + } +#else +#warning port me +#endif + return 0; +} + +int BaseWnd::onMouseWheelUp(int click, int lines) +{ + return 0; +} + +int BaseWnd::onMouseWheelDown(int click, int lines) +{ + return 0; +} + +int BaseWnd::onContextMenu(int x, int y) +{ + return 0; +} + +int BaseWnd::onChildContextMenu(int x, int y) +{ + return 0; +} + +int BaseWnd::onDeferredCallback(intptr_t param1, intptr_t param2) +{ + switch (param1) + { + case DEFERREDCB_FLUSHPAINT: + do_flushPaint(); + break; + case DEFERREDCB_INVALIDATE: + if (isPostOnInit()) + invalidate(); + break; + case DC_KILLGHOST: + if (ghosthwnd.getNumItems() > 0) + { + preventcancelcapture = 1; + for (int i = 0;i < ghosthwnd.getNumItems();i++) + Wasabi::Std::Wnd::destroyWnd(ghosthwnd.enumItem(i)); + ghosthwnd.freeAll(); + preventcancelcapture = 0; + } + break; + case DEFERREDCB_FOCUSFIRST: + assignRootFocus(NULL); + if (Wasabi::Std::Wnd::getFocus() == getOsWindowHandle()) + { + focusNext(); + } + break; + case 0x7849 /*DEFERREDCB_ONHIDE*/: + { + foreach(rootwndchildren) + ifc_window *w = rootwndchildren.getfor(); + if (w->isVisible(1)) // check internal flag only + w->onSetVisible(0); + endfor; + dependent_sendEvent(BaseWnd::depend_getClassGuid(), Event_SETVISIBLE, 0); + break; + } + } + return 0; +} + +int BaseWnd::onPaint(Canvas *canvas) +{ +#if 0 + // example: + PaintCanvas c; + if (!c.beginPaint(this)) return 0; + (do some painting) + c will self -destruct on return +#endif + if (renderbasetexture) + { + PaintCanvas paintcanvas; + if (canvas == NULL) + { + if (!paintcanvas.beginPaint(this)) return 0; + canvas = &paintcanvas; + } + RECT r; + getNonClientRect(&r); + RenderBaseTexture(canvas, r); + } + return 0; +} + +int BaseWnd::onPaint(Canvas *canvas, api_region *h) +{ + if (!canvas) return onPaint(canvas); + +#ifdef _WIN32 + int sdc = SaveDC(canvas->getHDC()); +#elif defined(__APPLE__) + CGContextSaveGState(canvas->getHDC()); +#endif + + canvas->selectClipRgn(h); + + int rs = onPaint(canvas); + +#ifdef _WIN32 + RestoreDC(canvas->getHDC(), sdc); +#elif defined(__APPLE__) + CGContextRestoreGState(canvas->getHDC()); +#endif + + return rs; +} + +int BaseWnd::getTransparency() +{ + return wndalpha; +} + +void BaseWnd::setTransparency(int amount) +{ + //if (wndalpha == amount) return; + if (amount == 254) amount = 255; + if (amount == 1) amount = 0; + + if (amount != -1) wndalpha = amount; else amount = wndalpha; + + if (!Wasabi::Std::Wnd::isDesktopAlphaAvailable()) + { + wndalpha = 255; + return ; + } + + if (w2k_alpha) + { + invalidate(); + return ; + } + +#ifdef WIN32 + + if (!isInited() || isVirtual()) return ; + if (!Wasabi::Std::Wnd::isValidWnd(getOsWindowHandle())) return ; + + if (amount < -1) amount = 0; + else if (amount > 255) amount = 255; + + //CUT DWORD dwLong = GetWindowLong(hwnd, GWL_EXSTYLE); + if (amount == 255 && !forceTransparencyFlag()) + { + Wasabi::Std::Wnd::setLayeredWnd(hwnd, FALSE); + //CUT if (dwLong & WS_EX_LAYERED) + //CUT SetWindowLong(hwnd, GWL_EXSTYLE, dwLong & ~WS_EX_LAYERED); + has_alpha_flag = 0; + } + else + { + if (!Wasabi::Std::Wnd::isLayeredWnd(hwnd)) + Wasabi::Std::Wnd::setLayeredWnd(hwnd, TRUE); + //CUT if (!(dwLong & WS_EX_LAYERED)) + //CUT SetWindowLong(hwnd, GWL_EXSTYLE, dwLong | WS_EX_LAYERED); + Wasabi::Std::Wnd::setLayeredAlpha(hwnd, amount); + //CUT setLayeredWindowAttributes(hwnd, RGB(0,0,0), amount, LWA_ALPHA); + has_alpha_flag = 1; + } +#endif +} + +int BaseWnd::forceTransparencyFlag() +{ + return 0; +} + +int BaseWnd::beginCapture() +{ + if (!getCapture()) + { + disable_tooltip_til_recapture = 0; + curVirtualChildCaptured = NULL; + /* oldCapture = */Wasabi::Std::Wnd::setCapture(getOsWindowHandle()); + /* if (oldCapture) { + DebugString("Stolen capture detected, this may be ok, but try to avoid it if possible. Saving old capture\n"); + }*/ + inputCaptured = 1; + } + return 1; +} + +int BaseWnd::endCapture() +{ + preventcancelcapture = 1; + if (Wasabi::Std::Wnd::getCapture() == getOsWindowHandle()) Wasabi::Std::Wnd::releaseCapture(); + /* if (oldCapture) { + DebugString("Restoring old capture\n"); + SetCapture(oldCapture); + oldCapture = NULL; + }*/ + inputCaptured = 0; + preventcancelcapture = 0; + return 1; +} + +int BaseWnd::getCapture() +{ + if (inputCaptured && Wasabi::Std::Wnd::getCapture() == getOsWindowHandle() && curVirtualChildCaptured == NULL) return 1; + return 0; +} + +void BaseWnd::cancelCapture() +{ + if (curVirtualChildCaptured != NULL) + { + curVirtualChildCaptured->cancelCapture(); + return ; + } + if (getCapture()) endCapture(); + onCancelCapture(); +} + +int BaseWnd::onMouseMove(int x, int y) +{ + onTipMouseMove(); + return 0; +} + +void BaseWnd::onTipMouseMove() +{ + POINT p; + + if (dragging) return ; + if (disable_tooltip_til_recapture) return ; + + tipbeenchecked = TRUE; + + Wasabi::Std::getMousePos(&p); + + if (WASABI_API_WND->rootWndFromPoint(&p) != (ifc_window *)this) + { + // leaving area + tip_done = FALSE; + if (tipawaytimer) + killTimer(TIP_AWAY_ID); + tipawaytimer = FALSE; + if (tipshowtimer) + { + // TODO: on the mac, use CreateMouseTrackingRegion + TRACKMOUSEEVENT tracker; + tracker.cbSize=sizeof(tracker); + tracker.dwFlags = TME_HOVER|TME_CANCEL; + tracker.hwndTrack = this->getOsWindowHandle(); + tracker.dwHoverTime = TIP_TIMER_THRESHOLD; + + TrackMouseEvent(&tracker); + } + tipshowtimer = FALSE; + destroyTip(); + } + else + { + // moving in area + const wchar_t *t = getTip(); + if (!disable_tooltip_til_recapture && !tipshowtimer && !tip_done && t != NULL && *t != 0) + { + //entering area & need tip + + // TODO: on the mac, use CreateMouseTrackingRegion + TRACKMOUSEEVENT tracker; + tracker.cbSize=sizeof(tracker); + tracker.dwFlags = TME_HOVER; + tracker.hwndTrack = this->getOsWindowHandle(); + tracker.dwHoverTime = TIP_TIMER_THRESHOLD; + + TrackMouseEvent(&tracker); + + tipshowtimer = TRUE; + } + /*else if (tipshowtimer) + { + TRACKMOUSEEVENT tracker; + tracker.cbSize=sizeof(tracker); + tracker.dwFlags = TME_HOVER; + tracker.hwndTrack = this->getOsWindowHandle(); + tracker.dwHoverTime = TIP_TIMER_THRESHOLD; + + TrackMouseEvent(&tracker); + }*/ + } +} + +int BaseWnd::onLeftButtonDblClk(int x, int y) +{ + return 0; +} + +int BaseWnd::onRightButtonDblClk(int x, int y) +{ + return 0; +} + +int BaseWnd::onGetFocus() +{ + // return TRUE if you override this + hasfocus = 1; + notifyParent(ChildNotify::GOTFOCUS); + getRootParent()->onSetRootFocus(this); + invalidate(); + Accessible *a = getAccessibleObject(); + if (a != NULL) + a->onGetFocus(); + return 1; +} + +int BaseWnd::onKillFocus() +{ + // return TRUE if you override this + hasfocus = 0; + notifyParent(ChildNotify::KILLFOCUS); + invalidate(); + return 1; +} + +#if defined(_WIN64) +int BaseWnd::childNotify(ifc_window* child, int msg, int p1, int p2) +{ + return 0; +} +#else +int BaseWnd::childNotify(ifc_window *child, int msg, intptr_t p1, intptr_t p2) +{ + return 0; +} +#endif + +int BaseWnd::addDragItem(const wchar_t *droptype, void *item) +{ + ASSERT(droptype != NULL); + if (item == NULL) return -1; + DragSet *set; + int pos = dragCheckData(droptype); + if (pos == -1) + { + set = new DragSet(); + set->setName(droptype); + dragsets.addItem(set); + pos = dragsets.getNumItems() - 1; + } + else set = dragsets[pos]; + set->addItem(item); + return pos; +} + +#ifdef _WIN32 +int BaseWnd::handleDrag() +{ + abortTip(); + if (dragsets.getNumItems() == 0) return 0; + + Wasabi::Std::Wnd::setCapture(hwnd); + SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_APPSTARTING))); + + dragging = 1; + stickyWnd = NULL; + + return 1; +} +#endif + +int BaseWnd::resetDragSet() +{ + dragsets.deleteAll(); + return 1; +} + +int BaseWnd::dragEnter(ifc_window *sourceWnd) +{ + ifc_window *rw = getParent(); //api_window::rootwndFromRootWnd(getParent()); //FG> note to self, check! + if (rw) return DI(rw).dragEnter(sourceWnd); + return 0; +} + +int BaseWnd::dragSetSticky(ifc_window *wnd, int left, int right, int up, int down) +{ + ASSERT(dragging); + stickyWnd = wnd; + + if (left < 0) left = 0; + if (right < 0) right = 0; + if (up < 0) up = 0; + if (down < 0) down = 0; + + Wasabi::Std::setRect(&sticky, left, up, right, down); + + return 1; +} + +void BaseWnd::setSuggestedDropTitle(const wchar_t *title) +{ + ASSERT(title != NULL); + suggestedTitle = title; +} + +const wchar_t *BaseWnd::dragGetSuggestedDropTitle() +{ + return suggestedTitle; // can be NULL +} + +int BaseWnd::dragCheckData(const wchar_t *type, int *nitems) +{ + for (int i = 0; i < dragsets.getNumItems(); i++) + { + if (!WCSICMP(type, dragsets[i]->getName())) + { + if (nitems != NULL) *nitems = dragsets[i]->getNumItems(); + return i; + } + } + return -1; +} + +void *BaseWnd::dragGetData(int slot, int itemnum) +{ + if (slot < 0 || slot >= dragsets.getNumItems()) return 0; + if (itemnum < 0 || itemnum >= dragsets[slot]->getNumItems()) return 0; + return dragsets[slot]->enumItem(itemnum); +} + +void BaseWnd::addDroppedFile(const wchar_t *filename, PtrList<FilenamePS> *plist) +{ +#ifdef RECURSE_SUBDIRS_ON_DROP + const char *slash = filename + STRLEN(filename) - 1; + for (; slash > filename; slash--) if (*slash == '/' || *slash == '\\') break; + if (STREQL(slash + 1, ".") || STREQL(slash + 1, "..")) return ; + + char buf[WA_MAX_PATH] = {0}; + STRCPY(buf, filename); + // try to resolve shortcuts + char *ext = buf + STRLEN(buf) - 1; + for (; ext > buf; ext--) if (*ext == '.' || *ext == '\\' || *ext == '/') break; +#ifdef WIN32 + if (!STRICMP(ext, ".lnk")) + { + char buf2[MAX_PATH] = {0}; + if (StdFile::resolveShortcut(buf, buf2)) STRCPY(buf, buf2); + } +#endif + + int isdir = 0; + + // handle root dir specially? + WIN32_FIND_DATA data = {0}; + HANDLE r = FindFirstFile(buf, &data); + if (!r) return ; + FindClose(r); + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) isdir = 1; + + if (isdir) + { + onExternalDropDirScan(buf); + + // enumerate that dir + char search[WA_MAX_PATH] = {0}; + wsprintf(search, "%s\\*.*", buf); + HANDLE files = FindFirstFile(search, &data); + if (files == INVALID_HANDLE_VALUE) return ; // nothin' in it + for (;;) + { + wchar_t obuf[WA_MAX_PATH] = {0}; + swprintf(obuf, L"%s\\%s", buf, data.cFileName); + addDroppedFile(obuf, plist); + if (!FindNextFile(files, &data)) + { + FindClose(files); + return ; + } + } + + // should never get here + } + else + { + addDragItem(DD_FILENAME, plist->addItem(new FilenamePS(StringPrintfW(L"file:%s", buf)))); + } +#else + addDragItem(DD_FILENAME, plist->addItem(new FilenamePS(StringPrintfW(L"file:%s", filename)))); +#endif +} + +bool BaseWnd::getNoCopyBits(void) +{ + return ncb; +} + +void BaseWnd::setNoCopyBits(bool newncb) +{ + ncb = newncb; +} + +int BaseWnd::onEraseBkgnd(HDC dc) +{ + return 1; +} + +void BaseWnd::setIcon(OSICONHANDLE icon, int _small) +{ + Wasabi::Std::Wnd::setIcon(getOsWindowHandle(), icon, !_small); + //CUT SendMessageW(getOsWindowHandle(), WM_SETICON, _small ? ICON_SMALL : ICON_BIG, (int)icon); +} + +const wchar_t *BaseWnd::getTip() +{ + return tip; +} + +void BaseWnd::setTip(const wchar_t *_tooltip) +{ + tip = _tooltip; + abortTip(); +} + +int BaseWnd::getStartHidden() +{ + return start_hidden; +} + +void BaseWnd::abortTip() +{ + if (tipshowtimer) + { + // TODO: on the mac, use CreateMouseTrackingRegion + TRACKMOUSEEVENT tracker; + tracker.cbSize=sizeof(tracker); + tracker.dwFlags = TME_HOVER|TME_CANCEL; + tracker.hwndTrack = this->getOsWindowHandle(); + tracker.dwHoverTime = TIP_TIMER_THRESHOLD; + + TrackMouseEvent(&tracker); + } + tipshowtimer = FALSE; + if (tipawaytimer) + killTimer(TIP_AWAY_ID); + tipawaytimer = FALSE; + if (tipdestroytimer) + killTimer(TIP_DESTROYTIMER_ID); + tipdestroytimer = FALSE; + destroyTip(); + tip_done = FALSE; + RECT r; + if (getOsWindowHandle() && Wasabi::Std::Wnd::getUpdateRect(getOsWindowHandle(), &r) != 0) // FG> avoids xoring over disapearing tip + repaint(); +} + +int BaseWnd::isVisible(int within) +{ + if (!isVirtual() && !getOsWindowHandle()) return 0; + if (!this_visible) return 0; + + if (within) return this_visible; // whatever, local + + if (isVirtual()) // virtual, global + if (getParent()) + return getParent()->isVisible(); + else + return 0; + + // non virtual, global + if (Wasabi::Std::Wnd::isPopup(getOsWindowHandle())) return this_visible; + if (!Wasabi::Std::Wnd::isValidWnd(Wasabi::Std::Wnd::getParent(getOsWindowHandle()))) return 0; + if (getParent()) return getParent()->isVisible(); // not a popup, check its parent or fail + return this_visible; +} + +void BaseWnd::registerRootWndChild(ifc_window *child) +{ + rootwndchildren.addItem(child); + if (child->isVirtual()) + virtualChildren.addItem(child); +} + +void BaseWnd::unregisterRootWndChild(ifc_window *child) +{ + delTabOrderEntry(child); + rootwndchildren.removeItem(child); + if (curVirtualChildCaptured == child) + { + setVirtualChildCapture(NULL); + } + if (curVirtualChildFocus == child) + curVirtualChildFocus = NULL; + virtualChildren.removeItem(child); + //WASABI_API_WND->timer_remove(this, -1); + if (isPostOnInit() && isVisible()) + postDeferredCallback(DEFERREDCB_INVALIDATE, 0); +} + +int BaseWnd::isVirtual() +{ + return 0; +} + +//CUT?inline int isInRect(RECT *r,int x,int y) { +//CUT? if (x>=r->left&&x<=r->right&&y>=r->top&&y<=r->bottom) return 1; +//CUT? return 0; +//CUT?} + +int BaseWnd::ensureVirtualCanvasOk() +{ + RECT ncr; + + if (isVirtual() && getParent()) return 1; + + int size_w = rwidth; + int size_h = rheight; + + if (!size_w || !size_h) return 0; + + if (!virtualCanvas || virtualCanvasH != size_h || virtualCanvasW != size_w) + { + if (virtualCanvas) + { + deleteFrameBuffer(virtualCanvas); + virtualCanvas = NULL; + } + delete scalecanvas; + scalecanvas = NULL; + virtualCanvas = createFrameBuffer(size_w, size_h); + prepareFrameBuffer(virtualCanvas, size_w, size_h); + virtualCanvas->setBaseWnd(this); + virtualCanvasH = size_h; virtualCanvasW = size_w; + BaseWnd::getNonClientRect(&ncr); + deferedInvalidateRect(&ncr); + } + return 1; +} + +Canvas *BaseWnd::createFrameBuffer(int w, int h) +{ + return new BltCanvas(w, h, getOsWindowHandle()); +} + +void BaseWnd::prepareFrameBuffer(Canvas *canvas, int w, int h) +{ + RECT r = {0, 0, w, h}; + RegionI reg(&r); + virtualBeforePaint(®); +#ifdef _WIN32 + canvas->selectClipRgn(NULL); + canvas->fillRect(&r, 0); +#elif defined(__APPLE__) + CGContextClearRect(canvas->getHDC(), CGRectInfinite); // TODO: make "clear" function in canvas +#endif + virtualAfterPaint(®); +} + +void BaseWnd::deleteFrameBuffer(Canvas *canvas) +{ + delete canvas; +} + +// paints the client content, followed by the virtual child tree. recursive +int BaseWnd::paintTree(Canvas *canvas, api_region *r) +{ + onPaint(canvas, r); + +#ifdef WASABI_DRAW_FOCUS_RECT + if (gotFocus()) + { + RECT ncr; + getNonClientRect(&ncr); + // try to use skinned focus rect + if (WASABI_API_WND->paintset_present(Paintset::FOCUSRECT)) + WASABI_API_WND->paintset_render(Paintset::FOCUSRECT, canvas, &ncr, 128); + else // otherwise this looks kinda nice :P + canvas->drawRect(&ncr, 0, 0xFFFFFF, 128); + } +#endif + + if (isVirtual() && !hasVirtualChildren()) return 0; + + api_region *hostrgn = NULL; + api_region *update = r; + + if (!(hwnd != NULL && getParent() == NULL)) + { + hostrgn = getRegion(); + update = r->clone(); + if (hostrgn && !isRectRgn()) + { + RECT ncr = clientRect(); + api_region *hostclone = hostrgn->clone(); + hostclone->addRegion(getComposedRegion()); + hostclone->offset(ncr.left, ncr.top); + update->andRegion(hostclone); + hostrgn->disposeClone(hostclone); + } + } + + RegionI client_update; + for (int i = 0;i < virtualChildren.getNumItems();i++) + { + if (!virtualChildren[i]->isVisible(1)) continue; + RECT rChild; + ifc_window *w = virtualChildren[i]; + w->getNonClientRect(&rChild); + if ((rChild.right != rChild.left) && (rChild.bottom != rChild.top)) + if (update->intersectRect(&rChild, &client_update)) + { + w->paintTree(canvas, &client_update); + } + } + + if (update != r) r->disposeClone(update); + + return 1; +} + +void BaseWnd::setVirtualCanvas(Canvas *c) +{ + virtualCanvas = c; +} + +int BaseWnd::pointInWnd(POINT *p) +{ + RECT r; + if (!isVisible(1)) return 0; + getWindowRect(&r); + if (!Wasabi::Std::pointInRect(r, *p)) + return 0; + for (int i = 0; i < getNumRootWndChildren(); i++) + { + ifc_window *c = enumRootWndChildren(i); + if (!c->isVisible(1)) continue; + RECT rChild; + c->getWindowRect(&rChild); + if (Wasabi::Std::pointInRect(rChild, *p)) + return 0; + } + //NONPORTABLE + /* HWND child = GetWindow(getOsWindowHandle(), GW_CHILD); + while (child != NULL) { + if (IsWindowVisible(child)) { + RECT r2; + GetWindowRect(child, &r2); + if (Std::pointInRect(r2, *p)) + return 0; + } + child = GetWindow(child, GW_HWNDNEXT); + }*/ + return 1; +} + +int BaseWnd::paint(Canvas *c, api_region *r) +{ + if (isVirtual()) + { + RegionI d; + RECT cr; + getClientRect(&cr); + if (r == NULL) + { + d.addRect(&cr); + } + else + { + d.addRegion(r); + d.offset(cr.left, cr.top); + } + ifc_window *rp = getRootParent(); + deferedInvalidate(); + rp->paint(NULL, &d); + BltCanvas *cc = static_cast<BltCanvas*>(rp->getFrameBuffer()); + if (r != NULL) c->selectClipRgn(r); + cc->blit(cr.left, cr.top, c, 0, 0, cr.right - cr.left, cr.bottom - cr.top); + return 1; + } + + if (!ensureVirtualCanvasOk()) return 0; + RegionI *deleteme = NULL; + if (r == NULL) + { + RECT cr; + getNonClientRect(&cr); + deleteme = new RegionI(&cr); + r = deleteme; + } + + virtualBeforePaint(r); + + RECT rcPaint; + r->getBox(&rcPaint); + + double ra = getRenderRatio(); + + if (deferedInvalidRgn) + { + api_region *nr = NULL; + if (renderRatioActive()) + { + nr = r->clone(); + double d = 1.0 / ra; + nr->scale(d, d, TRUE); + } + + if (deferedInvalidRgn->isEmpty() == 0) + { + // some deferednvalidated regions needs to be repainted + // TODO: need a "clear region" function in canvas + api_region *i = deferedInvalidRgn->clone(); +#ifdef _WIN32 + FillRgn(virtualCanvas->getHDC(), i->getOSHandle(), (HBRUSH)GetStockObject(BLACK_BRUSH)); +#elif defined(__APPLE__) + CGContextSaveGState(virtualCanvas->getHDC()); + virtualCanvas->selectClipRgn(i); + CGContextClearRect(virtualCanvas->getHDC(), CGRectInfinite); +// virtualCanvas->selectClipRgn(0); + CGContextRestoreGState(virtualCanvas->getHDC()); +#endif + paintTree(virtualCanvas, i); + + deferedValidateRgn(i); + deferedInvalidRgn->disposeClone(i); + + } + if (nr) r->disposeClone(nr); + } + + virtualAfterPaint(r); + + if (c != NULL) + { + commitFrameBuffer(c, &rcPaint, ra); //TH WDP2-212 + } + + delete deleteme; + return 1; +} + +int BaseWnd::virtualOnPaint() +{ +#ifdef _WIN32 + RECT cr; + getNonClientRect(&cr); + if (cr.left >= cr.right || cr.top >= cr.bottom) return 0; + + if (!ensureVirtualCanvasOk()) return 0; + + RegionI reg; + + //CUT GetUpdateRgn(getOsWindowHandle(), r->getOSHandle(), FALSE); + Wasabi::Std::Wnd::getUpdateRegion(getOsWindowHandle(), reg.getOSHandle()); + + PaintCanvas paintcanvas; + if (!paintcanvas.beginPaint(this)) + { + virtualAfterPaint(®); return 0; + } + + // DO NOT DELETE - This looks like it does nothing, but it actually makes the GDI call us again with WM_PAINT if some window + // moves over this one between BeginPaint and EndPaint. We still use GetUpdateRgn so we don't have to check for + // the version of Windows. See doc. If this function is not available (should be here in 95/98/NT/2K, but we never know) + // then we use the rcPaint rect... less precise, but still works. + //CUT if (getRandomRgn) { + if (Wasabi::Std::Wnd::haveGetRandomRegion()) + { + RegionI zap; + //CUT getRandomRgn(paintcanvas.getHDC(), zap.getOSHandle(), SYSRGN); + Wasabi::Std::Wnd::getRandomRegion(paintcanvas.getHDC(), zap.getOSHandle()); + } + else + { + RECT z; + paintcanvas.getRcPaint(&z); + reg.setRect(&z); + } + + // ------------- + + /*// for debug + HDC dc = GetDC(getOsWindowHandle()); + InvertRgn(dc, r->getHRGN()); + InvertRgn(dc, r->getHRGN()); + ReleaseDC(getOsWindowHandle(), dc);*/ + + paint(&paintcanvas, ®); +#else +#warning port me or remove me +#endif + + return 1; +} + +ifc_window *BaseWnd::enumVirtualChild(int _enum) +{ + return virtualChildren[_enum]; +} + +int BaseWnd::getNumVirtuals() +{ + return virtualChildren.getNumItems(); +} + +ifc_window *BaseWnd::enumRootWndChildren(int n) +{ + return rootwndchildren.enumItem(n); +} + +int BaseWnd::getNumRootWndChildren() +{ + return rootwndchildren.getNumItems(); +} + +ifc_window *BaseWnd::findRootWndChild(int x, int y, int only_virtuals) +{ + for (int i = getNumRootWndChildren() - 1; i > -1; i--) + { + RECT r; + ifc_window *child = enumRootWndChildren(i); + //DebugStringW(L"findRootWndChild = entering = %s\n", child->getId()); + if (only_virtuals && !child->isVirtual()) continue; + child->getNonClientRect(&r); + int _x = x; + int _y = y; + if (!child->isVirtual()) + { + POINT pt; + child->getPosition(&pt); + _x -= pt.x; + _y -= pt.y; + } + int iv = child->isVisible(1); + //int gpa = child->getPaintingAlpha(); + POINT _p = Wasabi::Std::makePoint(_x, _y); + if (iv /*&& gpa > 0*/ && Wasabi::Std::pointInRect(r, _p)) + { + // GROUP + ifc_window *z = child->findRootWndChild(_x, _y); + if (z) return z; + } + /*gpa > 0 &&*/ + /*if (iv && _x>=r.left&&_x<=r.right&&_y>=r.top&&_y<=r.bottom && !child->isClickThrough() && child->ptInRegion(_x, _y)) { + return child; + }*/ + } + return (!isClickThrough() && ptInRegion(x, y)) ? this : NULL; +} + +//PORTME +int BaseWnd::handleVirtualChildMsg(UINT uMsg, int x, int y, void *p, void *d) +{ +#ifdef _WIN32 + ifc_window *child = NULL; + + if (curVirtualChildCaptured) + child = curVirtualChildCaptured; + else + child = findRootWndChild(x, y, 1); // warning, can return this which is not virtual + + // ASSERT(child != NULL); // BU this came up and I don't know why, looks like it should never happen + // FG> actually it can happen when coming back from a popup menu when cpu usage is high, the window might be + // hidden (destroying) and ptInRegion returns false. + if (!child) return 0; + + //int isvirtual = child->isVirtual(); + + if (child) child = child->getForwardWnd(); + + if (child && child->isEnabled()) + { + switch (uMsg) + { + case WM_LBUTTONDOWN: + /* if (isvirtual && child != curVirtualChildFocus) + focusVirtualChild(child);*/ + autoFocus(child); + if (child->wantLeftClicks()) + child->onLeftButtonDown(x, y); + if (child->checkDoubleClick(uMsg, x, y) && child->wantDoubleClicks()) + child->onLeftButtonDblClk(x, y); + return 1; + case WM_RBUTTONDOWN: + /* if (isvirtual && child != curVirtualChildFocus) + focusVirtualChild(child);*/ + autoFocus(child); + if (child->wantRightClicks()) + child->onRightButtonDown(x, y); + if (child->checkDoubleClick(uMsg, x, y) && child->wantDoubleClicks()) + child->onRightButtonDblClk(x, y); + return 1; + case WM_LBUTTONUP: + if (child->wantLeftClicks()) + child->onLeftButtonUp(x, y); + return 1; + case WM_RBUTTONUP: + if (child->wantRightClicks()) + child->onRightButtonUp(x, y); + return 1; + case WM_MOUSEMOVE: + { + if (curVirtualChildCaptured == child || (curVirtualChildCaptured == NULL)) + { + if (child->wantMouseMoves()) + child->onMouseMove(x, y); + return 1; + } + return 0; + } + case WM_MOUSEHOVER: + ((BaseWnd *)child)->onTip(); + break; + case WM_SETCURSOR: + int a = child->getCursorType(x, y); + if (!p) return 0; + *(int *)p = a; + if (a == BASEWND_CURSOR_USERSET) + { + OSCURSORHANDLE c = child->getCustomCursor(x, y); + if (!d) return 0; + *(OSCURSORHANDLE *)d = c; + } + return 1; + } + } +#else +#warning port me or remove me +#endif + return 0; +} + +int BaseWnd::onLeftButtonDown(int x, int y) +{ + disable_tooltip_til_recapture = 1; + abortTip(); + return 0; +} + +int BaseWnd::onLeftButtonUp(int x, int y) +{ + disable_tooltip_til_recapture = 1; + abortTip(); + return 0; +} + +void BaseWnd::setVirtualChildCapture(ifc_window *child) +{ + if (child) + { + if (!inputCaptured) + { + beginCapture(); + } + } + else + { + endCapture(); + } + curVirtualChildCaptured = child; +} + +ifc_window *BaseWnd::getVirtualChildCapture() +{ + if (inputCaptured && Wasabi::Std::Wnd::getCapture() == getOsWindowHandle()) + return curVirtualChildCaptured; + else + if (inputCaptured) inputCaptured = 0; + return NULL; +} + +ifc_window *BaseWnd::getBaseTextureWindow() +{ + // return our base texture window if we have it + if (btexture) + return btexture; + // return our parent's if they have it + if (getParent()) + return getParent()->getBaseTextureWindow(); + else + return NULL; +} + +void BaseWnd::renderBaseTexture(ifc_canvas *c, const RECT &r, int alpha) +{ + WASABI_API_WND->skin_renderBaseTexture(getBaseTextureWindow(), c, r, this, alpha); +} + +void BaseWnd::setBaseTextureWindow(ifc_window *w) +{ + btexture = w; +} + +void BaseWnd::setNotifyWindow(ifc_window *newnotify) +{ + notifyWindow = newnotify; +} + +ifc_window *BaseWnd::getNotifyWindow() +{ + return destroying ? NULL : notifyWindow; +} + +int BaseWnd::gotFocus() +{ + return hasfocus && curVirtualChildFocus == NULL; +} + +int BaseWnd::isActive() +{ + OSWINDOWHANDLE h = hwnd; + if (h == NULL) + { + ifc_window *par = getParent(); + if (par == NULL) return 0; + h = par->getOsWindowHandle(); + } + if (h == NULL) return 0; + return (Wasabi::Std::Wnd::getActiveWindow() == h); +} + +int BaseWnd::onChar(unsigned int c) +{ + switch (c) + { + case 9: // TAB + if (Std::keyModifier(STDKEY_SHIFT)) + focusPrevious(); + else + focusNext(); + return 1; + } + return 0; +} + +/*int BaseWnd::focusVirtualChild(api_window *child) { + if (!gotFocus()) setFocus(); + if (!child->wantFocus()) return 0; + setVirtualChildFocus(child); + return 1; +}*/ + +int BaseWnd::wantFocus() +{ + return 0; +} + +// Return 1 if there is a modal window that is not this +int BaseWnd::checkModal() +{ + if (bypassModal()) return 0; + ifc_window *w = WASABI_API_WND->getModalWnd(); + if (w && w != static_cast<ifc_window*>(this) && w != getDesktopParent()) + { + return 1; + } + return 0; +} + +int BaseWnd::cascadeRepaintFrom(ifc_window *who, int pack) +{ + RECT r; + BaseWnd::getNonClientRect(&r); + return BaseWnd::cascadeRepaintRect(&r, pack); +} + +int BaseWnd::cascadeRepaint(int pack) +{ + return cascadeRepaintFrom(this, pack); +} + +int BaseWnd::cascadeRepaintRgn(api_region *r, int pack) +{ + return cascadeRepaintRgnFrom(r, this, pack); +} + +int BaseWnd::cascadeRepaintRect(RECT *r, int pack) +{ + return cascadeRepaintRectFrom(r, this, pack); +} + +int BaseWnd::cascadeRepaintRectFrom(RECT *r, ifc_window *who, int pack) +{ + RegionI reg(r); + int rt = cascadeRepaintRgnFrom(®, who, pack); + return rt; +} + +void BaseWnd::_cascadeRepaintRgn(api_region *rg) +{ + if (!ensureVirtualCanvasOk()) return ; + + WndCanvas paintcanvas; + if (paintcanvas.attachToClient(this) == 0) + return; + + virtualBeforePaint(rg); + + deferedInvalidateRgn(rg); + paintTree(virtualCanvas, rg); + + virtualAfterPaint(rg); + + double ra = getRenderRatio(); + + RECT rcPaint; + rg->getBox(&rcPaint); + + RECT rc; + getClientRect(&rc); //JF> this gets it in virtual (non-scaled) coordinates, + // so we need to do these comparisons before scaling. + rcPaint.bottom = MIN((int)rc.bottom, (int)rcPaint.bottom); + rcPaint.right = MIN((int)rc.right, (int)rcPaint.right); + + if (renderRatioActive()) // probably faster than scaling the clone + { + rcPaint.left = (int)((rcPaint.left - 1) * ra); + rcPaint.top = (int)((rcPaint.top - 1) * ra); + rcPaint.right = (int)(rcPaint.right * ra + 0.999999); + rcPaint.bottom = (int)(rcPaint.bottom * ra + 0.999999); + } + rcPaint.left = MAX(0, (int)rcPaint.left); + rcPaint.top = MAX(0, (int)rcPaint.top); + rcPaint.right = MIN((int)rcPaint.right, (int)(rwidth * ra)); + rcPaint.bottom = MIN((int)rcPaint.bottom, (int)(rheight * ra)); + + commitFrameBuffer(&paintcanvas, &rcPaint, ra); +} + + +void BaseWnd::packCascadeRepaintRgn(api_region *rg) +{ + if (!deferedCascadeRepaintRgn) deferedCascadeRepaintRgn = new RegionI; + deferedCascadeRepaintRgn->addRegion(rg); + need_flush_cascaderepaint = 1; +} + +int BaseWnd::cascadeRepaintRgnFrom(api_region *_rg, ifc_window *who, int pack) +{ + + api_region *rg = _rg->clone(); + + int j = virtualChildren.searchItem(who); + for (int i = 0; i < virtualChildren.getNumItems(); i++) + { + ifc_window *w = virtualChildren[i]; + if (w != who && w->wantSiblingInvalidations()) + w->onSiblingInvalidateRgn(rg, who, j, i); + } + + if (!pack) + { + _cascadeRepaintRgn(rg); + } + else + { + packCascadeRepaintRgn(rg); + } + + _rg->disposeClone(rg); + + return 1; +} + +void BaseWnd::setDesktopAlpha(int a) +{ + if (a && !Wasabi::Std::Wnd::isDesktopAlphaAvailable()) return ; + if (a == w2k_alpha) return ; + w2k_alpha = a; + if (!a && scalecanvas) + { + delete scalecanvas; + scalecanvas = NULL; + } + setLayeredWindow(w2k_alpha); + onSetDesktopAlpha(a); +} + +void BaseWnd::onSetDesktopAlpha(int a) { } + +void BaseWnd::commitFrameBuffer(Canvas *paintcanvas, RECT *r, double ra) +{ + if (w2k_alpha && Wasabi::Std::Wnd::isDesktopAlphaAvailable() && !cloaked) + { + //CUT BLENDFUNCTION blend= {AC_SRC_OVER, 0, wndalpha, AC_SRC_ALPHA }; + //CUT POINT pt={0,0}; + RECT spr; + getWindowRect(&spr); + //CUT POINT sp={spr.left,spr.top}; + //CUT SIZE ss={spr.right-spr.left, spr.bottom-spr.top}; + int sw = spr.right - spr.left, sh = spr.bottom - spr.top; + //CUT SysCanvas c; + + if (handleRatio() && renderRatioActive()) + { + // eek slow! + RECT r; + getWindowRect(&r); + int w = r.right - r.left; + int h = r.bottom - r.top; + if (!scalecanvas) scalecanvas = new BltCanvas(w, h, getOsWindowHandle()); + virtualCanvas->stretchblit(0, 0, (int)((double)virtualCanvasW * 65536.0), (int)((double)virtualCanvasH * 65536.0), scalecanvas, 0, 0, w, h); + } + + //CUT updateLayeredWindow(hwnd, c.getHDC(), &sp, &ss, (scalecanvas ? scalecanvas : virtualCanvas)->getHDC(), &pt, 0, &blend, ULW_ALPHA); + Wasabi::Std::Wnd::updateLayeredWnd(hwnd, spr.left, spr.top, sw, sh, (scalecanvas ? scalecanvas : virtualCanvas)->getHDC(), wndalpha); + } + else + { + if (ABS(ra - 1.0) <= 0.01) + { + virtualCanvas->blit(r->left, r->top, paintcanvas, r->left, r->top, r->right - r->left, r->bottom - r->top); + } + else + { + RECT tr = *r; + + double invra = 65536.0 / ra; + int lp = tr.left; + int tp = tr.top; + int w = tr.right - tr.left; + int h = tr.bottom - tr.top; + + int sx = (int)((double)lp * invra); + int sy = (int)((double)tp * invra); + int sw = (int)((double)w * invra); + int sh = (int)((double)h * invra); + + virtualCanvas->stretchblit(sx, sy, sw, sh, paintcanvas, lp, tp, w, h); + } + } +} + +void BaseWnd::flushPaint() +{ + postDeferredCallback(DEFERREDCB_FLUSHPAINT, 0); +} + +void BaseWnd::do_flushPaint() +{ + if (!deferedInvalidRgn || deferedInvalidRgn->isEmpty()) return ; + api_region *r = deferedInvalidRgn->clone(); + cascadeRepaintRgn(r); + deferedInvalidRgn->disposeClone(r); + deferedInvalidRgn->empty(); +} + +int BaseWnd::isMouseOver(int x, int y) +{ + POINT pt = {x, y}; + clientToScreen(&pt); + + return (WASABI_API_WND->rootWndFromPoint(&pt) == this); +} + +void BaseWnd::freeResources() +{} + +void BaseWnd::reloadResources() +{ + invalidate(); +} + +double BaseWnd::getRenderRatio() +{ + if (!handleRatio()) return 1.0; + if (!ratiolinked) return ratio; + return getParent() ? getParent()->getRenderRatio() : ratio; +} + +void BaseWnd::setRenderRatio(double r) +{ + // "snap" to 1.0 + if (ABS(r - 1.0) <= 0.02f) r = 1.0; + if (scalecanvas) + { + delete scalecanvas; + scalecanvas = NULL; + } + if (isInited() && r != ratio && !isVirtual() && (!getParent() || !ratiolinked)) + { + // must scale size & region accordingly + RECT rc; + BaseWnd::getWindowRect(&rc); + rc.right = rc.left + rwidth; + rc.bottom = rc.top + rheight; + ratio = r; + + resize(&rc); + + invalidate(); + if (isPostOnInit()) + onRatioChanged(); + } +} + +void BaseWnd::setRatioLinked(int l) +{ + ratiolinked = l; + if (isPostOnInit()) + setRenderRatio(ratio); +} + +int BaseWnd::renderRatioActive() +{ + return ABS(getRenderRatio() - 1.0) > 0.01f; +} + +void BaseWnd::multRatio(int *x, int *y) +{ + double rr = getRenderRatio(); + if (x) *x = (int)((double)(*x) * rr); + if (y) *y = (int)((double)(*y) * rr); +} + +void BaseWnd::multRatio(RECT *r) +{ + Wasabi::Std::scaleRect(r, getRenderRatio()); +} + +void BaseWnd::divRatio(int *x, int *y) +{ + double rr = getRenderRatio(); + if (x) *x = (int)((double)(*x) / rr + 0.5); + if (y) *y = (int)((double)(*y) / rr + 0.5); +} + +void BaseWnd::divRatio(RECT *r) +{ + double rr = getRenderRatio(); + Wasabi::Std::scaleRect(r, 1./rr); +} + +void BaseWnd::bringVirtualToFront(ifc_window *w) +{ + changeChildZorder(w, 0); +} + +void BaseWnd::bringVirtualToBack(ifc_window *w) +{ + changeChildZorder(w, virtualChildren.getNumItems()-1); +} + +void BaseWnd::bringVirtualAbove(ifc_window *w, ifc_window *b) +{ + ASSERT(b->isVirtual()); + int p = virtualChildren.searchItem(b); + if (p == -1) return ; + changeChildZorder(w, p); +} + +void BaseWnd::bringVirtualBelow(ifc_window *w, ifc_window *b) +{ + ASSERT(b->isVirtual()); + int p = virtualChildren.searchItem(b); + if (p == -1) return ; + changeChildZorder(w, p + 1); +} + +void BaseWnd::changeChildZorder(ifc_window *w, int newpos) +{ + int p = newpos; + p = MAX(p, (int)0); + p = MIN(p, virtualChildren.getNumItems()-1); + RECT cr; + w->getClientRect(&cr); + + PtrList<ifc_window> l; + int i; + for (i = 0;i < virtualChildren.getNumItems();i++) + if (virtualChildren[i] != w) + l.addItem(virtualChildren[i]); + + p = virtualChildren.getNumItems() - newpos - 1; + virtualChildren.removeAll(); + + int done = 0; + + for (i = 0;i < l.getNumItems();i++) + if (i == p && !done) + { + virtualChildren.addItem(w); + i--; + done++; + } + else + { + RECT dr, intersection; + l.enumItem(i)->getClientRect(&dr); + if (Wasabi::Std::rectIntersect(intersection, dr, &cr)) + l[i]->invalidateRect(&intersection); + virtualChildren.addItem(l.enumItem(i)); + } + if (i == p && !done) + virtualChildren.addItem(w); + w->invalidate(); +} + +int BaseWnd::onActivate() +{ + if (hasVirtualChildren()) + { + int l = getNumVirtuals(); + for (int i = 0; i < l; i++) + { + ifc_window *r = enumVirtualChild(i); + r->onActivate(); + } + } + + return 0; +} + +int BaseWnd::onDeactivate() +{ + if (hasVirtualChildren()) + { + int l = getNumVirtuals(); + for (int i = 0; i < l; i++) + { + ifc_window *r = enumVirtualChild(i); + r->onDeactivate(); + } + } + return 0; +} + +int BaseWnd::getDesktopAlpha() +{ + return w2k_alpha; +} + +api_region *BaseWnd::getRegion() +{ + return NULL; +} + +//CUT int BaseWnd::isTransparencyAvailable() { +//CUT #ifdef WIN32 +//CUT #else +//CUT #pragma warning port me! +//CUT #endif +//CUT return 0; +//CUT } + +int BaseWnd::handleTransparency() +{ + return 1; // by default all windows handle transparency, only windows blitting directly on the SCREEN (if you blit directly on the DC it's still ok), +} // for instance, a vis or a video using overlay should return 0, this will let the layout auto manage its alpha as that window is shown/hiden + +void BaseWnd::setAlpha(int active, int inactive) +{ + if (active == 254) active = 255; + if (active == 1) active = 0; + if (inactive == 254) inactive = 255; + if (inactive == 1) inactive = 0; + int oldactivealpha = activealpha; + active = MIN(255, MAX(0, active)); + if (inactive != -1) inactive = MIN(255, MAX(0, inactive)); + + if (active != activealpha) + { + activealpha = active; + if (isActive()) + { + invalidate(); + if ((oldactivealpha == 0 || activealpha == 0) && (oldactivealpha != 0 || activealpha != 0)) + invalidateWindowRegion(); + } + } + if (inactive == -1) inactive = active; + if (inactive != inactivealpha) + { + inactivealpha = inactive; + if (!isActive()) + { + invalidate(); + if ((oldactivealpha == 0 || activealpha == 0) && (oldactivealpha != 0 || activealpha != 0)) + invalidateWindowRegion(); + } + } +} + +void BaseWnd::getAlpha(int *active, int *inactive) +{ + if (active) *active = activealpha; + if (inactive) *inactive = inactivealpha; +} + +int BaseWnd::getPaintingAlpha(void) +{ + int a = isActive() ? MIN(255, MAX(0, activealpha)) : MIN(255, MAX(0, inactivealpha)); + ASSERT(a >= 0 && a <= 255); + if (getParent() && getParent()->isVirtual()) + { + int b = getParent()->getPaintingAlpha(); + a = (int)((double)a / 255.0 * (double)b); + } + if (a == 254) a = 255; + if (a == 1) a = 0; + if (!isEnabled()) a = (int)(a*0.6); + return a; +} + +void BaseWnd::setClickThrough(int ct) +{ + clickthrough = ct; +} + +int BaseWnd::isClickThrough() +{ + return clickthrough; +} + +int BaseWnd::handleRatio() +{ + return 1; +} + +#include <api/script/objects/c_script/c_rootobj.h> + +int BaseWnd::createTip() +{ + destroyTip(); + tooltip = new Tooltip(getTip()); + return -1; +} + +void BaseWnd::destroyTip() +{ + // this is to avoid pb if destroytip() is being called by a time while destroying tip + Tooltip *tt = tooltip; + tooltip = NULL; + delete tt; +} + + +int BaseWnd::runModal() +{ + //PORTME +#ifdef _WIN32 + ifc_window *dp = getDesktopParent(); + if (dp && dp != this) + return dp->runModal(); + + MSG msg; + + // SetCapture(NULL); + SetFocus(getOsWindowHandle()); + + WASABI_API_WND->pushModalWnd(this); + returnvalue = 0; + mustquit = 0; + + // Main message loop: + while (!mustquit) + { + mustquit = !GetMessage(&msg, NULL, 0, 0); + if (!msg.hwnd || !TranslateAccelerator(msg.hwnd, NULL, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + WASABI_API_WND->popModalWnd(this); + // SetCapture(NULL); + return returnvalue; +#else +#warning port me + return 0; +#endif +} + +void BaseWnd::endModal(int ret) +{ + ifc_window *dp = getDesktopParent(); + if (dp && dp != this) + { + dp->endModal(ret); + return ; + } + returnvalue = ret; + mustquit = 1; +} + +int BaseWnd::wantAutoContextMenu() +{ + return 1; +} + +void BaseWnd::onCancelCapture() +{} + +ifc_window *BaseWnd::getNextVirtualFocus(ifc_window *w) +{ + if (w == NULL) + { + if (childtabs.getNumItems() > 0) + return childtabs.getFirst()->wnd; + } + + int a = getTabOrderEntry(w) + 1; + + if (a < childtabs.getNumItems()) + return childtabs.enumItem(a)->wnd; + + return NULL; +} + + +void BaseWnd::setVirtualChildFocus(ifc_window *w) +{ + ASSERT(w && w->isVirtual()); + if (curVirtualChildFocus) + curVirtualChildFocus->onKillFocus(); + curVirtualChildFocus = w; + onSetRootFocus(w); + Wasabi::Std::Wnd::setFocus(getOsWindowHandle()); + if (curVirtualChildFocus) + curVirtualChildFocus->onGetFocus(); +} + +int BaseWnd::ptInRegion(int x, int y) +{ + RECT cr; + getNonClientRect(&cr); + POINT pt = {x - cr.left, y - cr.top}; + api_region *reg = getRegion(); + if (isRectRgn()) + return (x >= cr.left && x <= cr.right && y >= cr.top && y <= cr.bottom); + return reg ? reg->ptInRegion(&pt) : 0; +} + +api_region *BaseWnd::getComposedRegion() +{ + ensureWindowRegionValid(); + return composedrgn; +} + +api_region *BaseWnd::getSubtractorRegion() +{ + ensureWindowRegionValid(); + return subtractorrgn; +} + +int BaseWnd::ensureWindowRegionValid() +{ + if (!isInited()) return 0; + if (wndregioninvalid) + { + computeComposedRegion(); + return 1; + } + return 0; +} + +void BaseWnd::invalidateWindowRegion() +{ + wndregioninvalid = 1; + if (getParent()) getParent()->invalidateWindowRegion(); +} + +void BaseWnd::computeComposedRegion() +{ + if (!isPostOnInit()) return ; + + wndregioninvalid = 0; + + RECT r; + getNonClientRect(&r); + + api_region *reg = getRegion(); + RegionI *_reg = NULL; + + if (!reg) + { + _reg = new RegionI; + reg = _reg; + if (isRectRgn()) + reg->setRect(&r); + } + else + if (isRectRgn()) + reg->setRect(&r); + + api_region *wr = reg->clone(); + + if (!subtractorrgn) subtractorrgn = new RegionI(); + subtractorrgn->empty(); + if (!composedrgn) composedrgn = new RegionI; + composedrgn->empty(); + + RegionI *subme = NULL; + RegionI *andme = NULL; + RegionI *orme = NULL; + + // if subregion is now empty, we need to only use our region + RECT gr; + getNonClientRect(&gr); + for (int i = 0;i < virtualChildren.getNumItems();i++) + { + ifc_window *srw = virtualChildren.enumItem(i); + if (!srw->isVisible(1) || srw->getPaintingAlpha() == 0) continue; + if (srw->getRegionOp() != REGIONOP_NONE) + { + api_region *sr = srw->getComposedRegion(); + if (sr) + { + api_region *osr = sr->clone(); + RECT r; + srw->getNonClientRect(&r); + r.left -= gr.left; + r.top -= gr.top; + osr->offset(r.left, r.top); + /* sr->debug(); + osr->debug();*/ + if (srw->getRegionOp() == REGIONOP_OR) + { + if (!orme) orme = new RegionI; + orme->addRegion(osr); + } + else if (srw->getRegionOp() == REGIONOP_AND) + { + if (!andme) andme = new RegionI; + andme->addRegion(osr); + } + else if (srw->getRegionOp() == REGIONOP_SUB) + { + if (!subme) subme = new RegionI; + subme->addRegion(osr); + } + else if (srw->getRegionOp() == REGIONOP_SUB2) + { + if (!subme) subme = new RegionI; + subtractorrgn->addRegion(osr); + } + sr->disposeClone(osr); + } + } + api_region *sr = srw->getSubtractorRegion(); + if (sr != NULL && !sr->isEmpty()) + { + api_region *osr = sr->clone(); + RECT r; + srw->getNonClientRect(&r); + r.left -= gr.left; + r.top -= gr.top; + osr->offset(r.left, r.top); + subtractorrgn->addRegion(osr); + sr->disposeClone(osr); + } + } + + if (andme) + { + wr->andRegion(andme); + delete andme; + } + if (orme) + { + wr->addRegion(orme); + delete orme; + } + if (subme) + { + wr->subtractRgn(subme); + delete subme; + } + + composedrgn->addRegion(wr); + reg->disposeClone(wr); + delete _reg; +} + +void BaseWnd::updateWindowRegion() +{ + if (!isPostOnInit() || isVirtual()) return ; + if (getDesktopAlpha()) + { + // if desktopalpha is on, we can't use regions (thanks MS), we have to rely on the framebuffer correctness + //CUT SetWindowRgn(getOsWindowHandle(), NULL, FALSE); + Wasabi::Std::Wnd::setWndRegion(getOsWindowHandle(), NULL); + return ; + } + api_region *_r = getComposedRegion(); + api_region *_s = getSubtractorRegion(); + ASSERT(_r != NULL && _s != NULL); + + api_region *z = _r->clone(); + z->subtractRgn(_s); + + assignWindowRegion(z); + _r->disposeClone(z); +} + +// wr is NOT scaled!!! +void BaseWnd::assignWindowRegion(api_region *wr) +{ + ASSERT(wr != NULL); + + if (!isPostOnInit()) return ; + + int isrect = wr->isRect(); + + RECT r; + BaseWnd::getWindowRect(&r); + + //DebugStringW( L"\nBaseWnd::assignWindowRegion() r before - x = %d, y = %d, w = %d, h = %d \n", r.left, r.top, r.right - r.left, r.bottom - r.top ); + + r.right -= r.left; + r.left = 0; + r.bottom -= r.top; + r.top = 0; + + //DebugStringW( L"BaseWnd::assignWindowRegion() r after - x = %d, y = %d, w = %d, h = %d \n", r.left, r.top, r.right - r.left, r.bottom - r.top ); + + RECT z; + wr->getBox(&z); + + //DebugStringW( L"BaseWnd::assignWindowRegion() z before - x = %d, y = %d, w = %d, h = %d \n", z.left, z.top, z.right - z.left, z.bottom - z.top ); + + z.left = 0; + z.top = 0; + + //DebugStringW( L"BaseWnd::assignWindowRegion() z after - x = %d, y = %d, w = %d, h = %d \n", z.left, z.top, z.right - z.left, z.bottom - z.top ); + + if (renderRatioActive()) + { + double i = getRenderRatio(); + wr->scale(i, i, FALSE); + } + + RECT sz; + wr->getBox(&sz); + + //DebugStringW( L"BaseWnd::assignWindowRegion() sz before - x = %d, y = %d, w = %d, h = %d \n", sz.left, sz.top, sz.right - sz.left, sz.bottom - sz.top ); + + sz.right -= sz.left; + sz.bottom -= sz.top; + sz.left = 0; + sz.top = 0; + + //DebugStringW( L"BaseWnd::assignWindowRegion() sz after - x = %d, y = %d, w = %d, h = %d \n", sz.left, sz.top, sz.right - sz.left, sz.bottom - sz.top ); + + if (isrect && + ((z.right == rwidth && z.bottom == rheight) || + (sz.left == r.left && sz.right == r.right && sz.top == r.top && sz.bottom == r.bottom) || + (0) + ) + ) + { + //CUT SetWindowRgn(getOsWindowHandle(), NULL, TRUE); + if (!lastnullregion) + { + Wasabi::Std::Wnd::setWndRegion(getOsWindowHandle(), NULL, TRUE); + lastnullregion = 1; + } + } + else + { + //DebugStringW(L"setting region, rwidth = %d, rheight = %d, z.right = %d, z.bottom = %d\n", rwidth, rheight, z.right, z.bottom); + //CUT SetWindowRgn(getOsWindowHandle(), wr->makeWindowRegion(), TRUE); + Wasabi::Std::Wnd::setWndRegion(getOsWindowHandle(), wr->makeWindowRegion(), TRUE); + lastnullregion = 0; + } +} + +void BaseWnd::performBatchProcesses() +{ + // recompute the window region if needed and apply it to the HWND + if (wndregioninvalid && !isVirtual()) + if (ensureWindowRegionValid()) + updateWindowRegion(); + if (need_flush_cascaderepaint) + { + _cascadeRepaintRgn(deferedCascadeRepaintRgn); + deferedCascadeRepaintRgn->empty(); + need_flush_cascaderepaint = 0; + } +} + +int BaseWnd::getRegionOp() +{ + return regionop; +} + +void BaseWnd::setRegionOp(int op) +{ + if (regionop != op) + { + regionop = op; + invalidateWindowRegion(); + } +} + +int BaseWnd::isRectRgn() +{ + return rectrgn; +} + +void BaseWnd::setRectRgn(int i) +{ + rectrgn = i; +} + +TimerClient *BaseWnd::timerclient_getMasterClient() +{ + if (!isVirtual()) return this; + ifc_window *w = getParent(); + if (w) + { + TimerClient *tc = w->getTimerClient(); + if (tc) + return tc->timerclient_getMasterClient(); + } + return NULL; +} + +void BaseWnd::timerclient_onMasterClientMultiplex() +{ + performBatchProcesses(); +} + +TimerClient *BaseWnd::getTimerClient() +{ + return this; +} + +ifc_dependent *BaseWnd::rootwnd_getDependencyPtr() +{ + return this; +} + +ifc_dependent *BaseWnd::timerclient_getDependencyPtr() +{ + return this; +} + +void BaseWnd::addMinMaxEnforcer(ifc_window *w) +{ + minmaxEnforcers.addItem(w); + signalMinMaxEnforcerChanged(); +} + +void BaseWnd::removeMinMaxEnforcer(ifc_window *w) +{ + minmaxEnforcers.removeItem(w); + signalMinMaxEnforcerChanged(); +} + +void BaseWnd::signalMinMaxEnforcerChanged(void) +{ + ifc_window *w = getDesktopParent(); + if (w == NULL || w == this) onMinMaxEnforcerChanged(); + else w->signalMinMaxEnforcerChanged(); +} + +int BaseWnd::getNumMinMaxEnforcers() +{ + return minmaxEnforcers.getNumItems(); +} + +ifc_window *BaseWnd::enumMinMaxEnforcer(int n) +{ + return minmaxEnforcers.enumItem(n); +} + +int BaseWnd::onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source) +{ + return 1; +} + +int BaseWnd::sendAction(ifc_window *target, const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen) +{ + ASSERT(target != NULL); + return target->onAction(action, param, x, y, p1, p2, data, datalen, this); +} + +int BaseWnd::virtualBeforePaint(api_region *r) +{ + if (!virtualCanvas) return 0; + PaintCallbackInfoI pc(virtualCanvas, r); + dependent_sendEvent(BaseWnd::depend_getClassGuid(), Event_ONPAINT, PaintCallback::BEFOREPAINT, &pc); + return 1; +} + +int BaseWnd::virtualAfterPaint(api_region *r) +{ + if (!virtualCanvas) return 0; + PaintCallbackInfoI pc(virtualCanvas, r); + dependent_sendEvent(BaseWnd::depend_getClassGuid(), Event_ONPAINT, PaintCallback::AFTERPAINT, &pc); + return 1; +} + +int BaseWnd::timerclient_onDeferredCallback(intptr_t p1, intptr_t p2) +{ + TimerClientI::timerclient_onDeferredCallback(p1, p2); + return onDeferredCallback(p1, p2); +} + +void BaseWnd::timerclient_timerCallback(int id) +{ + TimerClientI::timerclient_timerCallback(id); + timerCallback(id); +} + +int BaseWnd::setTimer(int id, int ms) +{ + return timerclient_setTimer(id, ms); +} + +int BaseWnd::killTimer(int id) +{ + return timerclient_killTimer(id); +} + +void BaseWnd::postDeferredCallback(intptr_t p1, intptr_t p2, int mindelay) +{ +#ifdef _WIN32 + // TODO: re-enable, but post to some other window (e.g. some singleton window), not this window + // because our message pump might be blocked + // maybe make a hidden window in api_timer for this purpose + + //if (mindelay) + timerclient_postDeferredCallback(p1, p2, mindelay); + //else + //PostMessage(hwnd, WM_DEFER_CALLBACK, p1, p2); +#else +#warning "port me - I can be optimized - don't use timers for this, use mac os x equiv of PostMessage!" + timerclient_postDeferredCallback(p1, p2, mindelay); +#endif +} + +int BaseWnd::bypassModal() +{ + return 0; +} + +void BaseWnd::setRenderBaseTexture(int r) +{ + renderbasetexture = r; + if (isInited()) invalidate(); +} + +int BaseWnd::getRenderBaseTexture() +{ + return renderbasetexture; +} + +GuiObject *BaseWnd::getGuiObject() +{ + if (my_guiobject == NULL) + { + my_guiobject = static_cast<GuiObject *>(getInterface(guiObjectGuid)); + } + return my_guiobject; +} + +//CUT someday +int BaseWnd::getFlag(int flag) +{ + /* switch (flag) { + }*/ + return 0; +} + +int BaseWnd::triggerEvent(int event, intptr_t p1, intptr_t p2) +{ + //PORTME + switch (event) + { + case TRIGGER_ONRESIZE: + if (isPostOnInit()) + onResize(); + break; + case TRIGGER_INVALIDATE: + if (isPostOnInit()) + invalidate(); + break; + } + return 0; +} + +void BaseWnd::registerAcceleratorSection(const wchar_t *name, int global) +{ +#if defined(WASABI_COMPILE_LOCALES) + WASABI_API_LOCALE->locales_registerAcceleratorSection(name, this, global); +#endif +} + +int BaseWnd::onAcceleratorEvent(const wchar_t *name) +{ + for (int i = 0;i < getNumRootWndChildren();i++) + if (enumRootWndChildren(i)->onAcceleratorEvent(name)) + return 1; + return 0; +} + +int BaseWnd::allowDeactivation() +{ + return allow_deactivate & ((WASABI_API_WND == NULL) || WASABI_API_WND->appdeactivation_isallowed(this)); +} + +void BaseWnd::onMinimize() +{ + if (!isVirtual()) + { + dropVirtualCanvas(); + } +} + +void BaseWnd::dropVirtualCanvas() +{ + deferedInvalidate(); + delete virtualCanvas; + virtualCanvas = NULL; +} + +void BaseWnd::onRestore() +{ + if (getDesktopParent() == this) + { + cascadeRepaint(TRUE); + } +} + +ifc_window *BaseWnd::findWindow(const wchar_t *id) +{ + RootWndFinder find_object; + find_object.reset(); + find_object.setFindId(id); + ifc_window *ret = findWindowChain(&find_object); + +#ifdef _DEBUG + if (ret == NULL) + DebugStringW(L"findWindow : window not found by id ! %s \n", id); +#endif + + return ret; +} + +ifc_window *BaseWnd::findWindowByInterface(GUID interface_guid) +{ + RootWndFinder find_object; + find_object.reset(); + find_object.setFindGuid(interface_guid); + ifc_window *ret = findWindowChain(&find_object); + +#ifdef _DEBUG + char str[256] = {0}; + nsGUID::toChar(interface_guid, str); + if (ret == NULL) + DebugStringW(L"findWindow : object not found by guid ! %s \n", str); +#endif + + return ret; +} + +ifc_window *BaseWnd::findWindowByCallback(FindObjectCallback *cb) +{ + ifc_window *ret = findWindowChain(cb); +#ifdef _DEBUG + if (ret == NULL) + DebugStringW(L"findWindow : object not found by callback!\n"); +#endif + + return ret; +} + +ifc_window *BaseWnd::findWindowChain(FindObjectCallback *cb, ifc_window *wcaller) +{ + + if (!cb) return NULL; + + if (cb->findobjectcb_matchObject(this)) return this; + + // first lets not look in subdirectories + + for (int i = 0;i < getNumRootWndChildren();i++) + { + ifc_window *child = enumRootWndChildren(i); + if (!child || child == wcaller) continue; + if (cb->findobjectcb_matchObject(child)) + return child; + } + + // ok so it wasn't in our content, lets try to find it as a grandchildren + + for (int i = 0;i < getNumRootWndChildren();i++) + { + ifc_window *child = enumRootWndChildren(i); + if (child->getNumRootWndChildren() > 0) + { + ifc_window *ret = child->findWindowChain(cb, this); + if (ret) return ret; + } + } + + // so it wasnt one of our children, we'll hop the tree up one level and ask our parent to find it + // for us. of course, our parents are smart, they won't ask us back when asking our sibblings + ifc_window *p = getParent(); + if (p != NULL && wcaller != p) + { + return p->findWindowChain(cb, this); + } + + return NULL; +} + + +const wchar_t *BaseWnd::timerclient_getName() +{ + tcname = StringPrintfW(L"name=\"%S\", id=\"%s\"", getRootWndName(), getId()); + return tcname; +} + +void BaseWnd::setTabOrder(int a) +{ + if (getParent() != NULL) + getParent()->setVirtualTabOrder(this, a); +} + +int BaseWnd::getTabOrder() +{ + if (getParent() != NULL) + return getParent()->getVirtualTabOrder(this); + return -1; +} + +void BaseWnd::recursive_setVirtualTabOrder(ifc_window *w, float a, float lambda) +{ + ASSERT(w != NULL); + childtabs.setAutoSort(0); + int i = getTabOrderEntry(a); + if (i != -1) + { + TabOrderEntry *toe = childtabs.enumItem(i); + if (toe->wnd != w) + { + lambda += TABORDER_K; + if (lambda != 1.0) + recursive_setVirtualTabOrder(toe->wnd, a + lambda, lambda); + } + else + { + return ; + } + } + i = getTabOrderEntry(w); + if (i != -1) + { + delete childtabs.enumItem(i); + childtabs.removeByPos(i); + } + TabOrderEntry *toe = new TabOrderEntry; + toe->wnd = w; + toe->order = a; + childtabs.addItem(toe); +} + +void BaseWnd::setVirtualTabOrder(ifc_window *w, int a) +{ + if (a == -1) + { + delTabOrderEntry(w); + return ; + } + recursive_setVirtualTabOrder(w, (float)a); +} + +int BaseWnd::getVirtualTabOrder(ifc_window *w) +{ + int a = (int)getTabOrderEntry(w); + if (a == -1) return -1; + return (int)childtabs.enumItem(a); +} + +int BaseWnd::getTabOrderEntry(ifc_window *w) +{ + foreach(childtabs) + if (childtabs.getfor()->wnd == w) + return foreach_index; + endfor; + return -1; +} + +void BaseWnd::delTabOrderEntry(int i) +{ + int a = getTabOrderEntry((float)i); + if (a == -1) return ; + childtabs.removeByPos(a); +} + +void BaseWnd::delTabOrderEntry(ifc_window *w) +{ + int a = getTabOrderEntry(w); + if (a == -1) return ; + delete childtabs.enumItem(a); + childtabs.removeByPos(a); +} + +int BaseWnd::getTabOrderEntry(float order) +{ + foreach(childtabs) + if (childtabs.getfor()->order == order) + return foreach_index; + endfor; + return -1; +} + +void BaseWnd::setAutoTabOrder() +{ + if (!getParent()) return ; + getParent()->setVirtualAutoTabOrder(this); +} + +void BaseWnd::setVirtualAutoTabOrder(ifc_window *w) +{ + delTabOrderEntry(w); + float o = 0; + for (int i = 0;i < childtabs.getNumItems();i++) + { + o = MAX(o, childtabs.enumItem(i)->order); + } + setVirtualTabOrder(w, ((int)o) + 1); +} + +void BaseWnd::focusNext() +{ + ifc_window *dp = getDesktopParent(); + if (dp != this) + { + if (dp != NULL) + dp->focusNext(); + return ; + } + ifc_window *w = getTab(TAB_GETNEXT); + if (w != NULL) w->setFocus(); +} + +void BaseWnd::focusPrevious() +{ + ifc_window *dp = getDesktopParent(); + if (dp != this) + { + if (dp != NULL) + getDesktopParent()->focusPrevious(); + return ; + } + ifc_window *w = getTab(TAB_GETPREVIOUS); + if (w != NULL) w->setFocus(); +} + +void BaseWnd::recursive_buildTabList(ifc_window *from, PtrList<ifc_window> *list) +{ + for (int i = 0;i < from->getNumTabs();i++) + { + ifc_window *r = from->enumTab(i); + if (r->isVisible() && r->getPaintingAlpha() > 0) + { + if (r->wantFocus()) + list->addItem(r); + recursive_buildTabList(r, list); + } + } +} + +ifc_window *BaseWnd::getTab(int what) +{ + PtrList<ifc_window> listnow; + + recursive_buildTabList(this, &listnow); + + int p = listnow.searchItem(rootfocus); + + if (p == -1) + for (int i = 0; i < listnow.getNumItems(); i++) + { + ifc_window *r = listnow.enumItem(i); + if (r->gotFocus()) + { + //DebugString("desync of rootfocus, fixing\n"); + p = i; + assignRootFocus(r); + break; + } + } + + if (what == TAB_GETNEXT && rootfocus != NULL) + { + + p++; + if (p >= listnow.getNumItems()) + p = 0; + return listnow.enumItem(p); + + } + else if (what == TAB_GETPREVIOUS && rootfocus != NULL) + { + + p--; + if (p < 0) p = listnow.getNumItems() - 1; + return listnow.enumItem(p); + + } + else if (what == TAB_GETCURRENT) + { + + return rootfocus; + + } + else if (what == TAB_GETFIRST || (what == TAB_GETNEXT && rootfocus == NULL)) + { + + return listnow.getFirst(); + + } + else if (what == TAB_GETLAST || (what == TAB_GETPREVIOUS && rootfocus == NULL)) + { + + return listnow.getLast(); + + } + + return NULL; +} + +int BaseWnd::getNumTabs() +{ + return childtabs.getNumItems(); +} + +ifc_window *BaseWnd::enumTab(int i) +{ + childtabs.sort(); + return childtabs.enumItem(i)->wnd; +} + +void BaseWnd::onSetRootFocus(ifc_window *w) +{ + assignRootFocus(w); + ifc_window *dp = getDesktopParent(); + if (dp && dp != this) dp->onSetRootFocus(w); +} + +void BaseWnd::autoFocus(ifc_window *w) +{ + if (w->getFocusOnClick() && w->wantFocus()) + { + w->setFocus(); + return ; + } + ifc_window *g = w; + while (1) + { + ifc_window *p = g->getParent(); + if (p == NULL) break; + ifc_window *dp = p->getDesktopParent(); + if (dp && dp != p) + { + if (p->wantFocus() && p->getFocusOnClick()) + { + p->setFocus(); + return ; + } + g = p; + } + else + break; + } +} + +void BaseWnd::setNoLeftClicks(int no) +{ + noleftclick = no; +} + +void BaseWnd::setNoRightClicks(int no) +{ + norightclick = no; +} + +void BaseWnd::setNoDoubleClicks(int no) +{ + nodoubleclick = no; +} + +void BaseWnd::setNoMouseMoves(int no) +{ + nomousemove = no; +} + +void BaseWnd::setNoContextMenus(int no) +{ + nocontextmnu = no; +} + +void BaseWnd::setDefaultCursor(Cursor *c) +{ + customdefaultcursor = c; +} + + +OSCURSORHANDLE BaseWnd::getCustomCursor(int x, int y) +{ +#ifdef _WIN32 + return customdefaultcursor ? customdefaultcursor->getOSHandle() : NULL; +#else +#warning port me + return 0; +#endif +} + +Accessible *BaseWnd::createNewAccObj() +{ + waServiceFactory *f = WASABI_API_SVC->service_enumService(WaSvc::ACCESSIBILITY, 0); + if (f != NULL) + { + svc_accessibility *svc = castService<svc_accessibility>(f); + if (svc != NULL) + { + Accessible *a = svc->createAccessibleObject(this); + WASABI_API_SVC->service_release(svc); + return a; + } + } + return NULL; +} + +Accessible *BaseWnd::getAccessibleObject(int createifnotexist) +{ + if (!createifnotexist) return accessible; + if (!accessible) + accessible = createNewAccObj(); + else + accessible->addRef(); + return accessible; +} + +int BaseWnd::accessibility_getState() +{ + int state = 0; + if (!isVisible()) state |= STATE_SYSTEM_INVISIBLE; + //if (isVirtual() && !wantFocus()) state |= STATE_SYSTEM_INVISIBLE; + if (gotFocus()) state |= STATE_SYSTEM_FOCUSED; + return state; +} + +void BaseWnd::activate() +{ + Wasabi::Std::Wnd::setActiveWindow(getRootParent()->getOsWindowHandle()); +} + +void BaseWnd::setOSWndName(const wchar_t *name) +{ + if (isVirtual()) return ; +//#ifdef COMPILE_WASABI_SKIN // for some reason this isn't being correctly defined + if (name) + { + Wasabi::Std::Wnd::setWndName(getOsWindowHandle(), name); + } + else + Wasabi::Std::Wnd::setWndName(getOsWindowHandle(), L""); + +} + +const wchar_t *BaseWnd::getOSWndName() +{ + if (isVirtual()) return NULL; + wchar_t str[4096] = {0}; + Wasabi::Std::Wnd::getWndName(getOsWindowHandle(), str, 4095); + str[4095] = '\0'; + osname = str; + return osname; +} + +#ifdef EXPERIMENTAL_INDEPENDENT_AOT +void BaseWnd::setAlwaysOnTop(int i) +{ + // this function should not optimize itself + if (getDesktopParent() == this) + { + if (i) + { + //CUT SetWindowPos(getOsWindowHandle(), HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOOWNERZORDER); + Wasabi::Std::Wnd::setTopmost(getOsWindowHandle(), TRUE); + } + else + { + saveTopMosts(); + //CUT SetWindowPos(getOsWindowHandle(), HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOOWNERZORDER); + Wasabi::Std::Wnd::setTopmost(getOsWindowHandle(), FALSE); + restoreTopMosts(); + } + alwaysontop = i; + return ; + } + ifc_window *p = getParent(); + if (p != NULL) + p->setAlwaysOnTop(i); +} + +int BaseWnd::getAlwaysOnTop() +{ + if (getDesktopParent() == this) + return alwaysontop; + ifc_window *p = getParent(); + if (!p) return 0; + return p->getAlwaysOnTop(); +} +#endif + +void BaseWnd::wndwatcher_onDeleteWindow(ifc_window *w) +{ + if (w == rootfocus) + { + rootfocus = NULL; + } +} + +void BaseWnd::assignRootFocus(ifc_window *w) +{ + rootfocuswatcher.watchWindow(w); + rootfocus = w; +} + + +Canvas *BaseWnd::getFrameBuffer() +{ + return virtualCanvas; +} + +void BaseWnd::setForeignWnd(int i) +{ + m_takenOver = i; +} + +int BaseWnd::bufferizeLockedUIMsg(int uMsg, int wParam, int lParam) +{ + if (WASABI_API_SKIN && !WASABI_API_SKIN->skin_getLockUI()) return 0; + if (!uiwaslocked) + { + uiwaslocked = 1; + setTimer(BUFFEREDMSG_TIMER_ID, 20); + } + bufferedMsgStruct msg; + msg.msg = uMsg; + msg.wparam = wParam; + msg.lparam = lParam; + bufferedmsgs.addItem(msg); + return 1; +} + +void BaseWnd::checkLockedUI() +{ + //PORTME :( +#ifdef _WIN32 + + if (WASABI_API_SKIN && !WASABI_API_SKIN->skin_getLockUI()) + { + uiwaslocked = 0; + killTimer(BUFFEREDMSG_TIMER_ID); + while (bufferedmsgs.getNumItems() > 0) + { + bufferedMsgStruct msg = bufferedmsgs.enumItem(0); + bufferedmsgs.delByPos(0); + SendMessageW(gethWnd(), msg.msg, msg.wparam, msg.lparam); + } + uiwaslocked = 0; + killTimer(BUFFEREDMSG_TIMER_ID); + } +#else +#warning port me +#endif +} + +int BaseWnd::isMinimized() +{ + ifc_window *w = getDesktopParent(); + if (w == this || w == NULL) return minimized; + return w->isMinimized(); +} + +int BaseWnd::reinit() +{ +#ifdef _WIN32 + int nochild = (GetWindowLong(gethWnd(), GWL_STYLE) & WS_POPUP) ? 1 : 0; + int r = reinit(parentWnd ? parentWnd : WASABI_API_WND->main_getRootWnd(), nochild); + + if (w2k_alpha) + setLayeredWindow(1); + + return r; +#else +#warning port me! +#endif +} + + +int BaseWnd::reinit(ifc_window *parWnd, int nochild) +{ + OSWINDOWHANDLE phwnd = parWnd->getOsWindowHandle(); + ASSERT(phwnd != NULL); + int ret; + if (!nochild) parentWnd = parWnd; + else parentWnd = NULL; + ret = reinit(parWnd->getOsModuleHandle(), phwnd, nochild); + if (!ret) parentWnd = NULL; // abort + return ret; +} + +int BaseWnd::reinit(OSMODULEHANDLE moduleHandle, OSWINDOWHANDLE parent, int nochild) +{ + RECT r; + int w, h; + + onBeforeReinit(); + + pushWindowRect(); + preventcancelcapture = 1; + + int _isvisible = isVisible(1); + int hadcapture = inputCaptured; + //DebugString("had capture = %d\n", hadcapture); + Wasabi::Std::Wnd::releaseCapture(); + + unparentHWNDChildren(); + + BaseWnd::getClientRect(&r); + + hinstance = moduleHandle; + + ASSERT(hinstance != NULL); + + w = (r.right - r.left); + h = (r.bottom - r.top); + + rwidth = w; + rheight = h; + rx = r.left; + ry = r.top; + + WASABI_API_WND->appdeactivation_push_disallow(this); + + // destroy old window + Wasabi::Std::Wnd::hideWnd(hwnd); //Wasabi::Std::Wnd::destroyWnd(hwnd); + ghosthwnd.addItem(hwnd); + + hwnd = Wasabi::Std::Wnd::createWnd(&r, nochild, acceptExternalDrops(), parent, hinstance, static_cast<ifc_window*>(this)); +#ifdef __APPLE__ +#warning remove me + Wasabi::Std::Wnd::showWnd(hwnd); +#endif + + WASABI_API_WND->appdeactivation_pop_disallow(this); + + //ASSERT(hwnd != NULL); // lets fail nicely, this could happen for some win32 reason, we don't want to fail the whole app for it, so lets just fail the wnd + if (hwnd == NULL) + { + preventcancelcapture = 0; + return 0; + } + + //CUT nreal++; + +#ifdef _WIN32 + //FUCKO +#ifdef URLDROPS + if (acceptExternalDrops()) RegisterDragDrop(hwnd, &m_target); +#elif !defined(WA3COMPATIBILITY) + if (!m_target && WASABI_API_WND != NULL) + m_target = WASABI_API_WND->getDefaultDropTarget(); + if (m_target != NULL) + { + RegisterDragDrop(hwnd, (IDropTarget *)m_target); + } +#endif +#else +#warning port me - register drag & drop +#endif + + this_visible = _isvisible; + + //onInit(); + //this_visible = !start_hidden; + + reparentHWNDChildren(); + + popWindowRect(); + + invalidateWindowRegion(); + updateWindowRegion(); + + if (this_visible) + Wasabi::Std::Wnd::showWnd(hwnd, FALSE); + + if (hadcapture) + { + Wasabi::Std::Wnd::setCapture(hwnd); + } + preventcancelcapture = 0; + + forcedOnResize(); + redrawHWNDChildren(); + //onPostOnInit(); + + onAfterReinit(); + +#ifdef WASABI_ON_REPARENT + WASABI_ON_REINIT(getOsWindowHandle()); +#endif + + return 1; +} + +ReparentWndEntry::ReparentWndEntry(OSWINDOWHANDLE _wnd, OSWINDOWHANDLE parentwnd) +{ + wnd = _wnd; + Wasabi::Std::Wnd::getWindowRect(wnd, &rect); + Wasabi::Std::Wnd::screenToClient(wnd, (int *)&(rect.left), (int *)&(rect.top)); + Wasabi::Std::Wnd::clientToScreen(parentwnd, (int *)&(rect.left), (int *)&(rect.top)); +} + +void ReparentWndEntry::unparent() +{ + Wasabi::Std::Wnd::setWndPos(wnd, NULL, rect.left, -30000, 0, 0, TRUE, TRUE, FALSE, FALSE, TRUE); + Wasabi::Std::Wnd::setParent(wnd, NULL); +} + +void ReparentWndEntry::reparent(OSWINDOWHANDLE newparent) +{ + Wasabi::Std::Wnd::setParent(wnd, newparent); + Wasabi::Std::Wnd::setWndPos(wnd, NULL, rect.left, rect.top, 0, 0, TRUE, TRUE, FALSE, FALSE, TRUE); +} + +#ifdef _WIN32 +void BaseWnd::unparentHWNDChildren() +{ + // just in case + reparentwnds.deleteAll(); + +#ifndef WIN32 +#error port me ! // make a list of all the children oswindows and reparent them to the desktop somewhere we can't see +#endif + + OSWINDOWHANDLE wnd = GetWindow(getOsWindowHandle(), GW_CHILD); + while (wnd) + { + reparentwnds.addItem(new ReparentWndEntry(wnd, getOsWindowHandle())); + wnd = GetWindow(wnd, GW_HWNDNEXT); + } + foreach(reparentwnds) + reparentwnds.getfor()->unparent(); + endfor; +} +#endif + +void BaseWnd::reparentHWNDChildren() +{ + // reparent to the new oswindowhandle + foreach(reparentwnds) + reparentwnds.getfor()->reparent(getOsWindowHandle()); + endfor; +} + +void BaseWnd::redrawHWNDChildren() +{ + // reparent to the new oswindowhandle + foreach(reparentwnds) + Wasabi::Std::Wnd::update(getOsWindowHandle()); + endfor; +} + +void BaseWnd::maximize(int axis) +{ + //DebugString("maximize!\n"); + // if already maximized, don't use current rect, use restore_rect + if (!maximized) + { + restore_rect.left = rx; + restore_rect.top = ry; + restore_rect.right = rx + rwidth; + restore_rect.bottom = ry + rheight; + } + + RECT nr = restore_rect; + RECT dr; + + Wasabi::Std::getViewport(&dr, NULL, NULL, getOsWindowHandle(), 0); + + if (axis & MAXIMIZE_WIDTH) + { + nr.left = dr.left; + nr.right = dr.right; + } + if (axis & MAXIMIZE_HEIGHT) + { + nr.top = dr.top; + nr.bottom = dr.bottom; + } + maximized = 1; + if (axis != 0) resize(&nr); + onMaximize(); +} + +void BaseWnd::restore(int what) +{ + if (maximized) + { + //DebugString("restore!\n"); + if (what == (RESTORE_X | RESTORE_Y | RESTORE_WIDTH | RESTORE_HEIGHT)) + resize(&restore_rect); + else + { + resize((what & RESTORE_X) ? restore_rect.left : NOCHANGE, + (what & RESTORE_Y) ? restore_rect.top : NOCHANGE, + (what & RESTORE_WIDTH) ? restore_rect.right - restore_rect.left : NOCHANGE, + (what & RESTORE_HEIGHT) ? restore_rect.bottom - restore_rect.top : NOCHANGE); + } + maximized = 0; + onRestore(); + } +} + +void BaseWnd::pushWindowRect() +{ + //DebugString("pushWindowRect\n"); + RECT wr; + getWindowRect(&wr); + wr.right = wr.left + rwidth; + wr.bottom = wr.top + rheight; + windowrectstack.push(wr); +} + +int BaseWnd::popWindowRect(RECT *rc, int applyhow) +{ + //DebugString("popWindowRect\n"); + if (windowrectstack.peek() == 0) return 0; + RECT _rc; + windowrectstack.pop(&_rc); + RECT r; + getWindowRect(&r); + divRatio(&r); + if (applyhow) + { + if (applyhow == PWR_POSITION) + { + move(_rc.left, _rc.top); + if (rc) + { + int w = r.right - r.left; + int h = r.bottom - r.top; + rc->left = _rc.left; + rc->top = _rc.top; + rc->right = rc->left + w; + rc->bottom = rc->top + h; + } + } + else + { + if (applyhow & PWR_X) r.left = _rc.left; + if (applyhow & PWR_Y) r.top = _rc.top; + if (applyhow & PWR_WIDTH) r.right = r.left + (_rc.right - _rc.left); + if (applyhow & PWR_HEIGHT) r.bottom = r.top + (_rc.bottom - _rc.top); + resizeToRect(&r); + if (rc) *rc = _rc; + } + } + else if (rc) *rc = _rc; + return 1; +} + +void BaseWnd::setRestoredRect(RECT *r) +{ + if (!r) + return ; + + restore_rect = *r; + maximized = 1; +} + +int BaseWnd::getRestoredRect(RECT *r) +{ + if (!r) + return 0; + + if (!maximized) + return 0; + + *r = restore_rect; + + return 1; +} + +void BaseWnd::notifyDeferredMove(int x, int y) +{ + rx = x; + ry = y; +} + +void BaseWnd::setWindowTitle(const wchar_t *title) +{ + Layout *l = static_cast<Layout *>(getInterface(layoutGuid)); + if (l) + { + Container *c = l->getParentContainer(); + if (c) + { + c->setName(title); + } + } +} + +#ifdef __APPLE__ +OSStatus BaseWnd::eventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) +{ + return eventNotHandledErr; +} +#endif |