Skip to content

Commit

Permalink
Merge branch 'main' into widget_initialization_updated_travertino
Browse files Browse the repository at this point in the history
  • Loading branch information
HalfWhitt committed Dec 4, 2024
2 parents ad56c34 + df65161 commit af2a288
Show file tree
Hide file tree
Showing 43 changed files with 2,148 additions and 446 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,7 @@ jobs:
sudo apt update -y
sudo apt install -y --no-install-recommends \
mutter pkg-config python3-dev libgirepository1.0-dev libcairo2-dev \
gir1.2-webkit2-4.1 gir1.2-xapp-1.0 \
libjpeg-dev # remove once the version of Pillow has a wheel on PyPI for Python 3.12
gir1.2-webkit2-4.1 gir1.2-xapp-1.0
# Start Virtual X Server
echo "Start X server..."
Expand Down
10 changes: 0 additions & 10 deletions android/src/toga_android/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,16 +323,6 @@ def get_current_window(self):
def set_current_window(self, window):
pass

######################################################################
# Full screen control
######################################################################

def enter_full_screen(self, windows):
pass

def exit_full_screen(self, windows):
pass

######################################################################
# Platform-specific APIs
######################################################################
Expand Down
75 changes: 73 additions & 2 deletions android/src/toga_android/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from java import dynamic_proxy
from java.io import ByteArrayOutputStream

from toga.constants import WindowState
from toga.types import Position, Size

from .container import Container
Expand All @@ -36,6 +37,9 @@ def __init__(self, interface, title, position, size):
self.interface = interface
self.interface._impl = self
self._initial_title = title
# Use a shadow variable since the presence of ActionBar is not
# a reliable indicator for confirmation of presentation mode.
self._in_presentation_mode = False

######################################################################
# Window properties
Expand All @@ -47,6 +51,11 @@ def get_title(self):
def set_title(self, title):
self.app.native.setTitle(title)

def show_actionbar(self, show): # pragma: no cover
# The testbed can't create a simple window, so we can't test this.
# ActionBar is always hidden on Window.
pass

######################################################################
# Window lifecycle
######################################################################
Expand Down Expand Up @@ -137,8 +146,63 @@ def get_visible(self):
# Window state
######################################################################

def set_full_screen(self, is_full_screen):
self.interface.factory.not_implemented("Window.set_full_screen()")
def get_window_state(self, in_progress_state=False):
decor_view = self.app.native.getWindow().getDecorView()
system_ui_flags = decor_view.getSystemUiVisibility()
if system_ui_flags & (
decor_view.SYSTEM_UI_FLAG_FULLSCREEN
| decor_view.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| decor_view.SYSTEM_UI_FLAG_IMMERSIVE
):
if self._in_presentation_mode:
return WindowState.PRESENTATION
else:
return WindowState.FULLSCREEN
return WindowState.NORMAL

def set_window_state(self, state):
current_state = self.get_window_state()
decor_view = self.app.native.getWindow().getDecorView()

if current_state == state:
return

elif current_state != WindowState.NORMAL:
if current_state == WindowState.FULLSCREEN:
decor_view.setSystemUiVisibility(0)

else: # current_state == WindowState.PRESENTATION:
decor_view.setSystemUiVisibility(0)
self.show_actionbar(True)
self._in_presentation_mode = False

self.set_window_state(state)

else: # current_state == WindowState.NORMAL:
if state == WindowState.MAXIMIZED:
# no-op on Android.
pass

elif state == WindowState.MINIMIZED:
# no-op on Android.
pass

elif state == WindowState.FULLSCREEN:
decor_view.setSystemUiVisibility(
# These constants are all marked as deprecated as of API 30.
decor_view.SYSTEM_UI_FLAG_FULLSCREEN
| decor_view.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| decor_view.SYSTEM_UI_FLAG_IMMERSIVE
)

else: # state == WindowState.PRESENTATION:
decor_view.setSystemUiVisibility(
decor_view.SYSTEM_UI_FLAG_FULLSCREEN
| decor_view.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| decor_view.SYSTEM_UI_FLAG_IMMERSIVE
)
self.show_actionbar(False)
self._in_presentation_mode = True

######################################################################
# Window capabilities
Expand Down Expand Up @@ -168,3 +232,10 @@ def create_toolbar(self):
# Toolbar items are configured as part of onPrepareOptionsMenu; trigger that
# handler.
self.app.native.invalidateOptionsMenu()

def show_actionbar(self, show):
actionbar = self.app.native.getSupportActionBar()
if show:
actionbar.show()
else:
actionbar.hide()
21 changes: 19 additions & 2 deletions android/tests_backend/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,26 @@


class WindowProbe(BaseProbe, DialogsMixin):
supports_fullscreen = True
supports_presentation = True

def __init__(self, app, window):
super().__init__(app)
self.native = self.app._impl.native
self.window = window
self.impl = self.window._impl

async def wait_for_window(self, message, minimize=False, full_screen=False):
await self.redraw(message)
async def wait_for_window(
self,
message,
minimize=False,
full_screen=False,
state_switch_not_from_normal=False,
):
await self.redraw(
message,
delay=(0.5 if (full_screen or state_switch_not_from_normal) else 0.1),
)

@property
def content_size(self):
Expand All @@ -34,6 +47,10 @@ def top_bar_height(self):
def _native_menu(self):
return self.native.findViewById(appcompat_R.id.action_bar).getMenu()

@property
def instantaneous_state(self):
return self.impl.get_window_state(in_progress_state=False)

def _toolbar_items(self):
result = []
prev_group = None
Expand Down
1 change: 1 addition & 0 deletions changes/1857.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Toga apps can now detect and set their window states including maximized, minimized, normal, full screen and presentation states.
1 change: 1 addition & 0 deletions changes/1857.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"Full screen mode" on an app has been renamed "Presentation mode" to avoid the ambiguity with "full screen mode" on a window. The ``toga.App.enter_full_screen`` and ``toga.App.exit_full_screen`` APIs have been renamed ``toga.App.enter_presentation_mode`` and ``toga.App.exit_presentation_mode``, respectively. ```
1 change: 1 addition & 0 deletions changes/2893.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
An unnecessary dependency was removed from the Linux Wayland CI environment.
1 change: 1 addition & 0 deletions changes/3006.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Updated pytest from 8.3.3 to 8.3.4 in /core.
1 change: 1 addition & 0 deletions changes/3007.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Updated pytest from 8.3.3 to 8.3.4 in /testbed.
34 changes: 0 additions & 34 deletions cocoa/src/toga_cocoa/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
NSCursor,
NSMenu,
NSMenuItem,
NSNumber,
NSPanel,
NSScreen,
)
Expand Down Expand Up @@ -386,36 +385,3 @@ def get_current_window(self):

def set_current_window(self, window):
window._impl.native.makeKeyAndOrderFront(window._impl.native)

######################################################################
# Full screen control
######################################################################

def enter_full_screen(self, windows):
opts = NSMutableDictionary.alloc().init()
opts.setObject(
NSNumber.numberWithBool(True), forKey="NSFullScreenModeAllScreens"
)

for window, screen in zip(windows, NSScreen.screens):
# The widgets are actually added to window._impl.container.native, instead
# of window.content._impl.native. And window._impl.native.contentView is
# window._impl.container.native. Hence, we need to go fullscreen on
# window._impl.container.native instead.
window._impl.container.native.enterFullScreenMode(screen, withOptions=opts)
# Going full screen causes the window content to be re-homed
# in a NSFullScreenWindow; teach the new parent window
# about its Toga representations.
window._impl.container.native.window._impl = window._impl
window._impl.container.native.window.interface = window
window.content.refresh()

def exit_full_screen(self, windows):
opts = NSMutableDictionary.alloc().init()
opts.setObject(
NSNumber.numberWithBool(True), forKey="NSFullScreenModeAllScreens"
)

for window in windows:
window._impl.container.native.exitFullScreenModeWithOptions(opts)
window.content.refresh()
Loading

0 comments on commit af2a288

Please sign in to comment.