This is a "cheat sheet" for "gameframe_tools" extension by YellowAfterlife.
The extension can be found on itch.io.
Click on sections to expand/collapse them.
Quick display controls: Categories · Sections · Everything ·

Introduction

Gameframe is an extension gives GameMaker games a custom window border that acts like a native one.

That includes the minimize/maximize buttons, moving/resizing the window, common (and less common) keyboard and mouse shortcuts, and even the window shadow and rounded borders on Windows 11.

Having a custom border+caption subsequently allows for a few things:

  • Toggling window border on demand
  • Supporting exclusive fullscreen, borderless fullscreen, and windowed modes.
    (which as of writing this most players expect from you)
  • Not freezing the application while the user is dragging the window around.
    (essential for competitive online games)
  • Customizing the title bar and/or border
    (now that it's game code that's drawing them)
Setting up
  1. Disable the default window border in

    • GMS1: Global Game Settings - Windows - Graphics
    • GMS2 and GM2022+: Game Options - Windows - Graphics

    ("Borderless window" checkbox)

  2. Create a new persistent object for the extension system, or add code to your existing global controller object:

    Create:

    gameframe_init();
    

    Step:

    gameframe_update();
    

    Draw GUI:

    gameframe_draw()
    
Common use

Per introduction, Gameframe draws its custom interface on the GUI layer.

As result, the caption may draw over your game elements.

To prevent the frame from being "click-through", you have the gameframe_mouse_over_frame variable that you can check for, but there is also a trick to cut down on work required: you can show the game when it's needed (such as when a pause menu is open) and disable it at other times. Adjusted code could look like this:

Create:

gameframe_init();

Step:

var _show_frame = (global.paused
    || instance_exists(objMainMenu)
    // ... other checks that justify a state where a frame is desired
)
gameframe_can_input = _show_frame;

var _target_alpha;
if (_show_frame) _target_alpha = 1; else _target_alpha = 0; // or ?:
gameframe_alpha = lerp(gameframe_alpha, _target_alpha, 0.1);

gameframe_update();

Draw:

if (gameframe_alpha >= 1/255) gameframe_draw();

This would (instantly) disable frame input as soon as game resumes and quickly fade out the frame, then fade it back when the user pauses or quits to the main menu.

Callbacks
gameframe_init()

Should be called on Game Start or in Create - before other functions are used.

gameframe_update()

Should be called once a frame in Step event.

gameframe_draw()

Should be called in Draw GUI event to draw the frame.
If you don't rely on drawing logic, you may opt out of doing this when alpha is close to 0 or you otherwise know that you don't need the frame.

Configuration

Essentials:

gameframe_debug:bool

If enabled, logs semi-important events to output.

gameframe_blend:int

Can be set to quickly apply color blending to default elements

gameframe_alpha:number

Can be set to quickly apply an alpha multiplier to default elements

gameframe_can_input:bool

Can be set to false to disable all input polling. A common use case is to fade out the frame (using gameframe_alpha) and disable polling when your game is in "play" state to avoid dealing with window border UI.

gameframe_can_resize:bool

Can be set to false to disable resizing and maximize/restore button

gameframe_resize_padding:int

Clicking this close (in pixels) to the window edge initiates the resize operation, if enabled

gameframe_border_width:int

Effective width of window border (see gameframe_spr_border), used for deciding where to draw the window buttons

Sprites:

gameframe_spr_border:sprite

Outer window border (9-slice, 2 frames - inactive, active)

gameframe_spr_caption:sprite

Window caption (9-slice, 2 frames - inactive, active)

gameframe_spr_buttons:sprite

Window button icons (4 frames - minimize, maximize, restore, close)

gameframe_spr_pixel:sprite

A white square to be stretched when drawing colored rectangles

Cursor:

gameframe_default_cursor:window_cursor

This is the cursor that will be shown for the middle of the window.

gameframe_set_cursor:bool

If set to false, the extension will not try changing the cursor at all

gameframe_current_cursor:window_cursor
gameframe_dpi_scale:number

If you want to support multiple DPI levels, you can calculate display_get_dpi_x()/96, provide a set of sprites and fonts for the nearest size, and set this variable to the scale of the set you have provided - extension will then scale those to effective size (e.g. if you provided assets for 2x scale, but the system uses 1.5x, frame UI will be drawn at 0.75x scale to compensate)

NOTE: GMS1.4 does not support DPI scaling, display_get_dpi_x always returns 96.

State
gameframe_has_native_extension:bool

If the user gets rid of the DLL, extension will run in reduced mode.

gameframe_mouse_over_frame:bool

Can be read to figure out whether the mouse is currently over the border/titlebar - you should not be handling mouse press events when it is

gameframe_minimize()
gameframe_is_minimized()​bool

Returns whether the window is currently minimized.

gameframe_maximize()

Maximizes the window (much like pressing the button would)

gameframe_is_maximized()​bool

Returns whether the window is currently maximized.

gameframe_restore(?force)

Restores the window to non-maximized, non-full-screen state.

gameframe_set_fullscreen(mode)

Changes the fullscreen mode

  • 0 for returning to windowed mode
  • 1 for "exclusive" (DirectX) fullscreen
  • 2 for borderless fullscreen
gameframe_get_fullscreen()​int

Returns the current fullscreen mode

gameframe_is_fullscreen_window()​bool

Returns whether the window is currently in "fake fullscreen" (mode=2) mode

gameframe_get_drag_flags()​int
Caption & border
gameframe_caption_text:string
gameframe_caption_alpha:number

If you want to fade out the caption but keep the window border, you can change this instead of gameframe_alpha

gameframe_caption_font:font

If set, is used for drawing the above

gameframe_caption_text_align:text_align

Text alignment for the caption

gameframe_caption_icon:sprite
gameframe_caption_margin:int

Number of pixels between the edges of the caption and the icon/text

gameframe_caption_icon_margin:int

Number of pixels between the icon and the text

gameframe_caption_height_normal:number

Titlebar area height, in pixels.
If set to a negative value, is measured in a multiplier of gameframe_spr_caption's height (default -1 being 1x the height).

gameframe_caption_height_maximized:number

Titlebar area height while maximized, same rules as above. (default -2/3 being 2/3x of the sprite's height).

gameframe_caption_get_height()​int

Returns current height (depending on whether the window is maximized)

gameframe_caption_get_overlap()​number

Returns the amount of vertical overlap between the window caption and the game's application_surface, in surface pixels and assuming proportional scaling mode.

This can be used to adjust non-GUI-layer game elements to not overlap te window caption.

If the window is currently in one of the fullscreen modes, returns 0.

Drawing callbacks:

gameframe_caption_draw_border:function(x, y, width, height)

Is called to draw the outer window border.
Takes (x, y, width, height).
By default, this will draw gameframe_spr_border.

gameframe_caption_draw_background:function(x, y, width, height, buttonsX)
gameframe_caption_draw_text:function(x, y, width, height)
Button controller

The following functions relate to window buttons (minimize/maximize/restore/custom) in general.

gameframe_button_array:array

An array of buttons! You can add your own to it

gameframe_button_fade_time:number

Controls how fast (in seconds) buttons fade in/out on hover.
The default value (0.2) matches Win10 behaviour.

gameframe_button_get_combined_width()​int

Returns combined width of all buttons (including margins)

gameframe_button_get_combined_offset(windowWidth)​int

Returns where the window buttons should be, given the specified window width (window width - border width - combined width)

gameframe_button_reset()

Un-presses and un-hovers every button.
Used on occasions like minimizing the window.

Buttons

The following functions allow you to manipulate the existing buttons (minimize/maximize/close) or create your own.

game_frame_button_create(name, icon, subimg, onClick)​

Creates a new button.
Don't forget to add it to gameframe_button_array afterwards!

The name can be anything and is only useful to you.
icon is a sprite displayed in the middle of the button.
subimg is the subimage to use from that sprite.
onClick is the click handler for the button.

game_frame_button_set_name(game_frame_button, value)

Button names exist purely for telling them apart.

game_frame_button_get_name(game_frame_button)​string
game_frame_button_set_custom(game_frame_button, value)

Stores arbitrary user-defined values and can be used to attach additional metadata/state to the button.

game_frame_button_get_custom(game_frame_button)​

Icon:

game_frame_button_set_icon(game_frame_button, value)
game_frame_button_get_icon(game_frame_button)​sprite
game_frame_button_set_subimg(game_frame_button, value)

Subimage of above sprite to use

game_frame_button_get_subimg(game_frame_button)​int

Margins:

game_frame_button_set_margin_left(game_frame_button, value)

Empty space to add to the left of the button

game_frame_button_get_margin_left(game_frame_button)​int
game_frame_button_set_margin_right(game_frame_button, value)

Empty space to add to the right of the button

game_frame_button_get_margin_right(game_frame_button)​int

State:

game_frame_button_set_hover(game_frame_button, value)

Indicates whether the mouse is over the button.

game_frame_button_get_hover(game_frame_button)​bool
game_frame_button_set_pressed(game_frame_button, value)

Indicates whether the button is currently being held down.
(note that the mouse may no longer be over the button while doing so)

game_frame_button_get_pressed(game_frame_button)​bool
game_frame_button_set_enabled(game_frame_button, value)

Indicates whether the button is active.
(setting this to false disables interactions with it).

game_frame_button_get_enabled(game_frame_button)​bool
game_frame_button_set_fade(game_frame_button, value)
game_frame_button_get_fade(game_frame_button)​number

Handlers:

game_frame_button_set_click(game_frame_button, value)

Executed when the button is clicked.
Receives a button reference as the first argument.

game_frame_button_get_click(game_frame_button)​
game_frame_button_set_get_width(game_frame_button, value)

A function/script that takes a button and should return the button's width in pixels.
By default, returns the button sprite's width.

game_frame_button_get_get_width(game_frame_button)​
game_frame_button_set_update(game_frame_button, value)

Ran during update loop. Takes a button.
Can be used for things like calling icon/subimg/enabled to reflect button's state.
The default maximize/restore button uses this to change state.

game_frame_button_get_update(game_frame_button)​
game_frame_button_set_draw_underlay(game_frame_button, value)

Should draw a button's underlay at specified location.
Takes (button, x, y, width, height).
By default, draws a rectangle and does fade in/out based on button state.
Note that the default "close" button has its own handler for a red highlight!

game_frame_button_get_draw_underlay(game_frame_button)​
game_frame_button_set_draw_icon(game_frame_button, value)

Should draw the button icon at the specified location.
Takes (button, x, y, width, height).
By default, this draws the button's sprite amid the area.

game_frame_button_get_draw_icon(game_frame_button)​
Limitations
RTL support

The extension does not currently mirror the UI order on Hebrew and Arabic systems, like Windows itself does.

Purpose-specific operations

Windows works in mysterious ways and certain operations (like moving the window to the side of the screen to snap it) only work for windows with specific configuration.

However, messing with the game window's configuration in GameMaker is rather dangerous and easily results in soft-locking the game, so I don't.

FAQ
Mac & Linux

The extension uses Windows-specific tricks for some operations (such as resizing) so functionality on non-Windows is rather limited ... but also, Mac and Linux do not have the same problems as Windows does - the fullscreen Just Works, for example - no need to have two fullscreen modes.