/// <summary> /// Ensure that the window doesn't overlap docked toolbars on desktop (like taskbar) /// </summary> /// <param name="m">The message.</param> /// <returns></returns> private bool CalculateMaxSize(ref Message m) { if (_parentForm.Parent == null) { // create minMax info for maximize data var info = (MINMAXINFO)m.GetLParam(typeof(MINMAXINFO)); var rect = Screen.FromHandle(Handle).WorkingArea; rect.Offset(-rect.X, -rect.Y); var fullBorderSize = new Size(SystemInformation.Border3DSize.Width + SystemInformation.BorderSize.Width, SystemInformation.Border3DSize.Height + SystemInformation.BorderSize.Height); info.ptMaxPosition.x = rect.Left - fullBorderSize.Width; info.ptMaxPosition.y = rect.Top - fullBorderSize.Height; info.ptMaxSize.x = rect.Width + fullBorderSize.Width * 2; info.ptMaxSize.y = rect.Height + fullBorderSize.Height * 2; info.ptMinTrackSize.y += FormExtenders.GetCaptionHeight(_parentForm); if (!_parentForm.MaximumSize.IsEmpty) { info.ptMaxSize.x = Math.Min(info.ptMaxSize.x, _parentForm.MaximumSize.Width); info.ptMaxSize.y = Math.Min(info.ptMaxSize.y, _parentForm.MaximumSize.Height); info.ptMaxTrackSize.x = Math.Min(info.ptMaxTrackSize.x, _parentForm.MaximumSize.Width); info.ptMaxTrackSize.y = Math.Min(info.ptMaxTrackSize.y, _parentForm.MaximumSize.Height); } if (!_parentForm.MinimumSize.IsEmpty) { info.ptMinTrackSize.x = Math.Max(info.ptMinTrackSize.x, _parentForm.MinimumSize.Width); info.ptMinTrackSize.y = Math.Max(info.ptMinTrackSize.y, _parentForm.MinimumSize.Height); } // set wished maximize size Marshal.StructureToPtr(info, m.LParam, true); m.Result = (IntPtr)0; return(true); } return(false); }
/// <summary> /// Performs the non client HitTest /// </summary> /// <param name="m">The Message</param> /// <returns>true if the orginal handler should be suppressed otherwise false.</returns> private bool NcHitTest(ref Message m) { if (!IsProcessNcArea) { return(false); } Point point = new Point(m.LParam.ToInt32()); Rectangle rectScreen = FormExtenders.GetScreenRect(_parentForm); Rectangle rect = rectScreen; // custom processing if (rect.Contains(point)) { Size borderSize = FormExtenders.GetBorderSize(_parentForm); rect.Inflate(-borderSize.Width, -borderSize.Height); // let form handle hittest itself if we are on borders if (!rect.Contains(point)) { return(false); } Rectangle rectCaption = rect; rectCaption.Height = FormExtenders.GetCaptionHeight(_parentForm); // not in caption -> client if (!rectCaption.Contains(point)) { m.Result = (IntPtr)(int)HitTest.HTCLIENT; return(true); } // on icon? if (FormExtenders.HasMenu(_parentForm)) { Rectangle rectSysMenu = rectCaption; rectSysMenu.Size = SystemInformation.SmallIconSize; if (rectSysMenu.Contains(point)) { m.Result = (IntPtr)(int)HitTest.HTSYSMENU; return(true); } } // on Button? Point pt = new Point(point.X - rectScreen.X, point.Y - rectScreen.Y); CaptionButton sysButton = CommandButtonFromPoint(pt); if (sysButton != null) { m.Result = (IntPtr)sysButton.HitTest; return(true); } // on Caption? m.Result = (IntPtr)(int)HitTest.HTCAPTION; return(true); } m.Result = (IntPtr)(int)HitTest.HTNOWHERE; return(true); }
/// <summary> /// Redraws the non client area. /// </summary> /// <param name="invalidateBuffer">if set to <c>true</c> the buffer is invalidated.</param> /// <returns>true if the original painting should be suppressed otherwise false.</returns> private bool NcPaint(bool invalidateBuffer) { if (!IsProcessNcArea) { return(false); } bool result = false; IntPtr hdc = (IntPtr)0; Graphics g = null; Region region = null; IntPtr hrgn = (IntPtr)0; try { // no drawing needed if (_parentForm.MdiParent != null && _parentForm.WindowState == FormWindowState.Maximized) { _currentCacheSize = Size.Empty; return(false); } // prepare image bounds Size borderSize = FormExtenders.GetBorderSize(_parentForm); int captionHeight = FormExtenders.GetCaptionHeight(_parentForm); RECT rectScreen = new RECT(); Win32Api.GetWindowRect(_parentForm.Handle, ref rectScreen); Rectangle rectBounds = rectScreen.ToRectangle(); rectBounds.Offset(-rectBounds.X, -rectBounds.Y); // prepare clipping Rectangle rectClip = rectBounds; region = new Region(rectClip); rectClip.Inflate(-borderSize.Width, -borderSize.Height); rectClip.Y += captionHeight; rectClip.Height -= captionHeight; // create graphics handle hdc = Win32Api.GetDCEx(_parentForm.Handle, (IntPtr)0, (DCXFlags.DCX_CACHE | DCXFlags.DCX_CLIPSIBLINGS | DCXFlags.DCX_WINDOW)); g = Graphics.FromHdc(hdc); // Apply clipping region.Exclude(rectClip); hrgn = region.GetHrgn(g); Win32Api.SelectClipRgn(hdc, hrgn); // create new buffered graphics if needed if (_bufferGraphics == null || _currentCacheSize != rectBounds.Size) { if (_bufferGraphics != null) { _bufferGraphics.Dispose(); } _bufferGraphics = _bufferContext.Allocate(g, new Rectangle(0, 0, rectBounds.Width, rectBounds.Height)); _currentCacheSize = rectBounds.Size; invalidateBuffer = true; } if (invalidateBuffer) { // Create painting meta data for form SkinningFormPaintData paintData = new SkinningFormPaintData(_bufferGraphics.Graphics, rectBounds) { Borders = borderSize, CaptionHeight = captionHeight, Active = _formIsActive, HasMenu = FormExtenders.HasMenu(_parentForm), IconSize = SystemInformation.SmallIconSize, IsSmallCaption = captionHeight == SystemInformation.ToolWindowCaptionHeight, Text = _parentForm.Text }; // create painting meta data for caption buttons if (_captionButtons.Count > 0) { paintData.CaptionButtons = new CaptionButtonPaintData[_captionButtons.Count]; for (int i = 0; i < _captionButtons.Count; i++) { CaptionButton button = _captionButtons[i]; CaptionButtonPaintData buttonData = new CaptionButtonPaintData(_bufferGraphics.Graphics, button.Bounds) { Pressed = button.Pressed, Hovered = button.Hovered, Enabled = button.Enabled, HitTest = button.HitTest }; paintData.CaptionButtons[i] = buttonData; } } // paint result = _manager.CurrentSkin.OnNcPaint(_parentForm, paintData); } // render buffered graphics if (_bufferGraphics != null) { _bufferGraphics.Render(g); } } catch (Exception) {// error drawing result = false; } // cleanup data if (hdc != (IntPtr)0) { Win32Api.SelectClipRgn(hdc, (IntPtr)0); Win32Api.ReleaseDC(_parentForm.Handle, hdc); } if (region != null && hrgn != (IntPtr)0) { region.ReleaseHrgn(hrgn); } if (region != null) { region.Dispose(); } if (g != null) { g.Dispose(); } return(result); }
protected override void WndProc(ref Message m) { bool supressOriginalMessage = false; if (IsProcessNcArea) { switch ((Win32Messages)m.Msg) { // update form data on style change case Win32Messages.STYLECHANGED: UpdateStyle(); _manager.CurrentSkin.OnSetRegion(_parentForm, _parentForm.Size); break; #region Handle Form Activation case Win32Messages.ACTIVATEAPP: // redraw _formIsActive = (int)m.WParam != 0; NcPaint(true); break; case Win32Messages.ACTIVATE: // Set active state and redraw _formIsActive = ((int)WAFlags.WA_ACTIVE == (int)m.WParam || (int)WAFlags.WA_CLICKACTIVE == (int)m.WParam); NcPaint(true); break; case Win32Messages.MDIACTIVATE: // set active and redraw on activation if (m.WParam == _parentForm.Handle) { _formIsActive = false; } else if (m.LParam == _parentForm.Handle) { _formIsActive = true; } NcPaint(true); break; #endregion #region Handle Mouse Processing // Set Pressed button on mousedown case Win32Messages.NCLBUTTONDOWN: supressOriginalMessage = OnNcLButtonDown(ref m); break; // Set hovered button on mousemove case Win32Messages.NCMOUSEMOVE: OnNcMouseMove(m); break; // perform button actions if a button was clicked case Win32Messages.NCLBUTTONUP: // Handle button up if (OnNcLButtonUp(m)) { supressOriginalMessage = true; } break; // restore button states on mouseleave case Win32Messages.NCMOUSELEAVE: case Win32Messages.MOUSELEAVE: case Win32Messages.MOUSEHOVER: if (_pressedButton != null) { _pressedButton.Pressed = false; } if (_hoveredButton != null) { _hoveredButton.Hovered = false; _hoveredButton = null; } NcPaint(true); break; #endregion #region Size Processing // Set region as window is shown case Win32Messages.SHOWWINDOW: _manager.CurrentSkin.OnSetRegion(_parentForm, _parentForm.Size); break; // adjust region on resize case Win32Messages.SIZE: OnSize(m); break; // ensure that the window doesn't overlap docked toolbars on desktop (like taskbar) case Win32Messages.GETMINMAXINFO: supressOriginalMessage = CalculateMaxSize(ref m); break; // update region on resize case Win32Messages.WINDOWPOSCHANGING: WINDOWPOS wndPos = (WINDOWPOS)m.GetLParam(typeof(WINDOWPOS)); if ((wndPos.flags & (int)SWPFlags.SWP_NOSIZE) == 0) { _manager.CurrentSkin.OnSetRegion(_parentForm, new Size(wndPos.cx, wndPos.cy)); } break; // remove region on maximize or repaint on resize case Win32Messages.WINDOWPOSCHANGED: if (_parentForm.WindowState == FormWindowState.Maximized) { _parentForm.Region = null; } WINDOWPOS wndPos2 = (WINDOWPOS)m.GetLParam(typeof(WINDOWPOS)); if ((wndPos2.flags & (int)SWPFlags.SWP_NOSIZE) == 0) { UpdateCaption(); NcPaint(true); } break; #endregion #region Non Client Area Handling // paint the non client area case Win32Messages.NCPAINT: if (NcPaint(true)) { m.Result = (IntPtr)1; supressOriginalMessage = true; } break; // calculate the non client area size case Win32Messages.NCCALCSIZE: if (m.WParam == (IntPtr)1) { if (_parentForm.MdiParent != null) { break; } // add caption height to non client area NCCALCSIZE_PARAMS p = (NCCALCSIZE_PARAMS)m.GetLParam(typeof(NCCALCSIZE_PARAMS)); p.rect0.Top += FormExtenders.GetCaptionHeight(_parentForm); Marshal.StructureToPtr(p, m.LParam, true); } break; // non client hit test case Win32Messages.NCHITTEST: if (NcHitTest(ref m)) { supressOriginalMessage = true; } break; #endregion } } if (!supressOriginalMessage) { base.WndProc(ref m); } }