Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed cocoa window content visibilty in app full screen #2800

Merged
merged 5 commits into from
Sep 2, 2024

Conversation

proneon267
Copy link
Contributor

@proneon267 proneon267 commented Sep 1, 2024

Fixed cocoa window content visibilty in app full screen.

The bug was caused since in cocoa, widgets are not added to window.content._impl.native, but rather to window._impl.container.native. However, this PR uses NSWindow.contentView to remain internal-implementation independent and less likely to break with any future changes.

#2796

With window.content as toga.Box():

"""
My first application
"""

import toga


class HelloWorld(toga.App):
    def handle_exit(self, widget, **kwargs):
        self.exit_full_screen()

    def handle_press(self, widget, **kwargs):
        self.set_full_screen(self.main_window)
        self.main_window.content.add(toga.Label(text="We are in App Full Screen mode"))

    def startup(self):
        """Construct and show the Toga application.

        Usually, you would add your application to a main content box.
        We then create a main window (with a name matching the app), and
        show the main window.
        """

        self.main_window = toga.MainWindow(title=self.formal_name)
        self.main_window.content = toga.Box(
            children=[
                toga.Button(
                    text="Enter App Full Screen Mode", on_press=self.handle_press
                ),
                toga.Button(
                    text="Exit App Full Screen Mode", on_press=self.handle_exit
                ),
                toga.Label(
                    text=""" Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"""
                    """ Maecenas vitae felis non est vehicula pulvinar id eu augue.\n"""
                    """ Maecenas et lectus tellus. Sed et lacinia erat, at pharetra quam.\n"""
                ),
            ]
        )

        self.main_window.show()


def main():
    return HelloWorld()
Before Entering FullScreen After Entering FullScreen
Screenshot 2024-09-01 at 1 15 19 PM Screenshot 2024-09-01 at 1 16 47 PM

With window.content as toga.ScrollContainer():

"""
My first application
"""

import toga


class HelloWorld(toga.App):
    def handle_exit(self, widget, **kwargs):
        self.exit_full_screen()

    def handle_press(self, widget, **kwargs):
        self.set_full_screen(self.main_window)
        self.main_window.content.content.add(
            toga.Label(text="We are in App Full Screen mode")
        )

    def startup(self):
        """Construct and show the Toga application.

        Usually, you would add your application to a main content box.
        We then create a main window (with a name matching the app), and
        show the main window.
        """

        self.main_window = toga.MainWindow(title=self.formal_name)
        self.main_window.content = toga.ScrollContainer(
            content=toga.Box(
                children=[
                    toga.Button(
                        text="Enter App Full Screen Mode", on_press=self.handle_press
                    ),
                    toga.Button(
                        text="Exit App Full Screen Mode", on_press=self.handle_exit
                    ),
                    toga.Label(
                        text=""" Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"""
                        """ Maecenas vitae felis non est vehicula pulvinar id eu augue.\n"""
                        """ Maecenas et lectus tellus. Sed et lacinia erat, at pharetra quam.\n"""
                    ),
                ]
            )
        )

        self.main_window.show()


def main():
    return HelloWorld()
Before Entering FullScreen After Entering FullScreen
Screenshot 2024-09-01 at 1 08 32 PM Screenshot 2024-09-01 at 1 12 52 PM

PR Checklist:

  • All new features have been tested
  • All new features have been documented
  • I have read the CONTRIBUTING.md file
  • I will abide by the code of conduct

# In app full-screen mode, window._impl.native.contentView is moved to a
# _NSFullScreenWindow, making NSWindow.contentView as None. Hence, retain a
# reference to the view before going full-screen.
self.content_view = self.native.contentView
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Full explaination comment that I had previously written, but felt too big to include in the source file:

Once we go fullscreen on window._impl.native.contentView, the view referenced by window._impl.native.contentView is detached from the current native NSWindow, and attached to a _NSFullScreenWindow. And the view can remain attached to 1 native window at a time i.e., either to NSWindow or NSFullScreenWindow, but not to both.

Hence, we can no longer accesss the view by window._impl.native.contentView, since window._impl.native.contentView will be None. So, it is useful to retain a reference to the view attached to window._impl.native.contentView, before going fullscreen or doing any other operation that would displace the contentView from the current window.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may not be able to reference _impl.native.contentView, but you can reference _impl.container.native. That keeps the container as a source of truth, and removes any bugs that could leak in if the container content is changed but content_view isn't updated.

# guaranteed to be present and assigned on a NSWindow.
#
# Hence, we need to go fullscreen on window._impl.native.contentView instead.
window._impl.content_view.enterFullScreenMode(screen, withOptions=opts)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a bonus effect of using window._impl.native.contentView, we can lift the requirement of needing a content to be assigned to a window in cocoa, for entering into PRESENTATION mode in #2473

@proneon267
Copy link
Contributor Author

The linux-wayland testbed failure is unrelated and I haven't made any changes to other backends or to the core.

Copy link
Member

@freakboy3742 freakboy3742 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good analysis of the underlying problem. The fix broadly looks good, although as I've noted inline, it can be made cleaner by removing the copy of the content view and using the source of truth - the container's content.

There's also a need for a testbed test to validate the change works as expected. This is resolving a bug, so we should have a test to validate that the bug no longer exists. We have existing tests of going full screen; I suspect if we added a validation that the size of the rendered content is >0, it would fail until this fix is applied.

# In app full-screen mode, window._impl.native.contentView is moved to a
# _NSFullScreenWindow, making NSWindow.contentView as None. Hence, retain a
# reference to the view before going full-screen.
self.content_view = self.native.contentView
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may not be able to reference _impl.native.contentView, but you can reference _impl.container.native. That keeps the container as a source of truth, and removes any bugs that could leak in if the container content is changed but content_view isn't updated.

@freakboy3742
Copy link
Member

Oh - the Wayland failure is an intermittent issue we've seen that seems to be related to the specific timing of actions on CI under Wayland. I've been unable to replicate it locally, but re-running usually fixes it. Feel free to ignore that specific error if you see it in your own tests.

@proneon267
Copy link
Contributor Author

readthedocs failure is a temporary timeout of a fostodon link and is unrelated.

Copy link
Member

@freakboy3742 freakboy3742 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made a small tweak to the release note to make it clear this was a macOS problem, but otherwise - nice work!

@proneon267
Copy link
Contributor Author

Thank you!

@freakboy3742 freakboy3742 merged commit 44c4262 into beeware:main Sep 2, 2024
35 checks passed
@proneon267 proneon267 deleted the full_screen_fix branch September 3, 2024 00:28
@proneon267 proneon267 mentioned this pull request Sep 7, 2024
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants