diff options
author | Alex Corrado <alexc@xamarin.com> | 2013-11-15 00:37:23 +0400 |
---|---|---|
committer | Alex Corrado <alexc@xamarin.com> | 2013-11-15 00:47:27 +0400 |
commit | 0f6541f64866b6f45efd111fa116adf93694f48d (patch) | |
tree | 54b72321a4f5fa16f26faee65ed6772fc287ed86 /Xwt.WPF | |
parent | de09ae41195dd7c703cdc36a5b98de6865568e06 (diff) |
[WPF] Improve GetScaleFactor and return device-independent pixels from GetMouseLocation
This enables us to use the value of Desktop.MouseLocation to accurately set the
ScreenBounds of a window on WPF.
Diffstat (limited to 'Xwt.WPF')
-rw-r--r-- | Xwt.WPF/Xwt.WPFBackend/WpfDesktopBackend.cs | 62 |
1 files changed, 44 insertions, 18 deletions
diff --git a/Xwt.WPF/Xwt.WPFBackend/WpfDesktopBackend.cs b/Xwt.WPF/Xwt.WPFBackend/WpfDesktopBackend.cs index 1a0fa7e9..6eb8b7c7 100644 --- a/Xwt.WPF/Xwt.WPFBackend/WpfDesktopBackend.cs +++ b/Xwt.WPF/Xwt.WPFBackend/WpfDesktopBackend.cs @@ -23,7 +23,8 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -using System; +using System;
+using System.Reflection; using System.Runtime.InteropServices; using Xwt.Backends; using SWF = System.Windows.Forms; @@ -42,31 +43,54 @@ namespace Xwt.WPFBackend { System.Windows.Application.Current.Dispatcher.BeginInvoke (new Action (OnScreensChanged)); }; - } + }
+ static bool cannotCallGetDpiForMonitor; public override double GetScaleFactor (object backend) - { - var hdc = GetDC (IntPtr.Zero); - if (hdc == IntPtr.Zero) { - // GetDC failed for some reason - return base.GetScaleFactor (backend); - } - try { - //FIXME: Is it possible for the Y dpi to differ from the X dpi, - // and if so, what should we do about it? - var dpiX = GetDeviceCaps (hdc, LOGPIXELSX); - return dpiX / BASELINE_DPI; - } finally { - ReleaseDC (IntPtr.Zero, hdc); - } + {
+ //FIXME: Is it possible for the Y dpi to differ from the X dpi,
+ // and if so, what should we do about it?
+ int dpi = (int)BASELINE_DPI; + + // In Windows 8.1, there can be a different dpi per monitor
+ if (!cannotCallGetDpiForMonitor) {
+ // .. I wish there was a less hacky way of getting the HMONITOR from the SWF.Screen :/
+ var hmonitorField = typeof (SWF.Screen).GetField ("hmonitor", BindingFlags.Instance | BindingFlags.NonPublic);
+ if (hmonitorField == null) {
+ cannotCallGetDpiForMonitor = true;
+ } else {
+ try {
+ int dpiY;
+ GetDpiForMonitor ((IntPtr)hmonitorField.GetValue (backend), MDT_Effective_DPI, out dpi, out dpiY);
+ } catch {
+ cannotCallGetDpiForMonitor = true;
+ }
+ }
+ }
+ if (cannotCallGetDpiForMonitor) {
+ // Get system-wide dpi
+ var hdc = GetDC (IntPtr.Zero);
+ if (hdc != IntPtr.Zero) {
+ try {
+ dpi = GetDeviceCaps (hdc, LOGPIXELSX);
+ } finally {
+ ReleaseDC (IntPtr.Zero, hdc);
+ }
+ } + }
+ return dpi / BASELINE_DPI; } #region implemented abstract members of DesktopBackend public override Point GetMouseLocation() { - var loc = SWF.Cursor.Position; - return new Point (loc.X, loc.Y); + var loc = SWF.Cursor.Position;
+ var screen = SWF.Screen.FromPoint (loc);
+ var scale = GetScaleFactor (screen); + + // We need to convert the device pixels into WPF's device-independent pixels.. + return new Point (loc.X / scale, loc.Y / scale); } public override IEnumerable<object> GetScreens () @@ -102,10 +126,12 @@ namespace Xwt.WPFBackend const int LOGPIXELSX = 88; const int LOGPIXELSY = 90; + const int MDT_Effective_DPI = 0; [DllImport ("user32")] static extern IntPtr GetDC (IntPtr hWnd); [DllImport ("user32")] static extern int ReleaseDC (IntPtr hWnd, IntPtr hdc); [DllImport ("gdi32")] static extern int GetDeviceCaps (IntPtr hdc, int nIndex); + [DllImport ("Shcore")] static extern int GetDpiForMonitor (IntPtr hmonitor, int dpiType, out int dpiX, out int dpiY); #endregion } } |