Repository: beeware/toga

Issue:
Add content argument to MainWindow instantiation
### What is the problem or limitation you are having?

Right now, to create a MainWindow and add content to it, we have to do it in two steps and in a not so elegant way:

```
self.main_window = toga.MainWindow(
	title=self.formal_name
)

self.main_window.content = self.main_box
```

### Describe the solution you'd like

Allow assigning "content" during instantiation of MainWindow as well, so we can do it in one step and more elegantly:

```
self.main_window = toga.MainWindow(
	title=self.formal_name,
	content=self.main_box
)
```

This would be consistent with, for example, ScrollContainer.

### Describe alternatives you've considered

1. Make it consistent with other classes — that use "children" — and use "child" instead:

```
self.main_window = toga.MainWindow(
	title=self.formal_name,
	child=self.main_box
)
```

2. Or keep things as they are, at least until other higher priority tasks are completed, as this is a minor improvement

### Additional context

_No response_


Discussion:
That's an odd inconsistency - I'm surprised I didn't notice this before. Agreed that it's something we should address. 

`content=` would seem the obvious API spelling.

Resolving patch:
diff --git a/core/src/toga/app.py b/core/src/toga/app.py
--- a/core/src/toga/app.py
+++ b/core/src/toga/app.py
@@ -209,6 +209,7 @@ def __init__(
         size: tuple[int, int] = (640, 480),
         resizable: bool = True,
         minimizable: bool = True,
+        content: Widget | None = None,
         resizeable=None,  # DEPRECATED
         closeable=None,  # DEPRECATED
     ):
@@ -223,6 +224,7 @@ def __init__(
             pixels <css-units>`.
         :param resizable: Can the window be resized by the user?
         :param minimizable: Can the window be minimized by the user?
+        :param content: The initial content for the window.
         :param resizeable: **DEPRECATED** - Use ``resizable``.
         :param closeable: **DEPRECATED** - Use ``closable``.
         """
@@ -234,6 +236,7 @@ def __init__(
             resizable=resizable,
             closable=True,
             minimizable=minimizable,
+            content=content,
             # Deprecated arguments
             resizeable=resizeable,
             closeable=closeable,
diff --git a/core/src/toga/window.py b/core/src/toga/window.py
--- a/core/src/toga/window.py
+++ b/core/src/toga/window.py
@@ -127,6 +127,7 @@ def __init__(
         closable: bool = True,
         minimizable: bool = True,
         on_close: OnCloseHandler | None = None,
+        content: Widget | None = None,
         resizeable=None,  # DEPRECATED
         closeable=None,  # DEPRECATED
     ) -> None:
@@ -143,6 +144,7 @@ def __init__(
         :param closable: Can the window be closed by the user?
         :param minimizable: Can the window be minimized by the user?
         :param on_close: The initial :any:`on_close` handler.
+        :param content: The initial content for the window.
         :param resizeable: **DEPRECATED** - Use ``resizable``.
         :param closeable: **DEPRECATED** - Use ``closable``.
         """
@@ -193,6 +195,10 @@ def __init__(
             raise RuntimeError("Cannot create a Window before creating an App")
         App.app.windows.add(self)
 
+        # If content has been provided, set it
+        if content:
+            self.content = content
+
         # Create a toolbar that is linked to the app
         self._toolbar = CommandSet(on_change=self._impl.create_toolbar, app=self._app)
 


Test patch:
diff --git a/core/tests/window/test_window.py b/core/tests/window/test_window.py
--- a/core/tests/window/test_window.py
+++ b/core/tests/window/test_window.py
@@ -99,6 +99,25 @@ def test_set_app_with_content(window, app):
     assert content.app == app
 
 
+def test_set_app_with_content_at_instantiation(app):
+    """A window can be created with initial content"""
+    # Set up some initial content box with something inside it:
+    label1 = toga.Label("Hello World")
+    content = toga.Box(children=[label1])
+    assert content.app is None
+
+    window_with_content = toga.Window(content=content)
+
+    # The window content has been set
+    assert window_with_content.content == content
+    # The full tree of content has been assigned to the app
+    assert content.app == app
+    assert label1.app == app
+
+    assert content.window == window_with_content
+    assert label1.window == window_with_content
+
+
 @pytest.mark.parametrize(
     "value, expected",
     [
diff --git a/testbed/tests/test_window.py b/testbed/tests/test_window.py
--- a/testbed/tests/test_window.py
+++ b/testbed/tests/test_window.py
@@ -226,6 +226,24 @@ async def test_secondary_window_with_args(app, second_window, second_window_prob
 
         assert second_window not in app.windows
 
+    async def test_secondary_window_with_content(app):
+        """A window can be created with initial content"""
+        # Setup the box with something inside it:
+        label1 = toga.Label("Hello World")
+        content = toga.Box(children=[label1])
+
+        try:
+            window_with_content = toga.Window(content=content)
+            window_with_content_probe = window_probe(app, window_with_content)
+
+            window_with_content.show()
+            await window_with_content_probe.wait_for_window(
+                "Create a window with initial content"
+            )
+            assert window_with_content.content == content
+        finally:
+            window_with_content.close()
+
     async def test_secondary_window_cleanup(app_probe):
         """Memory for windows is cleaned up when windows are deleted."""
         # Create and show a window with content. We can't use the second_window fixture