962 lines
22 KiB
C++
962 lines
22 KiB
C++
#include <precomp.h>
|
|
|
|
#include <api/api.h>
|
|
#include <api/linux/api_linux.h>
|
|
|
|
#include <bfc/ptrlist.h>
|
|
#include <bfc/string/string.h>
|
|
#include <bfc/critsec.h>
|
|
#include <bfc/thread.h>
|
|
#include <api/application/ipcs.h>
|
|
|
|
#ifdef WASABI_COMPILE_WND
|
|
Display *Linux::display = NULL;
|
|
|
|
int linux_atoms_loaded = 0;
|
|
|
|
Atom winamp_msg;
|
|
Atom dnd_enter, dnd_position, dnd_status, dnd_leave, dnd_drop, dnd_finished;
|
|
Atom dnd_selection, dnd_wa3drop, dnd_private, dnd_typelist;
|
|
Atom dnd_urilist, dnd_textplain, dnd_mozurl;
|
|
#endif
|
|
|
|
#ifndef _NOSTUDIO
|
|
|
|
#ifdef WASABI_COMPILE_WND
|
|
void LoadAtoms() {
|
|
if ( !linux_atoms_loaded ) {
|
|
linux_atoms_loaded = 1;
|
|
winamp_msg = XInternAtom( Linux::getDisplay(), "Winamp3", False );
|
|
dnd_wa3drop = XInternAtom( Linux::getDisplay(), "Winamp3_drop", False );
|
|
dnd_enter = XInternAtom( Linux::getDisplay(), "XdndEnter", True );
|
|
dnd_position = XInternAtom( Linux::getDisplay(), "XdndPosition", True );
|
|
dnd_status = XInternAtom( Linux::getDisplay(), "XdndStatus", True );
|
|
dnd_leave = XInternAtom( Linux::getDisplay(), "XdndLeave", True );
|
|
dnd_drop = XInternAtom( Linux::getDisplay(), "XdndDrop", True );
|
|
dnd_finished = XInternAtom( Linux::getDisplay(), "XdndFinished", True );
|
|
dnd_selection = XInternAtom( Linux::getDisplay(), "XdndSelection", True );
|
|
dnd_private = XInternAtom( Linux::getDisplay(), "XdndActionPrivate", True );
|
|
dnd_typelist = XInternAtom( Linux::getDisplay(), "XdndTypeList", True );
|
|
dnd_urilist = XInternAtom( Linux::getDisplay(), "text/uri-list", True );
|
|
dnd_textplain = XInternAtom( Linux::getDisplay(), "text/plain", True );
|
|
dnd_mozurl = XInternAtom( Linux::getDisplay(), "text/x-moz-url", True );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
void OutputDebugString( const char *s ) {
|
|
#ifdef _DEBUG
|
|
fprintf( stderr, "%s", s );
|
|
#endif
|
|
char *file = getenv( "WASABI_LOG_FILE" );
|
|
if ( file ) {
|
|
if ( !STRCMP( file, "-" ) ) {
|
|
fprintf( stdout, "%s", s );
|
|
} else {
|
|
FILE *f = fopen( file, "a" );
|
|
if ( f ) {
|
|
fprintf( f, "%s", s );
|
|
fclose( f );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD GetTickCount() {
|
|
static int starttime = -1;
|
|
|
|
if ( starttime == -1 )
|
|
starttime = time( NULL );
|
|
|
|
struct timeb tb;
|
|
ftime( &tb );
|
|
tb.time -= starttime;
|
|
return tb.time * 1000 + tb.millitm;
|
|
}
|
|
void Sleep( int ms ) {
|
|
if ( ms != 0 ) {
|
|
struct timespec ts = { 0, 0 };
|
|
ts.tv_sec = ms / 1000;
|
|
ts.tv_nsec = (ms % 1000) * 1000000;
|
|
nanosleep( &ts, NULL);
|
|
// usleep(ms * 1000);
|
|
}
|
|
}
|
|
|
|
#ifndef _NOSTUDIO
|
|
|
|
#ifdef WASABI_COMPILE_WND
|
|
|
|
Display *Linux::getDisplay() {
|
|
if ( ! display )
|
|
display = WASABI_API_LINUX->linux_getDisplay();
|
|
|
|
return display;
|
|
}
|
|
|
|
XContext Linux::getContext() {
|
|
static XContext context = 0;
|
|
|
|
if ( context == 0 )
|
|
context = WASABI_API_LINUX->linux_getContext();
|
|
|
|
return context;
|
|
}
|
|
|
|
int Linux::getScreenNum() { return DefaultScreen( getDisplay() ); }
|
|
|
|
Window Linux::RootWin() {
|
|
return RootWindow( getDisplay(), getScreenNum() );
|
|
}
|
|
Visual *Linux::DefaultVis() {
|
|
return DefaultVisual( getDisplay(), getScreenNum() );
|
|
}
|
|
|
|
void Linux::setCursor( HWND h, int cursor ) {
|
|
Cursor c = XCreateFontCursor( Linux::getDisplay(), cursor );
|
|
|
|
if ( cursor == None )
|
|
XUndefineCursor( Linux::getDisplay(), h );
|
|
else
|
|
XDefineCursor( Linux::getDisplay(), h, c );
|
|
|
|
XFreeCursor( Linux::getDisplay(), c );
|
|
}
|
|
|
|
int Linux::convertEvent( MSG *m, XEvent *e ) {
|
|
m->hwnd = e->xany.window;
|
|
|
|
if ( m->hwnd ) {
|
|
api_window *rw =(api_window *)GetWindowLong( m->hwnd, GWL_USERDATA );
|
|
if ( !rw ) {
|
|
// This is to fix messages for dead windows...
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
switch ( e->type ) {
|
|
case ButtonPress:
|
|
switch( e->xbutton.button ) {
|
|
case 1:
|
|
m->message = WM_LBUTTONDOWN;
|
|
m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
m->message = WM_RBUTTONDOWN;
|
|
m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
|
|
break;
|
|
|
|
case 4:
|
|
m->message = WM_MOUSEWHEEL;
|
|
m->wParam = 120 << 16 | 0; // 1 tick, no modifiers
|
|
m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
|
|
break;
|
|
|
|
case 5:
|
|
m->message = WM_MOUSEWHEEL;
|
|
m->wParam = (-120) << 16 | 0; // 1 tick, no modifiers
|
|
m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
|
|
break;
|
|
}
|
|
break;
|
|
case ButtonRelease:
|
|
switch( e->xbutton.button ) {
|
|
case 1:
|
|
m->message = WM_LBUTTONUP;
|
|
m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
m->message = WM_RBUTTONUP;
|
|
m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
|
|
break;
|
|
}
|
|
break;
|
|
case MotionNotify:
|
|
{
|
|
m->message = WM_MOUSEMOVE;
|
|
do {
|
|
// Spin...
|
|
} while( XCheckTypedWindowEvent( Linux::getDisplay(), m->hwnd, MotionNotify, e ) );
|
|
|
|
RECT r;
|
|
POINT offset = {0, 0};
|
|
HWND hwnd = m->hwnd;
|
|
|
|
GetWindowRect( hwnd, &r );
|
|
|
|
m->lParam = ((e->xmotion.x_root - r.left) & 0xffff) |
|
|
((e->xmotion.y_root - r.top) << 16);
|
|
|
|
if ( ! (e->xmotion.state & ( Button1Mask | Button2Mask | Button3Mask )) )
|
|
PostMessage( m->hwnd, WM_SETCURSOR, m->hwnd, 0 );
|
|
}
|
|
break;
|
|
|
|
case KeyPress:
|
|
m->message = WM_KEYDOWN;
|
|
m->wParam = e->xkey.keycode;
|
|
break;
|
|
|
|
case KeyRelease:
|
|
m->message = WM_KEYUP;
|
|
m->wParam = e->xkey.keycode;
|
|
break;
|
|
|
|
case Expose:
|
|
{
|
|
RECT r;
|
|
m->message = WM_PAINT;
|
|
do {
|
|
r.left = e->xexpose.x;
|
|
r.top = e->xexpose.y;
|
|
r.right = r.left + e->xexpose.width;
|
|
r.bottom = r.top + e->xexpose.height;
|
|
InvalidateRect( m->hwnd, &r, FALSE );
|
|
} while( XCheckTypedWindowEvent( Linux::getDisplay(), m->hwnd, Expose, e ) );
|
|
}
|
|
break;
|
|
|
|
case ClientMessage: {
|
|
static int coord = -1;
|
|
static Atom supported = None;
|
|
XClientMessageEvent cme;
|
|
|
|
LoadAtoms();
|
|
|
|
int message = e->xclient.message_type;
|
|
if ( message == dnd_enter ) {
|
|
if ( e->xclient.data.l[1] & 1 ) {
|
|
Atom actual;
|
|
int format;
|
|
long unsigned int nitems, bytes;
|
|
unsigned char *data = NULL;
|
|
|
|
XGetWindowProperty( Linux::getDisplay(), e->xclient.data.l[0],
|
|
dnd_typelist, 0, 65536, True, XA_ATOM,
|
|
&actual, &format, &nitems, &bytes, &data );
|
|
|
|
Atom *atomdata = (Atom *)data;
|
|
|
|
supported = None;
|
|
for( int i = 0; i < nitems; i++ ) {
|
|
if ( atomdata[i] == dnd_urilist ) {
|
|
supported = dnd_urilist;
|
|
}
|
|
}
|
|
if ( supported == None ) {
|
|
for( int i = 0; i < nitems; i++ ) {
|
|
if ( atomdata[i] == dnd_textplain ) {
|
|
OutputDebugString( "text/plain found\n" );
|
|
supported = dnd_textplain;
|
|
}
|
|
}
|
|
}
|
|
if ( supported == None ) {
|
|
for( int i = 0; i < nitems; i++ ) {
|
|
if ( atomdata[i] == dnd_mozurl ) {
|
|
supported = dnd_mozurl;
|
|
}
|
|
}
|
|
}
|
|
|
|
XFree( data );
|
|
} else {
|
|
if ( e->xclient.data.l[2] == dnd_urilist ||
|
|
e->xclient.data.l[3] == dnd_urilist ||
|
|
e->xclient.data.l[4] == dnd_urilist ) {
|
|
supported = dnd_urilist;
|
|
} else if ( e->xclient.data.l[2] == dnd_mozurl ||
|
|
e->xclient.data.l[3] == dnd_mozurl ||
|
|
e->xclient.data.l[4] == dnd_mozurl ) {
|
|
supported = dnd_mozurl;
|
|
}
|
|
}
|
|
|
|
|
|
// DnD Enter
|
|
return 0;
|
|
|
|
} else if ( message == dnd_position ) {
|
|
// DnD Position Notify
|
|
|
|
cme.type = ClientMessage;
|
|
cme.message_type = dnd_status;
|
|
cme.format = 32;
|
|
cme.window = e->xclient.data.l[0];
|
|
cme.data.l[0] = e->xclient.window;
|
|
cme.data.l[1] = 1; // Can Accept
|
|
cme.data.l[2] = cme.data.l[3] = 0; // Empty rectangle - give us moves
|
|
cme.data.l[4] = dnd_private; // We're doing our own thing
|
|
|
|
if ( coord == -1 && supported != None ) {
|
|
XConvertSelection( Linux::getDisplay(), dnd_selection, supported,
|
|
dnd_wa3drop, cme.window, CurrentTime );
|
|
}
|
|
|
|
coord = e->xclient.data.l[2];
|
|
|
|
XSendEvent( Linux::getDisplay(), e->xclient.data.l[0], False,
|
|
NoEventMask, (XEvent *)&cme );
|
|
|
|
return 0;
|
|
|
|
} else if ( message == dnd_leave ) {
|
|
// DnD Leave
|
|
coord = -1;
|
|
supported = None;
|
|
|
|
return 0;
|
|
|
|
} else if ( message == dnd_drop ) {
|
|
// DnD Drop
|
|
|
|
Window win = e->xclient.data.l[0];
|
|
|
|
cme.type = ClientMessage;
|
|
cme.message_type = dnd_finished;
|
|
cme.format = 32;
|
|
cme.window = e->xclient.data.l[0];
|
|
cme.data.l[0] = e->xclient.window;
|
|
cme.data.l[1] = cme.data.l[2] = cme.data.l[3] = cme.data.l[4] = 0;
|
|
|
|
XSendEvent( Linux::getDisplay(), e->xclient.data.l[0], False,
|
|
NoEventMask, (XEvent *)&cme );
|
|
|
|
if ( supported != None ) {
|
|
Atom actual;
|
|
int format;
|
|
long unsigned int nitems, bytes;
|
|
unsigned char *data = NULL;
|
|
|
|
XGetWindowProperty( Linux::getDisplay(), cme.window, dnd_wa3drop,
|
|
0, 65536, True, supported, &actual,
|
|
&format, &nitems, &bytes,
|
|
&data );
|
|
|
|
OutputDebugString( StringPrintf( "Drop data (%d):\n%s\n", nitems, data ) );
|
|
|
|
m->message = WM_DROPFILES;
|
|
m->wParam = coord;
|
|
m->lParam = (LPARAM)data;
|
|
|
|
coord = -1;
|
|
supported = None;
|
|
|
|
} else {
|
|
coord = -1;
|
|
supported = None;
|
|
return 0;
|
|
}
|
|
|
|
break;
|
|
|
|
} else if ( message == winamp_msg ) {
|
|
// Internal Message ...
|
|
|
|
m->message = e->xclient.data.l[0];
|
|
m->wParam = e->xclient.data.l[1];
|
|
m->lParam = e->xclient.data.l[2];
|
|
break;
|
|
|
|
} else {
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LeaveNotify:
|
|
case EnterNotify:
|
|
m->message = WM_MOUSEMOVE;
|
|
m->lParam = (e->xcrossing.x & 0xffff) | (e->xcrossing.y << 16);
|
|
|
|
if ( ! (e->xcrossing.state & ( Button1Mask | Button2Mask | Button3Mask )) )
|
|
PostMessage( m->hwnd, WM_SETCURSOR, m->hwnd, 0 );
|
|
break;
|
|
|
|
case FocusIn:
|
|
m->message = WM_SETFOCUS;
|
|
break;
|
|
|
|
case FocusOut:
|
|
m->message = WM_KILLFOCUS;
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static HWND activeWindow;
|
|
|
|
HWND GetActiveWindow() {
|
|
return activeWindow;
|
|
}
|
|
|
|
int IntersectRect( RECT *out, const RECT *i1, const RECT *i2 ) {
|
|
return Std::rectIntersect(i1, i2, out);
|
|
}
|
|
|
|
void TranslateMessage( MSG *m ) {
|
|
if ( m->message != WM_CHAR && m->message != WM_KEYDOWN &&
|
|
m->message != WM_KEYUP )
|
|
return;
|
|
|
|
int index = !!( Std::keyDown( VK_SHIFT ));
|
|
|
|
m->wParam = XKeycodeToKeysym( Linux::getDisplay(), m->wParam, index );
|
|
}
|
|
|
|
void PostMessage( HWND win, UINT msg, WPARAM wParam, LPARAM lParam ) {
|
|
XEvent e;
|
|
|
|
LoadAtoms();
|
|
|
|
e.type = ClientMessage;
|
|
e.xclient.window = win;
|
|
e.xclient.message_type = winamp_msg;
|
|
e.xclient.format = 32;
|
|
e.xclient.data.l[0] = msg;
|
|
e.xclient.data.l[1] = wParam;
|
|
e.xclient.data.l[2] = lParam;
|
|
|
|
XSendEvent( Linux::getDisplay(), win, FALSE, NoEventMask, &e );
|
|
}
|
|
|
|
void PostQuitMessage( int i ) {
|
|
PostMessage( None, WM_QUIT, i, 0 );
|
|
}
|
|
|
|
#endif // wnd
|
|
|
|
#if defined(WASABI_API_TIMER) | defined(WASABI_API_WND)
|
|
|
|
struct TimerElem {
|
|
HWND win;
|
|
int id;
|
|
int nexttime;
|
|
int delta;
|
|
TIMERPROC tproc;
|
|
|
|
TimerElem( HWND _win, int _id, int ms, TIMERPROC _tproc ) {
|
|
win = _win;
|
|
id = _id;
|
|
delta = ms;
|
|
tproc = _tproc;
|
|
nexttime = Std::getTickCount() + delta;
|
|
}
|
|
};
|
|
|
|
int timer_id = 0;
|
|
CriticalSection timer_cs;
|
|
PtrList<TimerElem> timer_elems;
|
|
|
|
int SetTimer( HWND win, int id, int ms, TIMERPROC tproc ) {
|
|
KillTimer(win, id);
|
|
|
|
if ( win == (HWND)0 ) {
|
|
id = timer_id++;
|
|
}
|
|
|
|
TimerElem *te = new TimerElem( win, id, ms, tproc );
|
|
timer_cs.enter();
|
|
timer_elems.addItem( te, PTRLIST_POS_LAST );
|
|
timer_cs.leave();
|
|
|
|
return id;
|
|
}
|
|
|
|
void KillTimer( HWND win, int id ) {
|
|
timer_cs.enter();
|
|
for( int i = 0; i < timer_elems.getNumItems(); i++ )
|
|
if ( timer_elems[i]->win == win && timer_elems[i]->id == id ) {
|
|
delete timer_elems[i];
|
|
timer_elems.delByPos( i );
|
|
i--;
|
|
}
|
|
timer_cs.leave();
|
|
}
|
|
|
|
CriticalSection send_cs;
|
|
MSG *send_msg;
|
|
int sending = 0;
|
|
int send_ret;
|
|
pthread_t message_thread = (pthread_t)-1;
|
|
|
|
int _GetMessage( MSG *m, HWND, UINT, UINT, int block=1) {
|
|
MEMSET( m, 0, sizeof( MSG ) );
|
|
|
|
message_thread = pthread_self();
|
|
|
|
#ifdef WASABI_COMPILE_WND
|
|
XEvent e;
|
|
#endif // wnd
|
|
int curtime;
|
|
int done = 0;
|
|
int first = 1;
|
|
static wa_msgbuf ipcm;
|
|
static int qid = -1;
|
|
int size;
|
|
|
|
if ( qid == -1 ) { qid = WASABI_API_LINUX->linux_getIPCId(); }
|
|
|
|
if ( sending ) {
|
|
*m = *send_msg;
|
|
done = 1;
|
|
}
|
|
|
|
while( !done && (block || first)) {
|
|
if ( qid != -1 ) {
|
|
if ( (size = msgrcv( qid, &ipcm, IPC_MSGMAX , 0, IPC_NOWAIT )) != -1 ) {
|
|
m->hwnd = None;
|
|
m->message = WM_WA_IPC;
|
|
m->wParam = (WPARAM)&ipcm;
|
|
break;
|
|
}
|
|
}
|
|
|
|
curtime = GetTickCount();
|
|
|
|
timer_cs.enter();
|
|
for( int i = 0; i < timer_elems.getNumItems(); i++ ) {
|
|
if ( timer_elems[i]->nexttime < curtime ) {
|
|
if (block)
|
|
while( timer_elems[i]->nexttime < curtime )
|
|
timer_elems[i]->nexttime += timer_elems[i]->delta;
|
|
|
|
m->hwnd = timer_elems[i]->win;
|
|
m->message = WM_TIMER;
|
|
m->wParam = (WPARAM)timer_elems[i]->id;
|
|
m->lParam = (LPARAM)timer_elems[i]->tproc;
|
|
|
|
done = 1;
|
|
}
|
|
}
|
|
timer_cs.leave();
|
|
|
|
if ( !done && ! first )
|
|
Sleep( 1 );
|
|
else
|
|
first = 0;
|
|
|
|
#ifdef WASABI_API_WND
|
|
if ( !done && XPending( Linux::getDisplay() ) ) {
|
|
int n = XEventsQueued( Linux::getDisplay(), QueuedAlready );
|
|
|
|
for ( int i = 0; !done && i < n; i++ ) {
|
|
XNextEvent( Linux::getDisplay(), &e );
|
|
if ( Linux::convertEvent( m, &e ) )
|
|
done = 1;
|
|
}
|
|
if ( done )
|
|
break;
|
|
}
|
|
#endif // wnd
|
|
}
|
|
|
|
#ifdef WASABI_API_WND
|
|
activeWindow = m->hwnd;
|
|
#endif // wnd
|
|
|
|
return m->message != WM_QUIT;
|
|
}
|
|
|
|
int GetMessage( MSG *m, HWND w, UINT f, UINT l) {
|
|
return _GetMessage(m, w, f, l, 1);
|
|
}
|
|
|
|
// on linux, we don't really simply peek when PM_NOREMOVE is used,
|
|
// we just don't block, which is the only thing we want to accomplish here
|
|
int PeekMessage( MSG *m, HWND w, UINT f, UINT l, UINT remove) {
|
|
if (remove == PM_NOREMOVE) return _GetMessage(m, w, f, l, 0);
|
|
else _GetMessage(m, w, f, l, 1);
|
|
}
|
|
|
|
|
|
int DispatchMessage( MSG *m ) {
|
|
if ( m->message == WM_TIMER && m->hwnd == None ) {
|
|
TIMERPROC tproc = (TIMERPROC)m->lParam;
|
|
tproc( m->hwnd, m->message, m->wParam, 0 );
|
|
return 1;
|
|
}
|
|
|
|
int ret = 0;
|
|
|
|
#ifdef WASABI_COMPILE_WND
|
|
api_window *rootwnd = (api_window *)GetWindowLong( m->hwnd, GWL_USERDATA );
|
|
|
|
if ( rootwnd ) {
|
|
ret = rootwnd->wndProc( m->hwnd, m->message, m->wParam, m->lParam );
|
|
rootwnd->performBatchProcesses();
|
|
}
|
|
#endif // wnd
|
|
|
|
if ( sending ) {
|
|
send_ret = ret;
|
|
sending = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int SendMessage( HWND win, UINT msg, WPARAM wParam, LPARAM lParam ) {
|
|
MSG m;
|
|
m.hwnd = win;
|
|
m.message = msg;
|
|
m.wParam = wParam;
|
|
m.lParam = lParam;
|
|
|
|
int ret;
|
|
|
|
if ( pthread_equal( message_thread, pthread_self() ) ) {
|
|
return DispatchMessage( &m );
|
|
|
|
} else {
|
|
send_cs.enter();
|
|
sending = 1;
|
|
send_msg = &m;
|
|
while( sending ) { Sleep( 1 ); }
|
|
ret = send_ret;
|
|
send_cs.leave();
|
|
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
#endif // timer | wnd
|
|
|
|
int MulDiv( int m1, int m2, int d ) {
|
|
__asm__ volatile (
|
|
"mov %0, %%eax\n"
|
|
"mov %1, %%ebx\n"
|
|
"mov %2, %%ecx\n"
|
|
"mul %%ebx\n"
|
|
"div %%ecx\n"
|
|
: : "m" (m1), "m" (m2), "m" (d)
|
|
: "%eax", "%ebx", "%ecx", "%edx" );
|
|
}
|
|
|
|
void ExitProcess( int ret ) {
|
|
exit( ret );
|
|
}
|
|
|
|
#ifdef WASABI_COMPILE_WND
|
|
|
|
void Linux::initContextData( HWND h ) {
|
|
int *data;
|
|
XPointer xp;
|
|
|
|
ASSERT( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ));
|
|
|
|
data = (int *)MALLOC( GWL_ENUM_SIZE * sizeof( int ) );
|
|
|
|
data[GWL_HWND] = h;
|
|
|
|
XSaveContext( Linux::getDisplay(), h, Linux::getContext(), (char *)data );
|
|
}
|
|
|
|
void Linux::nukeContextData( HWND h ) {
|
|
int *data;
|
|
XPointer xp;
|
|
|
|
if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
|
|
return;
|
|
|
|
data = (int *)xp;
|
|
|
|
ASSERT( data[GWL_HWND] == h );
|
|
|
|
if ( data[GWL_INVALIDREGION] ) {
|
|
XDestroyRegion( (HRGN)data[GWL_INVALIDREGION] );
|
|
}
|
|
|
|
XDeleteContext( Linux::getDisplay(), h, Linux::getContext() );
|
|
|
|
FREE( data );
|
|
}
|
|
|
|
void SetWindowLong( HWND h, contextdata type, LONG value ) {
|
|
XPointer data;
|
|
|
|
if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &data ) )
|
|
return;
|
|
|
|
ASSERT( ((int *)data)[GWL_HWND] == h );
|
|
|
|
((int*)data)[type] = value;
|
|
}
|
|
|
|
LONG GetWindowLong( HWND h, contextdata type ) {
|
|
XPointer data;
|
|
|
|
if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &data ) )
|
|
return 0;
|
|
|
|
ASSERT( ((int *)data)[GWL_HWND] == h );
|
|
|
|
return ((int*)data)[type];
|
|
}
|
|
|
|
void MoveWindowRect( HWND h, int x, int y ) {
|
|
XPointer xp;
|
|
int *data;
|
|
|
|
if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
|
|
return;
|
|
|
|
data = (int *)xp;
|
|
|
|
ASSERT( data[GWL_HWND] == h );
|
|
|
|
data[GWL_RECT_RIGHT] -= data[GWL_RECT_LEFT] - x;
|
|
data[GWL_RECT_BOTTOM] -= data[GWL_RECT_TOP] - y;
|
|
data[GWL_RECT_LEFT] = x;
|
|
data[GWL_RECT_TOP] = y;
|
|
}
|
|
|
|
void SetWindowRect( HWND h, RECT *r ) {
|
|
int *data;
|
|
XPointer xp;
|
|
|
|
if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
|
|
return;
|
|
|
|
data = (int *)xp;
|
|
|
|
ASSERT( data[GWL_HWND] == h );
|
|
|
|
data[GWL_RECT_LEFT] = r->left;
|
|
data[GWL_RECT_TOP] = r->top;
|
|
data[GWL_RECT_RIGHT] = r->right;
|
|
data[GWL_RECT_BOTTOM] = r->bottom;
|
|
}
|
|
|
|
int GetWindowRect( HWND h, RECT *r ) {
|
|
int *data;
|
|
XPointer xp;
|
|
|
|
if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
|
|
return 0;
|
|
|
|
data = (int *)xp;
|
|
|
|
ASSERT( data[GWL_HWND] == h );
|
|
|
|
r->left = data[GWL_RECT_LEFT];
|
|
r->top = data[GWL_RECT_TOP];
|
|
r->right = data[GWL_RECT_RIGHT];
|
|
r->bottom = data[GWL_RECT_BOTTOM];
|
|
|
|
POINT offset = { 0, 0};
|
|
while( (h = data[GWL_PARENT]) != Linux::RootWin() ) {
|
|
if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
|
|
return 0;
|
|
|
|
data = (int *)xp;
|
|
|
|
ASSERT( data[GWL_HWND] == h );
|
|
|
|
offset.x += data[GWL_RECT_LEFT];
|
|
offset.y += data[GWL_RECT_TOP];
|
|
}
|
|
r->left += offset.x;
|
|
r->top += offset.y;
|
|
r->right += offset.x;
|
|
r->bottom += offset.y;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int GetUpdateRect( HWND h, RECT *ret, BOOL ) {
|
|
HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
|
|
if ( ! invalid || XEmptyRegion( invalid ) )
|
|
return 0;
|
|
|
|
XRectangle xr;
|
|
XClipBox( invalid, &xr );
|
|
ret->left = xr.x;
|
|
ret->top = xr.y;
|
|
ret->right = xr.x + xr.width;
|
|
ret->bottom = xr.y + xr.height;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void GetUpdateRgn( HWND h, HRGN r, BOOL ) {
|
|
XSubtractRegion( r, r, r );
|
|
|
|
HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
|
|
if ( ! invalid ) return;
|
|
|
|
|
|
XUnionRegion( r, invalid, r );
|
|
|
|
XRectangle xr;
|
|
|
|
RECT rct;
|
|
GetWindowRect( h, &rct );
|
|
xr.x = 0;
|
|
xr.y = 0;
|
|
xr.width = rct.right - rct.left;
|
|
xr.height = rct.bottom - rct.top;
|
|
|
|
HRGN tmp = XCreateRegion();
|
|
|
|
XUnionRectWithRegion( &xr, tmp, tmp );
|
|
XIntersectRegion( r, tmp, r );
|
|
XDestroyRegion( tmp );
|
|
}
|
|
|
|
void InvalidateRect( HWND h, const RECT *r, BOOL ) {
|
|
HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
|
|
if ( ! invalid ) {
|
|
invalid = XCreateRegion();
|
|
SetWindowLong( h, GWL_INVALIDREGION, (LONG)invalid );
|
|
}
|
|
|
|
XRectangle xr;
|
|
if ( r == NULL ) {
|
|
RECT rct;
|
|
GetWindowRect( h, &rct );
|
|
xr.x = 0;
|
|
xr.y = 0;
|
|
xr.width = rct.right - rct.left;
|
|
xr.height = rct.bottom - rct.top;
|
|
} else {
|
|
xr.x = r->left;
|
|
xr.y = r->top;
|
|
xr.width = r->right - r->left;
|
|
xr.height = r->bottom - r->top;
|
|
}
|
|
|
|
XUnionRectWithRegion( &xr, invalid, invalid );
|
|
|
|
PostMessage( h, WM_PAINT, 0, 0 );
|
|
}
|
|
|
|
void InvalidateRgn( HWND h, HRGN r, BOOL ) {
|
|
HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
|
|
|
|
if ( ! invalid ) {
|
|
invalid = XCreateRegion();
|
|
SetWindowLong( h, GWL_INVALIDREGION, (LONG)invalid );
|
|
}
|
|
|
|
ASSERT( r != invalid );
|
|
XUnionRegion( invalid, r, invalid );
|
|
|
|
PostMessage( h, WM_PAINT, 0, 0 );
|
|
}
|
|
|
|
void ValidateRect( HWND h, const RECT *r ) {
|
|
HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
|
|
if ( ! invalid ) return;
|
|
|
|
XRectangle xr;
|
|
if ( r == NULL ) {
|
|
XDestroyRegion( invalid );
|
|
SetWindowLong( h, GWL_INVALIDREGION, 0 );
|
|
return;
|
|
}
|
|
|
|
xr.x = r->left;
|
|
xr.y = r->top;
|
|
xr.width = r->right - r->left;
|
|
xr.height = r->bottom - r->top;
|
|
|
|
HRGN tmp = XCreateRegion();
|
|
XUnionRectWithRegion( &xr, tmp, tmp );
|
|
XSubtractRegion( invalid, tmp, invalid );
|
|
XDestroyRegion( tmp );
|
|
}
|
|
|
|
void ValidateRgn( HWND h, HRGN r ) {
|
|
HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
|
|
if ( ! invalid ) return;
|
|
|
|
ASSERT( r != invalid );
|
|
XSubtractRegion( invalid, r, invalid );
|
|
}
|
|
#endif // wnd
|
|
|
|
int SubtractRect( RECT *out, RECT *in1, RECT *in2 ) {
|
|
int ret;
|
|
if ( in1->left >= in2->left && in1->right <= in2->right ) {
|
|
out->left = in1->left; out->right = in1->right;
|
|
|
|
if ( in1->top >= in2->top && in2->bottom >= in2->top && in2->bottom <= in2->bottom ) {
|
|
out->top = in1->bottom; out->bottom = in2->bottom;
|
|
|
|
ret = 1;
|
|
} else if ( in1->top <= in2->top && in1->bottom >= in2->top && in1->bottom <= in2->bottom ) {
|
|
out->top = in1->top; out->bottom = in2->top;
|
|
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
|
|
} else if ( in1->top >= in2->top && in1->bottom <= in2->bottom ) {
|
|
out->top = in1->top; out->bottom = in1->bottom;
|
|
|
|
if ( in1->left >= in2->left && in2->right >= in2->left && in2->right <= in2->right ) {
|
|
out->left = in1->right; out->right = in2->right;
|
|
|
|
ret = 1;
|
|
} else if ( in1->left <= in2->left && in1->right >= in2->left && in1->right <= in2->right ) {
|
|
out->left = in1->left; out->right = in2->left;
|
|
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
|
|
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int EqualRect( RECT *a, RECT *b ) {
|
|
return ( a->top == b->top && a->bottom == b->bottom &&
|
|
a->left == b->left && a->right == b->right );
|
|
}
|
|
|
|
#ifdef WASABI_COMPILE_WND
|
|
|
|
HWND WindowFromPoint( POINT p ) {
|
|
int x, y;
|
|
Window child;
|
|
|
|
XTranslateCoordinates( Linux::getDisplay(), Linux::RootWin(), Linux::RootWin(), p.x, p.y, &x, &y, &child );
|
|
return child;
|
|
}
|
|
#endif // wnd
|
|
|
|
void CopyFile( const char *f1, const char *f2, BOOL b ) {
|
|
COPYFILE( f1, f2 );
|
|
}
|
|
|
|
DWORD GetModuleFileName(void *pid, const char *filename, int bufsize) {
|
|
char procbuffer[512];
|
|
sprintf(procbuffer, "/proc/%d/exe", (int)pid);
|
|
return readlink(procbuffer, (char *)filename, bufsize);
|
|
}
|
|
|
|
const char *CharPrev(const char *lpszStart, const char *lpszCurrent) {
|
|
if (lpszCurrent-1 >= lpszStart) return lpszCurrent-1;
|
|
return lpszStart;
|
|
}
|
|
|
|
#endif
|