ソースを参照

Multi-monitor fixes

Brian Fiete 5 年 前
コミット
26604017f8

+ 16 - 0
BeefLibs/Beefy2D/src/BFApp.bf

@@ -81,6 +81,9 @@ namespace Beefy
         [StdCall, CLink]
         static extern void BFApp_GetWorkspaceRect(out int32 x, out int32 y, out int32 width, out int32 height);
 
+		[StdCall, CLink]
+		static extern void BFApp_GetWorkspaceRectFrom(int32 x, int32 y, int32 width, int32 height, out int32 outX, out int32 outY, out int32 outWidth, out int32 outHeight);
+
         [StdCall, CLink]
         static extern void BFApp_Create();
 
@@ -447,6 +450,19 @@ namespace Beefy
 			height = heightOut;
         }
 
+		public void GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, out int outX, out int outY, out int outWidth, out int outHeight)
+		{
+			int32 xOut;
+			int32 yOut;
+			int32 widthOut;
+			int32 heightOut;
+		    BFApp_GetWorkspaceRectFrom((.)fromX, (.)fromY, (.)fromWidth, (.)fromHeight, out xOut, out yOut, out widthOut, out heightOut);
+			outX = xOut;
+			outY = yOut;
+			outWidth = widthOut;
+			outHeight = heightOut;
+		}
+
         public bool HasModalDialogs()
         {
             for (var window in mWindows)

+ 1 - 1
BeefLibs/Beefy2D/src/theme/dark/DarkTooltip.bf

@@ -51,7 +51,7 @@ namespace Beefy.theme.dark
             mText = new String(text);
             mAllowResize = allowResize;
 
-			BFApp.sApp.GetWorkspaceRect(var workspaceX, var workspaceY, var workspaceWidth, var workspaceHeight);
+			BFApp.sApp.GetWorkspaceRectFrom((.)x, (.)y, 0, 0, var workspaceX, var workspaceY, var workspaceWidth, var workspaceHeight);
 			float maxWidth = workspaceWidth - GS!(32);
 
             FontMetrics fontMetrics = .();

+ 9 - 5
BeefLibs/Beefy2D/src/widgets/Menu.bf

@@ -178,7 +178,7 @@ namespace Beefy.widgets
             base.Resize(x, y, width, height);
         }
 
-        public virtual void CalcContainerSize(MenuContainer menuContainer, bool allowScrollable, ref float screenX, ref float screenY, out float width, out float height)
+        public virtual void CalcContainerSize(float x, float y, MenuContainer menuContainer, bool allowScrollable, ref float screenX, ref float screenY, out float width, out float height)
         {
             Rect menuRect = menuContainer.CalcRectFromContent();
             width = Math.Min(mMaxContainerWidth, Math.Max(mMinContainerWidth, menuRect.mWidth));
@@ -188,7 +188,7 @@ namespace Beefy.widgets
             int workspaceY;
             int workspaceWidth;
             int workspaceHeight;
-            BFApp.sApp.GetWorkspaceRect(out workspaceX, out workspaceY, out workspaceWidth, out workspaceHeight);
+            BFApp.sApp.GetWorkspaceRectFrom((.)x, (.)y, 0, 0, out workspaceX, out workspaceY, out workspaceWidth, out workspaceHeight);
 
 			float maxY = workspaceY + workspaceHeight;
 
@@ -250,13 +250,14 @@ namespace Beefy.widgets
 				float screenX;
 				float screenY;
 				relativeWidget.SelfToRootTranslate(0, curY, out screenX, out screenY);
+				screenX += relativeWidget.mWidgetWindow.mClientX;
 				screenY += relativeWidget.mWidgetWindow.mClientY;
 
 				int wsX;
 				int wsY;
 				int wsWidth;
 				int wsHeight;
-				BFApp.sApp.GetWorkspaceRect(out wsX, out wsY, out wsWidth, out wsHeight);
+				BFApp.sApp.GetWorkspaceRectFrom((.)screenX, (.)screenY, 0, 0, out wsX, out wsY, out wsWidth, out wsHeight);
 				float spaceLeft = (wsY + wsHeight) - (screenY);
 				if (spaceLeft < minHeight)
 				{
@@ -299,7 +300,10 @@ namespace Beefy.widgets
 
                 float screenWidth;
                 float screenHeight;
-                CalcContainerSize(menuContainer, allowScrollable, ref screenX, ref screenY, out screenWidth, out screenHeight);
+                CalcContainerSize(screenX, screenY, menuContainer, allowScrollable, ref screenX, ref screenY, out screenWidth, out screenHeight);
+
+				screenWidth = Math.Max(screenWidth, 32);
+				screenHeight = Math.Max(screenHeight, 32);
 
 				WidgetWindow parentWindow = (relativeWidget != null) ? relativeWidget.mWidgetWindow : null;
                 curWidgetWindow = new WidgetWindow(parentWindow,
@@ -332,7 +336,7 @@ namespace Beefy.widgets
 
                 float screenWidth;
                 float screenHeight;
-                CalcContainerSize(menuContainer, allowScrollable, ref screenX, ref screenY, out screenWidth, out screenHeight);
+                CalcContainerSize(x, y, menuContainer, allowScrollable, ref screenX, ref screenY, out screenWidth, out screenHeight);
 
                 curWidgetWindow.Resize((int32)(screenX), (int32)(screenY),
                     (int32)screenWidth, (int32)screenHeight);

+ 1 - 0
BeefySysLib/BFApp.h

@@ -88,6 +88,7 @@ public:
 	virtual void			SetCursor(int cursor);
 	virtual void			GetDesktopResolution(int& width, int& height) = 0;
 	virtual void			GetWorkspaceRect(int& x, int& y, int& width, int& height) = 0;
+	virtual void			GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int& outX, int& outY, int& outWidth, int& outHeight) { GetWorkspaceRect(outX, outY, outWidth, outHeight); }
 
 	virtual BFWindow*		CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags) = 0;
 	virtual void			RemoveWindow(BFWindow* window);

+ 5 - 0
BeefySysLib/BeefySysLib.cpp

@@ -79,6 +79,11 @@ BF_EXPORT void BF_CALLTYPE BFApp_GetWorkspaceRect(int& x, int& y, int& width, in
 	gBFApp->GetWorkspaceRect(x, y, width, height);
 }
 
+BF_EXPORT void BF_CALLTYPE BFApp_GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int& outX, int& outY, int& outWidth, int& outHeight)
+{
+	gBFApp->GetWorkspaceRectFrom(fromX, fromY, fromWidth, fromHeight, outX, outY, outWidth, outHeight);
+}
+
 BF_EXPORT void BF_CALLTYPE BFApp_Create()
 {
 	new PlatformBFApp();

+ 98 - 24
BeefySysLib/platform/win/WinBFApp.cpp

@@ -43,6 +43,38 @@ static BOOL CALLBACK BFEnumResNameProc(
 	return FALSE;
 }
 
+struct AdjustedMonRect
+{
+	int mMonCount;
+	int mX;
+	int mY;
+	int mWidth;
+	int mHeight;
+};
+
+static BOOL ClipToMonitor(HMONITOR mon, HDC hdc, LPRECT monRect, LPARAM userArg)
+{
+	AdjustedMonRect* outRect = (AdjustedMonRect*)userArg;
+	
+	MONITORINFO monitorInfo = { sizeof(MONITORINFO) };
+	if (::GetMonitorInfo(mon, &monitorInfo) == 0)
+		return TRUE;
+
+	outRect->mMonCount++;
+	
+	if (outRect->mX < monitorInfo.rcWork.left)
+		outRect->mX = monitorInfo.rcWork.left;
+ 	else if (outRect->mX + outRect->mWidth >= monitorInfo.rcWork.right)
+		outRect->mX = BF_MAX((int)monitorInfo.rcWork.left, monitorInfo.rcWork.right - outRect->mWidth);
+ 
+ 	if (outRect->mY < monitorInfo.rcWork.top)
+		outRect->mY = monitorInfo.rcWork.top;
+ 	else if (outRect->mY + outRect->mHeight >= monitorInfo.rcWork.bottom)
+		outRect->mY = BF_MAX((int)monitorInfo.rcWork.top, monitorInfo.rcWork.bottom - outRect->mHeight);
+	
+	return TRUE;
+}
+
 WinBFWindow::WinBFWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)
 {
 	HINSTANCE hInstance = GetModuleHandle(NULL);
@@ -128,18 +160,16 @@ WinBFWindow::WinBFWindow(BFWindow* parent, const StringImpl& title, int x, int y
 	
 	if (windowFlags & BFWINDOW_POPUP_POSITION)
 	{
-		RECT desktopRect;
-		::SystemParametersInfo(SPI_GETWORKAREA, NULL, &desktopRect, NULL);		
-
-		if (x < desktopRect.left)
-			x = desktopRect.left;
-		else if (x + width >= desktopRect.right)
-			x = BF_MAX((int)desktopRect.left, desktopRect.right - width);
-
-		if (y < desktopRect.top)
-			y = desktopRect.top;
-		else if (y + height >= desktopRect.bottom)
-			y = BF_MAX((int)desktopRect.top, desktopRect.bottom - height);
+		AdjustedMonRect adjustRect = { 0, x, y, width, height };		
+		RECT wantRect = { x, y, x + width, y + height };
+
+		EnumDisplayMonitors(NULL, &wantRect, ClipToMonitor, (LPARAM)&adjustRect);
+		if (adjustRect.mMonCount == 0)
+			EnumDisplayMonitors(NULL, NULL, ClipToMonitor, (LPARAM)&adjustRect);
+		x = adjustRect.mX;
+		y = adjustRect.mY;
+		width = adjustRect.mWidth;
+		height = adjustRect.mHeight;
 	}
 	
 	mFlags = windowFlags;
@@ -1128,26 +1158,70 @@ void WinBFApp::GetDesktopResolution(int& width, int& height)
 	height = ::GetSystemMetrics(SM_CYSCREEN);
 }
 
-void WinBFApp::GetWorkspaceRect(int& x, int& y, int& width, int& height)
+static BOOL InflateRectToMonitor(HMONITOR mon, HDC hdc, LPRECT monRect, LPARAM userArg)
 {
-	RECT desktopRect;
+	AdjustedMonRect* inflatedRect = (AdjustedMonRect*)userArg;
 
-	if (::GetSystemMetrics(SM_CMONITORS) > 1) 
+	MONITORINFO monitorInfo = { sizeof(MONITORINFO) };
+	if (::GetMonitorInfo(mon, &monitorInfo) == 0)
+		return TRUE;
+
+	inflatedRect->mMonCount++;
+	if (inflatedRect->mMonCount == 1)
 	{
-		desktopRect.left = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
-		desktopRect.right = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
-		desktopRect.top = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
-		desktopRect.bottom = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
+		inflatedRect->mX = monitorInfo.rcWork.left;
+		inflatedRect->mY = monitorInfo.rcWork.top;
+		inflatedRect->mWidth = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
+		inflatedRect->mHeight = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
 	}
 	else
 	{
-		::SystemParametersInfo(SPI_GETWORKAREA, NULL, &desktopRect, NULL);	
+		int minLeft = BF_MIN(inflatedRect->mX, monitorInfo.rcWork.left);
+		int minTop = BF_MIN(inflatedRect->mY, monitorInfo.rcWork.top);
+		int maxRight = BF_MAX(inflatedRect->mX + inflatedRect->mWidth, monitorInfo.rcWork.right);
+		int maxBottom = BF_MAX(inflatedRect->mY + inflatedRect->mHeight, monitorInfo.rcWork.bottom);
+
+		inflatedRect->mX = minLeft;
+		inflatedRect->mY = minTop;
+		inflatedRect->mWidth = maxRight - minLeft;
+		inflatedRect->mHeight = maxBottom - minTop;
+	}
+
+	return TRUE;
+}
+
+void WinBFApp::GetWorkspaceRect(int& x, int& y, int& width, int& height)
+{	
+	AdjustedMonRect inflateRect = { 0 };
+
+	EnumDisplayMonitors(NULL, NULL, InflateRectToMonitor, (LPARAM)&inflateRect);
+	x = inflateRect.mX;
+	y = inflateRect.mY;
+	width = inflateRect.mWidth;
+	height = inflateRect.mHeight;
+}
+
+void WinBFApp::GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int & outX, int & outY, int & outWidth, int & outHeight)
+{
+	AdjustedMonRect inflateRect = { 0 };
+
+	RECT wantRect;
+	wantRect.left = fromX;
+	wantRect.top = fromY;
+	wantRect.right = fromX + BF_MAX(fromWidth, 1);
+	wantRect.bottom = fromY + BF_MAX(fromHeight, 1);
+	EnumDisplayMonitors(NULL, &wantRect, InflateRectToMonitor, (LPARAM)&inflateRect);
+
+	if (inflateRect.mMonCount == 0)
+	{
+		GetWorkspaceRect(outX, outY, outWidth, outHeight);
+		return;
 	}
 
-	x = desktopRect.left;
-	y = desktopRect.top;
-	width = desktopRect.right - desktopRect.left;
-	height = desktopRect.bottom - desktopRect.top;
+	outX = inflateRect.mX;
+	outY = inflateRect.mY;
+	outWidth = inflateRect.mWidth;
+	outHeight = inflateRect.mHeight;
 }
 
 BFWindow* WinBFApp::CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)

+ 3 - 2
BeefySysLib/platform/win/WinBFApp.h

@@ -105,8 +105,9 @@ public:
 	virtual void			Init() override;
 	virtual void			Run() override;		
 
-	virtual void			GetDesktopResolution(int& width, int& height);
-	virtual void			GetWorkspaceRect(int& x, int& y, int& width, int& height);
+	virtual void			GetDesktopResolution(int& width, int& height) override;
+	virtual void			GetWorkspaceRect(int& x, int& y, int& width, int& height) override;
+	virtual void			GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int& outX, int& outY, int& outWidth, int& outHeight) override;
 	virtual BFWindow*		CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags) override;	
 	virtual DrawLayer*		CreateDrawLayer(BFWindow* window);
 

+ 1 - 1
IDE/src/IDEApp.bf

@@ -10572,7 +10572,7 @@ namespace IDE
 			//
 			{
 				BFWindow.Flags flags = .Border | .ThickFrame | .Resizable | .SysMenu |
-	                .Caption | .Minimize | .Maximize | .QuitOnClose | .Menu;
+	                .Caption | .Minimize | .Maximize | .QuitOnClose | .Menu | .PopupPosition;
 				if (mRunningTestScript)
 					flags |= .NoActivate;