1
0

linux.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. #include <precomp.h>
  2. #include <api/api.h>
  3. #include <api/linux/api_linux.h>
  4. #include <bfc/ptrlist.h>
  5. #include <bfc/string/string.h>
  6. #include <bfc/critsec.h>
  7. #include <bfc/thread.h>
  8. #include <api/application/ipcs.h>
  9. #ifdef WASABI_COMPILE_WND
  10. Display *Linux::display = NULL;
  11. int linux_atoms_loaded = 0;
  12. Atom winamp_msg;
  13. Atom dnd_enter, dnd_position, dnd_status, dnd_leave, dnd_drop, dnd_finished;
  14. Atom dnd_selection, dnd_wa3drop, dnd_private, dnd_typelist;
  15. Atom dnd_urilist, dnd_textplain, dnd_mozurl;
  16. #endif
  17. #ifndef _NOSTUDIO
  18. #ifdef WASABI_COMPILE_WND
  19. void LoadAtoms() {
  20. if ( !linux_atoms_loaded ) {
  21. linux_atoms_loaded = 1;
  22. winamp_msg = XInternAtom( Linux::getDisplay(), "Winamp3", False );
  23. dnd_wa3drop = XInternAtom( Linux::getDisplay(), "Winamp3_drop", False );
  24. dnd_enter = XInternAtom( Linux::getDisplay(), "XdndEnter", True );
  25. dnd_position = XInternAtom( Linux::getDisplay(), "XdndPosition", True );
  26. dnd_status = XInternAtom( Linux::getDisplay(), "XdndStatus", True );
  27. dnd_leave = XInternAtom( Linux::getDisplay(), "XdndLeave", True );
  28. dnd_drop = XInternAtom( Linux::getDisplay(), "XdndDrop", True );
  29. dnd_finished = XInternAtom( Linux::getDisplay(), "XdndFinished", True );
  30. dnd_selection = XInternAtom( Linux::getDisplay(), "XdndSelection", True );
  31. dnd_private = XInternAtom( Linux::getDisplay(), "XdndActionPrivate", True );
  32. dnd_typelist = XInternAtom( Linux::getDisplay(), "XdndTypeList", True );
  33. dnd_urilist = XInternAtom( Linux::getDisplay(), "text/uri-list", True );
  34. dnd_textplain = XInternAtom( Linux::getDisplay(), "text/plain", True );
  35. dnd_mozurl = XInternAtom( Linux::getDisplay(), "text/x-moz-url", True );
  36. }
  37. }
  38. #endif
  39. #endif
  40. void OutputDebugString( const char *s ) {
  41. #ifdef _DEBUG
  42. fprintf( stderr, "%s", s );
  43. #endif
  44. char *file = getenv( "WASABI_LOG_FILE" );
  45. if ( file ) {
  46. if ( !STRCMP( file, "-" ) ) {
  47. fprintf( stdout, "%s", s );
  48. } else {
  49. FILE *f = fopen( file, "a" );
  50. if ( f ) {
  51. fprintf( f, "%s", s );
  52. fclose( f );
  53. }
  54. }
  55. }
  56. }
  57. DWORD GetTickCount() {
  58. static int starttime = -1;
  59. if ( starttime == -1 )
  60. starttime = time( NULL );
  61. struct timeb tb;
  62. ftime( &tb );
  63. tb.time -= starttime;
  64. return tb.time * 1000 + tb.millitm;
  65. }
  66. void Sleep( int ms ) {
  67. if ( ms != 0 ) {
  68. struct timespec ts = { 0, 0 };
  69. ts.tv_sec = ms / 1000;
  70. ts.tv_nsec = (ms % 1000) * 1000000;
  71. nanosleep( &ts, NULL);
  72. // usleep(ms * 1000);
  73. }
  74. }
  75. #ifndef _NOSTUDIO
  76. #ifdef WASABI_COMPILE_WND
  77. Display *Linux::getDisplay() {
  78. if ( ! display )
  79. display = WASABI_API_LINUX->linux_getDisplay();
  80. return display;
  81. }
  82. XContext Linux::getContext() {
  83. static XContext context = 0;
  84. if ( context == 0 )
  85. context = WASABI_API_LINUX->linux_getContext();
  86. return context;
  87. }
  88. int Linux::getScreenNum() { return DefaultScreen( getDisplay() ); }
  89. Window Linux::RootWin() {
  90. return RootWindow( getDisplay(), getScreenNum() );
  91. }
  92. Visual *Linux::DefaultVis() {
  93. return DefaultVisual( getDisplay(), getScreenNum() );
  94. }
  95. void Linux::setCursor( HWND h, int cursor ) {
  96. Cursor c = XCreateFontCursor( Linux::getDisplay(), cursor );
  97. if ( cursor == None )
  98. XUndefineCursor( Linux::getDisplay(), h );
  99. else
  100. XDefineCursor( Linux::getDisplay(), h, c );
  101. XFreeCursor( Linux::getDisplay(), c );
  102. }
  103. int Linux::convertEvent( MSG *m, XEvent *e ) {
  104. m->hwnd = e->xany.window;
  105. if ( m->hwnd ) {
  106. api_window *rw =(api_window *)GetWindowLong( m->hwnd, GWL_USERDATA );
  107. if ( !rw ) {
  108. // This is to fix messages for dead windows...
  109. return 0;
  110. }
  111. }
  112. switch ( e->type ) {
  113. case ButtonPress:
  114. switch( e->xbutton.button ) {
  115. case 1:
  116. m->message = WM_LBUTTONDOWN;
  117. m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
  118. break;
  119. case 2:
  120. case 3:
  121. m->message = WM_RBUTTONDOWN;
  122. m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
  123. break;
  124. case 4:
  125. m->message = WM_MOUSEWHEEL;
  126. m->wParam = 120 << 16 | 0; // 1 tick, no modifiers
  127. m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
  128. break;
  129. case 5:
  130. m->message = WM_MOUSEWHEEL;
  131. m->wParam = (-120) << 16 | 0; // 1 tick, no modifiers
  132. m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
  133. break;
  134. }
  135. break;
  136. case ButtonRelease:
  137. switch( e->xbutton.button ) {
  138. case 1:
  139. m->message = WM_LBUTTONUP;
  140. m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
  141. break;
  142. case 2:
  143. case 3:
  144. m->message = WM_RBUTTONUP;
  145. m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
  146. break;
  147. }
  148. break;
  149. case MotionNotify:
  150. {
  151. m->message = WM_MOUSEMOVE;
  152. do {
  153. // Spin...
  154. } while( XCheckTypedWindowEvent( Linux::getDisplay(), m->hwnd, MotionNotify, e ) );
  155. RECT r;
  156. POINT offset = {0, 0};
  157. HWND hwnd = m->hwnd;
  158. GetWindowRect( hwnd, &r );
  159. m->lParam = ((e->xmotion.x_root - r.left) & 0xffff) |
  160. ((e->xmotion.y_root - r.top) << 16);
  161. if ( ! (e->xmotion.state & ( Button1Mask | Button2Mask | Button3Mask )) )
  162. PostMessage( m->hwnd, WM_SETCURSOR, m->hwnd, 0 );
  163. }
  164. break;
  165. case KeyPress:
  166. m->message = WM_KEYDOWN;
  167. m->wParam = e->xkey.keycode;
  168. break;
  169. case KeyRelease:
  170. m->message = WM_KEYUP;
  171. m->wParam = e->xkey.keycode;
  172. break;
  173. case Expose:
  174. {
  175. RECT r;
  176. m->message = WM_PAINT;
  177. do {
  178. r.left = e->xexpose.x;
  179. r.top = e->xexpose.y;
  180. r.right = r.left + e->xexpose.width;
  181. r.bottom = r.top + e->xexpose.height;
  182. InvalidateRect( m->hwnd, &r, FALSE );
  183. } while( XCheckTypedWindowEvent( Linux::getDisplay(), m->hwnd, Expose, e ) );
  184. }
  185. break;
  186. case ClientMessage: {
  187. static int coord = -1;
  188. static Atom supported = None;
  189. XClientMessageEvent cme;
  190. LoadAtoms();
  191. int message = e->xclient.message_type;
  192. if ( message == dnd_enter ) {
  193. if ( e->xclient.data.l[1] & 1 ) {
  194. Atom actual;
  195. int format;
  196. long unsigned int nitems, bytes;
  197. unsigned char *data = NULL;
  198. XGetWindowProperty( Linux::getDisplay(), e->xclient.data.l[0],
  199. dnd_typelist, 0, 65536, True, XA_ATOM,
  200. &actual, &format, &nitems, &bytes, &data );
  201. Atom *atomdata = (Atom *)data;
  202. supported = None;
  203. for( int i = 0; i < nitems; i++ ) {
  204. if ( atomdata[i] == dnd_urilist ) {
  205. supported = dnd_urilist;
  206. }
  207. }
  208. if ( supported == None ) {
  209. for( int i = 0; i < nitems; i++ ) {
  210. if ( atomdata[i] == dnd_textplain ) {
  211. OutputDebugString( "text/plain found\n" );
  212. supported = dnd_textplain;
  213. }
  214. }
  215. }
  216. if ( supported == None ) {
  217. for( int i = 0; i < nitems; i++ ) {
  218. if ( atomdata[i] == dnd_mozurl ) {
  219. supported = dnd_mozurl;
  220. }
  221. }
  222. }
  223. XFree( data );
  224. } else {
  225. if ( e->xclient.data.l[2] == dnd_urilist ||
  226. e->xclient.data.l[3] == dnd_urilist ||
  227. e->xclient.data.l[4] == dnd_urilist ) {
  228. supported = dnd_urilist;
  229. } else if ( e->xclient.data.l[2] == dnd_mozurl ||
  230. e->xclient.data.l[3] == dnd_mozurl ||
  231. e->xclient.data.l[4] == dnd_mozurl ) {
  232. supported = dnd_mozurl;
  233. }
  234. }
  235. // DnD Enter
  236. return 0;
  237. } else if ( message == dnd_position ) {
  238. // DnD Position Notify
  239. cme.type = ClientMessage;
  240. cme.message_type = dnd_status;
  241. cme.format = 32;
  242. cme.window = e->xclient.data.l[0];
  243. cme.data.l[0] = e->xclient.window;
  244. cme.data.l[1] = 1; // Can Accept
  245. cme.data.l[2] = cme.data.l[3] = 0; // Empty rectangle - give us moves
  246. cme.data.l[4] = dnd_private; // We're doing our own thing
  247. if ( coord == -1 && supported != None ) {
  248. XConvertSelection( Linux::getDisplay(), dnd_selection, supported,
  249. dnd_wa3drop, cme.window, CurrentTime );
  250. }
  251. coord = e->xclient.data.l[2];
  252. XSendEvent( Linux::getDisplay(), e->xclient.data.l[0], False,
  253. NoEventMask, (XEvent *)&cme );
  254. return 0;
  255. } else if ( message == dnd_leave ) {
  256. // DnD Leave
  257. coord = -1;
  258. supported = None;
  259. return 0;
  260. } else if ( message == dnd_drop ) {
  261. // DnD Drop
  262. Window win = e->xclient.data.l[0];
  263. cme.type = ClientMessage;
  264. cme.message_type = dnd_finished;
  265. cme.format = 32;
  266. cme.window = e->xclient.data.l[0];
  267. cme.data.l[0] = e->xclient.window;
  268. cme.data.l[1] = cme.data.l[2] = cme.data.l[3] = cme.data.l[4] = 0;
  269. XSendEvent( Linux::getDisplay(), e->xclient.data.l[0], False,
  270. NoEventMask, (XEvent *)&cme );
  271. if ( supported != None ) {
  272. Atom actual;
  273. int format;
  274. long unsigned int nitems, bytes;
  275. unsigned char *data = NULL;
  276. XGetWindowProperty( Linux::getDisplay(), cme.window, dnd_wa3drop,
  277. 0, 65536, True, supported, &actual,
  278. &format, &nitems, &bytes,
  279. &data );
  280. OutputDebugString( StringPrintf( "Drop data (%d):\n%s\n", nitems, data ) );
  281. m->message = WM_DROPFILES;
  282. m->wParam = coord;
  283. m->lParam = (LPARAM)data;
  284. coord = -1;
  285. supported = None;
  286. } else {
  287. coord = -1;
  288. supported = None;
  289. return 0;
  290. }
  291. break;
  292. } else if ( message == winamp_msg ) {
  293. // Internal Message ...
  294. m->message = e->xclient.data.l[0];
  295. m->wParam = e->xclient.data.l[1];
  296. m->lParam = e->xclient.data.l[2];
  297. break;
  298. } else {
  299. return 0;
  300. }
  301. break;
  302. }
  303. case LeaveNotify:
  304. case EnterNotify:
  305. m->message = WM_MOUSEMOVE;
  306. m->lParam = (e->xcrossing.x & 0xffff) | (e->xcrossing.y << 16);
  307. if ( ! (e->xcrossing.state & ( Button1Mask | Button2Mask | Button3Mask )) )
  308. PostMessage( m->hwnd, WM_SETCURSOR, m->hwnd, 0 );
  309. break;
  310. case FocusIn:
  311. m->message = WM_SETFOCUS;
  312. break;
  313. case FocusOut:
  314. m->message = WM_KILLFOCUS;
  315. break;
  316. default:
  317. return 0;
  318. }
  319. return 1;
  320. }
  321. static HWND activeWindow;
  322. HWND GetActiveWindow() {
  323. return activeWindow;
  324. }
  325. int IntersectRect( RECT *out, const RECT *i1, const RECT *i2 ) {
  326. return Std::rectIntersect(i1, i2, out);
  327. }
  328. void TranslateMessage( MSG *m ) {
  329. if ( m->message != WM_CHAR && m->message != WM_KEYDOWN &&
  330. m->message != WM_KEYUP )
  331. return;
  332. int index = !!( Std::keyDown( VK_SHIFT ));
  333. m->wParam = XKeycodeToKeysym( Linux::getDisplay(), m->wParam, index );
  334. }
  335. void PostMessage( HWND win, UINT msg, WPARAM wParam, LPARAM lParam ) {
  336. XEvent e;
  337. LoadAtoms();
  338. e.type = ClientMessage;
  339. e.xclient.window = win;
  340. e.xclient.message_type = winamp_msg;
  341. e.xclient.format = 32;
  342. e.xclient.data.l[0] = msg;
  343. e.xclient.data.l[1] = wParam;
  344. e.xclient.data.l[2] = lParam;
  345. XSendEvent( Linux::getDisplay(), win, FALSE, NoEventMask, &e );
  346. }
  347. void PostQuitMessage( int i ) {
  348. PostMessage( None, WM_QUIT, i, 0 );
  349. }
  350. #endif // wnd
  351. #if defined(WASABI_API_TIMER) | defined(WASABI_API_WND)
  352. struct TimerElem {
  353. HWND win;
  354. int id;
  355. int nexttime;
  356. int delta;
  357. TIMERPROC tproc;
  358. TimerElem( HWND _win, int _id, int ms, TIMERPROC _tproc ) {
  359. win = _win;
  360. id = _id;
  361. delta = ms;
  362. tproc = _tproc;
  363. nexttime = Std::getTickCount() + delta;
  364. }
  365. };
  366. int timer_id = 0;
  367. CriticalSection timer_cs;
  368. PtrList<TimerElem> timer_elems;
  369. int SetTimer( HWND win, int id, int ms, TIMERPROC tproc ) {
  370. KillTimer(win, id);
  371. if ( win == (HWND)0 ) {
  372. id = timer_id++;
  373. }
  374. TimerElem *te = new TimerElem( win, id, ms, tproc );
  375. timer_cs.enter();
  376. timer_elems.addItem( te, PTRLIST_POS_LAST );
  377. timer_cs.leave();
  378. return id;
  379. }
  380. void KillTimer( HWND win, int id ) {
  381. timer_cs.enter();
  382. for( int i = 0; i < timer_elems.getNumItems(); i++ )
  383. if ( timer_elems[i]->win == win && timer_elems[i]->id == id ) {
  384. delete timer_elems[i];
  385. timer_elems.delByPos( i );
  386. i--;
  387. }
  388. timer_cs.leave();
  389. }
  390. CriticalSection send_cs;
  391. MSG *send_msg;
  392. int sending = 0;
  393. int send_ret;
  394. pthread_t message_thread = (pthread_t)-1;
  395. int _GetMessage( MSG *m, HWND, UINT, UINT, int block=1) {
  396. MEMSET( m, 0, sizeof( MSG ) );
  397. message_thread = pthread_self();
  398. #ifdef WASABI_COMPILE_WND
  399. XEvent e;
  400. #endif // wnd
  401. int curtime;
  402. int done = 0;
  403. int first = 1;
  404. static wa_msgbuf ipcm;
  405. static int qid = -1;
  406. int size;
  407. if ( qid == -1 ) { qid = WASABI_API_LINUX->linux_getIPCId(); }
  408. if ( sending ) {
  409. *m = *send_msg;
  410. done = 1;
  411. }
  412. while( !done && (block || first)) {
  413. if ( qid != -1 ) {
  414. if ( (size = msgrcv( qid, &ipcm, IPC_MSGMAX , 0, IPC_NOWAIT )) != -1 ) {
  415. m->hwnd = None;
  416. m->message = WM_WA_IPC;
  417. m->wParam = (WPARAM)&ipcm;
  418. break;
  419. }
  420. }
  421. curtime = GetTickCount();
  422. timer_cs.enter();
  423. for( int i = 0; i < timer_elems.getNumItems(); i++ ) {
  424. if ( timer_elems[i]->nexttime < curtime ) {
  425. if (block)
  426. while( timer_elems[i]->nexttime < curtime )
  427. timer_elems[i]->nexttime += timer_elems[i]->delta;
  428. m->hwnd = timer_elems[i]->win;
  429. m->message = WM_TIMER;
  430. m->wParam = (WPARAM)timer_elems[i]->id;
  431. m->lParam = (LPARAM)timer_elems[i]->tproc;
  432. done = 1;
  433. }
  434. }
  435. timer_cs.leave();
  436. if ( !done && ! first )
  437. Sleep( 1 );
  438. else
  439. first = 0;
  440. #ifdef WASABI_API_WND
  441. if ( !done && XPending( Linux::getDisplay() ) ) {
  442. int n = XEventsQueued( Linux::getDisplay(), QueuedAlready );
  443. for ( int i = 0; !done && i < n; i++ ) {
  444. XNextEvent( Linux::getDisplay(), &e );
  445. if ( Linux::convertEvent( m, &e ) )
  446. done = 1;
  447. }
  448. if ( done )
  449. break;
  450. }
  451. #endif // wnd
  452. }
  453. #ifdef WASABI_API_WND
  454. activeWindow = m->hwnd;
  455. #endif // wnd
  456. return m->message != WM_QUIT;
  457. }
  458. int GetMessage( MSG *m, HWND w, UINT f, UINT l) {
  459. return _GetMessage(m, w, f, l, 1);
  460. }
  461. // on linux, we don't really simply peek when PM_NOREMOVE is used,
  462. // we just don't block, which is the only thing we want to accomplish here
  463. int PeekMessage( MSG *m, HWND w, UINT f, UINT l, UINT remove) {
  464. if (remove == PM_NOREMOVE) return _GetMessage(m, w, f, l, 0);
  465. else _GetMessage(m, w, f, l, 1);
  466. }
  467. int DispatchMessage( MSG *m ) {
  468. if ( m->message == WM_TIMER && m->hwnd == None ) {
  469. TIMERPROC tproc = (TIMERPROC)m->lParam;
  470. tproc( m->hwnd, m->message, m->wParam, 0 );
  471. return 1;
  472. }
  473. int ret = 0;
  474. #ifdef WASABI_COMPILE_WND
  475. api_window *rootwnd = (api_window *)GetWindowLong( m->hwnd, GWL_USERDATA );
  476. if ( rootwnd ) {
  477. ret = rootwnd->wndProc( m->hwnd, m->message, m->wParam, m->lParam );
  478. rootwnd->performBatchProcesses();
  479. }
  480. #endif // wnd
  481. if ( sending ) {
  482. send_ret = ret;
  483. sending = 0;
  484. }
  485. return ret;
  486. }
  487. int SendMessage( HWND win, UINT msg, WPARAM wParam, LPARAM lParam ) {
  488. MSG m;
  489. m.hwnd = win;
  490. m.message = msg;
  491. m.wParam = wParam;
  492. m.lParam = lParam;
  493. int ret;
  494. if ( pthread_equal( message_thread, pthread_self() ) ) {
  495. return DispatchMessage( &m );
  496. } else {
  497. send_cs.enter();
  498. sending = 1;
  499. send_msg = &m;
  500. while( sending ) { Sleep( 1 ); }
  501. ret = send_ret;
  502. send_cs.leave();
  503. return ret;
  504. }
  505. }
  506. #endif // timer | wnd
  507. int MulDiv( int m1, int m2, int d ) {
  508. __asm__ volatile (
  509. "mov %0, %%eax\n"
  510. "mov %1, %%ebx\n"
  511. "mov %2, %%ecx\n"
  512. "mul %%ebx\n"
  513. "div %%ecx\n"
  514. : : "m" (m1), "m" (m2), "m" (d)
  515. : "%eax", "%ebx", "%ecx", "%edx" );
  516. }
  517. void ExitProcess( int ret ) {
  518. exit( ret );
  519. }
  520. #ifdef WASABI_COMPILE_WND
  521. void Linux::initContextData( HWND h ) {
  522. int *data;
  523. XPointer xp;
  524. ASSERT( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ));
  525. data = (int *)MALLOC( GWL_ENUM_SIZE * sizeof( int ) );
  526. data[GWL_HWND] = h;
  527. XSaveContext( Linux::getDisplay(), h, Linux::getContext(), (char *)data );
  528. }
  529. void Linux::nukeContextData( HWND h ) {
  530. int *data;
  531. XPointer xp;
  532. if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
  533. return;
  534. data = (int *)xp;
  535. ASSERT( data[GWL_HWND] == h );
  536. if ( data[GWL_INVALIDREGION] ) {
  537. XDestroyRegion( (HRGN)data[GWL_INVALIDREGION] );
  538. }
  539. XDeleteContext( Linux::getDisplay(), h, Linux::getContext() );
  540. FREE( data );
  541. }
  542. void SetWindowLong( HWND h, contextdata type, LONG value ) {
  543. XPointer data;
  544. if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &data ) )
  545. return;
  546. ASSERT( ((int *)data)[GWL_HWND] == h );
  547. ((int*)data)[type] = value;
  548. }
  549. LONG GetWindowLong( HWND h, contextdata type ) {
  550. XPointer data;
  551. if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &data ) )
  552. return 0;
  553. ASSERT( ((int *)data)[GWL_HWND] == h );
  554. return ((int*)data)[type];
  555. }
  556. void MoveWindowRect( HWND h, int x, int y ) {
  557. XPointer xp;
  558. int *data;
  559. if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
  560. return;
  561. data = (int *)xp;
  562. ASSERT( data[GWL_HWND] == h );
  563. data[GWL_RECT_RIGHT] -= data[GWL_RECT_LEFT] - x;
  564. data[GWL_RECT_BOTTOM] -= data[GWL_RECT_TOP] - y;
  565. data[GWL_RECT_LEFT] = x;
  566. data[GWL_RECT_TOP] = y;
  567. }
  568. void SetWindowRect( HWND h, RECT *r ) {
  569. int *data;
  570. XPointer xp;
  571. if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
  572. return;
  573. data = (int *)xp;
  574. ASSERT( data[GWL_HWND] == h );
  575. data[GWL_RECT_LEFT] = r->left;
  576. data[GWL_RECT_TOP] = r->top;
  577. data[GWL_RECT_RIGHT] = r->right;
  578. data[GWL_RECT_BOTTOM] = r->bottom;
  579. }
  580. int GetWindowRect( HWND h, RECT *r ) {
  581. int *data;
  582. XPointer xp;
  583. if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
  584. return 0;
  585. data = (int *)xp;
  586. ASSERT( data[GWL_HWND] == h );
  587. r->left = data[GWL_RECT_LEFT];
  588. r->top = data[GWL_RECT_TOP];
  589. r->right = data[GWL_RECT_RIGHT];
  590. r->bottom = data[GWL_RECT_BOTTOM];
  591. POINT offset = { 0, 0};
  592. while( (h = data[GWL_PARENT]) != Linux::RootWin() ) {
  593. if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
  594. return 0;
  595. data = (int *)xp;
  596. ASSERT( data[GWL_HWND] == h );
  597. offset.x += data[GWL_RECT_LEFT];
  598. offset.y += data[GWL_RECT_TOP];
  599. }
  600. r->left += offset.x;
  601. r->top += offset.y;
  602. r->right += offset.x;
  603. r->bottom += offset.y;
  604. return 1;
  605. }
  606. int GetUpdateRect( HWND h, RECT *ret, BOOL ) {
  607. HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
  608. if ( ! invalid || XEmptyRegion( invalid ) )
  609. return 0;
  610. XRectangle xr;
  611. XClipBox( invalid, &xr );
  612. ret->left = xr.x;
  613. ret->top = xr.y;
  614. ret->right = xr.x + xr.width;
  615. ret->bottom = xr.y + xr.height;
  616. return 1;
  617. }
  618. void GetUpdateRgn( HWND h, HRGN r, BOOL ) {
  619. XSubtractRegion( r, r, r );
  620. HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
  621. if ( ! invalid ) return;
  622. XUnionRegion( r, invalid, r );
  623. XRectangle xr;
  624. RECT rct;
  625. GetWindowRect( h, &rct );
  626. xr.x = 0;
  627. xr.y = 0;
  628. xr.width = rct.right - rct.left;
  629. xr.height = rct.bottom - rct.top;
  630. HRGN tmp = XCreateRegion();
  631. XUnionRectWithRegion( &xr, tmp, tmp );
  632. XIntersectRegion( r, tmp, r );
  633. XDestroyRegion( tmp );
  634. }
  635. void InvalidateRect( HWND h, const RECT *r, BOOL ) {
  636. HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
  637. if ( ! invalid ) {
  638. invalid = XCreateRegion();
  639. SetWindowLong( h, GWL_INVALIDREGION, (LONG)invalid );
  640. }
  641. XRectangle xr;
  642. if ( r == NULL ) {
  643. RECT rct;
  644. GetWindowRect( h, &rct );
  645. xr.x = 0;
  646. xr.y = 0;
  647. xr.width = rct.right - rct.left;
  648. xr.height = rct.bottom - rct.top;
  649. } else {
  650. xr.x = r->left;
  651. xr.y = r->top;
  652. xr.width = r->right - r->left;
  653. xr.height = r->bottom - r->top;
  654. }
  655. XUnionRectWithRegion( &xr, invalid, invalid );
  656. PostMessage( h, WM_PAINT, 0, 0 );
  657. }
  658. void InvalidateRgn( HWND h, HRGN r, BOOL ) {
  659. HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
  660. if ( ! invalid ) {
  661. invalid = XCreateRegion();
  662. SetWindowLong( h, GWL_INVALIDREGION, (LONG)invalid );
  663. }
  664. ASSERT( r != invalid );
  665. XUnionRegion( invalid, r, invalid );
  666. PostMessage( h, WM_PAINT, 0, 0 );
  667. }
  668. void ValidateRect( HWND h, const RECT *r ) {
  669. HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
  670. if ( ! invalid ) return;
  671. XRectangle xr;
  672. if ( r == NULL ) {
  673. XDestroyRegion( invalid );
  674. SetWindowLong( h, GWL_INVALIDREGION, 0 );
  675. return;
  676. }
  677. xr.x = r->left;
  678. xr.y = r->top;
  679. xr.width = r->right - r->left;
  680. xr.height = r->bottom - r->top;
  681. HRGN tmp = XCreateRegion();
  682. XUnionRectWithRegion( &xr, tmp, tmp );
  683. XSubtractRegion( invalid, tmp, invalid );
  684. XDestroyRegion( tmp );
  685. }
  686. void ValidateRgn( HWND h, HRGN r ) {
  687. HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
  688. if ( ! invalid ) return;
  689. ASSERT( r != invalid );
  690. XSubtractRegion( invalid, r, invalid );
  691. }
  692. #endif // wnd
  693. int SubtractRect( RECT *out, RECT *in1, RECT *in2 ) {
  694. int ret;
  695. if ( in1->left >= in2->left && in1->right <= in2->right ) {
  696. out->left = in1->left; out->right = in1->right;
  697. if ( in1->top >= in2->top && in2->bottom >= in2->top && in2->bottom <= in2->bottom ) {
  698. out->top = in1->bottom; out->bottom = in2->bottom;
  699. ret = 1;
  700. } else if ( in1->top <= in2->top && in1->bottom >= in2->top && in1->bottom <= in2->bottom ) {
  701. out->top = in1->top; out->bottom = in2->top;
  702. ret = 1;
  703. } else {
  704. ret = 0;
  705. }
  706. } else if ( in1->top >= in2->top && in1->bottom <= in2->bottom ) {
  707. out->top = in1->top; out->bottom = in1->bottom;
  708. if ( in1->left >= in2->left && in2->right >= in2->left && in2->right <= in2->right ) {
  709. out->left = in1->right; out->right = in2->right;
  710. ret = 1;
  711. } else if ( in1->left <= in2->left && in1->right >= in2->left && in1->right <= in2->right ) {
  712. out->left = in1->left; out->right = in2->left;
  713. ret = 1;
  714. } else {
  715. ret = 0;
  716. }
  717. } else {
  718. ret = 0;
  719. }
  720. return ret;
  721. }
  722. int EqualRect( RECT *a, RECT *b ) {
  723. return ( a->top == b->top && a->bottom == b->bottom &&
  724. a->left == b->left && a->right == b->right );
  725. }
  726. #ifdef WASABI_COMPILE_WND
  727. HWND WindowFromPoint( POINT p ) {
  728. int x, y;
  729. Window child;
  730. XTranslateCoordinates( Linux::getDisplay(), Linux::RootWin(), Linux::RootWin(), p.x, p.y, &x, &y, &child );
  731. return child;
  732. }
  733. #endif // wnd
  734. void CopyFile( const char *f1, const char *f2, BOOL b ) {
  735. COPYFILE( f1, f2 );
  736. }
  737. DWORD GetModuleFileName(void *pid, const char *filename, int bufsize) {
  738. char procbuffer[512];
  739. sprintf(procbuffer, "/proc/%d/exe", (int)pid);
  740. return readlink(procbuffer, (char *)filename, bufsize);
  741. }
  742. const char *CharPrev(const char *lpszStart, const char *lpszCurrent) {
  743. if (lpszCurrent-1 >= lpszStart) return lpszCurrent-1;
  744. return lpszStart;
  745. }
  746. #endif