Exemple Screen/WindowScreen with Alt-Tab and Alt-Enter
Posted: Sat Jan 03, 2026 6:59 pm
Hello everyone,
I've cleaned up some code I wrote a few years ago...
I'm sharing it with you because it might be useful, especially for beginners.
If anyone has any suggestions for improvement, please feel free to share them.
I've cleaned up some code I wrote a few years ago...
I'm sharing it with you because it might be useful, especially for beginners.
If anyone has any suggestions for improvement, please feel free to share them.
Code: Select all
EnableExplicit
; -----------------------------------------------------------------------------
; Structure containing all parameters and states related to display
; -----------------------------------------------------------------------------
Structure screenStruct
isFullScreen.b ; 0 = windowed, 1 = fullscreen
screenWidth.l ; desired width
screenHeight.l ; desired height
screenDepth.l ; color depth (bits)
screenFlags.l ; PB flags for the screen (sync, etc.)
screenTitle.s ; title
spriteMouse.i ; sprite ID used as cursor
mouseX.l ; mouse X position
mouseY.l ; mouse Y position
EndStructure
; Global instance of the screen structure
Global Screen.screenStruct
; -----------------------------------------------------------------------------
; Initialize default values
; -----------------------------------------------------------------------------
Screen\isFullScreen = #False
Screen\screenWidth = 1280
Screen\screenHeight = 720
Screen\screenDepth = 32
Screen\screenFlags = #PB_Screen_SmartSynchronization
Screen\screenTitle = "Demo Alt-Tab / Alt-Enter"
; -----------------------------------------------------------------------------
; Create assets (here a 16x16 sprite to simulate a red cursor)
; -----------------------------------------------------------------------------
Procedure InitAssets()
; Create the sprite + start a drawing context on this sprite
If CreateSprite(Screen\spriteMouse, 16, 16, #PB_Sprite_AlphaBlending) And StartDrawing(SpriteOutput(Screen\spriteMouse))
; Allows drawing with full alpha handling (RGBA channels)
DrawingMode(#PB_2DDrawing_AllChannels)
; Draw a centered red circle at (8,8) with radius 8 (simple cursor)
Circle(8, 8, 8, RGBA(255, 0, 0, 255))
StopDrawing()
Else
Debug "Error Draw cursor"
EndIf
EndProcedure
; -----------------------------------------------------------------------------
; Initialize the screen depending on the mode: fullscreen or windowed
; Returns #True if OK
; -----------------------------------------------------------------------------
Procedure.b InitScreen()
If Screen\isFullScreen
; In fullscreen mode, iterate through available modes to find a mode
; at least equal to the requested resolution, with a 60 Hz refresh.
ExamineScreenModes()
While NextScreenMode()
If ScreenModeWidth() >= Screen\screenWidth And ScreenModeHeight() >= Screen\screenHeight And ScreenModeRefreshRate() = 60
Screen\screenWidth = ScreenModeWidth()
Screen\screenHeight = ScreenModeHeight()
Break
EndIf
Wend
; Open the fullscreen screen
If OpenScreen(Screen\screenWidth, Screen\screenHeight, Screen\screenDepth, Screen\screenTitle, #PB_Screen_WaitSynchronization)
ProcedureReturn #True
Else
MessageRequester("Error", "Unable to open the screen")
End
EndIf
Else
; Windowed mode: create a PB window then a "WindowedScreen" inside it.
; DesktopUnscaledX/Y avoids surprises with Windows scaling (DPI).
If OpenWindow(0, 0, 0, DesktopUnscaledX(Screen\screenWidth), DesktopUnscaledY(Screen\screenHeight),
Screen\screenTitle, #PB_Window_ScreenCentered) And
OpenWindowedScreen(WindowID(0), 0, 0, Screen\screenWidth, Screen\screenHeight, #False, 0, 0, #PB_Screen_WaitSynchronization)
ProcedureReturn #True
EndIf
EndIf
EndProcedure
; -----------------------------------------------------------------------------
; Handle ALT+TAB (focus loss / inactive screen)
; Idea: if the screen is no longer active, close it and wait until activation returns.
; -----------------------------------------------------------------------------
Procedure CheckScreenFocus()
; IsScreenActive() = 0 => the screen is no longer active (e.g., Alt-Tab)
If IsScreenActive() = 0
; Release sprites
;TODO FreeAssets()
FreeSprite(Screen\spriteMouse)
; Create a tiny minimized/borderless window to "keep a window handle"
; while closing the screen. The goal is to wait for an activation event.
OpenWindow(0, 1, 1, 1, 1, Screen\screenTitle, #PB_Window_Minimize | #PB_Window_BorderLess)
; Close fullscreen / windowed screen
CloseScreen()
Protected Event.l
Repeat
Event = WaitWindowEvent()
; If the user closes the window, quit
If Event = #PB_Event_CloseWindow
End
Break
EndIf
; Wait until the window receives the activation event
Until Event = #PB_Event_ActivateWindow
; Once reactivated, close the small window
CloseWindow(0)
; Reinitialize screen + assets
InitScreen()
InitAssets()
EndIf
EndProcedure
; -----------------------------------------------------------------------------
; Toggle windowed <-> fullscreen via ALT + Enter
; -----------------------------------------------------------------------------
Procedure ToggleFullScreen()
; Logical XOR: invert 0/1
Screen\isFullScreen ! 1
; If switching to fullscreen, also close the windowed window.
If Screen\isFullScreen = #True
CloseScreen()
CloseWindow(0)
Else
; If switching back to windowed, only close the screen (window will be recreated)
CloseScreen()
EndIf
; Re-open the correct mode + recreate assets (cursor)
InitScreen()
InitAssets()
EndProcedure
; -----------------------------------------------------------------------------
; Main loop
; -----------------------------------------------------------------------------
Procedure Main()
Protected Event.i
; Initialize subsystems
InitSprite()
InitKeyboard()
InitMouse()
; Initialize display + assets
InitScreen()
InitAssets()
Repeat
; In windowed mode, drain window events to avoid "freeze"
If Screen\isFullScreen = #False
Repeat
Event = WindowEvent()
Until Event = 0
EndIf
; Clear the screen
ClearScreen(RGB(0, 0, 32))
; Update keyboard/mouse
ExamineKeyboard()
ExamineMouse()
; Read mouse position
Screen\mouseX = MouseX()
Screen\mouseY = MouseY()
; Display the cursor sprite at the mouse position
DisplayTransparentSprite(Screen\spriteMouse, Screen\mouseX, Screen\mouseY)
; ALT + Enter => toggle fullscreen
If KeyboardPushed(#PB_Key_LeftAlt) Or KeyboardPushed(#PB_Key_RightAlt)
If KeyboardReleased(#PB_Key_Return)
ToggleFullScreen()
EndIf
EndIf
; Swap buffers (double buffering)
FlipBuffers()
; Handle ALT+TAB / activation loss
CheckScreenFocus()
; Small CPU pause (1ms) to avoid monopolizing resources
Delay(1)
Until KeyboardPushed(#PB_Key_Escape)
; Cleanup
CloseScreen()
EndProcedure
Main()