mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-11-15 03:15:05 -05:00
1098 lines
26 KiB
C++
1098 lines
26 KiB
C++
#include "precomp_wasabi_bfc.h"
|
|
|
|
#include "wasabi_std_wnd.h"
|
|
#include "api.h"
|
|
#include <api/wnd/api_window.h>
|
|
#include <api/wnd/wndevent.h>
|
|
#include <api/wnd/wndevent.h>
|
|
#include <shobjidl.h>
|
|
#include "../winamp/wa_ipc.h"
|
|
|
|
#ifndef AC_SRC_ALPHA
|
|
const int AC_SRC_ALPHA = 1;
|
|
#endif
|
|
|
|
#ifndef THBN_CLICKED
|
|
#define THBN_CLICKED 0x1800
|
|
#endif
|
|
|
|
static int nreal = 0;
|
|
|
|
#ifdef __APPLE__
|
|
OSStatus MyWindowEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData);
|
|
OSStatus MyControlEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData);
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
static HINSTANCE gdi32instance = NULL;
|
|
|
|
static int(WINAPI *getRandomRgn)(HDC dc, HRGN rgn, int i) = NULL;
|
|
|
|
static int grrfailed = 0;
|
|
|
|
static void register_wndClass(HINSTANCE hInstance);
|
|
|
|
static int versionChecked = 0;
|
|
static int isNT = 0;
|
|
|
|
static int IsNT()
|
|
{
|
|
if (versionChecked)
|
|
return isNT;
|
|
|
|
if (GetVersion() < 0x80000000)
|
|
isNT = 1;
|
|
|
|
versionChecked = 1;
|
|
return isNT;
|
|
}
|
|
|
|
int Wasabi::Std::Wnd::alphaStretchBlit(HDC destHDC, int dstx, int dsty, int dstw, int dsth, HDC sourceHDC, int srcx, int srcy, int srcw, int srch)
|
|
{
|
|
if (IsNT())
|
|
{
|
|
SetStretchBltMode(destHDC, HALFTONE);
|
|
StretchBlt(destHDC, dstx, dsty, dstw, dsth, sourceHDC, srcx , srcy, srcw, srch, SRCCOPY);
|
|
return 1;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
|
enum
|
|
{
|
|
kWasabi = 'WASA'
|
|
};
|
|
|
|
const ControlID kWasabiID = { kWasabi, 0 };
|
|
|
|
void GetWasabiHIView(WindowRef window, HIViewRef *control)
|
|
{
|
|
GetControlByID(window, &kWasabiID, control);
|
|
}
|
|
|
|
|
|
OSStatus CreateHIView ( WindowRef inWindow, const Rect* inBounds,
|
|
ControlRef* outControl )
|
|
{
|
|
OSStatus err;
|
|
ControlRef root;
|
|
EventRef event;
|
|
|
|
|
|
// Make an initialization event
|
|
err = CreateEvent( NULL, kEventClassHIObject, kEventHIObjectInitialize,
|
|
GetCurrentEventTime(), 0, &event );
|
|
require_noerr( err, CantCreateEvent );
|
|
|
|
// If bounds were specified, push the them into the initialization event
|
|
// so that they can be used in the initialization handler.
|
|
if ( inBounds != NULL )
|
|
{
|
|
err = SetEventParameter( event, 'boun', typeQDRectangle,
|
|
sizeof( Rect ), inBounds );
|
|
require_noerr( err, CantSetParameter );
|
|
}
|
|
|
|
err = HIObjectCreate( kHIViewClassID, event, (HIObjectRef*)
|
|
outControl );
|
|
require_noerr( err, CantCreate );
|
|
|
|
|
|
// If a parent window was specified, place the new view into the
|
|
// parent window.
|
|
if ( inWindow != NULL )
|
|
{
|
|
err = GetRootControl( inWindow, &root );
|
|
require_noerr( err, CantGetRootControl );
|
|
|
|
|
|
err = HIViewAddSubview( root, *outControl );
|
|
SetControlID( *outControl, &kWasabiID );
|
|
HIViewSetVisible(*outControl, true);
|
|
}
|
|
|
|
|
|
CantCreate:
|
|
CantGetRootControl:
|
|
CantSetParameter:
|
|
CantCreateEvent:
|
|
ReleaseEvent( event );
|
|
|
|
|
|
CantRegister:
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
OSWINDOWHANDLE Wasabi::Std::Wnd::createWnd(RECT *r, int nochild, int acceptdrops, OSWINDOWHANDLE parent, OSMODULEHANDLE module, ifc_window *rw)
|
|
{
|
|
#ifdef _WIN32
|
|
register_wndClass(module);
|
|
|
|
int style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
|
int exstyle=0;
|
|
|
|
if (parent == NULL) {
|
|
exstyle |= WS_EX_TOOLWINDOW;
|
|
style |= WS_POPUP;
|
|
} else
|
|
style |= WS_CHILD;
|
|
|
|
if (nochild) style=WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
|
|
|
if (acceptdrops) exstyle |= WS_EX_ACCEPTFILES;
|
|
|
|
HWND ret = CreateWindowExW(exstyle, BASEWNDCLASSNAME, NULL, style,
|
|
r->left, r->top, r->right - r->left, r->bottom - r->top, parent, NULL, module, (LPVOID)rw);
|
|
if (ret != INVALIDOSWINDOWHANDLE)
|
|
{
|
|
nreal++;
|
|
if(NULL != WASABI_API_APP && 0 != (WS_POPUP & style))
|
|
WASABI_API_APP->app_registerGlobalWindow(ret);
|
|
}
|
|
return ret;
|
|
#elif defined(__APPLE__)
|
|
Rect wndRect;
|
|
SetRect(&wndRect, r->left, r->top, r->right, r->bottom);
|
|
WindowRef newWnd;
|
|
CreateNewWindow(kOverlayWindowClass, kWindowCompositingAttribute, &wndRect, &newWnd);
|
|
SetWindowGroup(newWnd, GetWindowGroupOfClass(kDocumentWindowClass));
|
|
// install a window event handler
|
|
const EventTypeSpec windowEventList[] =
|
|
{
|
|
{
|
|
kEventClassCommand, kEventProcessCommand
|
|
},
|
|
// { kEventClassWindow, kEventWindowBoundsChanging },
|
|
{ kEventClassWindow, kEventWindowBoundsChanged },
|
|
// { kEventClassWindow, kEventWindowInit },
|
|
|
|
{kEventClassMouse, kEventMouseDown},
|
|
{kEventClassMouse, kEventMouseUp},
|
|
{kEventClassMouse, kEventMouseMoved},
|
|
{kEventClassMouse, kEventMouseDragged},
|
|
//{kEventClassMouse, kEventMouseEntered},
|
|
//{kEventClassMouse, kEventMouseExited},
|
|
//{kEventClassMouse, kEventMouseWheelMoved},
|
|
|
|
{kEventClassKeyboard, kEventRawKeyDown},
|
|
{kEventClassKeyboard, kEventRawKeyUp},
|
|
|
|
};
|
|
InstallWindowEventHandler(newWnd, MyWindowEventHandler, GetEventTypeCount(windowEventList), windowEventList, rw, NULL);
|
|
|
|
// create the content view
|
|
HIViewRef myHIView;
|
|
CreateHIView(newWnd,&wndRect,(ControlRef*)&myHIView);
|
|
const EventTypeSpec controlEventList[] =
|
|
{
|
|
{ kEventClassControl, kEventControlDraw},
|
|
{ kEventClassControl, kEventControlApplyBackground},
|
|
};
|
|
|
|
InstallEventHandler(GetControlEventTarget(myHIView), MyControlEventHandler, GetEventTypeCount(controlEventList), controlEventList, rw, NULL);
|
|
|
|
return newWnd;
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::destroyWnd(OSWINDOWHANDLE wnd)
|
|
{
|
|
#ifdef _WIN32
|
|
|
|
if(NULL != WASABI_API_APP && 0 != (WS_POPUP & GetWindowLongPtr(wnd, GWL_STYLE)))
|
|
WASABI_API_APP->app_unregisterGlobalWindow(wnd);
|
|
|
|
DestroyWindow(wnd);
|
|
nreal--;
|
|
if (nreal == 0)
|
|
{
|
|
if (gdi32instance) FreeLibrary(gdi32instance);
|
|
|
|
gdi32instance = NULL;
|
|
getRandomRgn = NULL;
|
|
}
|
|
#elif defined(__APPLE__)
|
|
DisposeWindow(wnd);
|
|
#endif
|
|
}
|
|
|
|
int Wasabi::Std::Wnd::isValidWnd(OSWINDOWHANDLE wnd)
|
|
{
|
|
#ifdef _WIN32
|
|
return IsWindow(wnd);
|
|
#elif defined(__APPLE__)
|
|
// TODO: docs suggest that this function is slow
|
|
if (!wnd)
|
|
return 0;
|
|
return IsValidWindowPtr(wnd);
|
|
#endif
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
void Wasabi::Std::Wnd::setLayeredWnd(OSWINDOWHANDLE wnd, int layered)
|
|
{
|
|
if (layered)
|
|
{
|
|
// have to clear and reset, can't just set
|
|
SetWindowLong(wnd, GWL_EXSTYLE, GetWindowLong(wnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
|
|
SetWindowLong(wnd, GWL_EXSTYLE, GetWindowLong(wnd, GWL_EXSTYLE) | WS_EX_LAYERED);
|
|
}
|
|
else
|
|
{
|
|
SetWindowLong(wnd, GWL_EXSTYLE, GetWindowLong(wnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
|
|
}
|
|
}
|
|
|
|
int Wasabi::Std::Wnd::isLayeredWnd(OSWINDOWHANDLE wnd)
|
|
{
|
|
DWORD dwLong = GetWindowLong(wnd, GWL_EXSTYLE);
|
|
return !!(dwLong & WS_EX_LAYERED);
|
|
}
|
|
|
|
|
|
|
|
void Wasabi::Std::Wnd::setLayeredAlpha(OSWINDOWHANDLE wnd, int amount)
|
|
{
|
|
if (!isDesktopAlphaAvailable()) return;
|
|
SetLayeredWindowAttributes(wnd, RGB(0, 0, 0), amount, LWA_ALPHA);
|
|
}
|
|
|
|
|
|
void Wasabi::Std::Wnd::updateLayeredWnd(OSWINDOWHANDLE wnd, int x, int y, int w, int h, HDC surfdc, int alpha)
|
|
{
|
|
if (!isDesktopAlphaAvailable()) return;
|
|
BLENDFUNCTION blend = {AC_SRC_OVER, 0, (BYTE)alpha, AC_SRC_ALPHA };
|
|
POINT sp = {x, y}, pt = {0, 0};
|
|
SIZE ss = { w, h };
|
|
//HDC sysdc = GetDC(NULL);
|
|
UpdateLayeredWindow(wnd, NULL/*sysdc*/, &sp, &ss, surfdc, &pt, 0, &blend, ULW_ALPHA);
|
|
//ReleaseDC(NULL, sysdc);
|
|
}
|
|
#endif
|
|
|
|
void Wasabi::Std::Wnd::setWndPos(OSWINDOWHANDLE wnd, OSWINDOWHANDLE zorder, int x, int y, int w, int h,
|
|
int nozorder, int noactive, int nocopybits, int nomove, int noresize)
|
|
{
|
|
#ifdef _WIN32
|
|
SetWindowPos(wnd, zorder, x, y, w, h,
|
|
SWP_DEFERERASE | // we ignore WM_SYNCPAINT anyway
|
|
(nozorder ? SWP_NOZORDER : 0) |
|
|
(noactive ? SWP_NOACTIVATE : 0) |
|
|
(nocopybits ? SWP_NOCOPYBITS : 0) |
|
|
(nomove ? SWP_NOMOVE : 0) |
|
|
(noresize ? SWP_NOSIZE : 0));
|
|
#elif defined(__APPLE__)
|
|
if (!nomove)
|
|
{
|
|
MoveWindow(wnd, x, y, false);
|
|
}
|
|
if (!noresize)
|
|
{
|
|
Rect newRect;
|
|
newRect.left = x;
|
|
newRect.right=x+w;
|
|
newRect.top = y;
|
|
newRect.bottom = y+h;
|
|
// SetWindowBounds(wnd, kWindowStructureRgn, &newRect);
|
|
SizeWindow(wnd, w, h, false);
|
|
}
|
|
if (!noactive)
|
|
SelectWindow(wnd);
|
|
if (!nocopybits)
|
|
Wasabi::Std::Wnd::invalidateRect(wnd, 0);
|
|
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::bringToFront(OSWINDOWHANDLE wnd)
|
|
{
|
|
#ifdef _WIN32
|
|
SetWindowPos(wnd, HWND_TOP, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_DEFERERASE | SWP_NOOWNERZORDER);
|
|
#elif defined(__APPLE__)
|
|
BringToFront(wnd);
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::sendToBack(OSWINDOWHANDLE wnd)
|
|
{
|
|
#ifdef _WIN32
|
|
SetWindowPos(wnd, HWND_BOTTOM, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_DEFERERASE | SWP_NOOWNERZORDER);
|
|
#elif defined(__APPLE__)
|
|
SendBehind(wnd, 0);
|
|
#endif
|
|
}
|
|
|
|
OSWINDOWHANDLE Wasabi::Std::Wnd::getWindowFromPoint(POINT pt)
|
|
{
|
|
#ifdef _WIN32
|
|
return ::WindowFromPoint(pt);
|
|
#else
|
|
#warning port me
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int Wasabi::Std::Wnd::isWndVisible(OSWINDOWHANDLE wnd)
|
|
{
|
|
return IsWindowVisible(wnd);
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::showWnd(OSWINDOWHANDLE wnd, int noactivate)
|
|
{
|
|
#ifdef _WIN32
|
|
ShowWindow(wnd, noactivate ? SW_SHOWNA : SW_SHOWNORMAL);
|
|
#elif defined(__APPLE__)
|
|
ShowWindow(wnd);
|
|
if (!noactivate)
|
|
ActivateWindow(wnd, 1);
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::hideWnd(OSWINDOWHANDLE wnd)
|
|
{
|
|
#ifdef _WIN32
|
|
ShowWindow(wnd, SW_HIDE);
|
|
#elif defined(__APPLE__)
|
|
HideWindow(wnd);
|
|
#endif
|
|
}
|
|
|
|
int Wasabi::Std::Wnd::isPopup(OSWINDOWHANDLE wnd)
|
|
{
|
|
#ifdef _WIN32
|
|
return !!(GetWindowLong(wnd, GWL_STYLE) & WS_POPUP);
|
|
#elif defined(__APPLE__)
|
|
return 0; // TODO: maybe use window class or window group to determine
|
|
#endif
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
void Wasabi::Std::Wnd::setEnabled(OSWINDOWHANDLE wnd, int enabled)
|
|
{
|
|
EnableWindow(wnd, enabled);
|
|
}
|
|
#endif
|
|
|
|
void Wasabi::Std::Wnd::setFocus(OSWINDOWHANDLE wnd)
|
|
{
|
|
#ifdef _WIN32
|
|
SetFocus(wnd);
|
|
#elif defined(__APPLE__)
|
|
SetUserFocusWindow(wnd);
|
|
#endif
|
|
}
|
|
|
|
OSWINDOWHANDLE Wasabi::Std::Wnd::getFocus()
|
|
{
|
|
#ifdef _WIN32
|
|
return GetFocus();
|
|
#elif defined(__APPLE__)
|
|
return GetUserFocusWindow();
|
|
#endif
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
void Wasabi::Std::Wnd::setTopmost(OSWINDOWHANDLE wnd, int topmost)
|
|
{
|
|
SetWindowPos(wnd, topmost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
|
|
}
|
|
#endif
|
|
|
|
void Wasabi::Std::Wnd::invalidateRect(OSWINDOWHANDLE wnd, RECT *r)
|
|
{
|
|
#ifdef _WIN32
|
|
OSREGIONHANDLE reg = NULL;
|
|
if (r == NULL)
|
|
{
|
|
RECT cr;
|
|
if (!IsWindow(wnd))
|
|
return;
|
|
|
|
GetClientRect(wnd, &cr);
|
|
reg = CreateRectRgnIndirect(&cr);
|
|
}
|
|
else
|
|
reg = CreateRectRgnIndirect(r);
|
|
invalidateRegion(wnd, reg);
|
|
DeleteObject(reg);
|
|
#elif defined(__APPLE__)
|
|
HIViewRef view;
|
|
GetWasabiHIView(wnd, &view);
|
|
if (r == 0)
|
|
{
|
|
HIViewSetNeedsDisplay(view, true);
|
|
}
|
|
else
|
|
{
|
|
HIRect rect = CGRectMake(r->left, r->top, r->right-r->left, r->bottom - r->top);
|
|
HIViewSetNeedsDisplayInRect(view, &rect, true);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
void Wasabi::Std::Wnd::invalidateRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region)
|
|
{
|
|
#ifdef _WIN32
|
|
clipOSChildren(wnd, region);
|
|
InvalidateRgn(wnd, region, FALSE);
|
|
#elif defined(__APPLE__)
|
|
HIViewRef view;
|
|
GetWasabiHIView(wnd, &view);
|
|
HIViewSetNeedsDisplayInShape(view, region, true);
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::validateRect(OSWINDOWHANDLE wnd, RECT *r)
|
|
{
|
|
#ifdef _WIN32
|
|
ValidateRect(wnd, r);
|
|
#elif defined(__APPLE__)
|
|
HIViewRef view;
|
|
GetWasabiHIView(wnd, &view);
|
|
if (r == 0)
|
|
{
|
|
HIViewSetNeedsDisplay(view, false);
|
|
}
|
|
else
|
|
{
|
|
HIRect rect = CGRectMake(r->left, r->top, r->right-r->left, r->bottom - r->top);
|
|
HIViewSetNeedsDisplayInRect(view, &rect, false);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::validateRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region)
|
|
{
|
|
#ifdef _WIN32
|
|
ValidateRgn(wnd, region);
|
|
#elif defined(__APPLE__)
|
|
HIViewRef view;
|
|
GetWasabiHIView(wnd, &view);
|
|
HIViewSetNeedsDisplayInShape(view, region, false);
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::update(OSWINDOWHANDLE wnd)
|
|
{
|
|
#ifdef _WIN32
|
|
if (wnd != NULL)
|
|
UpdateWindow(wnd);
|
|
#elif defined(__APPLE__)
|
|
if (wnd)
|
|
{
|
|
HIViewRef view;
|
|
GetWasabiHIView(wnd, &view);
|
|
HIViewRender(view);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
int Wasabi::Std::Wnd::getUpdateRect(OSWINDOWHANDLE wnd, RECT *r)
|
|
{
|
|
#ifdef _WIN32
|
|
return GetUpdateRect(wnd, r, FALSE);
|
|
#else
|
|
Rect updateRect;
|
|
GetWindowBounds(wnd, kWindowUpdateRgn, &updateRect);
|
|
r->left=updateRect.left;
|
|
r->right = updateRect.right;
|
|
r->top = updateRect.top;
|
|
r->bottom = updateRect.bottom;
|
|
#endif
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
void Wasabi::Std::Wnd::getUpdateRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region)
|
|
{
|
|
GetUpdateRgn(wnd, region, FALSE);
|
|
}
|
|
#elif defined(__APPLE__)
|
|
// TODO: GetWindowRegion(wnd, kWindowUpdateRgn, region);
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
int Wasabi::Std::Wnd::haveGetRandomRegion()
|
|
{
|
|
// I assume linux will just return FALSE
|
|
if (gdi32instance == NULL && !grrfailed)
|
|
{
|
|
gdi32instance = LoadLibrary(L"GDI32.dll");
|
|
if (gdi32instance != NULL)
|
|
{
|
|
getRandomRgn = (int(WINAPI *)(HDC, HRGN, int)) GetProcAddress(gdi32instance, "GetRandomRgn");
|
|
if (getRandomRgn == NULL)
|
|
{
|
|
grrfailed = 1;
|
|
FreeLibrary(gdi32instance);
|
|
gdi32instance = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
grrfailed = 1;
|
|
}
|
|
}
|
|
return (getRandomRgn != NULL);
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::getRandomRegion(HDC hdc, OSREGIONHANDLE region)
|
|
{
|
|
if (!haveGetRandomRegion()) return;
|
|
(*getRandomRgn)(hdc, region, SYSRGN);
|
|
}
|
|
#endif
|
|
void Wasabi::Std::Wnd::setWndRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region, int redraw)
|
|
{
|
|
#ifdef _WIN32
|
|
SetWindowRgn(wnd, region, !!redraw);
|
|
#elif defined(__APPLE__)
|
|
#warning port me?
|
|
#endif
|
|
}
|
|
#ifdef _WIN32
|
|
int Wasabi::Std::Wnd::isDesktopAlphaAvailable()
|
|
{
|
|
return 1; // we're only targetting windows 2000 and up, so it's always available
|
|
}
|
|
#endif
|
|
int Wasabi::Std::Wnd::isTransparencyAvailable()
|
|
{
|
|
#ifdef _WIN32
|
|
// there is no win32 implementation that supports setLayeredWindowAttributes but not updateLayeredWindow
|
|
return Wasabi::Std::Wnd::isDesktopAlphaAvailable();
|
|
#elif defined(__APPLE__)
|
|
return 1;
|
|
#else
|
|
#error port me
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::getClientRect(OSWINDOWHANDLE wnd, RECT *r)
|
|
{
|
|
#ifdef _WIN32
|
|
GetClientRect(wnd, r);
|
|
#elif defined(__APPLE__)
|
|
Rect temp;
|
|
GetWindowBounds(wnd, kWindowContentRgn, &temp);
|
|
r->left = 0;
|
|
r->top = 0;
|
|
r->right = temp.right-temp.left;
|
|
r->bottom = temp.bottom-temp.top;
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::getWindowRect(OSWINDOWHANDLE wnd, RECT *r)
|
|
{
|
|
#ifdef _WIN32
|
|
GetWindowRect(wnd, r);
|
|
#elif defined(__APPLE__)
|
|
Rect temp;
|
|
GetWindowBounds(wnd, kWindowGlobalPortRgn, &temp);
|
|
r->left = temp.left;
|
|
r->top = temp.top;
|
|
r->right = temp.right;
|
|
r->bottom = temp.bottom;
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::clientToScreen(OSWINDOWHANDLE wnd, int *x, int *y)
|
|
{
|
|
#ifdef _WIN32
|
|
POINT p = { x ? *x : 0, y ? *y : 0 };
|
|
ClientToScreen(wnd, &p);
|
|
if (x) *x = p.x;
|
|
if (y) *y = p.y;
|
|
#elif defined(__APPLE__)
|
|
Point pt;
|
|
pt.h = x?*x:0;
|
|
pt.v = y?*y:0;
|
|
QDLocalToGlobalPoint(GetWindowPort(wnd) , &pt);
|
|
if (x) *x = pt.h;
|
|
if (y) *y = pt.v;
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::screenToClient(OSWINDOWHANDLE wnd, int *x, int *y)
|
|
{
|
|
#ifdef _WIN32
|
|
POINT p = { x ? *x : 0, y ? *y : 0 };
|
|
ScreenToClient(wnd, &p);
|
|
if (x) *x = p.x;
|
|
if (y) *y = p.y;
|
|
#elif defined(__APPLE__)
|
|
Point pt;
|
|
pt.h = x?*x:0;
|
|
pt.v = y?*y:0;
|
|
QDGlobalToLocalPoint(GetWindowPort(wnd) , &pt);
|
|
if (x) *x = pt.h;
|
|
if (y) *y = pt.v;
|
|
#endif
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
void Wasabi::Std::Wnd::setParent(OSWINDOWHANDLE child, OSWINDOWHANDLE newparent)
|
|
{
|
|
SetParent(child, newparent);
|
|
}
|
|
#endif
|
|
|
|
OSWINDOWHANDLE Wasabi::Std::Wnd::getParent(OSWINDOWHANDLE wnd)
|
|
{
|
|
#ifdef _WIN32
|
|
return GetParent(wnd);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
OSWINDOWHANDLE Wasabi::Std::Wnd::getTopmostChild(OSWINDOWHANDLE wnd)
|
|
{
|
|
return GetWindow(wnd, GW_CHILD);
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::setCapture(OSWINDOWHANDLE wnd)
|
|
{
|
|
SetCapture(wnd);
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::releaseCapture()
|
|
{
|
|
ReleaseCapture();
|
|
}
|
|
|
|
OSWINDOWHANDLE Wasabi::Std::Wnd::getCapture()
|
|
{
|
|
return GetCapture();
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::revokeDragNDrop(OSWINDOWHANDLE wnd)
|
|
{
|
|
if (wnd == NULL) return;
|
|
RevokeDragDrop(wnd);
|
|
}
|
|
#endif
|
|
void Wasabi::Std::Wnd::setWndName(OSWINDOWHANDLE wnd, const wchar_t *name)
|
|
{
|
|
#ifdef _WIN32
|
|
SetWindowTextW(wnd, name);
|
|
#elif defined(__APPLE__)
|
|
// TODO:
|
|
//SetWindowTitleWithCFString(wnd,
|
|
#endif
|
|
}
|
|
|
|
|
|
void Wasabi::Std::Wnd::getWndName(OSWINDOWHANDLE wnd, wchar_t *name, int maxlen)
|
|
{
|
|
#ifdef _WIN32
|
|
GetWindowTextW(wnd, name, maxlen);
|
|
#else
|
|
name[0]=0;
|
|
#warning port me
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::setIcon(OSWINDOWHANDLE wnd, OSICONHANDLE icon, int large)
|
|
{
|
|
#ifdef _WIN32
|
|
SendMessageW(wnd, WM_SETICON, !large ? ICON_SMALL : ICON_BIG, (LPARAM)icon);
|
|
#else
|
|
#warning port me
|
|
#endif
|
|
}
|
|
|
|
OSWINDOWHANDLE Wasabi::Std::Wnd::getActiveWindow()
|
|
{
|
|
#ifdef _WIN32
|
|
return GetActiveWindow();
|
|
#elif defined(__APPLE__)
|
|
return ActiveNonFloatingWindow();
|
|
#endif
|
|
}
|
|
|
|
void Wasabi::Std::Wnd::setActiveWindow(OSWINDOWHANDLE wnd)
|
|
{
|
|
#ifdef _WIN32
|
|
SetActiveWindow(wnd);
|
|
#elif defined(__APPLE__)
|
|
SelectWindow(wnd);
|
|
#endif
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
// clip oswindow children off the invalidation region
|
|
void Wasabi::Std::Wnd::clipOSChildren(OSWINDOWHANDLE wnd, OSREGIONHANDLE reg)
|
|
{
|
|
HWND w = GetWindow(wnd, GW_CHILD);
|
|
while (w != NULL)
|
|
{
|
|
if (IsWindowVisible(w))
|
|
{
|
|
RECT r;
|
|
GetClientRect(w, &r);
|
|
POINT p = {r.left, r.top};
|
|
ClientToScreen(w, &p);
|
|
ScreenToClient(wnd, &p);
|
|
OffsetRect(&r, p.x, p.y);
|
|
OSREGIONHANDLE cr = CreateRectRgnIndirect(&r);
|
|
OSREGIONHANDLE or = CreateRectRgn(0, 0, 0, 0);
|
|
CombineRgn(or, reg, 0, RGN_COPY);
|
|
CombineRgn(reg, or, cr, RGN_DIFF);
|
|
DeleteObject(cr);
|
|
DeleteObject(or);
|
|
}
|
|
w = GetWindow(w, GW_HWNDNEXT);
|
|
}
|
|
}
|
|
|
|
//////////////////////////
|
|
|
|
static LRESULT CALLBACK wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// fetch out the api_window *
|
|
if (uMsg == WM_CREATE)
|
|
{
|
|
CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
|
|
ASSERT(cs->lpCreateParams != NULL);
|
|
// stash pointer to self
|
|
SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams);
|
|
}
|
|
|
|
// pass the messages into the BaseWnd
|
|
ifc_window *rootwnd = (ifc_window*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
|
|
if (rootwnd == NULL || rootwnd->getOsWindowHandle() != hWnd)
|
|
{
|
|
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
LRESULT r = 0;
|
|
switch (uMsg)
|
|
{
|
|
case WM_CLOSE:
|
|
PostMessage(GetParent(hWnd), WM_CLOSE, wParam, lParam);
|
|
return 0;
|
|
case WM_NCPAINT: return 0;
|
|
case WM_SYNCPAINT: return 0;
|
|
// case WM_SETFOCUS: r = rootwnd->windowEvent(WndEvent::SETFOCUS);
|
|
// case WM_KILLFOCUS: r = rootwnd->windowEvent(WndEvent::KILLFOCUS);
|
|
case WM_ACTIVATE:
|
|
if ( (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) && IsIconic(GetParent(hWnd)) )
|
|
{
|
|
ShowWindow(GetParent(hWnd), SW_RESTORE);
|
|
}
|
|
r = rootwnd->wndProc(hWnd, uMsg, wParam, lParam);
|
|
break;
|
|
case WM_COMMAND:
|
|
if (HIWORD(wParam) == THBN_CLICKED)
|
|
{
|
|
HWND parentWnd = GetParent(hWnd);
|
|
if (parentWnd == NULL)
|
|
parentWnd = hWnd;
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case 0: //previous
|
|
{
|
|
SendMessage(parentWnd, WM_COMMAND, 40044, 0);
|
|
}
|
|
break;
|
|
case 1: //play
|
|
{
|
|
SendMessage(parentWnd, WM_COMMAND, 40045, 0);
|
|
}
|
|
break;
|
|
case 2: //pause
|
|
{
|
|
SendMessage(parentWnd, WM_COMMAND, 40046, 0);
|
|
}
|
|
break;
|
|
case 3: //stop
|
|
{
|
|
SendMessage(parentWnd, WM_COMMAND, 40047, 0);
|
|
}
|
|
break;
|
|
case 4: //next
|
|
{
|
|
SendMessage(parentWnd, WM_COMMAND, 40048, 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
default:
|
|
r = rootwnd->wndProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
if (IsWindow(hWnd)) // wndProc may have switched skin and killed this window
|
|
rootwnd->performBatchProcesses();
|
|
return r;
|
|
}
|
|
}
|
|
|
|
static void register_wndClass(HINSTANCE hInstance)
|
|
{
|
|
WNDCLASSW wc;
|
|
if (GetClassInfoW(hInstance, BASEWNDCLASSNAME, &wc)) return;
|
|
|
|
// regiszter pane class
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = (WNDPROC)wndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = NULL;
|
|
wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = BASEWNDCLASSNAME;
|
|
|
|
int r = RegisterClassW(&wc);
|
|
if (r == 0)
|
|
{
|
|
int res = GetLastError();
|
|
if (res != ERROR_CLASS_ALREADY_EXISTS)
|
|
{
|
|
char florp[WA_MAX_PATH] = {0};
|
|
SPRINTF(florp, "Failed to register class, err %d", res);
|
|
ASSERTPR(0, florp);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
|
|
|
// TODO: call into BaseWnd and take this out of here
|
|
#include <tataki/canvas/canvas.h>
|
|
#include <tataki/region/region.h>
|
|
#include <api/wnd/basewnd.h>
|
|
|
|
OSStatus MyWindowEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
|
|
{
|
|
HICommand hiCommand;
|
|
OSStatus err = eventNotHandledErr;
|
|
UInt32 eventClass = GetEventClass(inEvent);
|
|
UInt32 eventKind = GetEventKind(inEvent);
|
|
ifc_window *wasabiWnd = (ifc_window *)inUserData;
|
|
WindowRef window = wasabiWnd->getOsWindowHandle();
|
|
|
|
switch (eventClass)
|
|
{
|
|
case kEventClassKeyboard:
|
|
switch (eventKind)
|
|
{
|
|
case kEventRawKeyDown:
|
|
{
|
|
UInt32 keyCode;
|
|
GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32,
|
|
NULL, sizeof(keyCode), NULL, &keyCode);
|
|
|
|
if (wasabiWnd->onKeyDown(keyCode))
|
|
err = noErr;
|
|
}
|
|
break;
|
|
case kEventRawKeyUp:
|
|
{
|
|
UInt32 keyCode;
|
|
GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32,
|
|
NULL, sizeof(keyCode), NULL, &keyCode);
|
|
|
|
if (wasabiWnd->onKeyUp(keyCode))
|
|
err = noErr;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case kEventClassMouse:
|
|
switch (eventKind)
|
|
{
|
|
case kEventMouseDown:
|
|
{
|
|
HIPoint point;
|
|
|
|
GetEventParameter(inEvent, kEventParamWindowMouseLocation, typeHIPoint,
|
|
NULL, sizeof(point), NULL, &point);
|
|
|
|
EventMouseButton button;
|
|
|
|
GetEventParameter(inEvent, kEventParamMouseButton, typeMouseButton,
|
|
NULL, sizeof(button), NULL, &button);
|
|
|
|
UInt32 modifiers;
|
|
GetEventParameter(inEvent, kEventParamKeyModifiers, typeUInt32,
|
|
NULL, sizeof(modifiers), NULL, &modifiers);
|
|
|
|
|
|
switch (button)
|
|
{
|
|
case kEventMouseButtonPrimary:
|
|
if (modifiers & controlKey) // fake right click
|
|
wasabiWnd->onRightButtonDown(point.x, point.y);
|
|
else
|
|
wasabiWnd->onLeftButtonDown(point.x, point.y);
|
|
break;
|
|
case kEventMouseButtonSecondary:
|
|
wasabiWnd->onRightButtonDown(point.x, point.y);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case kEventMouseUp:
|
|
{
|
|
HIPoint point;
|
|
GetEventParameter(inEvent, kEventParamWindowMouseLocation, typeHIPoint,
|
|
NULL, sizeof(point), NULL, &point);
|
|
|
|
EventMouseButton button;
|
|
GetEventParameter(inEvent, kEventParamMouseButton, typeMouseButton,
|
|
NULL, sizeof(button), NULL, &button);
|
|
|
|
switch (button)
|
|
{
|
|
case kEventMouseButtonPrimary:
|
|
wasabiWnd->onLeftButtonUp(point.x, point.y);
|
|
break;
|
|
case kEventMouseButtonSecondary:
|
|
wasabiWnd->onRightButtonUp(point.x, point.y);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case kEventMouseMoved:
|
|
case kEventMouseDragged:
|
|
{
|
|
HIPoint point;
|
|
GetEventParameter(inEvent, kEventParamWindowMouseLocation, typeHIPoint,
|
|
NULL, sizeof(point), NULL, &point);
|
|
|
|
wasabiWnd->onMouseMove(point.x, point.y);
|
|
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case kEventClassCommand:
|
|
if (eventKind == kEventProcessCommand)
|
|
{
|
|
err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand,
|
|
NULL, sizeof(HICommand), NULL, &hiCommand);
|
|
|
|
switch (hiCommand.commandID)
|
|
{
|
|
default:
|
|
err = eventNotHandledErr;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case kEventClassWindow:
|
|
switch (eventKind)
|
|
{
|
|
case kEventWindowBoundsChanging:
|
|
break;
|
|
case kEventWindowBoundsChanged:
|
|
{
|
|
HIRect bounds;
|
|
UInt32 attributes;
|
|
Rect origBounds;
|
|
Rect currBounds;
|
|
ControlRef control;
|
|
|
|
// Get the change attributes
|
|
err = GetEventParameter(inEvent, kEventParamAttributes, typeUInt32,
|
|
NULL, sizeof(UInt32), NULL, &attributes);
|
|
|
|
// If the window size changed
|
|
//kWindowBoundsChangeOriginChanged
|
|
if (attributes & kWindowBoundsChangeSizeChanged)
|
|
{
|
|
GetEventParameter(inEvent, kEventParamOriginalBounds, typeQDRectangle,
|
|
NULL, sizeof(Rect), NULL, &origBounds);
|
|
|
|
GetEventParameter(inEvent, kEventParamCurrentBounds, typeQDRectangle,
|
|
NULL, sizeof(Rect), NULL, &currBounds);
|
|
|
|
// Get the clock control
|
|
err = GetControlByID( window, &kWasabiID, &control );
|
|
|
|
// Hide it (to avoid remnants when downsizing)
|
|
//HIViewSetVisible( control, false );
|
|
|
|
// Resize it
|
|
HIViewGetFrame( control, &bounds );
|
|
#define QDRECTWIDTH(R) ((R).right - (R).left)
|
|
#define QDRECTHEIGHT(R) ((R).bottom - (R).top)
|
|
|
|
bounds.size.width += QDRECTWIDTH( currBounds ) - QDRECTWIDTH( origBounds );
|
|
bounds.size.height += QDRECTHEIGHT( currBounds ) - QDRECTHEIGHT( origBounds );
|
|
HIViewSetFrame( control, &bounds );
|
|
|
|
// Show it
|
|
//HIViewSetVisible( control, true );
|
|
|
|
}
|
|
err = noErr;
|
|
}
|
|
break;
|
|
case kEventWindowInit:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
return err;
|
|
}
|
|
OSStatus MyControlEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
|
|
{
|
|
HICommand hiCommand;
|
|
OSStatus err = eventNotHandledErr;
|
|
UInt32 eventClass = GetEventClass(inEvent);
|
|
UInt32 eventKind = GetEventKind(inEvent);
|
|
ifc_window *wasabiWnd = (ifc_window *)inUserData;
|
|
switch(eventClass)
|
|
{
|
|
case kEventClassControl:
|
|
switch(eventKind)
|
|
{
|
|
|
|
case kEventControlDraw:
|
|
{
|
|
CGContextRef context;
|
|
RgnHandle rgn;
|
|
HIShapeRef shape;
|
|
HIViewRef view;
|
|
if (GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(context), NULL, &context) == noErr
|
|
&& GetEventParameter(inEvent, kEventParamRgnHandle, typeQDRgnHandle, NULL, sizeof(rgn), NULL, &rgn) == noErr
|
|
&& GetEventParameter(inEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof(view), NULL, &view) == noErr)
|
|
{
|
|
GetEventParameter(inEvent, kEventParamShape, typeHIShapeRef, NULL, sizeof(shape), NULL, &shape);
|
|
|
|
HIRect bounds;
|
|
HIViewGetBounds(view, &bounds);
|
|
|
|
Canvas canvas(context);
|
|
// RegionI region(rgn);
|
|
RegionI region(shape);
|
|
|
|
//((RootWndI *)wasabiWnd)->rootwnd_paintTree(&canvas, ®ion);
|
|
wasabiWnd->paint(&canvas, ®ion); // TODO: should be virtualOnPaint()
|
|
|
|
err = noErr;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return err;
|
|
}
|
|
#endif
|