from toga import GROUP_BREAK, SECTION_BREAK

from .libs import Point, Size, WinForms


class WinFormsViewport:
    def __init__(self, native, frame):
        self.native = native
        self.frame = frame
        self.baseline_dpi = 96

    @property
    def width(self):
        # Treat `native=None` as a 0x0 viewport
        if self.native is None:
            return 0
        return self.native.ClientSize.Width

    @property
    def height(self):
        if self.native is None:
            return 0
        # Subtract any vertical shift of the frame. This is to allow
        # for toolbars, or any other viewport-level decoration.
        return self.native.ClientSize.Height - self.frame.vertical_shift

    @property
    def dpi(self):
        if self.native is None:
            return self.baseline_dpi
        return self.native.CreateGraphics().DpiX


class Window:
    def __init__(self, interface, title, position, size):
        self.interface = interface
        self.interface._impl = self

        # Winforms close handling is caught on the FormClosing handler. To allow
        # for async close handling, we need to be able to abort this close
        # event, and then manually cause the close as part of the async result
        # handling. However, this then causes an is_closing event, which we need
        # to ignore. The `_is_closing` flag lets us easily identify if the
        # window is in the process of closing.
        self._is_closing = False

        self.native = WinForms.Form()
        self.native.interface = self.interface
        self.native.FormClosing += self.winforms_FormClosing

        self.set_title(title)
        self.set_size(size)
        self.set_position(position)

        self.toolbar_native = None
        self.toolbar_items = None
        if self.native.interface.resizeable:
            self.native.Resize += self.winforms_resize
        else:
            self.native.FormBorderStyle = self.native.FormBorderStyle.FixedSingle
            self.native.MaximizeBox = False

    def create_toolbar(self):
        self.toolbar_native = WinForms.ToolStrip()
        for cmd in self.interface.toolbar:
            if cmd == GROUP_BREAK:
                item = WinForms.ToolStripSeparator()
            elif cmd == SECTION_BREAK:
                item = WinForms.ToolStripSeparator()
            else:
                if cmd.icon is not None:
                    native_icon = cmd.icon._impl.native
                    item = WinForms.ToolStripMenuItem(cmd.label, native_icon.ToBitmap())
                else:
                    item = WinForms.ToolStripMenuItem(cmd.label)
                item.Click += cmd._impl.as_handler()
                cmd._impl.native.append(item)
            self.toolbar_native.Items.Add(item)

    def get_position(self):
        return (self.native.Location.X, self.native.Location.Y)

    def set_position(self, position):
        self.native.Location = Point(*position)

    def get_size(self):
        return (self.native.ClientSize.Width, self.native.ClientSize.Height)

    def set_size(self, size):
        self.native.ClientSize = Size(*size)

    def set_app(self, app):
        if app is None:
            return
        icon_impl = app.interface.icon._impl
        if icon_impl is None:
            return
        self.native.Icon = icon_impl.native

    @property
    def vertical_shift(self):
        # vertical shift is the toolbar height or 0
        result = 0
        try:
            result += self.native.interface._impl.toolbar_native.Height
        except AttributeError:
            pass
        try:
            result += self.native.interface._impl.native.MainMenuStrip.Height
        except AttributeError:
            pass
        return result

    def set_content(self, widget):
        if self.toolbar_native:
            self.native.Controls.Add(self.toolbar_native)
            # Create the lookup table of menu items,
            # then force the creation of the menus.
        self.native.Controls.Add(widget.native)

        # Set the widget's viewport to be based on the window's content.
        widget.viewport = WinFormsViewport(native=self.native, frame=self)
        widget.frame = self

        # Add all children to the content widget.
        for child in widget.interface.children:
            child._impl.container = widget

    def get_title(self):
        return self.native.Text

    def set_title(self, title):
        self.native.Text = title

    def show(self):
        # The first render of the content will establish the
        # minimum possible content size; use that to enforce
        # a minimum window size.
        TITLEBAR_HEIGHT = WinForms.SystemInformation.CaptionHeight
        # Now that the content is visible, we can do our initial hinting,
        # and use that as the basis for setting the minimum window size.
        self.interface.content._impl.rehint()
        self.interface.content.style.layout(
            self.interface.content,
            WinFormsViewport(native=None, frame=None),
        )
        self.native.MinimumSize = Size(
            int(self.interface.content.layout.width),
            int(self.interface.content.layout.height) + TITLEBAR_HEIGHT
        )
        self.interface.content.refresh()

        if self.interface is not self.interface.app._main_window:
            self.native.Icon = self.interface.app.icon.bind(self.interface.factory).native
            self.native.Show()

    def winforms_FormClosing(self, sender, event):
        # If the app is exiting, or a manual close has been requested,
        # don't get confirmation; just close.
        if not self.interface.app._impl._is_exiting and not self._is_closing:
            if not self.interface.closeable:
                # Closeability is implemented by shortcutting the close handler.
                event.Cancel = True
            elif self.interface.on_close:
                # If there is an on_close event handler, process it;
                # but then cancel the close event. If the result of
                # on_close handling indicates the window should close,
                # then it will be manually triggered as part of that
                # result handling.
                self.interface.on_close(self)
                event.Cancel = True

    def set_full_screen(self, is_full_screen):
        self.interface.factory.not_implemented('Window.set_full_screen()')

    def set_on_close(self, handler):
        pass

    def close(self):
        self._is_closing = True
        self.native.Close()

    def winforms_resize(self, sender, args):
        if self.interface.content:
            # Re-layout the content
            self.interface.content.refresh()

src/winforms/toga_winforms/window.py
from toga import GROUP_BREAK, SECTION_BREAK

from .libs import Point, Size, WinForms


class WinFormsViewport:
    def __init__(self, native, frame):
        self.native = native
        self.frame = frame
        self.baseline_dpi = 96

    @property
    def width(self):
        # Treat `native=None` as a 0x0 viewport
        if self.native is None:
            return 0
        return self.native.ClientSize.Width

    @property
    def height(self):
        if self.native is None:
            return 0
        # Subtract any vertical shift of the frame. This is to allow
        # for toolbars, or any other viewport-level decoration.
        return self.native.ClientSize.Height - self.frame.vertical_shift

    @property
    def dpi(self):
        if self.native is None:
            return self.baseline_dpi
        return self.native.CreateGraphics().DpiX


class Window:
    def __init__(self, interface, title, position, size):
        self.interface = interface
        self.interface._impl = self

        # Winforms close handling is caught on the FormClosing handler. To allow
        # for async close handling, we need to be able to abort this close
        # event, and then manually cause the close as part of the async result
        # handling. However, this then causes an is_closing event, which we need
        # to ignore. The `_is_closing` flag lets us easily identify if the
        # window is in the process of closing.
        self._is_closing = False

        self.native = WinForms.Form()
        self.native.interface = self.interface
        self.native.FormClosing += self.winforms_FormClosing

        self.native.MinimizeBox = self.native.interface.minimizable

        self.set_title(title)
        self.set_size(size)
        self.set_position(position)

        self.toolbar_native = None
        self.toolbar_items = None
        if self.native.interface.resizeable:
            self.native.Resize += self.winforms_resize
        else:
            self.native.FormBorderStyle = self.native.FormBorderStyle.FixedSingle
            self.native.MaximizeBox = False

    def create_toolbar(self):
        self.toolbar_native = WinForms.ToolStrip()
        for cmd in self.interface.toolbar:
            if cmd == GROUP_BREAK:
                item = WinForms.ToolStripSeparator()
            elif cmd == SECTION_BREAK:
                item = WinForms.ToolStripSeparator()
            else:
                if cmd.icon is not None:
                    native_icon = cmd.icon._impl.native
                    item = WinForms.ToolStripMenuItem(cmd.label, native_icon.ToBitmap())
                else:
                    item = WinForms.ToolStripMenuItem(cmd.label)
                item.Click += cmd._impl.as_handler()
                cmd._impl.native.append(item)
            self.toolbar_native.Items.Add(item)

    def get_position(self):
        return (self.native.Location.X, self.native.Location.Y)

    def set_position(self, position):
        self.native.Location = Point(*position)

    def get_size(self):
        return (self.native.ClientSize.Width, self.native.ClientSize.Height)

    def set_size(self, size):
        self.native.ClientSize = Size(*size)

    def set_app(self, app):
        if app is None:
            return
        icon_impl = app.interface.icon._impl
        if icon_impl is None:
            return
        self.native.Icon = icon_impl.native

    @property
    def vertical_shift(self):
        # vertical shift is the toolbar height or 0
        result = 0
        try:
            result += self.native.interface._impl.toolbar_native.Height
        except AttributeError:
            pass
        try:
            result += self.native.interface._impl.native.MainMenuStrip.Height
        except AttributeError:
            pass
        return result

    def set_content(self, widget):
        if self.toolbar_native:
            self.native.Controls.Add(self.toolbar_native)
            # Create the lookup table of menu items,
            # then force the creation of the menus.
        self.native.Controls.Add(widget.native)

        # Set the widget's viewport to be based on the window's content.
        widget.viewport = WinFormsViewport(native=self.native, frame=self)
        widget.frame = self

        # Add all children to the content widget.
        for child in widget.interface.children:
            child._impl.container = widget

    def get_title(self):
        return self.native.Text

    def set_title(self, title):
        self.native.Text = title

    def show(self):
        # The first render of the content will establish the
        # minimum possible content size; use that to enforce
        # a minimum window size.
        TITLEBAR_HEIGHT = WinForms.SystemInformation.CaptionHeight
        # Now that the content is visible, we can do our initial hinting,
        # and use that as the basis for setting the minimum window size.
        self.interface.content._impl.rehint()
        self.interface.content.style.layout(
            self.interface.content,
            WinFormsViewport(native=None, frame=None),
        )
        self.native.MinimumSize = Size(
            int(self.interface.content.layout.width),
            int(self.interface.content.layout.height) + TITLEBAR_HEIGHT
        )
        self.interface.content.refresh()

        if self.interface is not self.interface.app._main_window:
            self.native.Icon = self.interface.app.icon.bind(self.interface.factory).native
            self.native.Show()

    def winforms_FormClosing(self, sender, event):
        # If the app is exiting, or a manual close has been requested,
        # don't get confirmation; just close.
        if not self.interface.app._impl._is_exiting and not self._is_closing:
            if not self.interface.closeable:
                # Closeability is implemented by shortcutting the close handler.
                event.Cancel = True
            elif self.interface.on_close:
                # If there is an on_close event handler, process it;
                # but then cancel the close event. If the result of
                # on_close handling indicates the window should close,
                # then it will be manually triggered as part of that
                # result handling.
                self.interface.on_close(self)
                event.Cancel = True

    def set_full_screen(self, is_full_screen):
        self.interface.factory.not_implemented('Window.set_full_screen()')

    def set_on_close(self, handler):
        pass

    def close(self):
        self._is_closing = True
        self.native.Close()

    def winforms_resize(self, sender, args):
        if self.interface.content:
            # Re-layout the content
            self.interface.content.refresh()

src/winforms/toga_winforms/window.py
diff --git a/src/winforms/toga_winforms/window.py b/src/winforms/toga_winforms/window.py
index 3522c1edd3..fc2eb20813 100644
--- a/src/winforms/toga_winforms/window.py
+++ b/src/winforms/toga_winforms/window.py
@@ -48,6 +48,8 @@ def __init__(self, interface, title, position, size):
         self.native.interface = self.interface
         self.native.FormClosing += self.winforms_FormClosing
 
+        self.native.MinimizeBox = self.native.interface.minimizable
+
         self.set_title(title)
         self.set_size(size)
         self.set_position(position)

Window is always resizable, minimizable and closeable on windows
**Describe the bug**
Window seems to ignore `resizable`, `minimizable` and `closeable` args on OS Windows: if they're set to `False`, window still can be resized, minimized and closed.

**To Reproduce**
Steps to reproduce the behavior:
1. Pass `minimizable=False`, `resizable=False` and `closeable=False` to `Window.__init__`.
2. Resize it, minimize it, close it.

**Expected behavior**
Window should keep its size, and all of titlebar buttons should be hidden (minimize and close due to corresponding args, and fullscreen due to resizable).

**Simple example**
```python
import toga


class App(toga.App):
    def open_window(self, widget: toga.Widget):
        # resizable, minimizable and closeable are False
        window = toga.Window(
            "window id", "window title", size=(320, 240), resizeable=False, minimizable=False, closeable=False
        )
        window.content = toga.Box()
        self.windows += window
        window.show()

    def startup(self):
        # resizable and minimizable are False
        self.main_window = toga.MainWindow(
            title=self.formal_name, factory=self.factory, resizeable=False, minimizable=False
        )

        box = toga.Box()
        btn = toga.Button("Open second window", on_press=self.open_window)
        box.add(btn)
        self.main_window.content = box

        self.main_window.show()


def main():
    App("testing", "testing").main_loop()


if __name__ == "__main__":
    main()

```

**Screenshots**
![resizing](https://user-images.githubusercontent.com/2825638/152692206-4b1f3a1b-0945-4895-a71b-31c379e26fe6.gif)


**Environment:**
 - Operating System: Windows 10
 - Python version: 3.10.1
 - Software versions:
   - Toga: 0.3.0.dev30
