Skip to content

Commit

Permalink
Merge pull request #2135 from cwensley/curtis/wpf-focus-issues-continued
Browse files Browse the repository at this point in the history
Wpf/WinForms: Fix more window active issues.
  • Loading branch information
cwensley authored Feb 2, 2022
2 parents 06e291c + 784cd0a commit a4593db
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 110 deletions.
3 changes: 3 additions & 0 deletions src/Eto.WinForms/Forms/DialogHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ public Button DefaultButton
public void ShowModal()
{
ReloadButtons();
var owner = Widget.Owner;
if (owner != null && !owner.HasFocus)
owner.Focus();

Control.ShowDialog();
Control.Owner = null; // without this, the dialog is still active as part of the owner form
Expand Down
6 changes: 6 additions & 0 deletions src/Eto.WinForms/Forms/FormHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ protected override void Initialize()
Resizable = true;
}

internal override void InternalClosing()
{
base.InternalClosing();
SetOwner(null);
}

public void Show()
{
Control.Show();
Expand Down
23 changes: 4 additions & 19 deletions src/Eto.WinForms/Forms/HwndFormHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -442,35 +442,20 @@ public void Invalidate(Eto.Drawing.Rectangle rect, bool invalidateChildren)

public void SuspendLayout()
{
throw new NotImplementedException();
}

public void ResumeLayout()
{
throw new NotImplementedException();
}

public void Focus()
{
throw new NotImplementedException();
}
public void Focus() => Win32.SetActiveWindow(Control);

public bool HasFocus
{
get { throw new NotImplementedException(); }
}
public bool HasFocus => Win32.GetActiveWindow() == Control;

public bool Visible
{
get
{
return Win32.IsWindowVisible(Control);
}
set
{
Win32.ShowWindow(Control, value ? Win32.SW.SHOWNA : Win32.SW.HIDE);
}

get => Win32.IsWindowVisible(Control);
set => Win32.ShowWindow(Control, value ? Win32.SW.SHOWNA : Win32.SW.HIDE);
}

public void OnPreLoad(EventArgs e)
Expand Down
61 changes: 41 additions & 20 deletions src/Eto.WinForms/Forms/WindowHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public interface IWindowHandler
public class WindowHandler : Window.IWindowHandler
{
internal static readonly object MovableByWindowBackground_Key = new object();
internal static readonly object IsClosing_Key = new object();

public Window FromPoint(PointF point)
{
Expand Down Expand Up @@ -246,21 +247,7 @@ public override void AttachEvent(string id)
Control.FormClosed += (sender, e) => Callback.OnClosed(Widget, EventArgs.Empty);
break;
case Window.ClosingEvent:
Control.FormClosing += delegate(object sender, swf.FormClosingEventArgs e)
{
var args = new CancelEventArgs(e.Cancel);
Callback.OnClosing(Widget, args);

if (!e.Cancel && swf.Application.OpenForms.Count <= 1
|| e.CloseReason == swf.CloseReason.ApplicationExitCall
|| e.CloseReason == swf.CloseReason.WindowsShutDown)
{
var app = ((ApplicationHandler)Application.Instance.Handler);
app.Callback.OnTerminating(app.Widget, args);
}

e.Cancel = args.Cancel;
};
Control.FormClosing += Control_FormClosing;
break;
case Eto.Forms.Control.ShownEvent:
Control.Shown += delegate
Expand All @@ -275,10 +262,7 @@ public override void AttachEvent(string id)
};
break;
case Eto.Forms.Control.LostFocusEvent:
Control.Deactivate += delegate
{
Callback.OnLostFocus(Widget, EventArgs.Empty);
};
Control.Deactivate += (sender, e) => Application.Instance.AsyncInvoke(() => Callback.OnLostFocus(Widget, EventArgs.Empty));
break;
case Window.WindowStateChangedEvent:
var oldState = Control.WindowState;
Expand All @@ -300,6 +284,39 @@ public override void AttachEvent(string id)
}
}

bool IsClosing
{
get => Widget.Properties.Get<bool>(WindowHandler.IsClosing_Key);
set => Widget.Properties.Set(WindowHandler.IsClosing_Key, value);
}

private void Control_FormClosing(object sender, swf.FormClosingEventArgs e)
{
IsClosing = true;
var args = new CancelEventArgs(e.Cancel);
Callback.OnClosing(Widget, args);

if (!e.Cancel && swf.Application.OpenForms.Count <= 1
|| e.CloseReason == swf.CloseReason.ApplicationExitCall
|| e.CloseReason == swf.CloseReason.WindowsShutDown)
{
var app = ((ApplicationHandler)Application.Instance.Handler);
app.Callback.OnTerminating(app.Widget, args);
}

e.Cancel = args.Cancel;
IsClosing = !e.Cancel;

if (!e.Cancel)
{
InternalClosing();
}
}

internal virtual void InternalClosing()
{
}

public MenuBar Menu
{
get
Expand Down Expand Up @@ -389,7 +406,11 @@ public Eto.Forms.ToolBar ToolBar
}
}

public void Close() => Control.Close();
public void Close()
{
if (!IsClosing)
Control.Close();
}

public Icon Icon
{
Expand Down
6 changes: 6 additions & 0 deletions src/Eto.WinForms/Win32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,12 @@ public static MouseButtons GetMouseButtonWParam(IntPtr wParam)
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, SW nCmdShow);

[DllImport("user32.dll")]
public static extern IntPtr GetActiveWindow();

[DllImport("user32.dll")]
public static extern IntPtr SetActiveWindow(IntPtr hWnd);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
Expand Down
141 changes: 74 additions & 67 deletions src/Eto.Wpf/Forms/DialogHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public class DialogHandler : WpfWindow<sw.Window, Dialog, Dialog.ICallback>, Dia
{
Button defaultButton;
Rectangle? parentWindowBounds;
swc.DockPanel dockMain;
swc.Grid gridButtons;
swc.DockPanel dockMain;
swc.Grid gridButtons;

public DialogHandler() : this(new sw.Window()) { }

Expand All @@ -34,35 +34,42 @@ public DialogHandler(sw.Window window)
gridButtons.Margin = new sw.Thickness();
}

public override void SetContainerContent(sw.FrameworkElement content)
{
this.content.Children.Add(dockMain);
swc.DockPanel.SetDock(gridButtons, swc.Dock.Bottom);
dockMain.Children.Add(gridButtons);
dockMain.Children.Add(content);
}
public override void SetContainerContent(sw.FrameworkElement content)
{
this.content.Children.Add(dockMain);
swc.DockPanel.SetDock(gridButtons, swc.Dock.Bottom);
dockMain.Children.Add(gridButtons);
dockMain.Children.Add(content);
}

public DialogDisplayMode DisplayMode { get; set; }
public DialogDisplayMode DisplayMode { get; set; }

public void ShowModal()
{
ReloadButtons();
ReloadButtons();

var owner = Widget.Owner;

if (LocationSet)
{
Control.WindowStartupLocation = sw.WindowStartupLocation.Manual;
}
else if (Widget.Owner != null)
else if (owner != null)
{
// CenterOwner does not work in certain cases (e.g. with autosizing)
Control.WindowStartupLocation = sw.WindowStartupLocation.Manual;
parentWindowBounds = Widget.Owner.Bounds;
parentWindowBounds = owner.Bounds;
Control.Loaded += HandleLoaded;
}

// if the owner doesn't have focus, windows changes the owner's z-order after the dialog closes.
if (owner != null && !owner.HasFocus)
owner.Focus();

Control.ShowDialog();
WpfFrameworkElementHelper.ShouldCaptureMouse = false;

ClearButtons();
ClearButtons();
}

void Control_PreviewKeyDown(object sender, sw.Input.KeyEventArgs e)
Expand Down Expand Up @@ -99,59 +106,59 @@ void HandleLoaded(object sender, EventArgs e)
}

private void ClearButtons()
{
gridButtons.ColumnDefinitions.Clear();
gridButtons.Children.Clear();
}

private void ReloadButtons()
{
gridButtons.ColumnDefinitions.Add(new swc.ColumnDefinition { Width = new sw.GridLength(100, sw.GridUnitType.Star) });
var negativeButtons = Widget.NegativeButtons;
var positiveButtons = Widget.PositiveButtons;
var hasButtons = negativeButtons.Count + positiveButtons.Count > 0;

for (int i = positiveButtons.Count - 1; i >= 0; i--)
AddButton(positiveButtons.Count - i, positiveButtons[i]);

for (int i = 0;i < negativeButtons.Count;i++)
AddButton(positiveButtons.Count + 1 + i, negativeButtons[i]);
gridButtons.Visibility = hasButtons ? System.Windows.Visibility.Visible : System.Windows.Visibility.Hidden;
gridButtons.Margin = new sw.Thickness(hasButtons ? 8 : 0);
}

private void AddButton(int pos, Button button)
{
var native = button.ToNative();
native.Margin = new sw.Thickness(6, 0, 0, 0);

swc.Grid.SetColumn(native, pos);

gridButtons.ColumnDefinitions.Add(new swc.ColumnDefinition { Width = new sw.GridLength(1, sw.GridUnitType.Auto) });
gridButtons.Children.Add(native);
}

public void InsertDialogButton(bool positive, int index, Button item)
{
if(Widget.Visible)
{
ClearButtons();
ReloadButtons();
}
}

public void RemoveDialogButton(bool positive, int index, Button item)
{
if (Widget.Visible)
{
ClearButtons();
ReloadButtons();
}
}

public Button DefaultButton
{
gridButtons.ColumnDefinitions.Clear();
gridButtons.Children.Clear();
}

private void ReloadButtons()
{
gridButtons.ColumnDefinitions.Add(new swc.ColumnDefinition { Width = new sw.GridLength(100, sw.GridUnitType.Star) });

var negativeButtons = Widget.NegativeButtons;
var positiveButtons = Widget.PositiveButtons;
var hasButtons = negativeButtons.Count + positiveButtons.Count > 0;

for (int i = positiveButtons.Count - 1; i >= 0; i--)
AddButton(positiveButtons.Count - i, positiveButtons[i]);

for (int i = 0; i < negativeButtons.Count; i++)
AddButton(positiveButtons.Count + 1 + i, negativeButtons[i]);

gridButtons.Visibility = hasButtons ? System.Windows.Visibility.Visible : System.Windows.Visibility.Hidden;
gridButtons.Margin = new sw.Thickness(hasButtons ? 8 : 0);
}

private void AddButton(int pos, Button button)
{
var native = button.ToNative();
native.Margin = new sw.Thickness(6, 0, 0, 0);

swc.Grid.SetColumn(native, pos);

gridButtons.ColumnDefinitions.Add(new swc.ColumnDefinition { Width = new sw.GridLength(1, sw.GridUnitType.Auto) });
gridButtons.Children.Add(native);
}

public void InsertDialogButton(bool positive, int index, Button item)
{
if (Widget.Visible)
{
ClearButtons();
ReloadButtons();
}
}

public void RemoveDialogButton(bool positive, int index, Button item)
{
if (Widget.Visible)
{
ClearButtons();
ReloadButtons();
}
}

public Button DefaultButton
{
get { return defaultButton; }
set
Expand Down
3 changes: 1 addition & 2 deletions src/Eto.Wpf/Forms/FormHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@ public virtual void Show()
WpfFrameworkElementHelper.ShouldCaptureMouse = false;
}

protected override void InternalClose()
protected override void InternalClosing()
{
// Clear owner so WPF doesn't change the z-order of the parent when closing
SetOwner(null);
Control.Close();
}

public bool ShowActivated
Expand Down
10 changes: 8 additions & 2 deletions src/Eto.Wpf/Forms/WpfWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ private void Control_Closing(object sender, CancelEventArgs e)
e.Cancel = args.Cancel;
IsApplicationClosing = !e.Cancel && willShutDown;
IsClosing = !e.Cancel;
if (!e.Cancel)
{
InternalClosing();
}
}

float LastPixelSize
Expand Down Expand Up @@ -403,7 +407,9 @@ public Eto.Forms.ToolBar ToolBar
}
}

protected virtual void InternalClose() => Control.Close();
protected virtual void InternalClosing()
{
}

public void Close()
{
Expand All @@ -412,7 +418,7 @@ public void Close()
// prevent crash if we call this more than once..
if (!IsClosing)
{
InternalClose();
Control.Close();
}
}
else
Expand Down
Loading

0 comments on commit a4593db

Please sign in to comment.