Skip to content

Commit

Permalink
Merge pull request #2315 from cwensley/curtis/mac-fix-multiple-child-…
Browse files Browse the repository at this point in the history
…focus

Mac: Fix child window focus when there is more than one
  • Loading branch information
cwensley authored Sep 19, 2022
2 parents a6336f3 + aba3869 commit 230762d
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/Eto.Mac/Forms/MacWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1261,15 +1261,32 @@ public virtual void SetOwner(Window owner)
macWindow.Control.AddChildWindow(Control, NSWindowOrderingMode.Above);
OnSetAsChildWindow();
}
Widget.GotFocus += HandleGotFocusAsChild;
}
else
{
Widget.GotFocus -= HandleGotFocusAsChild;
var parentWindow = Control.ParentWindow;
if (parentWindow != null)
parentWindow.RemoveChildWindow(Control);
}
}
}

void HandleGotFocusAsChild(object sender, EventArgs e)
{
// When there are multiple modeless child windows, clicking on one doesn't bring it to front
// so, we remove then re-add the child window to get it to come above again.
var parentWindow = Control.ParentWindow;
var childWindows = parentWindow?.ChildWindows;

// .. only if it isn't already the last child window
if (parentWindow != null && childWindows?.Length > 1 && !Equals(Control.Handle, childWindows[childWindows.Length -1].Handle))
{
parentWindow.RemoveChildWindow(Control);
parentWindow.AddChildWindow(Control, NSWindowOrderingMode.Above);
}
}

internal virtual void OnSetAsChildWindow()
{
Expand Down
50 changes: 50 additions & 0 deletions test/Eto.Test/UnitTests/Forms/WindowTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Eto.Drawing;
using System.Threading;
using System.Threading.Tasks;
using System.ComponentModel;

namespace Eto.Test.UnitTests.Forms
{
Expand Down Expand Up @@ -306,6 +307,55 @@ public void WindowShouldCloseOnLostFocusWithoutHidingParent()
}
);
}

// Hm, this seems useful.. should it be added as an extension method somewhere?
static Task EventAsync<TWidget, TEvent>(TWidget control, Action<TWidget, EventHandler<TEvent>> addHandler, Action<TWidget, EventHandler<TEvent>> removeHandler = null)
where TWidget : Widget
{
var mre = new TaskCompletionSource<bool>();
void EventTriggered(object sender, TEvent e)
{
removeHandler?.Invoke(control, EventTriggered);
mre.TrySetResult(true);
}

addHandler(control, EventTriggered);
return mre.Task;
}

[Test, ManualTest]
public void MultipleChildWindowsShouldGetFocusWhenClicked() => Async(async () =>
{
var form1 = new Form { ClientSize = new Size(200, 200), Location = new Point(300, 300) };
form1.Owner = Application.Instance.MainForm;
form1.Title = "Form1";
form1.Content = new Label
{
VerticalAlignment = VerticalAlignment.Center,
TextAlignment = TextAlignment.Center,
Text = "Click on Form2, it should then get focus and be on top of this form."
};
// var form1ClosedTask = EventTask<EventArgs>(h => form1.Closed += h);
var form1ClosedTask = EventAsync<Form, EventArgs>(form1, (c, h) => c.Closed += h);

var form2 = new Form { ClientSize = new Size(200, 200), Location = new Point(400, 400) };
form2.Owner = Application.Instance.MainForm;
form2.Title = "Form2";
form2.Content = new Label
{
VerticalAlignment = VerticalAlignment.Center,
TextAlignment = TextAlignment.Center,
Text = "Click on Form1, it should then get focus and be on top of this form."
};
var form2ClosedTask = EventAsync<Form, EventArgs>(form2, (c, h) => c.Closed += h);

form1.Show();

form2.Show();

// wait till both forms are closed..
await Task.WhenAll(form1ClosedTask, form2ClosedTask);
});
}
}

0 comments on commit 230762d

Please sign in to comment.