Archived
1
0
This repository has been archived on 2024-10-17. You can view files and clone it, but cannot push or open issues or pull requests.
winamp/Src/Wasabi/api/wnd/basewnd.cpp
2024-09-24 14:54:57 +02:00

5744 lines
127 KiB
C++

#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(&reg);
#ifdef _WIN32
canvas->selectClipRgn(NULL);
canvas->fillRect(&r, 0);
#elif defined(__APPLE__)
CGContextClearRect(canvas->getHDC(), CGRectInfinite); // TODO: make "clear" function in canvas
#endif
virtualAfterPaint(&reg);
}
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(&reg); 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, &reg);
#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(&reg, 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