public Taskbar() { IntPtr taskbarHandle = PInvoke.FindWindow(Taskbar.ClassName, null); var data = new APPBARDATA { cbSize = (uint) Marshal.SizeOf(typeof (APPBARDATA)), hWnd = taskbarHandle }; IntPtr result = PInvoke.SHAppBarMessage(AppBarMessages.GetTaskbarPos, ref data); if (result == IntPtr.Zero) throw new InvalidOperationException(); this.Position = (TaskbarPosition) data.uEdge; this.Bounds = Rectangle.FromLTRB(data.rc.Left, data.rc.Top, data.rc.Right, data.rc.Bottom); data.cbSize = (uint) Marshal.SizeOf(typeof (APPBARDATA)); result = PInvoke.SHAppBarMessage(AppBarMessages.GetState, ref data); int state = result.ToInt32(); this.AlwaysOnTop = (state & AppBarState.AlwaysOnTop) == AppBarState.AlwaysOnTop; this.AutoHide = (state & AppBarState.Autohide) == AppBarState.Autohide; }
private void UnRegisterAppBar() { Log.Info("UnRegisterAppBar called"); if (getWindowState() != WindowStates.Docked) return; var abd = new APPBARDATA(); abd.cbSize = Marshal.SizeOf(abd); abd.hWnd = windowHandle; PInvoke.SHAppBarMessage(AppBarMessages.Remove, ref abd); appBarCallBackId = -1; }
private void SetAppBarSizeAndPosition(DockEdges dockPosition, Rect sizeAndPosition, bool isInitialising = false) { Log.InfoFormat("SetAppBarSizeAndPosition called with dockPosition:{0}, sizeAndPosition.Top:{1}, sizeAndPosition.Bottom:{2}, sizeAndPosition.Left:{3}, sizeAndPosition.Right:{4}", dockPosition, sizeAndPosition.Top, sizeAndPosition.Bottom, sizeAndPosition.Left, sizeAndPosition.Right); Log.InfoFormat("Screen bounds in px - Top:{0}, Left:{1}, Width:{2}, Height:{3}", screenBoundsInPx.Top, screenBoundsInPx.Left, screenBoundsInPx.Width, screenBoundsInPx.Height); if (getWindowState() != WindowStates.Docked) return; var barData = new APPBARDATA(); barData.cbSize = Marshal.SizeOf(barData); barData.hWnd = windowHandle; barData.uEdge = dockPosition.ToAppBarEdge(); barData.rc.Left = (int)Math.Round(sizeAndPosition.Left); barData.rc.Top = (int)Math.Round(sizeAndPosition.Top); barData.rc.Right = (int)Math.Round(sizeAndPosition.Right); barData.rc.Bottom = (int)Math.Round(sizeAndPosition.Bottom); //Submit a query for the proposed dock size and position, which might be updated PInvoke.SHAppBarMessage(AppBarMessages.QueryPos, ref barData); Log.InfoFormat("QueryPos returned barData.rc.Top:{0}, barData.rc.Bottom:{1}, barData.rc.Left:{2}, barData.rc.Right:{3}", barData.rc.Top, barData.rc.Bottom, barData.rc.Left, barData.rc.Right); //Compensate for lost thickness due to other app bars switch (dockPosition) { case DockEdges.Top: barData.rc.Bottom += barData.rc.Top - (int) Math.Round(sizeAndPosition.Top); break; case DockEdges.Bottom: barData.rc.Top -= (int)Math.Round(sizeAndPosition.Bottom) - barData.rc.Bottom; break; case DockEdges.Left: barData.rc.Right += barData.rc.Left - (int)Math.Round(sizeAndPosition.Left); break; case DockEdges.Right: barData.rc.Left -= (int)Math.Round(sizeAndPosition.Right) - barData.rc.Right; break; } Log.InfoFormat("Rect values adjusted (to compensate for other app bars) to barData.rc.Top:{0}, barData.rc.Bottom:{1}, barData.rc.Left:{2}, barData.rc.Right:{3}", barData.rc.Top, barData.rc.Bottom, barData.rc.Left, barData.rc.Right); //Then set the dock size and position, using the potentially updated barData PInvoke.SHAppBarMessage(AppBarMessages.SetPos, ref barData); Log.InfoFormat("SetPos returned barData.rc.Top:{0}, barData.rc.Bottom:{1}, barData.rc.Left:{2}, barData.rc.Right:{3}", barData.rc.Top, barData.rc.Bottom, barData.rc.Left, barData.rc.Right); var finalDockLeftInDp = barData.rc.Left/Graphics.DipScalingFactorX; var finalDockTopInDp = barData.rc.Top / Graphics.DipScalingFactorY; var finalDockWidthInDp = (barData.rc.Right - barData.rc.Left) / Graphics.DipScalingFactorX; var finalDockHeightInDp = (barData.rc.Bottom - barData.rc.Top) / Graphics.DipScalingFactorY; Log.InfoFormat("finalDockLeftInDp:{0}, finalDockTopInDp:{1}, finalDockWidthInDp:{2}, finalDockHeightInDp:{3}", finalDockLeftInDp, finalDockTopInDp, finalDockWidthInDp, finalDockHeightInDp); Log.InfoFormat("Screen bounds in dp - Top:{0}, Left:{1}, Width:{2}, Height:{3}", screenBoundsInDp.Top, screenBoundsInDp.Left, screenBoundsInDp.Width, screenBoundsInDp.Height); if (finalDockLeftInDp < 0 || finalDockTopInDp < 0 || finalDockWidthInDp <= 0 || finalDockHeightInDp <= 0 || (finalDockLeftInDp + finalDockWidthInDp) > screenBoundsInDp.Right || (finalDockTopInDp + finalDockHeightInDp) > screenBoundsInDp.Bottom) { Log.Error("Final dock size and/or position is invalid - reverting to floating size and position"); UnRegisterAppBar(); saveWindowState(WindowStates.Floating); savePreviousWindowState(WindowStates.Floating); PublishError(this, new ApplicationException("There was a problem positioning OptiKey - reverting to floating position")); } else if (!isInitialising) { //Apply final size and position to the window. This is dispatched with ApplicationIdle priority //as WPF will send a resize after a new appbar is added. We need to apply the received size & position after this happens. //RECT values are in pixels so I need to scale back to DIPs for WPF. var rect = new Rect(finalDockLeftInDp, finalDockTopInDp, finalDockWidthInDp, finalDockHeightInDp); window.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new ApplySizeAndPositionDelegate(ApplyAndPersistSizeAndPosition), rect); } }
private void RegisterAppBar() { Log.Info("RegisterAppBar called"); if (getWindowState() != WindowStates.Docked) return; //Register a new app bar with Windows - this adds it to a list of app bars var abd = new APPBARDATA(); abd.cbSize = Marshal.SizeOf(abd); abd.hWnd = windowHandle; appBarCallBackId = PInvoke.RegisterWindowMessage("AppBarMessage"); //Get a system wide unique window message (id) abd.uCallbackMessage = appBarCallBackId; var result = PInvoke.SHAppBarMessage((int)AppBarMessages.New, ref abd); //Add hook to receive position change messages from Windows HwndSource source = HwndSource.FromHwnd(abd.hWnd); source.AddHook(AppBarPositionChangeCallback); }
public static extern IntPtr SHAppBarMessage(AppBarMessages dwMessage, ref APPBARDATA pData);
private void SetAppBarSizeAndPosition(DockEdges dockPosition, Rect sizeAndPosition) { if (getWindowState() != WindowStates.Docked) return; var barData = new APPBARDATA(); barData.cbSize = Marshal.SizeOf(barData); barData.hWnd = windowHandle; barData.uEdge = dockPosition.ToAppBarEdge(); barData.rc.Left = (int)Math.Round(sizeAndPosition.Left); barData.rc.Top = (int)Math.Round(sizeAndPosition.Top); barData.rc.Right = (int)Math.Round(sizeAndPosition.Right); barData.rc.Bottom = (int)Math.Round(sizeAndPosition.Bottom); //Submit a query for the proposed dock size and position, which might be updated PInvoke.SHAppBarMessage(AppBarMessages.QueryPos, ref barData); //Compensate for lost thickness due to other app bars switch (dockPosition) { case DockEdges.Top: barData.rc.Bottom += barData.rc.Top - (int) Math.Round(sizeAndPosition.Top); break; case DockEdges.Bottom: barData.rc.Top -= (int)Math.Round(sizeAndPosition.Bottom) - barData.rc.Bottom; break; case DockEdges.Left: barData.rc.Right += barData.rc.Left - (int)Math.Round(sizeAndPosition.Left); break; case DockEdges.Right: barData.rc.Left -= (int)Math.Round(sizeAndPosition.Right) - barData.rc.Right; break; } //Then set the dock size and position, using the potentially updated barData PInvoke.SHAppBarMessage(AppBarMessages.SetPos, ref barData); //Extract the final size and position and apply to the window. This is dispatched with ApplicationIdle priority //as WPF will send a resize after a new appbar is added. We need to apply the received size & position after this happens. //RECT values are in pixels so I need to scale back to DIPs for WPF. var rect = new Rect( barData.rc.Left / Graphics.DipScalingFactorX, barData.rc.Top / Graphics.DipScalingFactorY, (barData.rc.Right - barData.rc.Left) / Graphics.DipScalingFactorX, (barData.rc.Bottom - barData.rc.Top) / Graphics.DipScalingFactorY); window.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new ApplySizeAndPositionDelegate(ApplyAndPersistSizeAndPosition), rect); }