system.win32.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. #include "system.h"
  2. #include <shlobj.h>
  3. typedef struct AsyncOp{
  4. BBSyncOp syncOp;
  5. BBObject *syncInfo;
  6. int asyncRet;
  7. BBAsyncOp asyncOp;
  8. int asyncInfo;
  9. }AsyncOp;
  10. static int _usew;
  11. static HHOOK msghook;
  12. static int mainThreadId;
  13. static int mods;
  14. static int started;
  15. static HWND mouseHwnd;
  16. static BBObject *mouseSource;
  17. static int mouseVisible;
  18. static const wchar_t *appTitleW(){
  19. return bbStringToWString( bbAppTitle );
  20. }
  21. static const char *appTitleA(){
  22. return bbStringToCString( bbAppTitle );
  23. }
  24. static int keyCode( int wp,int lp ){
  25. switch( ((lp>>17)&0x80)|((lp>>16)&0x7f) ){
  26. case 42:return VK_LSHIFT;
  27. case 54:return VK_RSHIFT;
  28. case 29:return VK_LCONTROL;
  29. case 157:return VK_RCONTROL;
  30. case 56:return VK_LMENU;
  31. case 184:return VK_RMENU;
  32. }
  33. return wp;
  34. }
  35. static void updateMods(){
  36. mods=0;
  37. if( GetKeyState( VK_SHIFT )<0 ) mods|=MODIFIER_SHIFT;
  38. if( GetKeyState( VK_CONTROL )<0 ) mods|=MODIFIER_CONTROL;
  39. if( GetKeyState( VK_MENU )<0 ) mods|=MODIFIER_OPTION;
  40. if( GetKeyState( VK_LWIN )<0 || GetKeyState( VK_RWIN )<0 ) mods|=MODIFIER_SYSTEM;
  41. }
  42. static void bbSystemShutdown(){
  43. if( !started ) return;
  44. timeEndPeriod( 1 );
  45. started=0;
  46. }
  47. static int isControl( HWND hwnd ){
  48. int style=GetWindowLong( hwnd,GWL_STYLE) & (WS_TABSTOP|WS_CHILD);
  49. return style==(WS_TABSTOP|WS_CHILD);
  50. }
  51. static void updateMouseVisibility(){
  52. int visible=mouseVisible || !mouseHwnd;
  53. int n=ShowCursor( visible );
  54. if( n<-1 || n>0 ) ShowCursor( !visible );
  55. }
  56. static void setMouseHwnd( HWND hwnd,int x,int y,BBObject *source ){
  57. if( hwnd==mouseHwnd ) return;
  58. if( hwnd && source ){
  59. BBRETAIN( source );
  60. }
  61. if( mouseHwnd ){
  62. POINT p;
  63. GetCursorPos( &p );
  64. ScreenToClient( mouseHwnd,&p );
  65. bbSystemEmitEvent( BBEVENT_MOUSELEAVE,mouseSource,0,0,p.x,p.y,&bbNullObject );
  66. if( mouseSource ){
  67. BBRELEASE( mouseSource );
  68. }
  69. }
  70. mouseHwnd=hwnd;
  71. updateMouseVisibility();
  72. if( mouseHwnd ){
  73. TRACKMOUSEEVENT tm={sizeof(tm),TME_LEAVE,hwnd,0};
  74. mouseSource=source;
  75. bbSystemEmitEvent( BBEVENT_MOUSEENTER,mouseSource,0,0,x,y,&bbNullObject );
  76. _TrackMouseEvent( &tm );
  77. }
  78. }
  79. static HWND focHwnd;
  80. static void beginPanel(){
  81. focHwnd=GetFocus();
  82. }
  83. static void endPanel(){
  84. SetFocus( focHwnd );
  85. }
  86. static LRESULT CALLBACK getMessageHook( int code,WPARAM wp,LPARAM lp ){
  87. if( code>=0 && wp==PM_REMOVE ){
  88. MSG *msg=(MSG*)lp;
  89. if( msg->message==WM_BBRESERVED1 ){
  90. AsyncOp *p=(AsyncOp*)msg->lParam;
  91. p->syncOp( p->syncInfo,p->asyncRet );
  92. if( p->asyncOp ){
  93. BBRELEASE( p->syncInfo );
  94. }
  95. free( p );
  96. }
  97. }
  98. return CallNextHookEx( msghook,code,wp,lp );
  99. }
  100. void bbSystemEmitOSEvent( HWND hwnd,UINT msg,WPARAM wp,LPARAM lp,BBObject *source ){
  101. RECT rect;
  102. POINT point;
  103. int inRect,id,data=0,x=0,y=0;
  104. switch( msg ){
  105. case WM_KEYDOWN:case WM_SYSKEYDOWN:
  106. if( wp<1 || wp>255 ) return;
  107. id=( lp & 0x40000000 ) ? BBEVENT_KEYREPEAT : BBEVENT_KEYDOWN;
  108. data=keyCode( wp,lp );
  109. break;
  110. case WM_KEYUP:case WM_SYSKEYUP:
  111. if( wp<1 || wp>255 ) return;
  112. id=BBEVENT_KEYUP;
  113. data=keyCode( wp,lp );
  114. break;
  115. case WM_CHAR:case WM_SYSCHAR:
  116. id=BBEVENT_KEYCHAR;
  117. data=wp;
  118. break;
  119. case WM_LBUTTONDOWN:case WM_RBUTTONDOWN:case WM_MBUTTONDOWN:
  120. SetCapture( hwnd );
  121. id=BBEVENT_MOUSEDOWN;
  122. data=(msg==WM_LBUTTONDOWN) ? 1 : (msg==WM_RBUTTONDOWN ? 2 : 3);
  123. x=(short)LOWORD(lp);
  124. y=(short)HIWORD(lp);
  125. break;
  126. case WM_LBUTTONUP:case WM_RBUTTONUP:case WM_MBUTTONUP:
  127. ReleaseCapture();
  128. id=BBEVENT_MOUSEUP;
  129. data=(msg==WM_LBUTTONUP) ? 1 : (msg==WM_RBUTTONUP ? 2 : 3);
  130. x=(short)LOWORD(lp);
  131. y=(short)HIWORD(lp);
  132. break;
  133. case WM_MOUSEMOVE:
  134. x=(short)LOWORD(lp);
  135. y=(short)HIWORD(lp);
  136. if (wp&MK_LBUTTON) data=1;
  137. if (wp&MK_MBUTTON) data=4;
  138. if (wp&MK_RBUTTON) data=2;
  139. GetClientRect( hwnd,&rect );
  140. inRect=(x>=0 && y>=0 && x<rect.right && y<rect.bottom);
  141. setMouseHwnd( inRect ? hwnd : 0,x,y,source );
  142. id=BBEVENT_MOUSEMOVE;
  143. break;
  144. case WM_MOUSELEAVE:
  145. if( hwnd==mouseHwnd ) setMouseHwnd( 0,(short)LOWORD(lp),(short)HIWORD(lp),&bbNullObject );
  146. return;
  147. case WM_MOUSEWHEEL:
  148. id=BBEVENT_MOUSEWHEEL;
  149. data=(short)HIWORD(wp)/120;
  150. point.x=(short)LOWORD(lp);
  151. point.y=(short)HIWORD(lp);
  152. ScreenToClient( hwnd,&point );
  153. x=point.x;
  154. y=point.y;
  155. break;
  156. case WM_CLOSE:
  157. id=BBEVENT_APPTERMINATE;
  158. break;
  159. case WM_ACTIVATE:
  160. if( LOWORD(wp)==WA_INACTIVE || !IsIconic(hwnd) ){
  161. DWORD proc;
  162. GetWindowThreadProcessId( lp,&proc );
  163. if( proc!=GetCurrentProcessId() ){
  164. id = (LOWORD(wp) == WA_INACTIVE) ? BBEVENT_APPSUSPEND : BBEVENT_APPRESUME;
  165. break;
  166. }
  167. }
  168. return;
  169. /*
  170. case WM_ACTIVATEAPP:
  171. //
  172. // WM_ACTIVATEAPP appears to be broken.
  173. //
  174. // Clicking on taskbar button to minimize an app appears to confuse poor old windows.
  175. //
  176. // So, we'll use the WM_ACTIVATE code above courtesy of Seb...
  177. //
  178. id=wp ? BBEVENT_APPRESUME : BBEVENT_APPSUSPEND;
  179. break;
  180. */
  181. default:
  182. return;
  183. }
  184. bbSystemEmitEvent( id,source,data,mods,x,y,&bbNullObject );
  185. }
  186. void bbSystemStartup(){
  187. OSVERSIONINFO os={ sizeof(os) };
  188. if( started ) return;
  189. if( GetVersionEx( &os ) ){
  190. if( os.dwPlatformId==VER_PLATFORM_WIN32_NT ){
  191. _usew=1;
  192. }
  193. }
  194. mouseVisible=1;
  195. mainThreadId=GetCurrentThreadId();
  196. msghook=SetWindowsHookEx( WH_GETMESSAGE,getMessageHook,0,mainThreadId );
  197. timeBeginPeriod( 1 );
  198. atexit( bbSystemShutdown );
  199. started=1;
  200. }
  201. void bbSystemPoll(){
  202. MSG msg;
  203. while( PeekMessage( &msg,0,0,0,PM_REMOVE ) ){
  204. switch( msg.message ){
  205. case WM_KEYDOWN:case WM_KEYUP:
  206. case WM_SYSKEYDOWN:case WM_SYSKEYUP:
  207. switch( msg.wParam ){
  208. case VK_SHIFT:
  209. case VK_CONTROL:
  210. case VK_MENU:
  211. case VK_LWIN:case VK_RWIN:
  212. updateMods();
  213. break;
  214. }
  215. break;
  216. }
  217. if( isControl( msg.hwnd ) ){
  218. HWND hwnd=GetParent( msg.hwnd );
  219. while( hwnd && isControl( hwnd ) ) hwnd=GetParent( hwnd );
  220. if( hwnd && IsDialogMessage( hwnd,&msg ) ) continue;
  221. }
  222. TranslateMessage( &msg );
  223. DispatchMessage( &msg );
  224. }
  225. }
  226. void bbSystemWait(){
  227. MsgWaitForMultipleObjects( 0,0,0,INFINITE,QS_ALLINPUT ); //QS_ALLEVENTS );
  228. bbSystemPoll();
  229. }
  230. void bbSystemMoveMouse( int x,int y ){
  231. POINT point={x,y};
  232. HWND hwnd=GetActiveWindow();
  233. if( hwnd ) ClientToScreen( hwnd,&point );
  234. SetCursorPos( point.x,point.y );
  235. }
  236. void bbSystemSetMouseVisible( int visible ){
  237. mouseVisible=visible;
  238. updateMouseVisibility();
  239. }
  240. static int systemPanel( BBString *text,int flags ){
  241. int n;
  242. beginPanel();
  243. if( _usew ){
  244. n=MessageBoxW( GetActiveWindow(),bbTmpWString(text),appTitleW(),flags );
  245. }else{
  246. n=MessageBoxA( GetActiveWindow(),bbTmpCString(text),appTitleA(),flags );
  247. }
  248. endPanel();
  249. return n;
  250. }
  251. void bbSystemNotify( BBString *text,int serious ){
  252. int flags=(serious?MB_ICONWARNING:MB_ICONINFORMATION)|MB_OK|MB_APPLMODAL|MB_TOPMOST;
  253. systemPanel( text,flags );
  254. }
  255. int bbSystemConfirm( BBString *text,int serious ){
  256. int flags=(serious?MB_ICONWARNING:MB_ICONINFORMATION)|MB_OKCANCEL|MB_APPLMODAL|MB_TOPMOST;
  257. int n=systemPanel( text,flags );
  258. if( n==IDOK ) return 1;
  259. return 0;
  260. }
  261. int bbSystemProceed( BBString *text,int serious ){
  262. int flags=(serious?MB_ICONWARNING:MB_ICONINFORMATION)|MB_YESNOCANCEL|MB_APPLMODAL|MB_TOPMOST;
  263. int n=systemPanel( text,flags );
  264. if( n==IDYES ) return 1;
  265. if( n==IDNO ) return 0;
  266. return -1;
  267. }
  268. BBString *bbSystemRequestFile( BBString *text,BBString *exts,int defext,int save,BBString *file,BBString *dir ){
  269. BBString *str=&bbEmptyString;
  270. if( _usew ){
  271. wchar_t buf[MAX_PATH];
  272. OPENFILENAMEW of={sizeof(of)};
  273. wcscpy( buf,bbTmpWString( file ) );
  274. of.hwndOwner=GetActiveWindow();
  275. of.lpstrTitle=bbTmpWString( text );
  276. of.lpstrFilter=bbTmpWString( exts );
  277. of.nFilterIndex=defext;
  278. of.lpstrFile=buf;
  279. of.lpstrInitialDir=dir->length ? bbTmpWString( dir ) : 0;
  280. of.nMaxFile=MAX_PATH;
  281. of.Flags=OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
  282. beginPanel();
  283. if( save ){
  284. of.lpstrDefExt=L"";
  285. of.Flags|=OFN_OVERWRITEPROMPT;
  286. if( GetSaveFileNameW( &of ) ){
  287. str=bbStringFromWString( buf );
  288. }
  289. }else{
  290. of.Flags|=OFN_FILEMUSTEXIST;
  291. if( GetOpenFileNameW( &of ) ){
  292. str=bbStringFromWString( buf );
  293. }
  294. }
  295. endPanel();
  296. }else{
  297. char buf[MAX_PATH];
  298. OPENFILENAMEA of={sizeof(of)};
  299. strcpy( buf,bbTmpCString( file ) );
  300. of.hwndOwner=GetActiveWindow();
  301. of.lpstrTitle=bbTmpCString( text );
  302. of.lpstrFilter=bbTmpCString( exts );
  303. of.nFilterIndex=defext;
  304. of.lpstrFile=buf;
  305. of.lpstrInitialDir=dir->length ? bbTmpCString( dir ) : 0;
  306. of.nMaxFile=MAX_PATH;
  307. of.Flags=OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
  308. beginPanel();
  309. if( save ){
  310. of.lpstrDefExt="";
  311. of.Flags|=OFN_OVERWRITEPROMPT;
  312. if( GetSaveFileNameA( &of ) ){
  313. str=bbStringFromCString( buf );
  314. }
  315. }else{
  316. of.Flags|=OFN_FILEMUSTEXIST;
  317. if( GetOpenFileNameA( &of ) ){
  318. str=bbStringFromCString( buf );
  319. }
  320. }
  321. endPanel();
  322. }
  323. return str;
  324. }
  325. static int CALLBACK BrowseForFolderCallbackW( HWND hwnd,UINT uMsg,LPARAM lp,LPARAM pData ){
  326. wchar_t szPath[MAX_PATH];
  327. switch( uMsg ){
  328. case BFFM_INITIALIZED:
  329. SendMessageW( hwnd,BFFM_SETSELECTIONW,TRUE,pData );
  330. break;
  331. case BFFM_SELCHANGED:
  332. if( SHGetPathFromIDListW( (LPITEMIDLIST)lp,szPath ) ){
  333. SendMessageW( hwnd,BFFM_SETSTATUSTEXTW,0,(LPARAM)szPath );
  334. }
  335. break;
  336. }
  337. return 0;
  338. }
  339. static int CALLBACK BrowseForFolderCallbackA( HWND hwnd,UINT uMsg,LPARAM lp,LPARAM pData ){
  340. char szPath[MAX_PATH];
  341. switch( uMsg ){
  342. case BFFM_INITIALIZED:
  343. SendMessageA( hwnd,BFFM_SETSELECTIONA,TRUE,pData );
  344. break;
  345. case BFFM_SELCHANGED:
  346. if( SHGetPathFromIDListA( (LPITEMIDLIST)lp,szPath ) ){
  347. SendMessageA( hwnd,BFFM_SETSTATUSTEXTA,0,(LPARAM)szPath );
  348. }
  349. break;
  350. }
  351. return 0;
  352. }
  353. BBString *bbSystemRequestDir( BBString *text,BBString *dir ){
  354. BBString *str=&bbEmptyString;
  355. if( _usew ){
  356. LPMALLOC shm;
  357. ITEMIDLIST *idlist;
  358. BROWSEINFOW bi={0};
  359. wchar_t buf[MAX_PATH],*p;
  360. GetFullPathNameW( bbTmpWString(dir),MAX_PATH,buf,&p );
  361. bi.hwndOwner=GetActiveWindow();
  362. bi.lpszTitle=bbTmpWString( text );
  363. bi.ulFlags=BIF_RETURNONLYFSDIRS|BIF_NEWDIALOGSTYLE;
  364. bi.lpfn=BrowseForFolderCallbackW;
  365. bi.lParam=(LPARAM)buf;
  366. beginPanel();
  367. idlist=SHBrowseForFolderW(&bi);
  368. endPanel();
  369. if( idlist ){
  370. SHGetPathFromIDListW( idlist,buf );
  371. str=bbStringFromWString( buf );
  372. //SHFree( idlist ); //?!?
  373. }
  374. } else {
  375. LPMALLOC shm;
  376. ITEMIDLIST *idlist;
  377. BROWSEINFOA bi={0};
  378. char buf[MAX_PATH],*p;
  379. GetFullPathNameA( bbTmpCString(dir),MAX_PATH,buf,&p );
  380. bi.hwndOwner=GetActiveWindow();
  381. bi.lpszTitle=bbTmpCString( text );
  382. bi.ulFlags=BIF_RETURNONLYFSDIRS|BIF_NEWDIALOGSTYLE;
  383. bi.lpfn=BrowseForFolderCallbackA;
  384. bi.lParam=(LPARAM)buf;
  385. beginPanel();
  386. idlist=SHBrowseForFolderA(&bi);
  387. endPanel();
  388. if( idlist ){
  389. SHGetPathFromIDListA( idlist,buf );
  390. str=bbStringFromCString( buf );
  391. //SHFree( idlist ); //?!?
  392. }
  393. }
  394. return str;
  395. }
  396. int bbOpenURL( BBString *url ){
  397. int n;
  398. if( _usew ){
  399. n=(int)ShellExecuteW( 0,0,(wchar_t*)bbTmpWString(url),0,0,10 )>32; //SW_SHOWDEFAULT
  400. }else{
  401. n=(int)ShellExecuteA( 0,0,bbTmpCString(url),0,0,10 )>32; //SW_SHOWDEFAULT
  402. }
  403. return n;
  404. }
  405. static DWORD WINAPI asyncOpThread( void *t ){
  406. AsyncOp *p=(AsyncOp*)t;
  407. p->asyncRet=p->asyncOp( p->asyncInfo );
  408. PostThreadMessage( mainThreadId,WM_BBRESERVED1,0,(LPARAM)p );
  409. }
  410. void bbSystemPostSyncOp( BBSyncOp syncOp,BBObject *syncInfo,int asyncRet ){
  411. AsyncOp *p=(AsyncOp*)malloc( sizeof( AsyncOp ) );
  412. p->asyncOp=0;
  413. p->asyncRet=asyncRet;
  414. p->syncOp=syncOp;
  415. p->syncInfo=syncInfo;
  416. PostThreadMessage( mainThreadId,WM_BBRESERVED1,0,(LPARAM)p );
  417. }
  418. void bbSystemStartAsyncOp( BBAsyncOp asyncOp,int asyncInfo,BBSyncOp syncOp,BBObject *syncInfo ){
  419. DWORD threadId;
  420. AsyncOp *p=(AsyncOp*)malloc( sizeof( AsyncOp ) );
  421. BBRETAIN( syncInfo );
  422. p->asyncOp=asyncOp;
  423. p->asyncInfo=asyncInfo;
  424. p->syncOp=syncOp;
  425. p->syncInfo=syncInfo;
  426. CreateThread( 0,0,asyncOpThread,p,0,&threadId );
  427. }
  428. int DesktopCaps(int index){
  429. HWND hwnd = GetDesktopWindow();
  430. HDC dc = GetDC(hwnd);
  431. int caps = GetDeviceCaps(dc,index);
  432. ReleaseDC(hwnd,dc);
  433. return caps;
  434. }
  435. int bbSystemDesktopWidth(){
  436. return DesktopCaps(HORZRES);
  437. }
  438. int bbSystemDesktopHeight(){
  439. return DesktopCaps(VERTRES);
  440. }
  441. int bbSystemDesktopDepth(){
  442. return DesktopCaps(BITSPIXEL);
  443. }
  444. int bbSystemDesktopHertz(){
  445. return DesktopCaps(VREFRESH);
  446. }