WinBFApp.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702
  1. #include <dsound.h>
  2. #include "WinBFApp.h"
  3. #include "DXRenderDevice.h"
  4. #include <signal.h>
  5. #include "../../util/BeefPerf.h"
  6. #include "DSoundManager.h"
  7. #include <dwmapi.h>
  8. #pragma comment(lib, "dwmapi.lib")
  9. #include "util/AllocDebug.h"
  10. USING_NS_BF;
  11. int Beefy::WinBFMenu::mMenuCount = 0;
  12. int PrintStuff()
  13. {
  14. OutputDebugStringA("Hey!\n");
  15. return 123;
  16. }
  17. WinBFMenu::WinBFMenu()
  18. {
  19. mIsPlaceholder = false;
  20. mMenu = NULL;
  21. mParent = NULL;
  22. mMenuId = 0;
  23. }
  24. ///
  25. static HICON gMainIcon = NULL;
  26. static BOOL CALLBACK BFEnumResNameProc(
  27. HMODULE hModule,
  28. LPCWSTR lpszType,
  29. LPWSTR lpszName,
  30. LONG_PTR lParam
  31. )
  32. {
  33. gMainIcon = ::LoadIconW(hModule, lpszName);
  34. return FALSE;
  35. }
  36. WinBFWindow::WinBFWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)
  37. {
  38. HINSTANCE hInstance = GetModuleHandle(NULL);
  39. mMinWidth = 128;
  40. mMinHeight = 128;
  41. WNDCLASSW wc;
  42. wc.style = CS_DBLCLKS;
  43. wc.cbClsExtra = 0;
  44. wc.cbWndExtra = 0;
  45. wc.hbrBackground = NULL;
  46. //wc.hbrBackground = ::CreateSolidBrush(::GetSysColor(COLOR_BTNFACE));
  47. wc.hCursor = NULL;
  48. //wc.hIcon = (HICON) ::LoadImageA(hInstance, "MainIcon", IMAGE_ICON, 0, 0, 0);
  49. //wc.hIcon = (HICON) ::LoadImageA(hInstance, MAKEINTRESOURCEA(32512), IMAGE_ICON, 0, 0, 0);
  50. if (gMainIcon != NULL)
  51. {
  52. wc.hIcon = gMainIcon;
  53. }
  54. else
  55. {
  56. wc.hIcon = (HICON) ::LoadIconA(hInstance, "MainIcon");
  57. if (wc.hIcon == NULL)
  58. {
  59. EnumResourceNamesW(hInstance, (LPCWSTR)RT_GROUP_ICON, BFEnumResNameProc, 0);
  60. wc.hIcon = gMainIcon;
  61. }
  62. }
  63. wc.hInstance = hInstance;
  64. wc.lpfnWndProc = WindowProcStub;
  65. wc.lpszClassName = L"BFWindow";
  66. wc.lpszMenuName = NULL;
  67. RegisterClassW(&wc);
  68. int requestedX = x;
  69. int requestedY = y;
  70. int aWindowFlags = 0;
  71. bool hasDestAlpha = (windowFlags & BFWINDOW_DEST_ALPHA) != 0;
  72. if (windowFlags & BFWINDOW_MENU)
  73. {
  74. WinBFMenu* aMenu = new WinBFMenu();
  75. aMenu->mMenu = ::CreateMenu();
  76. mHMenuMap[aMenu->mMenu] = aMenu;
  77. mMenu = aMenu;
  78. }
  79. int windowFlagsEx = /*WS_EX_COMPOSITED |*/ WS_EX_LAYERED;
  80. if (windowFlags & BFWINDOW_TOOLWINDOW)
  81. windowFlagsEx |= WS_EX_TOOLWINDOW;
  82. if (windowFlags & BFWINDOW_BORDER)
  83. aWindowFlags |= WS_BORDER;
  84. if (windowFlags & BFWINDOW_THICKFRAME)
  85. aWindowFlags |= WS_THICKFRAME;
  86. if ((windowFlags & BFWINDOW_RESIZABLE) && (!hasDestAlpha))
  87. aWindowFlags |= WS_SIZEBOX;
  88. if (windowFlags & BFWINDOW_SYSMENU)
  89. aWindowFlags |= WS_SYSMENU;
  90. if (windowFlags & BFWINDOW_CAPTION)
  91. aWindowFlags |= WS_CAPTION;
  92. else
  93. aWindowFlags |= WS_POPUP;
  94. if (windowFlags & BFWINDOW_MINIMIZE)
  95. aWindowFlags |= WS_MINIMIZEBOX;
  96. if (windowFlags & BFWINDOW_MAXIMIZE)
  97. aWindowFlags |= WS_MAXIMIZEBOX;
  98. if ((windowFlags & BFWINDOW_TOPMOST) && (parent == NULL))
  99. windowFlagsEx |= WS_EX_TOPMOST;
  100. if (windowFlags & BFWINDOW_CLIENT_SIZED)
  101. {
  102. RECT rect = {0, 0, width, height};
  103. AdjustWindowRectEx(&rect, aWindowFlags, mMenu != NULL, windowFlagsEx);
  104. x += rect.left;
  105. y += rect.top;
  106. width = rect.right - rect.left;
  107. height = rect.bottom - rect.top;
  108. }
  109. if (windowFlags & BFWINDOW_POPUP_POSITION)
  110. {
  111. RECT desktopRect;
  112. ::SystemParametersInfo(SPI_GETWORKAREA, NULL, &desktopRect, NULL);
  113. if (x + width >= desktopRect.right)
  114. x = BF_MAX((int)desktopRect.left, requestedX - width);
  115. if (y + height >= desktopRect.bottom)
  116. y = BF_MAX((int)desktopRect.top, requestedY - height);
  117. }
  118. mFlags = windowFlags;
  119. mMouseVisible = true;
  120. mParent = parent;
  121. HWND parentHWnd = NULL;
  122. if (parent != NULL)
  123. parentHWnd = ((WinBFWindow*) parent)->mHWnd;
  124. if (mMenu != NULL)
  125. {
  126. WinBFMenu* placeholderMenu = (WinBFMenu*) AddMenuItem(mMenu, 0, ": Placeholder Menu Item :", NULL, NULL, false, -1, false);
  127. placeholderMenu->mIsPlaceholder = true;
  128. }
  129. mHWnd = CreateWindowExW(windowFlagsEx, L"BFWindow", UTF8Decode(title).c_str(),
  130. aWindowFlags,
  131. x, y,
  132. width,
  133. height,
  134. parentHWnd,
  135. (mMenu != NULL) ? ((WinBFMenu*) mMenu)->mMenu : NULL,
  136. hInstance,
  137. 0);
  138. if ((windowFlags & BFWINDOW_ALPHA_MASK) == 0)
  139. SetLayeredWindowAttributes(mHWnd, 0, 255, 0);
  140. HWND relativeWindow = NULL;
  141. if ((windowFlags & BFWINDOW_TOPMOST) && (parent == NULL))
  142. relativeWindow = HWND_TOP;
  143. int showFlags = SWP_SHOWWINDOW;
  144. mHasFocus = true;
  145. mSoftHasFocus = true;
  146. if (windowFlags & BFWINDOW_FAKEFOCUS)
  147. {
  148. showFlags |= SWP_NOACTIVATE;
  149. if (windowFlags & BFWINDOW_NO_ACTIVATE)
  150. {
  151. mHasFocus = false;
  152. mSoftHasFocus = false;
  153. }
  154. }
  155. else if (windowFlags & BFWINDOW_NO_ACTIVATE)
  156. {
  157. showFlags |= SWP_NOACTIVATE;
  158. mHasFocus = false;
  159. mSoftHasFocus = false;
  160. }
  161. SetWindowPos(mHWnd, relativeWindow, x, y, width, height, showFlags);
  162. SetTimer(mHWnd, 0, 10, NULL);
  163. mIsMouseInside = false;
  164. mRenderWindow = new DXRenderWindow((DXRenderDevice*) gBFApp->mRenderDevice, mHWnd, (windowFlags & BFWINDOW_FULLSCREEN) == 0);
  165. mRenderWindow->mWindow = this;
  166. gBFApp->mRenderDevice->AddRenderWindow(mRenderWindow);
  167. SetWindowLongPtr(mHWnd, GWLP_USERDATA, (LONG_PTR)this);
  168. mIsMenuKeyHandled = false;
  169. mAlphaMaskBitmap = NULL;
  170. mAlphaMaskDC = NULL;
  171. mAlphaMaskPixels = NULL;
  172. mAlphaMaskWidth = 0;
  173. mAlphaMaskHeight = 0;
  174. mNeedsStateReset = false;
  175. if (windowFlags & BFWINDOW_DEST_ALPHA)
  176. {
  177. MARGINS dWMMargins = {-1, -1, -1, -1};
  178. DwmExtendFrameIntoClientArea(mHWnd, &dWMMargins);
  179. }
  180. if (windowFlags & BFWINDOW_MODAL)
  181. {
  182. EnableWindow(parentHWnd, FALSE);
  183. }
  184. if (parent != NULL)
  185. {
  186. auto winParent = (WinBFWindow*)parent;
  187. BF_ASSERT(winParent->mHWnd);
  188. parent->mChildren.push_back(this);
  189. }
  190. }
  191. WinBFWindow::~WinBFWindow()
  192. {
  193. for (auto child : mChildren)
  194. {
  195. NOP;
  196. }
  197. if (mHWnd != NULL)
  198. Destroy();
  199. }
  200. void* WinBFWindow::GetUnderlying()
  201. {
  202. return mHWnd;
  203. }
  204. void WinBFWindow::Destroy()
  205. {
  206. if (mAlphaMaskDC != NULL)
  207. DeleteDC(mAlphaMaskDC);
  208. mAlphaMaskDC = NULL;
  209. if (mAlphaMaskBitmap != NULL)
  210. DeleteObject(mAlphaMaskBitmap);
  211. mAlphaMaskBitmap = NULL;
  212. for (auto& menu : mMenuIDMap)
  213. {
  214. delete menu.mValue;
  215. }
  216. mMenuIDMap.Clear();
  217. ::DestroyWindow(mHWnd);
  218. BF_ASSERT(mHWnd == NULL);
  219. }
  220. bool WinBFWindow::TryClose()
  221. {
  222. SendMessage(mHWnd, WM_CLOSE, 0, 0);
  223. return mHWnd == NULL;
  224. }
  225. void WinBFWindow::SetTitle(const char* title)
  226. {
  227. SetWindowTextA(mHWnd, title);
  228. }
  229. void WinBFWindow::LostFocus(BFWindow* newFocus)
  230. {
  231. WinBFWindow* bfNewFocus = (WinBFWindow*)newFocus;
  232. mSoftHasFocus = false;
  233. for (int i = 0; i < KEYCODE_MAX; i++)
  234. {
  235. // Only transfer mode keys
  236. if (mIsKeyDown[i])
  237. {
  238. mIsKeyDown[i] = false;
  239. mKeyUpFunc(this, i);
  240. if ((newFocus != NULL) &&
  241. ((i == VK_SHIFT) || (i == VK_CONTROL) || (i == VK_MENU)))
  242. {
  243. newFocus->mIsKeyDown[i] = true;
  244. newFocus->mKeyDownFunc(newFocus, i, 0);
  245. }
  246. }
  247. }
  248. }
  249. void WinBFWindow::SetForeground()
  250. {
  251. if (mFlags & BFWINDOW_FAKEFOCUS)
  252. {
  253. mHasFocus = true;
  254. mSoftHasFocus = true;
  255. return;
  256. }
  257. ::SetFocus(mHWnd);
  258. ::SetForegroundWindow(mHWnd);
  259. //OutputDebugStrF("SetForeground %p\n", mHWnd);
  260. }
  261. static POINT gLastScreenMouseCoords = { -1, -1 };
  262. void WinBFWindow::RehupMouseOver(bool isMouseOver)
  263. {
  264. if ((!mIsMouseInside) && (isMouseOver))
  265. {
  266. TRACKMOUSEEVENT tme;
  267. tme.cbSize = sizeof(TRACKMOUSEEVENT);
  268. tme.dwFlags = TME_LEAVE;
  269. tme.hwndTrack = mHWnd;
  270. TrackMouseEvent(&tme);
  271. mIsMouseInside = true;
  272. }
  273. if ((mIsMouseInside) && (!isMouseOver))
  274. {
  275. mIsMouseInside = false;
  276. mMouseLeaveFunc(this);
  277. }
  278. }
  279. LRESULT WinBFWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  280. {
  281. WinBFApp* app = (WinBFApp*) gBFApp;
  282. if (app == NULL)
  283. {
  284. PrintStuff();
  285. }
  286. switch (uMsg)
  287. {
  288. case WM_KEYDOWN:
  289. case WM_KEYUP:
  290. case WM_SYSKEYDOWN:
  291. case WM_CHAR:
  292. for (auto child : mChildren)
  293. {
  294. auto childWindow = (WinBFWindow*)child;
  295. if ((childWindow->mSoftHasFocus) && (childWindow->mFlags & BFWINDOW_FAKEFOCUS))
  296. {
  297. return childWindow->WindowProc(hWnd, uMsg, wParam, lParam);
  298. }
  299. }
  300. break;
  301. }
  302. switch (uMsg)
  303. {
  304. case WM_CLOSE:
  305. {
  306. //OutputDebugStrF("WM_CLOSE %08X NewFocus:%08X\n", hWnd, GetFocus());
  307. if (mCloseQueryFunc(this) != 0)
  308. gBFApp->RemoveWindow(this);
  309. HWND newFocus = GetFocus();
  310. for (auto window : gBFApp->mWindowList)
  311. {
  312. WinBFWindow* winWindow = (WinBFWindow*)window;
  313. if (winWindow->mHWnd == newFocus)
  314. {
  315. while (true)
  316. {
  317. WinBFWindow* altFocusWindow = NULL;
  318. for (auto checkChild : winWindow->mChildren)
  319. {
  320. auto checkWinChild = (WinBFWindow*)checkChild;
  321. if (checkWinChild->mFlags & BFWINDOW_FAKEFOCUS)
  322. altFocusWindow = checkWinChild;
  323. }
  324. if (altFocusWindow == NULL)
  325. break;
  326. winWindow = altFocusWindow;
  327. }
  328. winWindow->mHasFocus = true;
  329. winWindow->mSoftHasFocus = true;
  330. winWindow->mGotFocusFunc(winWindow);
  331. }
  332. }
  333. return 0;
  334. }
  335. break;
  336. case WM_DESTROY:
  337. /*if (mFlags & BFWINDOW_QUIT_ON_CLOSE)
  338. {
  339. gBFApp->mRunning = false;
  340. }*/
  341. SetWindowLongPtr(mHWnd, GWLP_USERDATA, (LONG_PTR)0);
  342. mHWnd = NULL;
  343. if (!mChildren.IsEmpty())
  344. {
  345. NOP;
  346. }
  347. break;
  348. }
  349. LRESULT result = 0;
  350. bool doResult = false;
  351. if (!app->mInMsgProc)
  352. {
  353. if (mNeedsStateReset)
  354. {
  355. for (int i = 0; i < KEYCODE_MAX; i++)
  356. {
  357. if (mIsKeyDown[i])
  358. {
  359. mIsKeyDown[i] = false;
  360. mKeyUpFunc(this, i);
  361. }
  362. }
  363. POINT mousePoint;
  364. ::GetCursorPos(&mousePoint);
  365. ::ScreenToClient(hWnd, &mousePoint);
  366. for (int i = 0; i < MOUSEBUTTON_MAX; i++)
  367. {
  368. if (mIsMouseDown[i])
  369. {
  370. mMouseUpFunc(this, mousePoint.x, mousePoint.y, i);
  371. mIsMouseDown[i] = false;
  372. }
  373. }
  374. //OutputDebugStrF("Rehup ReleaseCapture()\n");
  375. ReleaseCapture();
  376. mNeedsStateReset = false;
  377. mIsMouseInside = false;
  378. }
  379. WinBFWindow* menuTarget = this;
  380. if (mFlags & BFWINDOW_USE_PARENT_MENU)
  381. menuTarget = ((WinBFWindow*)mParent);
  382. auto* menuIDMap = &menuTarget->mMenuIDMap;
  383. auto* hMenuMap = &menuTarget->mHMenuMap;
  384. app->mInMsgProc = true;
  385. switch (uMsg)
  386. {
  387. case WM_SIZE:
  388. mRenderWindow->Resized();
  389. if (mMovedFunc != NULL)
  390. mMovedFunc(this);
  391. break;
  392. case WM_PAINT:
  393. break;
  394. case WM_NCHITTEST:
  395. {
  396. //OutputDebugStrF("WM_NCHITTEST %X\n", mHWnd);
  397. int x = (short)LOWORD(lParam);
  398. int y = (short)HIWORD(lParam);
  399. result = mHitTestFunc(this, x, y);
  400. doResult = (result != -3);
  401. }
  402. break;
  403. case WM_LBUTTONDOWN:
  404. case WM_RBUTTONDOWN:
  405. case WM_MBUTTONDOWN:
  406. case WM_LBUTTONDBLCLK:
  407. case WM_RBUTTONDBLCLK:
  408. case WM_LBUTTONUP:
  409. case WM_RBUTTONUP:
  410. case WM_MBUTTONUP:
  411. case WM_MOUSEWHEEL:
  412. case WM_MOUSEMOVE:
  413. {
  414. int x = (short)LOWORD(lParam);
  415. int y = (short)HIWORD(lParam);
  416. bool releaseCapture = false;
  417. POINT point = {x, y};
  418. if (uMsg != WM_MOUSEWHEEL)
  419. ::ClientToScreen(hWnd, &point);
  420. if ((uMsg == WM_MOUSEMOVE) && (point.x == gLastScreenMouseCoords.x) && (point.y == gLastScreenMouseCoords.y))
  421. {
  422. // Don't process a WM_MOUSEMOVE if it's at the same point at the last mouse event
  423. // This keeps us from getting a WM_MOUSEMOVE when we popup a window under the current cursor location.
  424. // This is important for keyboard cursor control - so the first down arrow keypress selects the first item in the list
  425. // irregardless of the mouse cursor position.
  426. break;
  427. }
  428. gLastScreenMouseCoords.x = point.x;
  429. gLastScreenMouseCoords.y = point.y;
  430. HWND windowAtPoint = ::WindowFromPoint(point);
  431. bool isMouseOver = windowAtPoint == hWnd;
  432. RehupMouseOver(isMouseOver);
  433. //OutputDebugStrF("HWnd: %X Focus Window: %X Capture: %X\n", hWnd, windowAtPoint, ::GetCapture());
  434. bool checkNonTransparentMousePosition = mNonExclusiveMouseCapture;
  435. switch (uMsg)
  436. {
  437. case WM_LBUTTONDOWN:
  438. //OutputDebugStrF("WM_LBUTTONDOWN Capture HWnd: %X\n", hWnd);
  439. SetCapture(hWnd);
  440. mIsMouseDown[0] = true;
  441. mMouseDownFunc(this, x, y, 0, 1);
  442. break;
  443. case WM_RBUTTONDOWN:
  444. //OutputDebugStrF("WM_RBUTTONDOWN Capture HWnd: %X\n", hWnd);
  445. SetCapture(hWnd);
  446. mIsMouseDown[1] = true;
  447. mMouseDownFunc(this, x, y, 1, 1);
  448. break;
  449. case WM_MBUTTONDOWN:
  450. SetCapture(hWnd);
  451. mIsMouseDown[2] = true;
  452. mMouseDownFunc(this, x, y, 2, 1);
  453. break;
  454. case WM_LBUTTONDBLCLK:
  455. SetCapture(hWnd);
  456. mMouseDownFunc(this, x, y, 0, 2);
  457. break;
  458. case WM_RBUTTONDBLCLK:
  459. SetCapture(hWnd);
  460. mMouseDownFunc(this, x, y, 1, 2);
  461. break;
  462. case WM_MBUTTONDBLCLK:
  463. SetCapture(hWnd);
  464. mMouseDownFunc(this, x, y, 2, 2);
  465. break;
  466. case WM_LBUTTONUP:
  467. releaseCapture = true;
  468. mIsMouseDown[0] = false;
  469. mMouseUpFunc(this, x, y, 0);
  470. break;
  471. case WM_RBUTTONUP:
  472. releaseCapture = true;
  473. mIsMouseDown[1] = false;
  474. mMouseUpFunc(this, x, y, 1);
  475. break;
  476. case WM_MBUTTONUP:
  477. releaseCapture = true;
  478. mIsMouseDown[2] = false;
  479. mMouseUpFunc(this, x, y, 2);
  480. break;
  481. case WM_MOUSEWHEEL:
  482. {
  483. WinBFWindow* cursorWindow = this;
  484. if ((gBFApp->mWindowList.size() > 1) && (GetCapture() == NULL))
  485. {
  486. // See if our mouse is down and has entered into another window's space
  487. POINT point = { x, y };
  488. HWND windowAtPoint = ::WindowFromPoint(point);
  489. BFWindowList::iterator itr = gBFApp->mWindowList.begin();
  490. while (itr != gBFApp->mWindowList.end())
  491. {
  492. WinBFWindow* aWindow = (WinBFWindow*) *itr;
  493. LONG targetStyle = ::GetWindowLong(aWindow->mHWnd, GWL_EXSTYLE);
  494. if ((::IsWindowEnabled(aWindow->mHWnd)) && ((targetStyle & WS_EX_TRANSPARENT) == 0))
  495. {
  496. if (aWindow->mHWnd == windowAtPoint)
  497. {
  498. aWindow->mIsMouseInside = true;
  499. cursorWindow = aWindow;
  500. }
  501. }
  502. ++itr;
  503. }
  504. }
  505. if ((cursorWindow != this) && (mIsMouseInside))
  506. {
  507. mMouseLeaveFunc(this);
  508. mIsMouseInside = false;
  509. }
  510. POINT pt = {x, y};
  511. ScreenToClient(cursorWindow->mHWnd, &pt);
  512. int delta = ((int16)HIWORD(wParam)) / 120;
  513. mMouseWheelFunc(cursorWindow, pt.x, pt.y, delta);
  514. }
  515. break;
  516. case WM_MOUSEMOVE:
  517. {
  518. //OutputDebugStrF("WM_MOUSEMOVE %d\n", hWnd);
  519. mMouseMoveFunc(this, x, y);
  520. // If we are dragging a transparent window then check for mouse positions under cursor
  521. HWND captureWindow = GetCapture();
  522. if (captureWindow != NULL)
  523. {
  524. LONG captureStyle = ::GetWindowLong(captureWindow, GWL_EXSTYLE);
  525. if ((captureStyle & WS_EX_TRANSPARENT) != 0)
  526. checkNonTransparentMousePosition = true;
  527. }
  528. }
  529. break;
  530. }
  531. if ((checkNonTransparentMousePosition) && (gBFApp->mWindowList.size() > 1))
  532. {
  533. // See if our mouse is down and has entered into another window's space
  534. POINT point = { x, y };
  535. ::ClientToScreen(hWnd, &point);
  536. HWND windowAtPoint = ::WindowFromPoint(point);
  537. BFWindowList::iterator itr = gBFApp->mWindowList.begin();
  538. while (itr != gBFApp->mWindowList.end())
  539. {
  540. WinBFWindow* aWindow = (WinBFWindow*) *itr;
  541. if (aWindow != this)
  542. {
  543. LONG myStyle = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
  544. LONG targetStyle = ::GetWindowLong(aWindow->mHWnd, GWL_EXSTYLE);
  545. if ((targetStyle & WS_EX_TRANSPARENT) == 0)
  546. {
  547. if (aWindow->mHWnd == windowAtPoint)
  548. {
  549. POINT clientPt = point;
  550. ::ScreenToClient(aWindow->mHWnd, &clientPt);
  551. aWindow->mMouseProxyMoveFunc(aWindow, clientPt.x, clientPt.y);
  552. aWindow->mIsMouseInside = true;
  553. }
  554. else if (aWindow->mIsMouseInside)
  555. {
  556. aWindow->mMouseLeaveFunc(aWindow);
  557. aWindow->mIsMouseInside = false;
  558. }
  559. }
  560. }
  561. ++itr;
  562. }
  563. }
  564. if (releaseCapture)
  565. {
  566. for (int i = 0; i < MOUSEBUTTON_MAX; i++)
  567. if (mIsMouseDown[i])
  568. releaseCapture = false;
  569. }
  570. if (releaseCapture)
  571. {
  572. //OutputDebugStrF("ReleaseCapture\n");
  573. ReleaseCapture();
  574. BFWindowList::iterator itr = gBFApp->mWindowList.begin();
  575. while (itr != gBFApp->mWindowList.end())
  576. {
  577. WinBFWindow* aWindow = (WinBFWindow*) *itr;
  578. if ((aWindow != this) && (aWindow->mIsMouseInside))
  579. {
  580. aWindow->mMouseLeaveFunc(aWindow);
  581. aWindow->mIsMouseInside = false;
  582. }
  583. ++itr;
  584. }
  585. }
  586. }
  587. break;
  588. case WM_COMMAND:
  589. {
  590. WinBFMenu* aMenu = (*menuIDMap)[(uint32)wParam];
  591. if (aMenu != NULL)
  592. menuTarget->mMenuItemSelectedFunc(menuTarget, aMenu);
  593. }
  594. break;
  595. case WM_APPCOMMAND:
  596. {
  597. if ((mFlags & BFWINDOW_CAPTURE_MEDIA_KEYS) != 0)
  598. {
  599. int cmd = GET_APPCOMMAND_LPARAM(lParam);
  600. int uDevice = GET_DEVICE_LPARAM(lParam);
  601. int dwKeys = GET_KEYSTATE_LPARAM(lParam);
  602. int key = cmd | 0x1000;
  603. mKeyDownFunc(this, key, false);
  604. result = TRUE;
  605. doResult = true;
  606. }
  607. }
  608. break;
  609. case WM_INITMENUPOPUP:
  610. {
  611. if (mIsKeyDown[VK_MENU])
  612. {
  613. mKeyUpFunc(this, (int)VK_MENU);
  614. mIsKeyDown[VK_MENU] = false;
  615. }
  616. HMENU hMenu = (HMENU) wParam;
  617. WinBFMenu* aMenu = (*hMenuMap)[hMenu];
  618. if (aMenu != NULL)
  619. menuTarget->mMenuItemSelectedFunc(menuTarget, aMenu);
  620. }
  621. break;
  622. case WM_MOUSEACTIVATE:
  623. if (mFlags & BFWINDOW_NO_MOUSE_ACTIVATE)
  624. {
  625. doResult = true;
  626. result = MA_NOACTIVATE;
  627. }
  628. else if (mFlags & BFWINDOW_FAKEFOCUS)
  629. {
  630. doResult = true;
  631. result = MA_NOACTIVATE;
  632. SetForeground();
  633. }
  634. break;
  635. case WM_ACTIVATE:
  636. //OutputDebugStrF("WM_ACTIVATE %p\n", hWnd);
  637. break;
  638. case WM_KILLFOCUS:
  639. //OutputDebugStrF("WM_KILLFOCUS %p\n", hWnd);
  640. mHasFocus = false;
  641. mSoftHasFocus = false;
  642. LostFocus(NULL);
  643. mLostFocusFunc(this);
  644. break;
  645. case WM_SETFOCUS:
  646. //OutputDebugStrF("WM_SETFOCUS %p\n", hWnd);
  647. mHasFocus = true;
  648. mSoftHasFocus = true;
  649. mGotFocusFunc(this);
  650. break;
  651. case WM_ENTERMENULOOP:
  652. //OutputDebugStrF("WM_ENTERMENULOOP %08X\n", hWnd);
  653. if (mMenu != NULL)
  654. mNeedsStateReset = true;
  655. break;
  656. case WM_EXITMENULOOP:
  657. //OutputDebugStrF("WM_EXITMENULOOP %08X\n", hWnd);
  658. if (mMenu != NULL)
  659. mNeedsStateReset = true;
  660. break;
  661. case WM_NCMOUSELEAVE:
  662. mIsMouseInside = false;
  663. mMouseLeaveFunc(this);
  664. break;
  665. case WM_CHAR:
  666. {
  667. /*if (wParam == 'z')
  668. {
  669. ID3D11Debug* pD3DDebug = NULL;
  670. HRESULT hr = ((DXRenderDevice*)mRenderWindow->mRenderDevice)->mD3DDevice->QueryInterface(__uuidof(ID3D11Debug), (void**)&pD3DDebug);
  671. if (pD3DDebug != NULL)
  672. {
  673. pD3DDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
  674. pD3DDebug->Release();
  675. }
  676. }*/
  677. if ((!mIsKeyDown[VK_MENU]) && (!mIsKeyDown[VK_CONTROL]))
  678. {
  679. for (int i = 0; i < (lParam & 0x7FFF); i++)
  680. mKeyCharFunc(this, (WCHAR)wParam);
  681. }
  682. }
  683. break;
  684. case WM_MENUCHAR:
  685. if (mIsMenuKeyHandled)
  686. {
  687. result = MNC_CLOSE << 16;
  688. doResult = true;
  689. }
  690. break;
  691. case WM_SYSKEYDOWN:
  692. case WM_KEYDOWN:
  693. {
  694. mIsMenuKeyHandled = false;
  695. int keyCode = (int) wParam;
  696. if (keyCode == VK_APPS)
  697. break; // This is handled in WM_CONTEXTMENU
  698. mIsKeyDown[keyCode] = true;
  699. for (auto kv : *menuIDMap)
  700. {
  701. WinBFMenu* aMenu = kv.mValue;
  702. if ((aMenu->mKeyCode == keyCode) &&
  703. (aMenu->mKeyShift == mIsKeyDown[VK_SHIFT]) &&
  704. (aMenu->mKeyCtrl == mIsKeyDown[VK_CONTROL]) &&
  705. (aMenu->mKeyAlt == mIsKeyDown[VK_MENU]))
  706. {
  707. mIsMenuKeyHandled = true;
  708. menuTarget->mMenuItemSelectedFunc(menuTarget, aMenu);
  709. doResult = true;
  710. break;
  711. }
  712. }
  713. if (!mIsMenuKeyHandled)
  714. {
  715. if (mKeyDownFunc(this, (int) wParam, (lParam & 0x7FFF) != 0))
  716. {
  717. mIsMenuKeyHandled = true;
  718. doResult = true;
  719. }
  720. }
  721. }
  722. break;
  723. case WM_SYSCHAR:
  724. {
  725. int keyCode = toupper((int) wParam);
  726. for (auto& menuKV : *menuIDMap)
  727. {
  728. WinBFMenu* aMenu = menuKV.mValue;
  729. if ((aMenu->mKeyCode == keyCode) &&
  730. (aMenu->mKeyShift == mIsKeyDown[VK_SHIFT]) &&
  731. (aMenu->mKeyCtrl == mIsKeyDown[VK_CONTROL]) &&
  732. (aMenu->mKeyAlt == mIsKeyDown[VK_MENU]))
  733. {
  734. doResult = true;
  735. break;
  736. }
  737. }
  738. if (!mIsKeyDown[VK_MENU])
  739. {
  740. // If we don't have the alt key down then we assume we must have
  741. // had keyups forced by losing focus from the mMenuItemSelectedFunc
  742. doResult = true;
  743. }
  744. }
  745. break;
  746. case WM_SYSKEYUP:
  747. case WM_KEYUP:
  748. {
  749. int keyCode = (int) wParam;
  750. if (mIsKeyDown[keyCode])
  751. {
  752. mKeyUpFunc(this, (int) wParam);
  753. mIsKeyDown[keyCode] = false;
  754. }
  755. }
  756. break;
  757. case WM_SYSCOMMAND:
  758. // Ignore F10
  759. if ((wParam == SC_KEYMENU) && (lParam == 0))
  760. {
  761. doResult = true;
  762. result = 0;
  763. }
  764. break;
  765. case WM_CONTEXTMENU:
  766. {
  767. int x = (short)LOWORD(lParam);
  768. int y = (short)HIWORD(lParam);
  769. if ((x == -1) && (y == -1))
  770. {
  771. mKeyDownFunc(this, VK_APPS, false);
  772. mKeyUpFunc(this, VK_APPS);
  773. }
  774. }
  775. break;
  776. case WM_TIMER:
  777. if (gBFApp->mSysDialogCnt == 0)
  778. {
  779. auto checkNonFake = this;
  780. while (checkNonFake->mFlags & BFWINDOW_FAKEFOCUS)
  781. {
  782. checkNonFake = (WinBFWindow*)checkNonFake->mParent;
  783. }
  784. bool isFocused = GetForegroundWindow() == checkNonFake->mHWnd;
  785. if ((!isFocused) && (mHasFocus))
  786. {
  787. mSoftHasFocus = false;
  788. mHasFocus = false;
  789. LostFocus(NULL);
  790. mLostFocusFunc(this);
  791. //OutputDebugStrF("Timer detected lost focus %p\r\n", hWnd);
  792. }
  793. else if ((isFocused) && (!mHasFocus) && (checkNonFake == this))
  794. {
  795. mHasFocus = true;
  796. mSoftHasFocus = true;
  797. mGotFocusFunc(this);
  798. //OutputDebugStrF("Timer detected got focus %p\r\n", hWnd);
  799. }
  800. mSoftHasFocus = mHasFocus;
  801. gBFApp->Process();
  802. // Don't do anything with 'this' after Process, we may be deleted now
  803. doResult = true;
  804. result = 0;
  805. }
  806. break;
  807. case WM_SETCURSOR:
  808. gBFApp->PhysSetCursor();
  809. break;
  810. case WM_GETMINMAXINFO:
  811. {
  812. MINMAXINFO* minMaxInfo = (MINMAXINFO*)lParam;
  813. minMaxInfo->ptMinTrackSize.x = mMinWidth;
  814. minMaxInfo->ptMinTrackSize.y = mMinHeight;
  815. result = 0;
  816. doResult = true;
  817. }
  818. break;
  819. case WM_MOVE:
  820. case WM_MOVING:
  821. if (mMovedFunc != NULL)
  822. mMovedFunc(this);
  823. break;
  824. case WM_SIZING:
  825. mRenderWindow->Resized();
  826. if (mMovedFunc != NULL)
  827. mMovedFunc(this);
  828. if (gBFApp->mSysDialogCnt == 0)
  829. gBFApp->Process();
  830. break;
  831. }
  832. app->mInMsgProc = false;
  833. }
  834. else
  835. {
  836. // We got messages we couldn't process (due to reentrancy)
  837. switch (uMsg)
  838. {
  839. case WM_LBUTTONUP:
  840. case WM_RBUTTONUP:
  841. case WM_MBUTTONUP:
  842. case WM_MOUSEMOVE:
  843. case WM_KEYUP:
  844. case WM_MOUSELEAVE:
  845. mNeedsStateReset = true;
  846. break;
  847. }
  848. }
  849. if (doResult)
  850. return result;
  851. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  852. }
  853. LRESULT CALLBACK WinBFWindow::WindowProcStub(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  854. {
  855. WinBFWindow* aWindow = (WinBFWindow*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
  856. if (aWindow != NULL)
  857. return aWindow->WindowProc(hWnd, Msg, wParam, lParam);
  858. else
  859. return DefWindowProc(hWnd, Msg, wParam, lParam);
  860. }
  861. //
  862. static int WinBFReportHook( int reportType, char *message, int *returnValue )
  863. {
  864. if (reportType == 0)
  865. return 0;
  866. //__crtMessageWindowW(nRptType, szFile, (nLine ? szLineMessage : NULL), szModule, szUserMessage);;
  867. if (gBFApp)
  868. ((WinBFApp*) gBFApp)->mInMsgProc = true;
  869. int nCode = ::MessageBoxA(NULL, message,
  870. "Microsoft Visual C++ Debug Library",
  871. MB_TASKMODAL|MB_ICONHAND|MB_ABORTRETRYIGNORE|MB_SETFOREGROUND);
  872. if (gBFApp)
  873. ((WinBFApp*) gBFApp)->mInMsgProc = false;
  874. /* Abort: abort the program */
  875. if (IDABORT == nCode)
  876. {
  877. /* note that it is better NOT to call abort() here, because the
  878. * default implementation of abort() will call Watson
  879. */
  880. /* raise abort signal */
  881. raise(SIGABRT);
  882. /* We usually won't get here, but it's possible that
  883. SIGABRT was ignored. So exit the program anyway. */
  884. _exit(3);
  885. }
  886. /* Retry: return 1 to call the debugger */
  887. if (IDRETRY == nCode)
  888. return 1;
  889. /* Ignore: continue execution */
  890. return 0;
  891. return 1;
  892. }
  893. extern HINSTANCE gDLLInstance;
  894. WinBFApp::WinBFApp()
  895. {
  896. #ifndef BF_MINGW
  897. //_CrtSetReportHook(WinBFReportHook);
  898. #endif
  899. mRunning = false;
  900. mRenderDevice = NULL;
  901. mInstallDir = "Hey";
  902. WCHAR aStr[MAX_PATH];
  903. GetModuleFileNameW(gDLLInstance, aStr, MAX_PATH);
  904. mInstallDir = UTF8Encode(aStr);
  905. int a2DArray[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
  906. int lastSlash = (int) mInstallDir.LastIndexOf(L'\\');
  907. if (lastSlash != -1)
  908. mInstallDir = mInstallDir.Substring(0, lastSlash + 1);
  909. mDataDir = mInstallDir;
  910. mInMsgProc = false;
  911. mDSoundManager = NULL;
  912. }
  913. WinBFApp::~WinBFApp()
  914. {
  915. delete mRenderDevice;
  916. delete mDSoundManager;
  917. }
  918. void WinBFApp::Init()
  919. {
  920. BP_ZONE("WinBFApp::Init");
  921. mRunning = true;
  922. mInMsgProc = false;
  923. mRenderDevice = new DXRenderDevice();
  924. mRenderDevice->Init(this);
  925. }
  926. void WinBFApp::Run()
  927. {
  928. MSG msg;
  929. while (mRunning)
  930. {
  931. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  932. {
  933. TranslateMessage(&msg);
  934. DispatchMessage(&msg);
  935. }
  936. if (mRunning)
  937. Process();
  938. }
  939. }
  940. void WinBFApp::Draw()
  941. {
  942. mRenderDevice->FrameStart();
  943. BFApp::Draw();
  944. mRenderDevice->FrameEnd();
  945. }
  946. void WinBFApp::GetDesktopResolution(int& width, int& height)
  947. {
  948. width = ::GetSystemMetrics(SM_CXSCREEN);
  949. height = ::GetSystemMetrics(SM_CYSCREEN);
  950. }
  951. void WinBFApp::GetWorkspaceRect(int& x, int& y, int& width, int& height)
  952. {
  953. RECT desktopRect;
  954. ::SystemParametersInfo(SPI_GETWORKAREA, NULL, &desktopRect, NULL);
  955. x = desktopRect.left;
  956. y = desktopRect.top;
  957. width = desktopRect.right - desktopRect.left;
  958. height = desktopRect.bottom - desktopRect.top;
  959. }
  960. BFWindow* WinBFApp::CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)
  961. {
  962. BFWindow* aWindow = new WinBFWindow(parent, title, x, y, width, height, windowFlags);
  963. mWindowList.push_back(aWindow);
  964. return aWindow;
  965. }
  966. void WinBFApp::RehupMouse()
  967. {
  968. HWND windowAtPoint = ::WindowFromPoint(gLastScreenMouseCoords);
  969. for (auto window : mWindowList)
  970. {
  971. auto winWindow = (WinBFWindow*)window;
  972. winWindow->RehupMouseOver(winWindow->mHWnd == windowAtPoint);
  973. }
  974. }
  975. void WinBFWindow::SetMinimumSize(int minWidth, int minHeight, bool clientSized)
  976. {
  977. if (clientSized)
  978. {
  979. DWORD windowFlags = ::GetWindowLong(mHWnd, GWL_STYLE);
  980. DWORD windowFlagsEx = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
  981. RECT rect = { 0, 0, minWidth, minHeight };
  982. AdjustWindowRectEx(&rect, windowFlags, mMenu != NULL, windowFlagsEx);
  983. minWidth = rect.right - rect.left;
  984. minHeight = rect.bottom - rect.top;
  985. }
  986. mMinWidth = minWidth;
  987. mMinHeight = minHeight;
  988. if (mHWnd != NULL)
  989. {
  990. RECT windowRect;
  991. ::GetWindowRect(mHWnd, &windowRect);
  992. bool resized = false;
  993. if (windowRect.right - windowRect.left < minWidth)
  994. {
  995. windowRect.right = windowRect.left + minWidth;
  996. resized = true;
  997. }
  998. if (windowRect.bottom - windowRect.top < minHeight)
  999. {
  1000. windowRect.bottom = windowRect.top + minHeight;
  1001. resized = true;
  1002. }
  1003. if (resized)
  1004. {
  1005. ::MoveWindow(mHWnd, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE);
  1006. mRenderWindow->Resized();
  1007. if (mMovedFunc != NULL)
  1008. mMovedFunc(this);
  1009. }
  1010. }
  1011. }
  1012. void WinBFWindow::GetPosition(int* x, int* y, int* width, int* height, int* clientX, int* clientY, int* clientWidth, int* clientHeight)
  1013. {
  1014. RECT windowRect;
  1015. GetWindowRect(mHWnd, &windowRect);
  1016. RECT clientRect;
  1017. GetClientRect(mHWnd, &clientRect);
  1018. if (clientRect.right <= clientRect.left)
  1019. return; // TODO: return failure?
  1020. *x = windowRect.left;
  1021. *y = windowRect.top;
  1022. *width = windowRect.right - windowRect.left;
  1023. *height = windowRect.bottom - windowRect.top;
  1024. *clientWidth = clientRect.right - clientRect.left;
  1025. *clientHeight = clientRect.bottom - clientRect.top;
  1026. POINT startPt = {0, 0};
  1027. ::ClientToScreen(mHWnd, &startPt);
  1028. *clientX = startPt.x;
  1029. *clientY = startPt.y;
  1030. }
  1031. void WinBFWindow::Resize(int x, int y, int width, int height)
  1032. {
  1033. ::MoveWindow(mHWnd, x, y, width, height, FALSE);
  1034. mRenderWindow->Resized();
  1035. if (mMovedFunc != NULL)
  1036. mMovedFunc(this);
  1037. }
  1038. void WinBFApp::PhysSetCursor()
  1039. {
  1040. static HCURSOR cursors [] =
  1041. {
  1042. ::LoadCursor(NULL, IDC_ARROW),
  1043. //TODO: mApp->mHandCursor);
  1044. ::LoadCursor(NULL, IDC_HAND),
  1045. //TODO: mApp->mDraggingCursor);
  1046. ::LoadCursor(NULL, IDC_SIZEALL),
  1047. ::LoadCursor(NULL, IDC_IBEAM),
  1048. ::LoadCursor(NULL, IDC_NO),
  1049. ::LoadCursor(NULL, IDC_SIZEALL),
  1050. ::LoadCursor(NULL, IDC_SIZENESW),
  1051. ::LoadCursor(NULL, IDC_SIZENS),
  1052. ::LoadCursor(NULL, IDC_SIZENWSE),
  1053. ::LoadCursor(NULL, IDC_SIZEWE),
  1054. ::LoadCursor(NULL, IDC_WAIT),
  1055. NULL
  1056. };
  1057. ::SetCursor(cursors[mCursor]);
  1058. }
  1059. void WinBFWindow::SetClientPosition(int x, int y)
  1060. {
  1061. RECT rect;
  1062. ::GetClientRect(mHWnd, &rect);
  1063. ::OffsetRect(&rect, x, y);
  1064. LONG aStyle = ::GetWindowLong(mHWnd, GWL_STYLE);
  1065. LONG exStyle = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
  1066. ::AdjustWindowRectEx(&rect, aStyle, mMenu != NULL, exStyle);
  1067. ::MoveWindow(mHWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
  1068. if (mMovedFunc != NULL)
  1069. mMovedFunc(this);
  1070. }
  1071. void WinBFWindow::SetMouseVisible(bool isMouseVisible)
  1072. {
  1073. mMouseVisible = isMouseVisible;
  1074. LONG aStyle = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
  1075. if (!isMouseVisible)
  1076. aStyle |= WS_EX_TRANSPARENT;
  1077. else
  1078. aStyle &= ~WS_EX_TRANSPARENT;
  1079. ::SetWindowLong(mHWnd, GWL_EXSTYLE, aStyle);
  1080. }
  1081. void WinBFWindow::SetAlpha(float alpha, uint32 destAlphaSrcMask, bool isMouseVisible)
  1082. {
  1083. if (destAlphaSrcMask != 0)
  1084. {
  1085. if (mAlphaMaskBitmap == NULL)
  1086. {
  1087. RECT clientRect;
  1088. GetClientRect(mHWnd, &clientRect);
  1089. RECT windowRect;
  1090. GetWindowRect(mHWnd, &windowRect);
  1091. int aWidth = clientRect.right - clientRect.left;
  1092. int aHeight = clientRect.bottom - clientRect.top;
  1093. mAlphaMaskWidth = aWidth;
  1094. mAlphaMaskHeight = aHeight;
  1095. mAlphaMaskDC = CreateCompatibleDC(NULL);
  1096. BITMAPINFO bi = {};
  1097. bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1098. bi.bmiHeader.biBitCount = 32;
  1099. bi.bmiHeader.biWidth = aWidth;
  1100. bi.bmiHeader.biHeight = -aHeight;
  1101. bi.bmiHeader.biCompression = BI_RGB;
  1102. bi.bmiHeader.biPlanes = 1;
  1103. mAlphaMaskBitmap = CreateDIBSection(mAlphaMaskDC, &bi,
  1104. DIB_RGB_COLORS, (void**)&mAlphaMaskPixels, NULL, 0);
  1105. GdiFlush();
  1106. }
  1107. HDC hdc = GetDC(mHWnd);
  1108. if (hdc)
  1109. {
  1110. DXRenderWindow* renderWindow = (DXRenderWindow*) mRenderWindow;
  1111. renderWindow->CopyBitsTo(mAlphaMaskPixels, mAlphaMaskWidth, mAlphaMaskHeight);
  1112. //for (int i = 0; i < mAlphaMaskWidth*mAlphaMaskHeight/2; i++)
  1113. //mAlphaMaskPixels[i] = 0x80FF8000;
  1114. HGDIOBJ hPrevObj = 0;
  1115. POINT ptDest = {0, 0};
  1116. POINT ptSrc = {0, 0};
  1117. SIZE client = {mAlphaMaskWidth, mAlphaMaskHeight};
  1118. BLENDFUNCTION blendFunc = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
  1119. hPrevObj = SelectObject(mAlphaMaskDC, mAlphaMaskBitmap);
  1120. ClientToScreen(mHWnd, &ptDest);
  1121. BOOL worked = ::UpdateLayeredWindow(mHWnd, hdc, NULL, &client,
  1122. mAlphaMaskDC, &ptSrc, 0, &blendFunc, ULW_ALPHA);
  1123. DWORD error = GetLastError();
  1124. SelectObject(mAlphaMaskDC, hPrevObj);
  1125. ReleaseDC(mHWnd, hdc);
  1126. }
  1127. }
  1128. else
  1129. {
  1130. ::SetLayeredWindowAttributes(mHWnd, 0, (int) (alpha * 255), LWA_ALPHA);
  1131. }
  1132. SetMouseVisible(isMouseVisible);
  1133. }
  1134. void WinBFWindow::CaptureMouse()
  1135. {
  1136. //OutputDebugStrF("CaptureMouse() Capture HWnd: %X\n", mHWnd);
  1137. ::SetCapture(mHWnd);
  1138. for (auto window : gBFApp->mWindowList)
  1139. {
  1140. if (window == this)
  1141. continue;
  1142. for (int i = 0; i < MOUSEBUTTON_MAX; i++)
  1143. {
  1144. if (window->mIsMouseDown[i])
  1145. {
  1146. window->mMouseUpFunc(window, -1, -1, i);
  1147. window->mIsMouseDown[i] = false;
  1148. }
  1149. }
  1150. }
  1151. }
  1152. bool WinBFWindow::IsMouseCaptured()
  1153. {
  1154. return (mHWnd != NULL) && (GetCapture() == mHWnd);
  1155. }
  1156. uint32 WinBFApp::GetClipboardFormat(const StringImpl& format)
  1157. {
  1158. if (format == "text")
  1159. return CF_UNICODETEXT;
  1160. else if (format == "atext")
  1161. return CF_TEXT;
  1162. // StringToUIntMap::iterator itr = mClipboardFormatMap.find(format);
  1163. // if (itr != mClipboardFormatMap.end())
  1164. // return itr->second;
  1165. uint32 aFormat;
  1166. if (mClipboardFormatMap.TryGetValue(format, &aFormat))
  1167. return aFormat;
  1168. String sysFormatName = "BF_" + format;
  1169. aFormat = ::RegisterClipboardFormatA(sysFormatName.c_str());
  1170. mClipboardFormatMap[sysFormatName] = aFormat;
  1171. return aFormat;
  1172. }
  1173. void* WinBFApp::GetClipboardData(const StringImpl& format, int* size)
  1174. {
  1175. HWND aWindow = NULL;
  1176. if (!mWindowList.empty())
  1177. aWindow = ((WinBFWindow*) mWindowList.front())->mHWnd;
  1178. uint32 aFormat = GetClipboardFormat(format);
  1179. if (aFormat != 0)
  1180. {
  1181. if (OpenClipboard(aWindow))
  1182. {
  1183. HGLOBAL globalHandle = ::GetClipboardData(aFormat);
  1184. if (globalHandle == NULL)
  1185. {
  1186. if (format == "text")
  1187. {
  1188. int aSize = 0;
  1189. char* charPtr = (char*) GetClipboardData("atext", &aSize);
  1190. if (charPtr == NULL)
  1191. return NULL;
  1192. *size = (int)::GlobalSize(globalHandle);
  1193. void* aPtr = ::GlobalLock(globalHandle);
  1194. mLockedHGlobalMap[aPtr] = globalHandle;
  1195. CloseClipboard();
  1196. return aPtr;
  1197. }
  1198. CloseClipboard();
  1199. *size = 0;
  1200. return NULL;
  1201. }
  1202. *size = (int)::GlobalSize(globalHandle);
  1203. void* aPtr = ::GlobalLock(globalHandle);
  1204. static String utf8String;
  1205. utf8String = UTF8Encode((WCHAR*)aPtr);
  1206. ::GlobalUnlock(globalHandle);
  1207. CloseClipboard();
  1208. return (void*)utf8String.c_str();
  1209. }
  1210. }
  1211. *size = 0;
  1212. return NULL;
  1213. }
  1214. void WinBFApp::ReleaseClipboardData(void* ptr)
  1215. {
  1216. HGLOBAL globalHandle;
  1217. if (mLockedHGlobalMap.Remove(ptr, &globalHandle))
  1218. {
  1219. ::GlobalUnlock(globalHandle);
  1220. }
  1221. }
  1222. void WinBFApp::SetClipboardData(const StringImpl& format, const void* ptr, int size, bool resetClipboard)
  1223. {
  1224. BP_ZONE("WinBFApp::SetClipboardData");
  1225. HWND aWindow = NULL;
  1226. if (!mWindowList.empty())
  1227. aWindow = ((WinBFWindow*) mWindowList.front())->mHWnd;
  1228. uint32 aFormat = GetClipboardFormat(format);
  1229. if (aFormat != 0)
  1230. {
  1231. if (OpenClipboard(aWindow))
  1232. {
  1233. if (resetClipboard)
  1234. {
  1235. BP_ZONE("WinBFApp::SetClipboardData:empty");
  1236. EmptyClipboard();
  1237. }
  1238. if (format == "text")
  1239. {
  1240. BP_ZONE("WinBFApp::SetClipboardData:text");
  1241. HGLOBAL globalHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size * 2);
  1242. char* data = (char*)GlobalLock(globalHandle);
  1243. UTF16String wString;
  1244. //
  1245. {
  1246. BP_ZONE("WinBFApp::SetClipboardData:utf8decode");
  1247. wString = UTF8Decode((char*)ptr);
  1248. }
  1249. memcpy(data, wString.c_str(), size * 2);
  1250. GlobalUnlock(globalHandle);
  1251. ::SetClipboardData(CF_UNICODETEXT, globalHandle);
  1252. }
  1253. else if (format == "atext")
  1254. {
  1255. HGLOBAL globalHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
  1256. char* data = (char*)GlobalLock(globalHandle);
  1257. memcpy(data, ptr, size);
  1258. GlobalUnlock(globalHandle);
  1259. ::SetClipboardData(CF_TEXT, globalHandle);
  1260. }
  1261. CloseClipboard();
  1262. }
  1263. }
  1264. /*if (format == "text")
  1265. {
  1266. //String aString = ToString((const WCHAR*) ptr);
  1267. String aString = (const char*)ptr;
  1268. SetClipboardData("atext", aString.c_str(), (int)aString.length() + 1, false);
  1269. }*/
  1270. }
  1271. BFMenu* WinBFWindow::AddMenuItem(BFMenu* parent, int insertIdx, const char* text, const char* hotKey, BFSysBitmap* sysBitmap, bool enabled, int checkState, bool radioCheck)
  1272. {
  1273. UTF16String lText;
  1274. if (text != NULL)
  1275. lText = UTF8Decode(text);
  1276. UTF16String lHotKey;
  1277. if (hotKey != NULL)
  1278. lHotKey = UTF8Decode(hotKey);
  1279. bool wasEmpty = mMenu->mBFMenuList.size() == 0;
  1280. if (parent == NULL)
  1281. parent = mMenu;
  1282. if ((parent->mBFMenuList.size() == 1) && (((WinBFMenu*) parent->mBFMenuList.front())->mIsPlaceholder))
  1283. {
  1284. // Get rid of placeholder menu item
  1285. auto placeholderMenuItem = parent->mBFMenuList.front();
  1286. RemoveMenuItem(placeholderMenuItem);
  1287. delete placeholderMenuItem;
  1288. }
  1289. WinBFMenu* winBFMenuParent = (WinBFMenu*) parent;
  1290. WinBFMenu* newMenu = new WinBFMenu();
  1291. newMenu->mMenuId = ++WinBFMenu::mMenuCount;
  1292. newMenu->mParent = parent;
  1293. //static int allocIdx = 0;
  1294. //allocIdx++;
  1295. //OutputDebugStrF("MenuIdx %d %@\n", allocIdx, newMenu);
  1296. if ((winBFMenuParent != NULL) && (winBFMenuParent->mMenu == NULL))
  1297. {
  1298. winBFMenuParent->mMenu = ::CreateMenu();
  1299. mHMenuMap[winBFMenuParent->mMenu] = winBFMenuParent;
  1300. MENUITEMINFO menuItem;
  1301. memset(&menuItem, 0, sizeof(MENUITEMINFO));
  1302. menuItem.cbSize = sizeof(MENUITEMINFO);
  1303. menuItem.fMask = MIIM_SUBMENU;
  1304. menuItem.hSubMenu = winBFMenuParent->mMenu;
  1305. ::SetMenuItemInfo(((WinBFMenu*) winBFMenuParent->mParent)->mMenu, winBFMenuParent->mMenuId, FALSE, &menuItem);
  1306. }
  1307. mMenuIDMap[newMenu->mMenuId] = newMenu;
  1308. BF_ASSERT(insertIdx <= (int) parent->mBFMenuList.size());
  1309. ////
  1310. UTF16String lCombinedName;
  1311. MENUITEMINFOW menuItem;
  1312. memset(&menuItem, 0, sizeof(MENUITEMINFO));
  1313. menuItem.cbSize = sizeof(MENUITEMINFO);
  1314. menuItem.fMask = MIIM_FTYPE | MIIM_ID;
  1315. if (text != NULL)
  1316. {
  1317. menuItem.fMask |= MIIM_STRING;
  1318. menuItem.fType = MFT_STRING;
  1319. }
  1320. else
  1321. menuItem.fType = MFT_SEPARATOR;
  1322. menuItem.fState = enabled ? MFS_DEFAULT : MFS_GRAYED;
  1323. if (checkState == 0)
  1324. menuItem.fState |= MFS_UNCHECKED;
  1325. if (checkState == 1)
  1326. menuItem.fState |= MFS_CHECKED;
  1327. if (radioCheck)
  1328. menuItem.fType = MFT_RADIOCHECK;
  1329. menuItem.wID = newMenu->mMenuId;
  1330. if (text != NULL)
  1331. {
  1332. menuItem.dwTypeData = (WCHAR*)lText.c_str();
  1333. }
  1334. if (hotKey != NULL)
  1335. {
  1336. String combinedName = String(text);
  1337. combinedName += "\t";
  1338. if (hotKey[0] == '#')
  1339. {
  1340. combinedName += hotKey + 1;
  1341. }
  1342. else
  1343. {
  1344. combinedName += hotKey;
  1345. newMenu->ParseHotKey(hotKey);
  1346. }
  1347. lCombinedName = UTF8Decode(combinedName);
  1348. menuItem.dwTypeData = (WCHAR*)lCombinedName.c_str();
  1349. }
  1350. ::InsertMenuItemW(winBFMenuParent->mMenu, insertIdx, TRUE, &menuItem);
  1351. ////////
  1352. /*MENUITEMINFO menuItem;
  1353. memset(&menuItem, 0, sizeof(MENUITEMINFO));
  1354. menuItem.cbSize = sizeof(MENUITEMINFO);
  1355. menuItem.fMask = MIIM_ID;
  1356. menuItem.wID = newMenu->mMenuId;
  1357. ::InsertMenuItem(winBFMenuParent->mMenu, insertIdx, TRUE, &menuItem);*/
  1358. ModifyMenuItem(newMenu, text, hotKey, sysBitmap, enabled, checkState, radioCheck);
  1359. parent->mBFMenuList.push_back(newMenu);
  1360. return newMenu;
  1361. }
  1362. void WinBFWindow::ModifyMenuItem(BFMenu* item, const char* text, const char* hotKey, BFSysBitmap* sysBitmap, bool enabled, int checkState, bool radioCheck)
  1363. {
  1364. UTF16String lText;
  1365. if (text != NULL)
  1366. lText = UTF8Decode(text);
  1367. UTF16String lHotKey;
  1368. if (hotKey != NULL)
  1369. lHotKey = UTF8Decode(hotKey);
  1370. WinBFMenu* aMenu = (WinBFMenu*)item;
  1371. WinBFMenu* parentMenu = (WinBFMenu*) item->mParent;
  1372. UTF16String lCombinedName;
  1373. MENUITEMINFOW menuItem;
  1374. memset(&menuItem, 0, sizeof(MENUITEMINFO));
  1375. menuItem.cbSize = sizeof(MENUITEMINFO);
  1376. menuItem.fMask = MIIM_FTYPE | MIIM_ID;
  1377. ::GetMenuItemInfoW(parentMenu->mMenu, aMenu->mMenuId, FALSE, &menuItem);
  1378. menuItem.fMask |= MIIM_STATE;
  1379. if (text != NULL)
  1380. {
  1381. menuItem.fMask |= MIIM_STRING;
  1382. //menuItem.fType = MFT_STRING;
  1383. }
  1384. /*else
  1385. menuItem.fType = MFT_SEPARATOR;*/
  1386. menuItem.fState = enabled ? /*MFS_DEFAULT*/0 : MFS_GRAYED;
  1387. if (checkState != -1)
  1388. {
  1389. menuItem.fMask |= MIIM_CHECKMARKS;
  1390. }
  1391. if (checkState == 0)
  1392. menuItem.fState |= MFS_UNCHECKED;
  1393. if (checkState == 1)
  1394. menuItem.fState |= MFS_CHECKED;
  1395. if (radioCheck)
  1396. menuItem.fType = MFT_RADIOCHECK;
  1397. menuItem.wID = aMenu->mMenuId;
  1398. menuItem.dwTypeData = (WCHAR*)lText.c_str();
  1399. if (hotKey != NULL)
  1400. {
  1401. menuItem.fMask |= MIIM_DATA;
  1402. String combinedName = String(text);
  1403. combinedName += "\t";
  1404. if (hotKey[0] == '#')
  1405. {
  1406. combinedName += hotKey + 1;
  1407. }
  1408. else
  1409. {
  1410. combinedName += hotKey;
  1411. aMenu->ParseHotKey(hotKey);
  1412. }
  1413. lCombinedName = UTF8Decode(combinedName);
  1414. menuItem.dwTypeData = (WCHAR*)lCombinedName.c_str();
  1415. }
  1416. ::SetMenuItemInfoW(parentMenu->mMenu, aMenu->mMenuId, FALSE, &menuItem);
  1417. }
  1418. void WinBFWindow::RemoveMenuItem(BFMenu* item)
  1419. {
  1420. WinBFMenu* aMenu = (WinBFMenu*) item;
  1421. WinBFMenu* parentMenu = (WinBFMenu*) item->mParent;
  1422. //auto itr = mMenuIDMap.find(aMenu->mMenuId);
  1423. //mMenuIDMap.erase(itr);
  1424. mMenuIDMap.Remove(aMenu->mMenuId);
  1425. ::RemoveMenu(parentMenu->mMenu, aMenu->mMenuId, MF_BYCOMMAND);
  1426. }
  1427. BFSysBitmap* WinBFApp::LoadSysBitmap(const WCHAR* fileName)
  1428. {
  1429. return NULL;
  1430. }
  1431. BFSoundManager* WinBFApp::GetSoundManager()
  1432. {
  1433. if (mDSoundManager == NULL)
  1434. mDSoundManager = new DSoundManager(NULL);
  1435. return mDSoundManager;
  1436. }
  1437. void WinBFWindow::ModalsRemoved()
  1438. {
  1439. ::EnableWindow(mHWnd, TRUE);
  1440. if (mChildren.empty())
  1441. ::SetFocus(mHWnd);
  1442. }
  1443. DrawLayer* WinBFApp::CreateDrawLayer(BFWindow* window)
  1444. {
  1445. DXDrawLayer* drawLayer = new DXDrawLayer();
  1446. if (window != NULL)
  1447. {
  1448. drawLayer->mRenderWindow = window->mRenderWindow;
  1449. window->mRenderWindow->mDrawLayerList.push_back(drawLayer);
  1450. }
  1451. drawLayer->mRenderDevice = mRenderDevice;
  1452. return drawLayer;
  1453. }