system.linux.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. #include "system.h"
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <signal.h>
  5. #include <pthread.h>
  6. #include <sys/time.h>
  7. #include <sys/sysinfo.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/wait.h>
  10. #include <X11/Xutil.h>
  11. #include <X11/extensions/xf86vmode.h>
  12. #define INTERLACE 0x010
  13. #define DBLSCAN 0x020
  14. typedef struct AsyncOp{
  15. struct AsyncOp *succ;
  16. BBSyncOp syncOp;
  17. BBObject *syncInfo;
  18. size_t asyncRet;
  19. BBAsyncOp asyncOp;
  20. int asyncInfo;
  21. }AsyncOp;
  22. static AsyncOp *asyncOps;
  23. static pthread_mutex_t asyncMutex=PTHREAD_MUTEX_INITIALIZER;
  24. static int async_pipe[2];
  25. static Display *x_display;
  26. static int x_fd;
  27. static int x_window;
  28. static Cursor x_cursor;
  29. int (*xeventhandler)(XEvent *);
  30. int getxkey(XEvent *event);
  31. int brl_system_XKeyHandler(int type,int key,int mask);
  32. static void postAsyncOp( AsyncOp *p ){
  33. int ch=0;
  34. XEvent event;
  35. AsyncOp **q=&asyncOps,*t;
  36. p->succ=0;
  37. pthread_mutex_lock( &asyncMutex );
  38. while( *q ) q=&(*q)->succ;
  39. *q=p;
  40. write( async_pipe[1],&ch,1 );
  41. pthread_mutex_unlock( &asyncMutex );
  42. }
  43. int bbSystemAsyncFD(){
  44. return async_pipe[0];
  45. }
  46. void bbSystemFlushAsyncOps(){
  47. int rd;
  48. AsyncOp *p;
  49. if( !asyncOps ) return;
  50. pthread_mutex_lock( &asyncMutex );
  51. p=asyncOps;
  52. asyncOps=0;
  53. if( !ioctl( async_pipe[0],FIONREAD,&rd ) ){
  54. static char *buf;
  55. static int buf_sz;
  56. if( rd>buf_sz ){
  57. free( buf );
  58. buf=(char*)malloc( rd );
  59. buf_sz=rd;
  60. }
  61. read( async_pipe[0],buf,rd );
  62. }
  63. pthread_mutex_unlock( &asyncMutex );
  64. while( p ){
  65. AsyncOp *t=p->succ;
  66. p->syncOp( p->syncInfo,p->asyncRet );
  67. if( p->asyncOp ){
  68. BBRELEASE( p->syncInfo );
  69. }
  70. free( p );
  71. p=t;
  72. }
  73. }
  74. void bbSystemShutdown(){
  75. // XCloseDisplay(x_display); causes crash with fltk canvas usage
  76. }
  77. void bbAppTerminate(int signum) {
  78. bbSystemEmitEvent( BBEVENT_APPTERMINATE,&bbNullObject,0,0,0,0,&bbNullObject );
  79. }
  80. void bbSystemStartup(){
  81. atexit( bbSystemShutdown );
  82. struct sigaction action;
  83. memset(&action, 0, sizeof(struct sigaction));
  84. action.sa_handler = bbAppTerminate;
  85. sigaction(SIGTERM, &action, NULL);
  86. XInitThreads();
  87. x_display=XOpenDisplay(0);
  88. x_fd=ConnectionNumber( x_display );
  89. pipe( async_pipe );
  90. }
  91. Display *bbSystemDisplay(){
  92. return x_display;
  93. }
  94. void bbSetSystemWindow(int window){
  95. x_window=window;
  96. }
  97. void bbMoveMouse(int x,int y){
  98. XWarpPointer(x_display,None,x_window,0,0,0,0,x,y);
  99. }
  100. void bbSetMouseVisible(visible){
  101. if (!x_window) return;
  102. if (visible)
  103. {
  104. XUndefineCursor(x_display,x_window);
  105. }
  106. else
  107. {
  108. if (!x_cursor)
  109. {
  110. XColor black;
  111. char bm[]={0,0,0,0,0,0,0,0};
  112. Pixmap pix=XCreateBitmapFromData(x_display,x_window,bm,8,8);
  113. memset(&black,0,sizeof(XColor));
  114. black.flags=DoRed|DoGreen|DoBlue;
  115. x_cursor=XCreatePixmapCursor(x_display,pix,pix,&black,&black,0,0);
  116. XFreePixmap(x_display,pix);
  117. }
  118. XDefineCursor(x_display,x_window,x_cursor);
  119. }
  120. }
  121. void bbSystemEventHandler( int(*handler)(XEvent*) ){
  122. xeventhandler=handler;
  123. }
  124. static inline void bbHandleMouse(int event, int eventButton, int * id, int * data) {
  125. *id=event;
  126. switch (eventButton) {
  127. case Button1:
  128. *data = 1;
  129. return;
  130. case Button2:
  131. *data = 3;
  132. return;
  133. case Button3:
  134. *data = 2;
  135. return;
  136. case 8:
  137. *data = 4;
  138. return;
  139. case 9:
  140. *data = 5;
  141. return;
  142. default:
  143. if (eventButton == 4) {
  144. *id=BBEVENT_MOUSEWHEEL;
  145. *data=1;
  146. return;
  147. } else if (eventButton == 5) {
  148. *id=BBEVENT_MOUSEWHEEL;
  149. *data=-1;
  150. return;
  151. }
  152. }
  153. }
  154. void bbSystemEmitOSEvent( XEvent *xevent,BBObject *source ){
  155. XKeyEvent *keyevent;
  156. BBObject *event;
  157. int id,data=0,x=0,y=0,mods=0;
  158. char mybuffer[16];
  159. KeySym mykeysym;
  160. int i,n;
  161. if (xeventhandler){
  162. if (xeventhandler(xevent)) return;
  163. }
  164. x=xevent->xbutton.x;
  165. y=xevent->xbutton.y;
  166. switch( xevent->type ){
  167. case KeyPress:
  168. //
  169. data=getxkey(xevent);
  170. bbSystemEmitEvent( BBEVENT_KEYDOWN,source,data,mods,x,y,&bbNullObject );
  171. //
  172. //Mark swapped above/below - ie: keydown before keychar
  173. //
  174. n=XLookupString( xevent,mybuffer,15,&mykeysym,0 );
  175. for (i=0;i<n;i++){
  176. bbSystemEmitEvent( BBEVENT_KEYCHAR,source,mybuffer[i],0,0,0,&bbNullObject );
  177. }
  178. return;
  179. case KeyRelease:
  180. //
  181. data=getxkey(xevent);
  182. //
  183. //Mark's dodgy fix to generate key repeat events
  184. //Works with "Graphics" style apps - dunno about fltk stuff...
  185. //
  186. if( x_display && XPending( x_display ) ){
  187. XEvent event;
  188. XPeekEvent( x_display,&event );
  189. if( event.type==KeyPress && getxkey( &event )==data ){
  190. XNextEvent( x_display,&event );
  191. //
  192. //generate KEYREPEAT event...
  193. bbSystemEmitEvent( BBEVENT_KEYREPEAT,source,data,mods,x,y,&bbNullObject );
  194. //
  195. //generate KEYCHAR events...
  196. n=XLookupString( xevent,mybuffer,15,&mykeysym,0 );
  197. for (i=0;i<n;i++){
  198. bbSystemEmitEvent( BBEVENT_KEYCHAR,source,mybuffer[i],0,0,0,&bbNullObject );
  199. }
  200. return;
  201. }
  202. }
  203. id=BBEVENT_KEYUP;
  204. break;
  205. case ButtonPress:
  206. bbHandleMouse(BBEVENT_MOUSEDOWN, xevent->xbutton.button, &id, &data);
  207. break;
  208. case ButtonRelease:
  209. bbHandleMouse(BBEVENT_MOUSEUP, xevent->xbutton.button, &id, &data);
  210. break;
  211. case MotionNotify:
  212. id=BBEVENT_MOUSEMOVE;
  213. break;
  214. case FocusIn:
  215. id=BBEVENT_APPRESUME;
  216. break;
  217. case FocusOut:
  218. //ignore if lost focus because the window got grabbed
  219. //(moving around the windowed application)
  220. if( xevent->xfocus.mode == NotifyGrab || xevent->xfocus.mode == NotifyUngrab) {
  221. break;
  222. }
  223. id=BBEVENT_APPSUSPEND;
  224. break;
  225. case ClientMessage:
  226. if( xevent->xclient.data.l[0]==XInternAtom( x_display,"WM_DELETE_WINDOW",True ) ){
  227. id=BBEVENT_APPTERMINATE;
  228. }else{
  229. return;
  230. }
  231. break;
  232. default:
  233. return;
  234. }
  235. bbSystemEmitEvent( id,source,data,mods,x,y,&bbNullObject );
  236. }
  237. void bbSystemPoll(){
  238. if( !x_display ) return;
  239. while( XPending( x_display ) ){
  240. XEvent event;
  241. XNextEvent( x_display,&event );
  242. bbSystemEmitOSEvent(&event,&bbNullObject);
  243. }
  244. bbSystemFlushAsyncOps();
  245. }
  246. void bbSystemWait(){
  247. fd_set in_fds;
  248. struct timeval tv;
  249. if( !x_display ) return;
  250. FD_ZERO( &in_fds );
  251. FD_SET( x_fd,&in_fds );
  252. FD_SET( async_pipe[0],&in_fds );
  253. tv.tv_sec=10;
  254. tv.tv_usec=0;
  255. select( (x_fd>async_pipe[0] ? x_fd : async_pipe[0]) + 1,&in_fds,0,0,&tv );
  256. bbSystemPoll();
  257. }
  258. int getxkey(XEvent *event)
  259. {
  260. int key;
  261. key=XLookupKeysym(&event->xkey,0)&255;
  262. if (key>=97&&key<=126) return key+(65-97); //a..z
  263. if (key>=81&&key<=84) return key+(37-81); //arrow keys
  264. if (key>=190 && key<=201) return key+(112-190); //function keys
  265. if (key==99) return 45; //insert
  266. if (key==227) return 162; //lctrl
  267. if (key==233) return 164; //lalt
  268. if (key==234) return 165; //ralt
  269. if (key==228) return 163; //rctrl
  270. if (key==225) return 160; //lshift
  271. if (key==226) return 161; //rshiftz
  272. if (key==127) return 144; //numlock
  273. if (key==20) return 145; //scroll
  274. if (key==158) return 96; //numkeys 0..9
  275. if (key==156) return 97;
  276. if (key==153) return 98;
  277. if (key==155) return 99;
  278. if (key==150) return 100;
  279. if (key==157) return 101;
  280. if (key==152) return 102;
  281. if (key==149) return 103;
  282. if (key==151) return 104;
  283. if (key==154) return 105;
  284. if (key==235) return 91; //left windows key
  285. if (key==236) return 92; //right windows key
  286. if (key==103) return 93; //startmenu windows key
  287. if (key==80) return 36; //home
  288. if (key==85) return 33; //pageup
  289. if (key==255) return 46; //delete
  290. if (key==87) return 35; //end
  291. if (key==86) return 34; //pagedown
  292. if (key==97) return 42; //print screen
  293. if (key==159) return 110; //keypad .
  294. if (key==141) return 13; //keypad enter
  295. if (key==171) return 107; //keypad add
  296. if (key==173) return 109; //keypad minus
  297. if (key==170) return 106; //keypad mult
  298. if (key==175) return 111; //keypad divide
  299. if (key==96) return 192; //tilde key
  300. if (key=='-') return 189; //minus
  301. if (key=='=') return 187; //equals
  302. if (key==91) return 219; //[
  303. if (key==93) return 221; //]
  304. if (key==92) return 226; //backslash
  305. if (key==59) return 186; //semicolon
  306. if (key==39) return 222; //quotes
  307. if (key==44) return 188; //comma key
  308. if (key==46) return 190; //period key
  309. if (key==47) return 191; //questionmark key
  310. return key;
  311. }
  312. void *asyncOpThread( void *t ){
  313. AsyncOp *p=(AsyncOp*)t;
  314. p->asyncRet=p->asyncOp( p->asyncInfo );
  315. postAsyncOp( p );
  316. return 0;
  317. }
  318. void bbSystemPostSyncOp( BBSyncOp syncOp,BBObject *syncInfo,size_t asyncRet ){
  319. AsyncOp *p=(AsyncOp*)malloc( sizeof( AsyncOp ) );
  320. p->asyncOp=0;
  321. p->asyncRet=asyncRet;
  322. p->syncOp=syncOp;
  323. p->syncInfo=syncInfo;
  324. postAsyncOp( p );
  325. }
  326. void bbSystemStartAsyncOp( BBAsyncOp asyncOp,int asyncInfo,BBSyncOp syncOp,BBObject *syncInfo ){
  327. pthread_t thread;
  328. AsyncOp *p=(AsyncOp*)malloc( sizeof( AsyncOp ) );
  329. BBRETAIN( syncInfo );
  330. p->asyncOp=asyncOp;
  331. p->asyncInfo=asyncInfo;
  332. p->syncOp=syncOp;
  333. p->syncInfo=syncInfo;
  334. pthread_create( &thread,0,asyncOpThread,p );
  335. pthread_detach( thread );
  336. }
  337. static int _calchertz( XF86VidModeModeInfo *m ){
  338. int freq=( m->dotclock*1000.0 )/( m->htotal*m->vtotal )+.5;
  339. if( m->flags&INTERLACE ) freq<<=1;
  340. if( m->flags&DBLSCAN ) freq>>=1;
  341. return freq;
  342. }
  343. int bbSystemDesktopWidth(){
  344. int count=0,sz=0;
  345. XF86VidModeModeInfo **xmodes=0;
  346. XF86VidModeGetAllModeLines( x_display,DefaultScreen( x_display ),&count,&xmodes );
  347. sz=count>0 ? xmodes[0]->hdisplay : 640;
  348. XFree( xmodes );
  349. return sz;
  350. }
  351. int bbSystemDesktopHeight(){
  352. int count=0,sz=0;
  353. XF86VidModeModeInfo **xmodes=0;
  354. XF86VidModeGetAllModeLines( x_display,DefaultScreen( x_display ),&count,&xmodes );
  355. sz=count>0 ? xmodes[0]->vdisplay : 480;
  356. XFree( xmodes );
  357. return sz;
  358. }
  359. int bbSystemDesktopDepth(){
  360. return 24;
  361. }
  362. int bbSystemDesktopHertz(){
  363. int count=0,sz=0;
  364. XF86VidModeModeInfo **xmodes=0;
  365. XF86VidModeGetAllModeLines( x_display,DefaultScreen( x_display ),&count,&xmodes );
  366. sz=count>0 ? _calchertz( xmodes[0] ) : 60;
  367. XFree( xmodes );
  368. return sz;
  369. }