2021-07-18 17:47:07 -07:00
//! Window type and related functions
const std = @import ( " std " ) ;
const c = @import ( " c.zig " ) . c ;
const Error = @import ( " errors.zig " ) . Error ;
const getError = @import ( " errors.zig " ) . getError ;
2021-07-18 21:35:52 -07:00
const Monitor = @import ( " Monitor.zig " ) ;
2021-07-18 17:47:07 -07:00
const Window = @This ( ) ;
2021-07-18 21:35:52 -07:00
handle : * c . GLFWwindow ,
2021-07-18 17:47:07 -07:00
/// Resets all window hints to their default values.
///
/// This function resets all window hints to their default values.
///
/// Possible errors include glfw.Error.NotInitialized.
///
/// @thread_safety This function must only be called from the main thread.
///
/// see also: window_hints, glfw.Window.hint, glfw.Window.hintString
2021-07-18 22:04:03 -07:00
pub inline fn defaultHints ( ) Error ! void {
2021-07-18 17:47:07 -07:00
c . glfwDefaultWindowHints ( ) ;
try getError ( ) ;
}
2021-07-18 20:01:16 -07:00
/// Sets the specified window hint to the desired value.
///
/// This function sets hints for the next call to glfw.Window.create. The hints, once set, retain
/// their values until changed by a call to this function or glfw.window.defaultHints, or until the
/// library is terminated.
///
/// Only integer value hints can be set with this function. String value hints are set with
/// glfw.Window.hintString.
///
/// This function does not check whether the specified hint values are valid. If you set hints to
/// invalid values this will instead be reported by the next call to glfw.createWindow.
///
/// Some hints are platform specific. These may be set on any platform but they will only affect
/// their specific platform. Other platforms will ignore them.
///
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.InvalidEnum.
///
/// @thread_safety This function must only be called from the main thread.
///
/// see also: window_hints, glfw.Window.hintString, glfw.Window.defaultHints
2021-07-18 22:04:03 -07:00
pub inline fn hint ( hint_const : usize , value : isize ) Error ! void {
2021-07-18 20:01:16 -07:00
c . glfwWindowHint ( @intCast ( c_int , hint_const ) , @intCast ( c_int , value ) ) ;
try getError ( ) ;
}
2021-07-18 20:33:04 -07:00
/// Sets the specified window hint to the desired value.
///
/// This function sets hints for the next call to glfw.Window.create. The hints, once set, retain
/// their values until changed by a call to this function or glfw.Window.defaultHints, or until the
/// library is terminated.
///
/// Only string type hints can be set with this function. Integer value hints are set with
/// glfw.Window.hint.
///
/// This function does not check whether the specified hint values are valid. If you set hints to
/// invalid values this will instead be reported by the next call to glfw.window.create.
///
/// Some hints are platform specific. These may be set on any platform but they will only affect
/// their specific platform. Other platforms will ignore them. Setting these hints requires no
/// platform specific headers or functions.
///
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.InvalidEnum.
///
/// @pointer_lifetime The specified string is copied before this function returns.
///
/// @thread_safety This function must only be called from the main thread.
///
/// see also: window_hints, glfw.Window.hint, glfw.Window.defaultHints
2021-07-18 22:04:03 -07:00
pub inline fn hintString ( hint_const : usize , value : [ : 0 ] const u8 ) Error ! void {
2021-07-18 20:33:04 -07:00
c . glfwWindowHintString ( @intCast ( c_int , hint_const ) , & value [ 0 ] ) ;
try getError ( ) ;
}
2021-07-18 21:35:52 -07:00
/// Creates a window and its associated context.
///
/// This function creates a window and its associated OpenGL or OpenGL ES context. Most of the
/// options controlling how the window and its context should be created are specified with window
/// hints using `glfw.Window.hint`.
///
/// Successful creation does not change which context is current. Before you can use the newly
/// created context, you need to make it current using `glfw.Window.makeContextCurrent`. For
/// information about the `share` parameter, see context_sharing.
///
/// The created window, framebuffer and context may differ from what you requested, as not all
/// parameters and hints are hard constraints. This includes the size of the window, especially for
/// full screen windows. To query the actual attributes of the created window, framebuffer and
/// context, see glfw.Window.getAttrib, glfw.Window.getSize and glfw.window.getFramebufferSize.
///
/// To create a full screen window, you need to specify the monitor the window will cover. If no
/// monitor is specified, the window will be windowed mode. Unless you have a way for the user to
/// choose a specific monitor, it is recommended that you pick the primary monitor. For more
/// information on how to query connected monitors, see @ref monitor_monitors.
///
/// For full screen windows, the specified size becomes the resolution of the window's _desired
/// video mode_. As long as a full screen window is not iconified, the supported video mode most
/// closely matching the desired video mode is set for the specified monitor. For more information
/// about full screen windows, including the creation of so called _windowed full screen_ or
/// _borderless full screen_ windows, see window_windowed_full_screen.
///
/// Once you have created the window, you can switch it between windowed and full screen mode with
/// glfw.Window.setMonitor. This will not affect its OpenGL or OpenGL ES context.
///
/// By default, newly created windows use the placement recommended by the window system. To create
/// the window at a specific position, make it initially invisible using the glfw.version window
/// hint, set its position and then show it.
///
/// As long as at least one full screen window is not iconified, the screensaver is prohibited from
/// starting.
///
/// Window systems put limits on window sizes. Very large or very small window dimensions may be
/// overridden by the window system on creation. Check the actual size after creation.
///
/// The swap interval is not set during window creation and the initial value may vary depending on
/// driver settings and defaults.
///
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum, glfw.Error.InvalidValue,
/// glfw.Error.APIUnavailable, glfw.Error.VersionUnavailable, glfw.Error.FormatUnavailable and
/// glfw.Error.PlatformError.
///
/// Parameters are as follows:
///
/// * `width` The desired width, in screen coordinates, of the window.
/// * `height` The desired height, in screen coordinates, of the window.
/// * `title` The initial, UTF-8 encoded window title.
/// * `monitor` The monitor to use for full screen mode, or `null` for windowed mode.
/// * `share` The window whose context to share resources with, or `null` to not share resources.
///
/// win32: Window creation will fail if the Microsoft GDI software OpenGL implementation is the
/// only one available.
///
/// win32: If the executable has an icon resource named `GLFW_ICON`, it will be set as the initial
/// icon for the window. If no such icon is present, the `IDI_APPLICATION` icon will be used
/// instead. To set a different icon, see glfw.Window.setIcon.
///
/// win32: The context to share resources with must not be current on any other thread.
///
/// macos: The OS only supports forward-compatible core profile contexts for OpenGL versions 3.2
/// and later. Before creating an OpenGL context of version 3.2 or later you must set the
/// `glfw.opengl_forward_compat` and `glfw.opengl_profile` hints accordingly. OpenGL 3.0 and 3.1
/// contexts are not supported at all on macOS.
///
/// macos: The GLFW window has no icon, as it is not a document window, but the dock icon will be
/// the same as the application bundle's icon. For more information on bundles, see the
/// [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
/// in the Mac Developer Library.
///
/// macos: The first time a window is created the menu bar is created. If GLFW finds a `MainMenu.nib`
/// it is loaded and assumed to contain a menu bar. Otherwise a minimal menu bar is created
/// manually with common commands like Hide, Quit and About. The About entry opens a minimal about
/// dialog with information from the application's bundle. Menu bar creation can be disabled
/// entirely with the glfw.cocoa_menubar init hint.
///
/// macos: On OS X 10.10 and later the window frame will not be rendered at full resolution on
/// Retina displays unless the glfw.cocoa_retina_framebuffer hint is true (1) and the `NSHighResolutionCapable`
/// key is enabled in the application bundle's `Info.plist`. For more information, see
/// [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html)
/// in the Mac Developer Library. The GLFW test and example programs use a custom `Info.plist`
/// template for this, which can be found as `CMake/MacOSXBundleInfo.plist.in` in the source tree.
///
/// macos: When activating frame autosaving with glfw.cocoa_frame_name, the specified window size
/// and position may be overridden by previously saved values.
///
/// x11: Some window managers will not respect the placement of initially hidden windows.
///
/// x11: Due to the asynchronous nature of X11, it may take a moment for a window to reach its
/// requested state. This means you may not be able to query the final size, position or other
/// attributes directly after window creation.
///
/// x11: The class part of the `WM_CLASS` window property will by default be set to the window title
/// passed to this function. The instance part will use the contents of the `RESOURCE_NAME`
/// environment variable, if present and not empty, or fall back to the window title. Set the glfw.x11_class_name
/// and glfw.x11_instance_name window hints to override this.
///
/// wayland: Compositors should implement the xdg-decoration protocol for GLFW to decorate the
/// window properly. If this protocol isn't supported, or if the compositor prefers client-side
/// decorations, a very simple fallback frame will be drawn using the wp_viewporter protocol. A
/// compositor can still emit close, maximize or fullscreen events, using for instance a keybind
/// mechanism. If neither of these protocols is supported, the window won't be decorated.
///
/// wayland: A full screen window will not attempt to change the mode, no matter what the
/// requested size or refresh rate.
///
/// wayland: Screensaver inhibition requires the idle-inhibit protocol to be implemented in the
/// user's compositor.
///
/// @thread_safety This function must only be called from the main thread.
///
/// see also: window_creation, glfw.Window.destroy
2021-07-18 22:04:03 -07:00
pub inline fn create ( width : usize , height : usize , title : [ * c ] const u8 , monitor : ? Monitor , share : ? Window ) Error ! Window {
2021-07-18 21:35:52 -07:00
const handle = c . glfwCreateWindow (
@intCast ( c_int , width ) ,
@intCast ( c_int , height ) ,
& title [ 0 ] ,
if ( monitor ) | m | m . handle else null ,
if ( share ) | w | w . handle else null ,
) ;
try getError ( ) ;
return Window { . handle = handle . ? } ;
}
2021-07-18 21:41:21 -07:00
/// Destroys the specified window and its context.
///
/// This function destroys the specified window and its context. On calling this function, no
/// further callbacks will be called for that window.
///
/// If the context of the specified window is current on the main thread, it is detached before
/// being destroyed.
///
/// note: The context of the specified window must not be current on any other thread when this
/// function is called.
///
/// @reentrancy This function must not be called from a callback.
///
/// @thread_safety This function must only be called from the main thread.
///
/// see also: window_creation, glfw.Window.create
2021-07-18 22:04:03 -07:00
pub inline fn destroy ( self : Window ) void {
2021-07-18 21:41:21 -07:00
c . glfwDestroyWindow ( self . handle ) ;
// Technically, glfwDestroyWindow could produce errors including glfw.Error.NotInitialized and
// glfw.Error.PlatformError. But how would anybody handle them? By creating a new window to
// warn the user? That seems user-hostile. Also, `defer try window.destroy()` isn't possible in
// Zig, so by returning an error we'd make it harder to destroy the window properly. So we differ
// from GLFW here: we discard any potential error from this operation.
getError ( ) catch { } ;
}
2021-07-18 21:57:46 -07:00
/// Checks the close flag of the specified window.
///
/// This function returns the value of the close flag of the specified window.
///
/// @thread_safety This function may be called from any thread. Access is not synchronized.
///
/// see also: window_close
2021-07-18 22:04:03 -07:00
pub inline fn shouldClose ( self : Window ) bool {
2021-07-18 21:57:46 -07:00
const flag = c . glfwWindowShouldClose ( self . handle ) ;
// The only error shouldClose could return would be glfw.Error.NotInitialized, which would
// definitely have occurred before calls to shouldClose. Returning an error here makes the API
// awkward to use, so we discard it instead.
getError ( ) catch { } ;
return flag = = c . GLFW_TRUE ;
}
2021-07-18 22:01:18 -07:00
/// Sets the close flag of the specified window.
///
/// This function sets the value of the close flag of the specified window. This can be used to
/// override the user's attempt to close the window, or to signal that it should be closed.
///
/// Possible errors include glfw.Error.NotInitialized.
///
/// @thread_safety This function may be called from any thread. Access is not
/// synchronized.
///
/// see also: window_close
2021-07-18 22:04:03 -07:00
pub inline fn setShouldClose ( self : Window , value : bool ) Error ! void {
2021-07-18 22:01:18 -07:00
const boolean = if ( value ) c . GLFW_TRUE else c . GLFW_FALSE ;
c . glfwSetWindowShouldClose ( self . handle , boolean ) ;
try getError ( ) ;
}
2021-07-18 17:47:07 -07:00
test " defaultHints " {
const glfw = @import ( " main.zig " ) ;
try glfw . init ( ) ;
defer glfw . terminate ( ) ;
try defaultHints ( ) ;
}
2021-07-18 20:01:16 -07:00
test " hint " {
const glfw = @import ( " main.zig " ) ;
try glfw . init ( ) ;
defer glfw . terminate ( ) ;
try hint ( glfw . focused , 1 ) ;
try defaultHints ( ) ;
}
2021-07-18 20:33:04 -07:00
test " hintString " {
const glfw = @import ( " main.zig " ) ;
try glfw . init ( ) ;
defer glfw . terminate ( ) ;
try hintString ( glfw . x11_class_name , " myclass " ) ;
}
2021-07-18 21:35:52 -07:00
test " createWindow " {
const glfw = @import ( " main.zig " ) ;
try glfw . init ( ) ;
defer glfw . terminate ( ) ;
const window = glfw . Window . create ( 640 , 480 , " Hello, Zig! " , null , null ) catch | err | {
// return without fail, because most of our CI environments are headless / we cannot open
// windows on them.
std . debug . print ( " note: failed to create window: {} \n " , . { err } ) ;
return ;
} ;
2021-07-18 21:41:21 -07:00
defer window . destroy ( ) ;
2021-07-18 21:35:52 -07:00
}
2021-07-18 22:01:18 -07:00
test " setShouldClose " {
const glfw = @import ( " main.zig " ) ;
try glfw . init ( ) ;
defer glfw . terminate ( ) ;
const window = glfw . Window . create ( 640 , 480 , " Hello, Zig! " , null , null ) catch | err | {
// return without fail, because most of our CI environments are headless / we cannot open
// windows on them.
std . debug . print ( " note: failed to create window: {} \n " , . { err } ) ;
return ;
} ;
try window . setShouldClose ( true ) ;
defer window . destroy ( ) ;
}