void MetroWindow_WindowDpiChanged(object sender, EventArgs e) { var window = (MetroWindow)sender; UpdateMainWindowDpi(window); DpiChanged?.Invoke(this, new WindowDpiChangedEventArgs(window)); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Callback, called when the window procedure. </summary> /// /// <param name="message"> [in,out] The message. </param> /// /// <returns> An int. </returns> //////////////////////////////////////////////////////////////////////////////////////////////////// private bool WndProcCallback(ref WindowHookManager.HookMessage message) { switch (message.HookMsgType) { case WindowHookManager.HookMsgType.DPICHANGED: //Note that if the method is enabled and handles scaling, I am afraid to return // true because the originally installed WndProc will not be called and I don't // know what effect that will have regarding a DPI change. Considering that // this entire class removes the window border and TitleBar, there shouldn't be // any issue related to returning false and allowing other listeners to be // notified. _ = ScaleContentForDpiIfEnabled(); DpiChanged?.Invoke(this, EventArgs.Empty); break; case WindowHookManager.HookMsgType.WINDOWPOSCHANGED: LocationChanged?.Invoke(this, EventArgs.Empty); break; } //If you do not handle the message then return false. There may be times when you handle the // message and still need to return false so that other custom callbacks as well as the // original WndProc that was attached to the Window can be called. return(false); }
private void InitDpi() { using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero)) { RawDpiX = graphics.DpiX; RawDpiY = graphics.DpiY; ScalingFactor = RawDpiX / 96f; DpiChanged?.Invoke(); } }
private void UpdateDpi() { var displayInformation = Windows.Graphics.Display.DisplayInformation.GetForCurrentView(); ScalingFactor = displayInformation.LogicalDpi / 96f; RawDpiX = displayInformation.RawDpiX; RawDpiY = displayInformation.RawDpiY; DpiChanged?.Invoke(); }
private IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch ((Utils.WM)msg) { case Utils.WM.WM_DPICHANGED: Utils.RECT rect = (Utils.RECT)Marshal.PtrToStructure(lParam, typeof(Utils.RECT)); if (rect.left != -32000 && rect.top != -32000) { Utils.MySetWindowPos(hwnd, new Rect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top)); DpiChanged?.Invoke(); } break; } return(IntPtr.Zero); }
private void CheckRenderLoopEvents() { //WaitOne(0) checks state without blocking if (_ctrlResized.WaitOne(0)) { if (AutoResize) { ChangeResolution(_prevClientWidth, _prevClientHeight); } } if (_ctrlDpiChanged.WaitOne(0)) { DpiChanged?.Invoke(this, EventArgs.Empty); } }
/// <summary> /// Raises the <see cref="E:DpiChanged" /> event. /// </summary> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> protected virtual void OnDpiChanged(EventArgs e) { DpiChanged?.Invoke(this, e); }
private void OnWindowDpiChanged(int newDpi) { WindowDpiChangedEventArgs windowDpiChangedEvent = new(this, newDpi); DpiChanged.Invoke(this, windowDpiChangedEvent); }
private void ChangeDpi(WindowStatus status = WindowStatus.None) { if (Interlocked.CompareExchange(ref _blocker, new object(), null) != null) { return; } try { // Take information which is to be tested from _dueInfo and set null in return. var testInfo = Interlocked.Exchange(ref _dueInfo, null); while (testInfo != null) { var testRect = new Rect(new Point(_targetWindow.Left, _targetWindow.Top), testInfo.Size); bool changesNow = true; switch (status) { case WindowStatus.None: case WindowStatus.SizeChanged: // None. break; case WindowStatus.LocationChanged: // Determine whether to reflect information now. var testDpi = DpiChecker.GetDpiFromRect(testRect); changesNow = testInfo.Dpi.Equals(testDpi); break; } if (changesNow) { // Update WindowDpi first so that it can provide new DPI during succeeding changes in target // Window. var oldDpi = WindowDpi; WindowDpi = testInfo.Dpi; switch (status) { case WindowStatus.None: case WindowStatus.LocationChanged: // Change location and size of target Window. Setting these properties may fire // LocationChanged and SizeChanged events twice in target Window. However, to use // SetWindowPos function, a complicated conversion of coordinates is required. // Also, it may cause a problem in applying styles if used in OnSourceInitialized // method. Debug.WriteLine($"Old Size: {_targetWindow.Width}-{_targetWindow.Height}"); _targetWindow.Left = testRect.Left; _targetWindow.Top = testRect.Top; _targetWindow.Width = testRect.Width; _targetWindow.Height = testRect.Height; Debug.WriteLine($"New Size: {_targetWindow.Width}-{_targetWindow.Height}"); break; case WindowStatus.SizeChanged: // None. break; } // Scale contents of target Window. var content = _targetElement ?? _targetWindow.Content as FrameworkElement; if (content != null) { content.LayoutTransform = (testInfo.Dpi.Equals(SystemDpi)) ? Transform.Identity : new ScaleTransform( (double)WindowDpi.X / SystemDpi.X, (double)WindowDpi.Y / SystemDpi.Y); } // Fire DpiChanged event last so that it can be utilized to supplement preceding changes // in target Window. DpiChanged?.Invoke(this, new DpiChangedEventArgs(oldDpi, WindowDpi)); // Take new information which is to be tested from _dueInfo again for the case where new // information has been stored during this operation. If there is new information, repeat // the operation. testInfo = Interlocked.Exchange(ref _dueInfo, null); } else { // Store old information which has been tested but determined not to be reflected now to // _dueInfo and take new information in return. If there is new information, repeat // the operation. If not, old information stored back may be overwritten by new information // later but has a chance to be tested again in the case where it is the last information // at this move/resize. In such case, the information may be tested at next move/resize. testInfo = Interlocked.Exchange(ref _dueInfo, testInfo); } } } finally { Interlocked.Exchange(ref _blocker, null); } }
private IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { //if(this.WindowState == WindowState.Maximized) //{ // return IntPtr.Zero; //} //if (0x0200 == msg || 0x0084 == msg || 0x0020 == msg || 0x00A0 == msg) //{ // return IntPtr.Zero; //} //log.DebugFormat("Main Window DragHook, msg={0:X000}, hwnd={1:X000}", msg, hwnd); //if (0x0005 == msg) //{ // int width = LOWORD((uint)lParam); // int height = HIWORD((uint)lParam); // log.DebugFormat("Main window receive msg WM_SIZE, width={0}, height={1}", width, height); //} switch ((Utils.WM)msg) { case Utils.WM.WM_GETMINMAXINFO: { // log.DebugFormat("WM.WM_GETMINMAXINFO, window state:{0}", this.WindowState); WmGetMinMaxInfo(hwnd, lParam); handled = true; } break; case Utils.WM.WM_SYSCOMMAND: { // log.DebugFormat("receive syscommand: {0:X000}, window state:{1}", (int)wParam, this.WindowState); if (wParam == new IntPtr(0xF030)) // Maximize event - SC_MAXIMIZE from Winuser.h { // log.Debug("WM.WM_SYSCOMMAND -- wParam == new IntPtr(0xF030)"); _maximized = true; } else if (wParam == new IntPtr(0xF120) || wParam == new IntPtr(0xF020)) // SC_RESTORE or SC_MINIMIZE { // log.Debug("WM.WM_SYSCOMMAND -- wParam == new IntPtr(0xF120) || wParam == new IntPtr(0xF020)"); // do nothing } else { // log.DebugFormat("WM.WM_SYSCOMMAND -- else, wParam={0:X000}", wParam); _maximized = false; } } break; case Utils.WM.WINDOWPOSCHANGING: { if (FullScreenStatus) { return(IntPtr.Zero); } Utils.WINDOWPOS pos = (Utils.WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(Utils.WINDOWPOS)); //log.DebugFormat("WM.WINDOWPOSCHANGING, window state:{0}", this.WindowState); if (_maximized) { //log.DebugFormat("WM.WINDOWPOSCHANGING -- _maximized, position:x={0}, y={1}, cx={2}, cy={3}, width={4}, height={5}", pos.x, pos.y, pos.cx, pos.cy, this.Width, this.Height); if (pos.x > -32000 && pos.y > -32000 && 0 != pos.cx && 0 != pos.cy) { if ((pos.cx != _maxWindowWidth || pos.cy != _maxWindowHeight) && (_maxWindowWidth > 0 && _maxWindowHeight > 0)) { //The size of window is not equal to the maximize and set to the maximize. log.DebugFormat("The size of window is not equal to the maximize and set to the maximize. pos.cx={0}, pos.cy={1}, maxCx={2}, maxCy={3}", pos.cx, pos.cy, _maxWindowWidth, _maxWindowHeight); pos.cx = _maxWindowWidth; pos.cy = _maxWindowHeight; Marshal.StructureToPtr(pos, lParam, true); handled = true; } } return(IntPtr.Zero); } if (_maxWinWhenLoaded) { _maxWinWhenLoaded = false; FullScreenStatus = false; ChangeWindowState(WindowState.Maximized); return(IntPtr.Zero); } if ((pos.flags & (int)Utils.SWP_NOMOVE) != 0) { //log.Debug("WM.WINDOWPOSCHANGING -- (pos.flags & (int)SWP.NOMOVE) != 0"); return(IntPtr.Zero); } Window wnd = (Window)HwndSource.FromHwnd(hwnd).RootVisual; if (wnd == null) { //log.Debug("WM.WINDOWPOSCHANGING -- wnd == null"); return(IntPtr.Zero); } if ((pos.cx == _maxWindowWidth && pos.cy == _maxWindowHeight) && (_maxWindowWidth > 0 && _maxWindowHeight > 0)) { log.DebugFormat("The window maybe is maximized."); return(IntPtr.Zero); } if ((pos.cx > _maxWindowWidth || pos.cy > _maxWindowHeight) && (_maxWindowWidth > 0 && _maxWindowHeight > 0)) { // The window size exceed the max size. Maybe the window is maximized by dragging the window to the top log.Debug("The window size exceed the max size. Maybe the window is maximized by dragging the window to the top"); pos.cx = _maxWindowWidth; pos.cy = _maxWindowHeight; Marshal.StructureToPtr(pos, lParam, true); handled = true; return(IntPtr.Zero); } if ((pos.cx == _maxWindowWidth || pos.cy == _maxWindowHeight) && (_maxWindowWidth > 0 && _maxWindowHeight > 0)) { log.Debug("The window maybe is dragged to the right of left of screen to half max."); handled = true; return(IntPtr.Zero); } //log.DebugFormat("Main window original position, x={0}, y={1}, cx={2}, cy={3}", pos.x, pos.y, pos.cx, pos.cy); // determine what dimension is changed by detecting the mouse position relative to the // window bounds. if gripped in the corner, either will work. if (!_adjustingHeight.HasValue) { Point p = Utils.GetMousePosition(); double diffWidth = Math.Min(Math.Abs(p.X - pos.x), Math.Abs(p.X - pos.x - pos.cx)); double diffHeight = Math.Min(Math.Abs(p.Y - pos.y), Math.Abs(p.Y - pos.y - pos.cy)); _adjustingHeight = diffHeight > diffWidth; } if (_adjustingHeight.Value) { // log.DebugFormat("Adjust pos.cy, original pos.cy:{0}", pos.cy); pos.cy = (int)((pos.cx / _aspectRatio) + _titlebarHeight * (DpiY / 96d)); // adjusting height to width change // log.DebugFormat("Changed pos.cy:{0}", pos.cy); } else { // log.DebugFormat("Adjust pos.cx, original pos.cx:{0}", pos.cx); pos.cx = (int)((pos.cy - _titlebarHeight * (DpiY / 96d)) * _aspectRatio); // adjusting width to heigth change // log.DebugFormat("Changed pos.cx:{0}", pos.cx); } //log.InfoFormat("Main window changed position, x={0}, y={1}, cx={2}, cy={3}", pos.x, pos.y, pos.cx, pos.cy); Marshal.StructureToPtr(pos, lParam, true); handled = true; } break; case Utils.WM.EXITSIZEMOVE: //log.Debug("WM.EXITSIZEMOVE"); _adjustingHeight = null; // reset adjustment dimension and detect again next time window is resized break; case Utils.WM.WM_DPICHANGED: Utils.RECT rect = (Utils.RECT)Marshal.PtrToStructure(lParam, typeof(Utils.RECT)); if (rect.left != -32000 && rect.top != -32000) { //sync trigger system event(DisplaySettingChanged and DpiChanged) //if first trigger DisplaySettingChanged, after trigger DpiChanged, skip DpiChanged event;because DpiChanged position is wrong; if ((DateTime.Now - _displaySettingChangedTime).TotalSeconds >= 2) { UpdateDpiValue(); Utils.MySetWindowPos(hwnd, new Rect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top)); DpiChanged?.Invoke(); } } else { log.DebugFormat("--------------neglect dpichanged, because rect.left={0}, rect.top={1}", rect.left, rect.top); } break; } return(IntPtr.Zero); }