Skip to content

Commit 0f95aa9

Browse files
authored
Merge pull request #125 from cairoshell/appbar-refactors
AppBar refactoring and improvements
2 parents c9425e8 + 9abbd29 commit 0f95aa9

5 files changed

Lines changed: 222 additions & 338 deletions

File tree

src/ManagedShell.AppBar/AppBarManager.cs

Lines changed: 59 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@ public class AppBarManager : IDisposable
1717
private AppBarMessageDelegate _appBarMessageDelegate;
1818
private int uCallBack;
1919

20-
private int retryNum;
21-
private Rect retryRect;
22-
private DateTime retryTimestamp;
23-
private int maxRetryNum = 20;
24-
private TimeSpan maxRetryTimespan = TimeSpan.FromSeconds(10);
25-
2620
public List<AppBarWindow> AppBars { get; } = new List<AppBarWindow>();
2721
public List<AppBarWindow> AutoHideBars { get; } = new List<AppBarWindow>();
2822
public EventHandler<AppBarEventArgs> AppBarEvent;
@@ -226,7 +220,7 @@ public void UnregisterAutoHideBar(AppBarWindow window)
226220
AutoHideBars.Remove(window);
227221
}
228222

229-
public int RegisterBar(AppBarWindow abWindow, double width, double height, AppBarEdge edge = AppBarEdge.Top)
223+
public int RegisterBar(AppBarWindow abWindow)
230224
{
231225
lock (appBarLock)
232226
{
@@ -250,7 +244,7 @@ public int RegisterBar(AppBarWindow abWindow, double width, double height, AppBa
250244

251245
if (!EnvironmentHelper.IsAppRunningAsShell)
252246
{
253-
ABSetPos(abWindow, width, height, edge, true);
247+
ABSetPos(abWindow);
254248
}
255249
else
256250
{
@@ -279,12 +273,17 @@ public int RegisterBar(AppBarWindow abWindow, double width, double height, AppBa
279273
return uCallBack;
280274
}
281275

282-
public void AppBarActivate(IntPtr hwnd)
276+
public void AppBarActivate(AppBarWindow abWindow)
283277
{
278+
if (!AppBars.Contains(abWindow))
279+
{
280+
return;
281+
}
282+
284283
APPBARDATA abd = new APPBARDATA
285284
{
286285
cbSize = Marshal.SizeOf(typeof(APPBARDATA)),
287-
hWnd = hwnd,
286+
hWnd = abWindow.Handle,
288287
lParam = (IntPtr)Convert.ToInt32(true)
289288
};
290289

@@ -297,12 +296,17 @@ public void AppBarActivate(IntPtr hwnd)
297296
}
298297
}
299298

300-
public void AppBarWindowPosChanged(IntPtr hwnd)
299+
public void AppBarWindowPosChanged(AppBarWindow abWindow)
301300
{
301+
if (!AppBars.Contains(abWindow))
302+
{
303+
return;
304+
}
305+
302306
APPBARDATA abd = new APPBARDATA
303307
{
304308
cbSize = Marshal.SizeOf(typeof(APPBARDATA)),
305-
hWnd = hwnd
309+
hWnd = abWindow.Handle
306310
};
307311

308312
SHAppBarMessage((int)ABMsg.ABM_WINDOWPOSCHANGED, ref abd);
@@ -314,237 +318,115 @@ public void AppBarWindowPosChanged(IntPtr hwnd)
314318
}
315319
}
316320

317-
public void ABSetPos(AppBarWindow abWindow, double width, double height, AppBarEdge edge, bool isCreate = false)
321+
public bool ABSetPos(AppBarWindow abWindow)
318322
{
319323
lock (appBarLock)
320324
{
325+
Rect desiredRect = abWindow.GetDesiredRect();
321326
APPBARDATA abd = new APPBARDATA
322327
{
323328
cbSize = Marshal.SizeOf(typeof(APPBARDATA)),
324329
hWnd = abWindow.Handle,
325-
uEdge = (int)edge
330+
uEdge = (int)abWindow.AppBarEdge,
331+
rc = desiredRect
326332
};
327333

328-
int sWidth = Convert.ToInt32(width);
329-
int sHeight = Convert.ToInt32(height);
330-
331-
int top = 0;
332-
int left = 0;
333-
int right = ScreenHelper.PrimaryMonitorDeviceSize.Width;
334-
int bottom = ScreenHelper.PrimaryMonitorDeviceSize.Height;
335-
336-
int edgeOffset = 0;
337-
338-
if (abWindow.Screen != null)
339-
{
340-
top = abWindow.Screen.Bounds.Y;
341-
left = abWindow.Screen.Bounds.X;
342-
right = abWindow.Screen.Bounds.Right;
343-
bottom = abWindow.Screen.Bounds.Bottom;
344-
}
345-
346-
if (!abWindow.RequiresScreenEdge)
347-
{
348-
edgeOffset = Convert.ToInt32(GetAppBarEdgeWindowsHeight((AppBarEdge)abd.uEdge, abWindow.Screen));
349-
}
350-
351-
if (abd.uEdge == (int)AppBarEdge.Left || abd.uEdge == (int)AppBarEdge.Right)
352-
{
353-
abd.rc.Top = top;
354-
abd.rc.Bottom = bottom;
355-
if (abd.uEdge == (int)AppBarEdge.Left)
356-
{
357-
abd.rc.Left = left + edgeOffset;
358-
abd.rc.Right = abd.rc.Left + sWidth;
359-
}
360-
else
361-
{
362-
abd.rc.Right = right - edgeOffset;
363-
abd.rc.Left = abd.rc.Right - sWidth;
364-
}
365-
}
366-
else
367-
{
368-
abd.rc.Left = left;
369-
abd.rc.Right = right;
370-
if (abd.uEdge == (int)AppBarEdge.Top)
371-
{
372-
abd.rc.Top = top + edgeOffset;
373-
abd.rc.Bottom = abd.rc.Top + sHeight;
374-
}
375-
else
376-
{
377-
abd.rc.Bottom = bottom - edgeOffset;
378-
abd.rc.Top = abd.rc.Bottom - sHeight;
379-
}
380-
}
381-
382334
SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref abd);
383335

384336
// system doesn't adjust all edges for us, do some adjustments
385337
switch (abd.uEdge)
386338
{
387339
case (int)AppBarEdge.Left:
388-
abd.rc.Right = abd.rc.Left + sWidth;
340+
abd.rc.Right = abd.rc.Left + desiredRect.Width;
389341
break;
390342
case (int)AppBarEdge.Right:
391-
abd.rc.Left = abd.rc.Right - sWidth;
343+
abd.rc.Left = abd.rc.Right - desiredRect.Width;
392344
break;
393345
case (int)AppBarEdge.Top:
394-
abd.rc.Bottom = abd.rc.Top + sHeight;
346+
abd.rc.Bottom = abd.rc.Top + desiredRect.Height;
395347
break;
396348
case (int)AppBarEdge.Bottom:
397-
abd.rc.Top = abd.rc.Bottom - sHeight;
349+
abd.rc.Top = abd.rc.Bottom - desiredRect.Height;
398350
break;
399351
}
400352

401353
SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref abd);
402354

403-
// check if new coords
404-
bool isSameCoords = false;
405-
Rect currentRect;
406-
GetWindowRect(abWindow.Handle, out currentRect);
407-
if (!isCreate)
408-
{
409-
bool topUnchanged = abd.rc.Top == currentRect.Top;
410-
bool leftUnchanged = abd.rc.Left == currentRect.Left;
411-
bool bottomUnchanged = abd.rc.Bottom == currentRect.Bottom;
412-
bool rightUnchanged = abd.rc.Right == currentRect.Right;
413-
414-
isSameCoords = topUnchanged
415-
&& leftUnchanged
416-
&& bottomUnchanged
417-
&& rightUnchanged;
418-
}
419-
420-
if (!isSameCoords)
421-
{
422-
ShellLogger.Debug($"AppBarManager: {abWindow.Name} changing position (TxLxBxR) to {abd.rc.Top}x{abd.rc.Left}x{abd.rc.Bottom}x{abd.rc.Right} from {currentRect.Top}x{currentRect.Left}x{currentRect.Bottom}x{currentRect.Right}");
423-
abWindow.SetAppBarPosition(abd.rc);
424-
}
425-
426-
abWindow.AfterAppBarPos(isSameCoords, abd.rc);
427-
428-
if ((((abd.uEdge == (int)AppBarEdge.Top || abd.uEdge == (int)AppBarEdge.Bottom) && abd.rc.Bottom - abd.rc.Top < sHeight) ||
429-
((abd.uEdge == (int)AppBarEdge.Left || abd.uEdge == (int)AppBarEdge.Right) && abd.rc.Right - abd.rc.Left < sWidth)) && allowRetry(abd.rc))
430-
{
431-
// The system did not respect the coordinates we selected, resulting in an unexpected window size.
432-
ABSetPos(abWindow, width, height, edge);
433-
}
355+
return abWindow.SetWindowPosition(abd.rc);
434356
}
435357
}
436-
437-
private bool allowRetry(Rect rect)
438-
{
439-
// The system did not respect the coordinates we selected. This may or may not need remediation, so keep track of attempts to prevent infinite looping.
440-
441-
if (rect.Top == retryRect.Top && rect.Left == retryRect.Left && rect.Right == retryRect.Right && rect.Bottom == retryRect.Bottom)
442-
{
443-
// Repeat rect
444-
if (DateTime.Now.Subtract(retryTimestamp) < maxRetryTimespan)
445-
{
446-
// within retry span
447-
if (retryNum >= maxRetryNum)
448-
{
449-
// hit max retries
450-
ShellLogger.Debug("AppBarManager: Max retries limit reached");
451-
return false;
452-
}
453-
else
454-
{
455-
// allow retry
456-
ShellLogger.Debug("AppBarManager: Allowing retry of ABSetPos");
457-
retryNum++;
458-
return true;
459-
}
460-
}
461-
}
462-
463-
// Reset
464-
ShellLogger.Debug("AppBarManager: Resetting retry of ABSetPos");
465-
retryNum = 0;
466-
retryRect = rect;
467-
retryTimestamp = DateTime.Now;
468-
469-
return true;
470-
}
471358
#endregion
472359

473360
#region Work area
474-
public double GetAppBarEdgeWindowsHeight(AppBarEdge edge, AppBarScreen screen)
361+
public int GetAppBarEdgeWindowsHeight(AppBarEdge edge, AppBarScreen screen, IntPtr hWndIgnore)
475362
{
476-
double edgeHeight = 0;
477-
double dpiScale = 1;
478-
Rect workAreaRect = GetWorkArea(ref dpiScale, screen, true, true);
363+
int edgeHeight = 0;
364+
Rect workAreaRect = GetWorkArea(screen, true, true, hWndIgnore);
479365

480366
switch (edge)
481367
{
482368
case AppBarEdge.Top:
483-
edgeHeight += (workAreaRect.Top - screen.Bounds.Top) / dpiScale;
369+
edgeHeight += workAreaRect.Top - screen.Bounds.Top;
484370
break;
485371
case AppBarEdge.Bottom:
486-
edgeHeight += (screen.Bounds.Bottom - workAreaRect.Bottom) / dpiScale;
372+
edgeHeight += screen.Bounds.Bottom - workAreaRect.Bottom;
487373
break;
488374
case AppBarEdge.Left:
489-
edgeHeight += (workAreaRect.Left - screen.Bounds.Left) / dpiScale;
375+
edgeHeight += workAreaRect.Left - screen.Bounds.Left;
490376
break;
491377
case AppBarEdge.Right:
492-
edgeHeight += (screen.Bounds.Right - workAreaRect.Right) / dpiScale;
378+
edgeHeight += screen.Bounds.Right - workAreaRect.Right;
493379
break;
494380
}
495381

496382
return edgeHeight;
497383
}
498384

499-
public Rect GetWorkArea(ref double dpiScale, AppBarScreen screen, bool edgeBarsOnly, bool enabledBarsOnly)
385+
public Rect GetWorkArea(AppBarScreen screen, bool edgeBarsOnly, bool enabledBarsOnly, IntPtr hWndIgnore)
500386
{
501-
double topEdgeWindowHeight = 0;
502-
double bottomEdgeWindowHeight = 0;
503-
double leftEdgeWindowWidth = 0;
504-
double rightEdgeWindowWidth = 0;
387+
int topEdgeWindowHeight = 0;
388+
int bottomEdgeWindowHeight = 0;
389+
int leftEdgeWindowWidth = 0;
390+
int rightEdgeWindowWidth = 0;
505391
Rect rc;
506392

507393
// get appropriate windows for this display
508394
foreach (var window in AppBars)
509395
{
510-
if (window.Screen.DeviceName == screen.DeviceName)
396+
if (window.Screen.DeviceName == screen.DeviceName &&
397+
window.Handle != hWndIgnore &&
398+
(window.AppBarMode == AppBarMode.Normal || !enabledBarsOnly) &&
399+
(window.RequiresScreenEdge || !edgeBarsOnly))
511400
{
512-
if ((window.AppBarMode == AppBarMode.Normal || !enabledBarsOnly) && (window.RequiresScreenEdge || !edgeBarsOnly))
401+
switch (window.AppBarEdge)
513402
{
514-
if (window.AppBarEdge == AppBarEdge.Top)
515-
{
516-
topEdgeWindowHeight += window.ActualHeight;
517-
}
518-
else if (window.AppBarEdge == AppBarEdge.Bottom)
519-
{
520-
bottomEdgeWindowHeight += window.ActualHeight;
521-
}
522-
else if (window.AppBarEdge == AppBarEdge.Left)
523-
{
524-
leftEdgeWindowWidth += window.ActualWidth;
525-
}
526-
else if (window.AppBarEdge == AppBarEdge.Right)
527-
{
528-
rightEdgeWindowWidth += window.ActualWidth;
529-
}
403+
case AppBarEdge.Left:
404+
leftEdgeWindowWidth += window.WindowRect.Width;
405+
break;
406+
case AppBarEdge.Right:
407+
rightEdgeWindowWidth += window.WindowRect.Width;
408+
break;
409+
case AppBarEdge.Bottom:
410+
bottomEdgeWindowHeight += window.WindowRect.Height;
411+
break;
412+
case AppBarEdge.Top:
413+
topEdgeWindowHeight += window.WindowRect.Height;
414+
break;
530415
}
531-
532-
dpiScale = window.DpiScale;
533416
}
534417
}
535418

536-
rc.Top = screen.Bounds.Top + Convert.ToInt32(topEdgeWindowHeight * dpiScale);
537-
rc.Bottom = screen.Bounds.Bottom - Convert.ToInt32(bottomEdgeWindowHeight * dpiScale);
538-
rc.Left = screen.Bounds.Left + Convert.ToInt32(leftEdgeWindowWidth * dpiScale);
539-
rc.Right = screen.Bounds.Right - Convert.ToInt32(rightEdgeWindowWidth * dpiScale);
419+
rc.Top = screen.Bounds.Top + topEdgeWindowHeight;
420+
rc.Bottom = screen.Bounds.Bottom - bottomEdgeWindowHeight;
421+
rc.Left = screen.Bounds.Left + leftEdgeWindowWidth;
422+
rc.Right = screen.Bounds.Right - rightEdgeWindowWidth;
540423

541424
return rc;
542425
}
543426

544427
public void SetWorkArea(AppBarScreen screen)
545428
{
546-
double dpiScale = 1;
547-
Rect rc = GetWorkArea(ref dpiScale, screen, false, true);
429+
Rect rc = GetWorkArea(screen, false, true, IntPtr.Zero);
548430

549431
SystemParametersInfo((int)SPI.SETWORKAREA, 1, ref rc, (uint)(SPIF.UPDATEINIFILE | SPIF.SENDWININICHANGE));
550432
}

0 commit comments

Comments
 (0)