-#include "wayland-client.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @page page_idle_inhibit_unstable_v1 The idle_inhibit_unstable_v1 protocol
- * @section page_ifaces_idle_inhibit_unstable_v1 Interfaces
- * - @subpage page_iface_zwp_idle_inhibit_manager_v1 - control behavior when display idles
- * - @subpage page_iface_zwp_idle_inhibitor_v1 - context object for inhibiting idle behavior
- * @section page_copyright_idle_inhibit_unstable_v1 Copyright
- *
- *
- * Copyright © 2015 Samsung Electronics Co., Ltd
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- */
-struct wl_surface;
-struct zwp_idle_inhibit_manager_v1;
-struct zwp_idle_inhibitor_v1;
-
-#ifndef ZWP_IDLE_INHIBIT_MANAGER_V1_INTERFACE
-#define ZWP_IDLE_INHIBIT_MANAGER_V1_INTERFACE
-/**
- * @page page_iface_zwp_idle_inhibit_manager_v1 zwp_idle_inhibit_manager_v1
- * @section page_iface_zwp_idle_inhibit_manager_v1_desc Description
- *
- * This interface permits inhibiting the idle behavior such as screen
- * blanking, locking, and screensaving. The client binds the idle manager
- * globally, then creates idle-inhibitor objects for each surface.
- *
- * Warning! The protocol described in this file is experimental and
- * backward incompatible changes may be made. Backward compatible changes
- * may be added together with the corresponding interface version bump.
- * Backward incompatible changes are done by bumping the version number in
- * the protocol and interface names and resetting the interface version.
- * Once the protocol is to be declared stable, the 'z' prefix and the
- * version number in the protocol and interface names are removed and the
- * interface version number is reset.
- * @section page_iface_zwp_idle_inhibit_manager_v1_api API
- * See @ref iface_zwp_idle_inhibit_manager_v1.
- */
-/**
- * @defgroup iface_zwp_idle_inhibit_manager_v1 The zwp_idle_inhibit_manager_v1 interface
- *
- * This interface permits inhibiting the idle behavior such as screen
- * blanking, locking, and screensaving. The client binds the idle manager
- * globally, then creates idle-inhibitor objects for each surface.
- *
- * Warning! The protocol described in this file is experimental and
- * backward incompatible changes may be made. Backward compatible changes
- * may be added together with the corresponding interface version bump.
- * Backward incompatible changes are done by bumping the version number in
- * the protocol and interface names and resetting the interface version.
- * Once the protocol is to be declared stable, the 'z' prefix and the
- * version number in the protocol and interface names are removed and the
- * interface version number is reset.
- */
-extern const struct wl_interface zwp_idle_inhibit_manager_v1_interface;
-#endif
-#ifndef ZWP_IDLE_INHIBITOR_V1_INTERFACE
-#define ZWP_IDLE_INHIBITOR_V1_INTERFACE
-/**
- * @page page_iface_zwp_idle_inhibitor_v1 zwp_idle_inhibitor_v1
- * @section page_iface_zwp_idle_inhibitor_v1_desc Description
- *
- * An idle inhibitor prevents the output that the associated surface is
- * visible on from being set to a state where it is not visually usable due
- * to lack of user interaction (e.g. blanked, dimmed, locked, set to power
- * save, etc.) Any screensaver processes are also blocked from displaying.
- *
- * If the surface is destroyed, unmapped, becomes occluded, loses
- * visibility, or otherwise becomes not visually relevant for the user, the
- * idle inhibitor will not be honored by the compositor; if the surface
- * subsequently regains visibility the inhibitor takes effect once again.
- * Likewise, the inhibitor isn't honored if the system was already idled at
- * the time the inhibitor was established, although if the system later
- * de-idles and re-idles the inhibitor will take effect.
- * @section page_iface_zwp_idle_inhibitor_v1_api API
- * See @ref iface_zwp_idle_inhibitor_v1.
- */
-/**
- * @defgroup iface_zwp_idle_inhibitor_v1 The zwp_idle_inhibitor_v1 interface
- *
- * An idle inhibitor prevents the output that the associated surface is
- * visible on from being set to a state where it is not visually usable due
- * to lack of user interaction (e.g. blanked, dimmed, locked, set to power
- * save, etc.) Any screensaver processes are also blocked from displaying.
- *
- * If the surface is destroyed, unmapped, becomes occluded, loses
- * visibility, or otherwise becomes not visually relevant for the user, the
- * idle inhibitor will not be honored by the compositor; if the surface
- * subsequently regains visibility the inhibitor takes effect once again.
- * Likewise, the inhibitor isn't honored if the system was already idled at
- * the time the inhibitor was established, although if the system later
- * de-idles and re-idles the inhibitor will take effect.
- */
-extern const struct wl_interface zwp_idle_inhibitor_v1_interface;
-#endif
-
-#define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY 0
-#define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR 1
-
-
-/**
- * @ingroup iface_zwp_idle_inhibit_manager_v1
- */
-#define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_zwp_idle_inhibit_manager_v1
- */
-#define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR_SINCE_VERSION 1
-
-/** @ingroup iface_zwp_idle_inhibit_manager_v1 */
-static inline void
-zwp_idle_inhibit_manager_v1_set_user_data(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) zwp_idle_inhibit_manager_v1, user_data);
-}
-
-/** @ingroup iface_zwp_idle_inhibit_manager_v1 */
-static inline void *
-zwp_idle_inhibit_manager_v1_get_user_data(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) zwp_idle_inhibit_manager_v1);
-}
-
-static inline uint32_t
-zwp_idle_inhibit_manager_v1_get_version(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1);
-}
-
-/**
- * @ingroup iface_zwp_idle_inhibit_manager_v1
- *
- * Destroy the inhibit manager.
- */
-static inline void
-zwp_idle_inhibit_manager_v1_destroy(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibit_manager_v1,
- ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_zwp_idle_inhibit_manager_v1
- *
- * Create a new inhibitor object associated with the given surface.
- */
-static inline struct zwp_idle_inhibitor_v1 *
-zwp_idle_inhibit_manager_v1_create_inhibitor(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1, struct wl_surface *surface)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibit_manager_v1,
- ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR, &zwp_idle_inhibitor_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1), 0, NULL, surface);
-
- return (struct zwp_idle_inhibitor_v1 *) id;
-}
-
-#define ZWP_IDLE_INHIBITOR_V1_DESTROY 0
-
-
-/**
- * @ingroup iface_zwp_idle_inhibitor_v1
- */
-#define ZWP_IDLE_INHIBITOR_V1_DESTROY_SINCE_VERSION 1
-
-/** @ingroup iface_zwp_idle_inhibitor_v1 */
-static inline void
-zwp_idle_inhibitor_v1_set_user_data(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) zwp_idle_inhibitor_v1, user_data);
-}
-
-/** @ingroup iface_zwp_idle_inhibitor_v1 */
-static inline void *
-zwp_idle_inhibitor_v1_get_user_data(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) zwp_idle_inhibitor_v1);
-}
-
-static inline uint32_t
-zwp_idle_inhibitor_v1_get_version(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibitor_v1);
-}
-
-/**
- * @ingroup iface_zwp_idle_inhibitor_v1
- *
- * Remove the inhibitor effect from the associated wl_surface.
- */
-static inline void
-zwp_idle_inhibitor_v1_destroy(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibitor_v1,
- ZWP_IDLE_INHIBITOR_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibitor_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pkg/glfw/wayland-headers/pointer-constraints-unstable-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/pointer-constraints-unstable-v1-client-protocol-code.h
deleted file mode 100644
index 4184538d5..000000000
--- a/pkg/glfw/wayland-headers/pointer-constraints-unstable-v1-client-protocol-code.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-/*
- * Copyright © 2014 Jonas Ådahl
- * Copyright © 2015 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include
-#include
-#include
-#include "wayland-util.h"
-
-#ifndef __has_attribute
-# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
-#endif
-
-#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
-#define WL_PRIVATE __attribute__ ((visibility("hidden")))
-#else
-#define WL_PRIVATE
-#endif
-
-extern const struct wl_interface wl_pointer_interface;
-extern const struct wl_interface wl_region_interface;
-extern const struct wl_interface wl_surface_interface;
-extern const struct wl_interface zwp_confined_pointer_v1_interface;
-extern const struct wl_interface zwp_locked_pointer_v1_interface;
-
-static const struct wl_interface *pointer_constraints_unstable_v1_types[] = {
- NULL,
- NULL,
- &zwp_locked_pointer_v1_interface,
- &wl_surface_interface,
- &wl_pointer_interface,
- &wl_region_interface,
- NULL,
- &zwp_confined_pointer_v1_interface,
- &wl_surface_interface,
- &wl_pointer_interface,
- &wl_region_interface,
- NULL,
- &wl_region_interface,
- &wl_region_interface,
-};
-
-static const struct wl_message zwp_pointer_constraints_v1_requests[] = {
- { "destroy", "", pointer_constraints_unstable_v1_types + 0 },
- { "lock_pointer", "noo?ou", pointer_constraints_unstable_v1_types + 2 },
- { "confine_pointer", "noo?ou", pointer_constraints_unstable_v1_types + 7 },
-};
-
-WL_PRIVATE const struct wl_interface zwp_pointer_constraints_v1_interface = {
- "zwp_pointer_constraints_v1", 1,
- 3, zwp_pointer_constraints_v1_requests,
- 0, NULL,
-};
-
-static const struct wl_message zwp_locked_pointer_v1_requests[] = {
- { "destroy", "", pointer_constraints_unstable_v1_types + 0 },
- { "set_cursor_position_hint", "ff", pointer_constraints_unstable_v1_types + 0 },
- { "set_region", "?o", pointer_constraints_unstable_v1_types + 12 },
-};
-
-static const struct wl_message zwp_locked_pointer_v1_events[] = {
- { "locked", "", pointer_constraints_unstable_v1_types + 0 },
- { "unlocked", "", pointer_constraints_unstable_v1_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface zwp_locked_pointer_v1_interface = {
- "zwp_locked_pointer_v1", 1,
- 3, zwp_locked_pointer_v1_requests,
- 2, zwp_locked_pointer_v1_events,
-};
-
-static const struct wl_message zwp_confined_pointer_v1_requests[] = {
- { "destroy", "", pointer_constraints_unstable_v1_types + 0 },
- { "set_region", "?o", pointer_constraints_unstable_v1_types + 13 },
-};
-
-static const struct wl_message zwp_confined_pointer_v1_events[] = {
- { "confined", "", pointer_constraints_unstable_v1_types + 0 },
- { "unconfined", "", pointer_constraints_unstable_v1_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface zwp_confined_pointer_v1_interface = {
- "zwp_confined_pointer_v1", 1,
- 2, zwp_confined_pointer_v1_requests,
- 2, zwp_confined_pointer_v1_events,
-};
-
diff --git a/pkg/glfw/wayland-headers/pointer-constraints-unstable-v1-client-protocol.h b/pkg/glfw/wayland-headers/pointer-constraints-unstable-v1-client-protocol.h
deleted file mode 100644
index 09c05ea8c..000000000
--- a/pkg/glfw/wayland-headers/pointer-constraints-unstable-v1-client-protocol.h
+++ /dev/null
@@ -1,667 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-#ifndef POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H
-#define POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H
-
-#include
-#include
-#include "wayland-client.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @page page_pointer_constraints_unstable_v1 The pointer_constraints_unstable_v1 protocol
- * protocol for constraining pointer motions
- *
- * @section page_desc_pointer_constraints_unstable_v1 Description
- *
- * This protocol specifies a set of interfaces used for adding constraints to
- * the motion of a pointer. Possible constraints include confining pointer
- * motions to a given region, or locking it to its current position.
- *
- * In order to constrain the pointer, a client must first bind the global
- * interface "wp_pointer_constraints" which, if a compositor supports pointer
- * constraints, is exposed by the registry. Using the bound global object, the
- * client uses the request that corresponds to the type of constraint it wants
- * to make. See wp_pointer_constraints for more details.
- *
- * Warning! The protocol described in this file is experimental and backward
- * incompatible changes may be made. Backward compatible changes may be added
- * together with the corresponding interface version bump. Backward
- * incompatible changes are done by bumping the version number in the protocol
- * and interface names and resetting the interface version. Once the protocol
- * is to be declared stable, the 'z' prefix and the version number in the
- * protocol and interface names are removed and the interface version number is
- * reset.
- *
- * @section page_ifaces_pointer_constraints_unstable_v1 Interfaces
- * - @subpage page_iface_zwp_pointer_constraints_v1 - constrain the movement of a pointer
- * - @subpage page_iface_zwp_locked_pointer_v1 - receive relative pointer motion events
- * - @subpage page_iface_zwp_confined_pointer_v1 - confined pointer object
- * @section page_copyright_pointer_constraints_unstable_v1 Copyright
- *
- *
- * Copyright © 2014 Jonas Ådahl
- * Copyright © 2015 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- */
-struct wl_pointer;
-struct wl_region;
-struct wl_surface;
-struct zwp_confined_pointer_v1;
-struct zwp_locked_pointer_v1;
-struct zwp_pointer_constraints_v1;
-
-#ifndef ZWP_POINTER_CONSTRAINTS_V1_INTERFACE
-#define ZWP_POINTER_CONSTRAINTS_V1_INTERFACE
-/**
- * @page page_iface_zwp_pointer_constraints_v1 zwp_pointer_constraints_v1
- * @section page_iface_zwp_pointer_constraints_v1_desc Description
- *
- * The global interface exposing pointer constraining functionality. It
- * exposes two requests: lock_pointer for locking the pointer to its
- * position, and confine_pointer for locking the pointer to a region.
- *
- * The lock_pointer and confine_pointer requests create the objects
- * wp_locked_pointer and wp_confined_pointer respectively, and the client can
- * use these objects to interact with the lock.
- *
- * For any surface, only one lock or confinement may be active across all
- * wl_pointer objects of the same seat. If a lock or confinement is requested
- * when another lock or confinement is active or requested on the same surface
- * and with any of the wl_pointer objects of the same seat, an
- * 'already_constrained' error will be raised.
- * @section page_iface_zwp_pointer_constraints_v1_api API
- * See @ref iface_zwp_pointer_constraints_v1.
- */
-/**
- * @defgroup iface_zwp_pointer_constraints_v1 The zwp_pointer_constraints_v1 interface
- *
- * The global interface exposing pointer constraining functionality. It
- * exposes two requests: lock_pointer for locking the pointer to its
- * position, and confine_pointer for locking the pointer to a region.
- *
- * The lock_pointer and confine_pointer requests create the objects
- * wp_locked_pointer and wp_confined_pointer respectively, and the client can
- * use these objects to interact with the lock.
- *
- * For any surface, only one lock or confinement may be active across all
- * wl_pointer objects of the same seat. If a lock or confinement is requested
- * when another lock or confinement is active or requested on the same surface
- * and with any of the wl_pointer objects of the same seat, an
- * 'already_constrained' error will be raised.
- */
-extern const struct wl_interface zwp_pointer_constraints_v1_interface;
-#endif
-#ifndef ZWP_LOCKED_POINTER_V1_INTERFACE
-#define ZWP_LOCKED_POINTER_V1_INTERFACE
-/**
- * @page page_iface_zwp_locked_pointer_v1 zwp_locked_pointer_v1
- * @section page_iface_zwp_locked_pointer_v1_desc Description
- *
- * The wp_locked_pointer interface represents a locked pointer state.
- *
- * While the lock of this object is active, the wl_pointer objects of the
- * associated seat will not emit any wl_pointer.motion events.
- *
- * This object will send the event 'locked' when the lock is activated.
- * Whenever the lock is activated, it is guaranteed that the locked surface
- * will already have received pointer focus and that the pointer will be
- * within the region passed to the request creating this object.
- *
- * To unlock the pointer, send the destroy request. This will also destroy
- * the wp_locked_pointer object.
- *
- * If the compositor decides to unlock the pointer the unlocked event is
- * sent. See wp_locked_pointer.unlock for details.
- *
- * When unlocking, the compositor may warp the cursor position to the set
- * cursor position hint. If it does, it will not result in any relative
- * motion events emitted via wp_relative_pointer.
- *
- * If the surface the lock was requested on is destroyed and the lock is not
- * yet activated, the wp_locked_pointer object is now defunct and must be
- * destroyed.
- * @section page_iface_zwp_locked_pointer_v1_api API
- * See @ref iface_zwp_locked_pointer_v1.
- */
-/**
- * @defgroup iface_zwp_locked_pointer_v1 The zwp_locked_pointer_v1 interface
- *
- * The wp_locked_pointer interface represents a locked pointer state.
- *
- * While the lock of this object is active, the wl_pointer objects of the
- * associated seat will not emit any wl_pointer.motion events.
- *
- * This object will send the event 'locked' when the lock is activated.
- * Whenever the lock is activated, it is guaranteed that the locked surface
- * will already have received pointer focus and that the pointer will be
- * within the region passed to the request creating this object.
- *
- * To unlock the pointer, send the destroy request. This will also destroy
- * the wp_locked_pointer object.
- *
- * If the compositor decides to unlock the pointer the unlocked event is
- * sent. See wp_locked_pointer.unlock for details.
- *
- * When unlocking, the compositor may warp the cursor position to the set
- * cursor position hint. If it does, it will not result in any relative
- * motion events emitted via wp_relative_pointer.
- *
- * If the surface the lock was requested on is destroyed and the lock is not
- * yet activated, the wp_locked_pointer object is now defunct and must be
- * destroyed.
- */
-extern const struct wl_interface zwp_locked_pointer_v1_interface;
-#endif
-#ifndef ZWP_CONFINED_POINTER_V1_INTERFACE
-#define ZWP_CONFINED_POINTER_V1_INTERFACE
-/**
- * @page page_iface_zwp_confined_pointer_v1 zwp_confined_pointer_v1
- * @section page_iface_zwp_confined_pointer_v1_desc Description
- *
- * The wp_confined_pointer interface represents a confined pointer state.
- *
- * This object will send the event 'confined' when the confinement is
- * activated. Whenever the confinement is activated, it is guaranteed that
- * the surface the pointer is confined to will already have received pointer
- * focus and that the pointer will be within the region passed to the request
- * creating this object. It is up to the compositor to decide whether this
- * requires some user interaction and if the pointer will warp to within the
- * passed region if outside.
- *
- * To unconfine the pointer, send the destroy request. This will also destroy
- * the wp_confined_pointer object.
- *
- * If the compositor decides to unconfine the pointer the unconfined event is
- * sent. The wp_confined_pointer object is at this point defunct and should
- * be destroyed.
- * @section page_iface_zwp_confined_pointer_v1_api API
- * See @ref iface_zwp_confined_pointer_v1.
- */
-/**
- * @defgroup iface_zwp_confined_pointer_v1 The zwp_confined_pointer_v1 interface
- *
- * The wp_confined_pointer interface represents a confined pointer state.
- *
- * This object will send the event 'confined' when the confinement is
- * activated. Whenever the confinement is activated, it is guaranteed that
- * the surface the pointer is confined to will already have received pointer
- * focus and that the pointer will be within the region passed to the request
- * creating this object. It is up to the compositor to decide whether this
- * requires some user interaction and if the pointer will warp to within the
- * passed region if outside.
- *
- * To unconfine the pointer, send the destroy request. This will also destroy
- * the wp_confined_pointer object.
- *
- * If the compositor decides to unconfine the pointer the unconfined event is
- * sent. The wp_confined_pointer object is at this point defunct and should
- * be destroyed.
- */
-extern const struct wl_interface zwp_confined_pointer_v1_interface;
-#endif
-
-#ifndef ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM
-#define ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM
-/**
- * @ingroup iface_zwp_pointer_constraints_v1
- * wp_pointer_constraints error values
- *
- * These errors can be emitted in response to wp_pointer_constraints
- * requests.
- */
-enum zwp_pointer_constraints_v1_error {
- /**
- * pointer constraint already requested on that surface
- */
- ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED = 1,
-};
-#endif /* ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM */
-
-#ifndef ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM
-#define ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM
-/**
- * @ingroup iface_zwp_pointer_constraints_v1
- * constraint lifetime
- *
- * These values represent different lifetime semantics. They are passed
- * as arguments to the factory requests to specify how the constraint
- * lifetimes should be managed.
- */
-enum zwp_pointer_constraints_v1_lifetime {
- /**
- * the pointer constraint is defunct once deactivated
- *
- * A oneshot pointer constraint will never reactivate once it has
- * been deactivated. See the corresponding deactivation event
- * (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined)
- * for details.
- */
- ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT = 1,
- /**
- * the pointer constraint may reactivate
- *
- * A persistent pointer constraint may again reactivate once it
- * has been deactivated. See the corresponding deactivation event
- * (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined)
- * for details.
- */
- ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT = 2,
-};
-#endif /* ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM */
-
-#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY 0
-#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER 1
-#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER 2
-
-
-/**
- * @ingroup iface_zwp_pointer_constraints_v1
- */
-#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_zwp_pointer_constraints_v1
- */
-#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER_SINCE_VERSION 1
-/**
- * @ingroup iface_zwp_pointer_constraints_v1
- */
-#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER_SINCE_VERSION 1
-
-/** @ingroup iface_zwp_pointer_constraints_v1 */
-static inline void
-zwp_pointer_constraints_v1_set_user_data(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) zwp_pointer_constraints_v1, user_data);
-}
-
-/** @ingroup iface_zwp_pointer_constraints_v1 */
-static inline void *
-zwp_pointer_constraints_v1_get_user_data(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) zwp_pointer_constraints_v1);
-}
-
-static inline uint32_t
-zwp_pointer_constraints_v1_get_version(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1);
-}
-
-/**
- * @ingroup iface_zwp_pointer_constraints_v1
- *
- * Used by the client to notify the server that it will no longer use this
- * pointer constraints object.
- */
-static inline void
-zwp_pointer_constraints_v1_destroy(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1,
- ZWP_POINTER_CONSTRAINTS_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_zwp_pointer_constraints_v1
- *
- * The lock_pointer request lets the client request to disable movements of
- * the virtual pointer (i.e. the cursor), effectively locking the pointer
- * to a position. This request may not take effect immediately; in the
- * future, when the compositor deems implementation-specific constraints
- * are satisfied, the pointer lock will be activated and the compositor
- * sends a locked event.
- *
- * The protocol provides no guarantee that the constraints are ever
- * satisfied, and does not require the compositor to send an error if the
- * constraints cannot ever be satisfied. It is thus possible to request a
- * lock that will never activate.
- *
- * There may not be another pointer constraint of any kind requested or
- * active on the surface for any of the wl_pointer objects of the seat of
- * the passed pointer when requesting a lock. If there is, an error will be
- * raised. See general pointer lock documentation for more details.
- *
- * The intersection of the region passed with this request and the input
- * region of the surface is used to determine where the pointer must be
- * in order for the lock to activate. It is up to the compositor whether to
- * warp the pointer or require some kind of user interaction for the lock
- * to activate. If the region is null the surface input region is used.
- *
- * A surface may receive pointer focus without the lock being activated.
- *
- * The request creates a new object wp_locked_pointer which is used to
- * interact with the lock as well as receive updates about its state. See
- * the the description of wp_locked_pointer for further information.
- *
- * Note that while a pointer is locked, the wl_pointer objects of the
- * corresponding seat will not emit any wl_pointer.motion events, but
- * relative motion events will still be emitted via wp_relative_pointer
- * objects of the same seat. wl_pointer.axis and wl_pointer.button events
- * are unaffected.
- */
-static inline struct zwp_locked_pointer_v1 *
-zwp_pointer_constraints_v1_lock_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1,
- ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER, &zwp_locked_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), 0, NULL, surface, pointer, region, lifetime);
-
- return (struct zwp_locked_pointer_v1 *) id;
-}
-
-/**
- * @ingroup iface_zwp_pointer_constraints_v1
- *
- * The confine_pointer request lets the client request to confine the
- * pointer cursor to a given region. This request may not take effect
- * immediately; in the future, when the compositor deems implementation-
- * specific constraints are satisfied, the pointer confinement will be
- * activated and the compositor sends a confined event.
- *
- * The intersection of the region passed with this request and the input
- * region of the surface is used to determine where the pointer must be
- * in order for the confinement to activate. It is up to the compositor
- * whether to warp the pointer or require some kind of user interaction for
- * the confinement to activate. If the region is null the surface input
- * region is used.
- *
- * The request will create a new object wp_confined_pointer which is used
- * to interact with the confinement as well as receive updates about its
- * state. See the the description of wp_confined_pointer for further
- * information.
- */
-static inline struct zwp_confined_pointer_v1 *
-zwp_pointer_constraints_v1_confine_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1,
- ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER, &zwp_confined_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), 0, NULL, surface, pointer, region, lifetime);
-
- return (struct zwp_confined_pointer_v1 *) id;
-}
-
-/**
- * @ingroup iface_zwp_locked_pointer_v1
- * @struct zwp_locked_pointer_v1_listener
- */
-struct zwp_locked_pointer_v1_listener {
- /**
- * lock activation event
- *
- * Notification that the pointer lock of the seat's pointer is
- * activated.
- */
- void (*locked)(void *data,
- struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1);
- /**
- * lock deactivation event
- *
- * Notification that the pointer lock of the seat's pointer is no
- * longer active. If this is a oneshot pointer lock (see
- * wp_pointer_constraints.lifetime) this object is now defunct and
- * should be destroyed. If this is a persistent pointer lock (see
- * wp_pointer_constraints.lifetime) this pointer lock may again
- * reactivate in the future.
- */
- void (*unlocked)(void *data,
- struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1);
-};
-
-/**
- * @ingroup iface_zwp_locked_pointer_v1
- */
-static inline int
-zwp_locked_pointer_v1_add_listener(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1,
- const struct zwp_locked_pointer_v1_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) zwp_locked_pointer_v1,
- (void (**)(void)) listener, data);
-}
-
-#define ZWP_LOCKED_POINTER_V1_DESTROY 0
-#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT 1
-#define ZWP_LOCKED_POINTER_V1_SET_REGION 2
-
-/**
- * @ingroup iface_zwp_locked_pointer_v1
- */
-#define ZWP_LOCKED_POINTER_V1_LOCKED_SINCE_VERSION 1
-/**
- * @ingroup iface_zwp_locked_pointer_v1
- */
-#define ZWP_LOCKED_POINTER_V1_UNLOCKED_SINCE_VERSION 1
-
-/**
- * @ingroup iface_zwp_locked_pointer_v1
- */
-#define ZWP_LOCKED_POINTER_V1_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_zwp_locked_pointer_v1
- */
-#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT_SINCE_VERSION 1
-/**
- * @ingroup iface_zwp_locked_pointer_v1
- */
-#define ZWP_LOCKED_POINTER_V1_SET_REGION_SINCE_VERSION 1
-
-/** @ingroup iface_zwp_locked_pointer_v1 */
-static inline void
-zwp_locked_pointer_v1_set_user_data(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) zwp_locked_pointer_v1, user_data);
-}
-
-/** @ingroup iface_zwp_locked_pointer_v1 */
-static inline void *
-zwp_locked_pointer_v1_get_user_data(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) zwp_locked_pointer_v1);
-}
-
-static inline uint32_t
-zwp_locked_pointer_v1_get_version(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1);
-}
-
-/**
- * @ingroup iface_zwp_locked_pointer_v1
- *
- * Destroy the locked pointer object. If applicable, the compositor will
- * unlock the pointer.
- */
-static inline void
-zwp_locked_pointer_v1_destroy(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1,
- ZWP_LOCKED_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_zwp_locked_pointer_v1
- *
- * Set the cursor position hint relative to the top left corner of the
- * surface.
- *
- * If the client is drawing its own cursor, it should update the position
- * hint to the position of its own cursor. A compositor may use this
- * information to warp the pointer upon unlock in order to avoid pointer
- * jumps.
- *
- * The cursor position hint is double buffered. The new hint will only take
- * effect when the associated surface gets it pending state applied. See
- * wl_surface.commit for details.
- */
-static inline void
-zwp_locked_pointer_v1_set_cursor_position_hint(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, wl_fixed_t surface_x, wl_fixed_t surface_y)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1,
- ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), 0, surface_x, surface_y);
-}
-
-/**
- * @ingroup iface_zwp_locked_pointer_v1
- *
- * Set a new region used to lock the pointer.
- *
- * The new lock region is double-buffered. The new lock region will
- * only take effect when the associated surface gets its pending state
- * applied. See wl_surface.commit for details.
- *
- * For details about the lock region, see wp_locked_pointer.
- */
-static inline void
-zwp_locked_pointer_v1_set_region(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, struct wl_region *region)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1,
- ZWP_LOCKED_POINTER_V1_SET_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), 0, region);
-}
-
-/**
- * @ingroup iface_zwp_confined_pointer_v1
- * @struct zwp_confined_pointer_v1_listener
- */
-struct zwp_confined_pointer_v1_listener {
- /**
- * pointer confined
- *
- * Notification that the pointer confinement of the seat's
- * pointer is activated.
- */
- void (*confined)(void *data,
- struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1);
- /**
- * pointer unconfined
- *
- * Notification that the pointer confinement of the seat's
- * pointer is no longer active. If this is a oneshot pointer
- * confinement (see wp_pointer_constraints.lifetime) this object is
- * now defunct and should be destroyed. If this is a persistent
- * pointer confinement (see wp_pointer_constraints.lifetime) this
- * pointer confinement may again reactivate in the future.
- */
- void (*unconfined)(void *data,
- struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1);
-};
-
-/**
- * @ingroup iface_zwp_confined_pointer_v1
- */
-static inline int
-zwp_confined_pointer_v1_add_listener(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1,
- const struct zwp_confined_pointer_v1_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) zwp_confined_pointer_v1,
- (void (**)(void)) listener, data);
-}
-
-#define ZWP_CONFINED_POINTER_V1_DESTROY 0
-#define ZWP_CONFINED_POINTER_V1_SET_REGION 1
-
-/**
- * @ingroup iface_zwp_confined_pointer_v1
- */
-#define ZWP_CONFINED_POINTER_V1_CONFINED_SINCE_VERSION 1
-/**
- * @ingroup iface_zwp_confined_pointer_v1
- */
-#define ZWP_CONFINED_POINTER_V1_UNCONFINED_SINCE_VERSION 1
-
-/**
- * @ingroup iface_zwp_confined_pointer_v1
- */
-#define ZWP_CONFINED_POINTER_V1_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_zwp_confined_pointer_v1
- */
-#define ZWP_CONFINED_POINTER_V1_SET_REGION_SINCE_VERSION 1
-
-/** @ingroup iface_zwp_confined_pointer_v1 */
-static inline void
-zwp_confined_pointer_v1_set_user_data(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) zwp_confined_pointer_v1, user_data);
-}
-
-/** @ingroup iface_zwp_confined_pointer_v1 */
-static inline void *
-zwp_confined_pointer_v1_get_user_data(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) zwp_confined_pointer_v1);
-}
-
-static inline uint32_t
-zwp_confined_pointer_v1_get_version(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1);
-}
-
-/**
- * @ingroup iface_zwp_confined_pointer_v1
- *
- * Destroy the confined pointer object. If applicable, the compositor will
- * unconfine the pointer.
- */
-static inline void
-zwp_confined_pointer_v1_destroy(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zwp_confined_pointer_v1,
- ZWP_CONFINED_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_zwp_confined_pointer_v1
- *
- * Set a new region used to confine the pointer.
- *
- * The new confine region is double-buffered. The new confine region will
- * only take effect when the associated surface gets its pending state
- * applied. See wl_surface.commit for details.
- *
- * If the confinement is active when the new confinement region is applied
- * and the pointer ends up outside of newly applied region, the pointer may
- * warped to a position within the new confinement region. If warped, a
- * wl_pointer.motion event will be emitted, but no
- * wp_relative_pointer.relative_motion event.
- *
- * The compositor may also, instead of using the new region, unconfine the
- * pointer.
- *
- * For details about the confine region, see wp_confined_pointer.
- */
-static inline void
-zwp_confined_pointer_v1_set_region(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, struct wl_region *region)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zwp_confined_pointer_v1,
- ZWP_CONFINED_POINTER_V1_SET_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1), 0, region);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pkg/glfw/wayland-headers/relative-pointer-unstable-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/relative-pointer-unstable-v1-client-protocol-code.h
deleted file mode 100644
index 605149b2a..000000000
--- a/pkg/glfw/wayland-headers/relative-pointer-unstable-v1-client-protocol-code.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-/*
- * Copyright © 2014 Jonas Ådahl
- * Copyright © 2015 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include
-#include
-#include
-#include "wayland-util.h"
-
-#ifndef __has_attribute
-# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
-#endif
-
-#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
-#define WL_PRIVATE __attribute__ ((visibility("hidden")))
-#else
-#define WL_PRIVATE
-#endif
-
-extern const struct wl_interface wl_pointer_interface;
-extern const struct wl_interface zwp_relative_pointer_v1_interface;
-
-static const struct wl_interface *relative_pointer_unstable_v1_types[] = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- &zwp_relative_pointer_v1_interface,
- &wl_pointer_interface,
-};
-
-static const struct wl_message zwp_relative_pointer_manager_v1_requests[] = {
- { "destroy", "", relative_pointer_unstable_v1_types + 0 },
- { "get_relative_pointer", "no", relative_pointer_unstable_v1_types + 6 },
-};
-
-WL_PRIVATE const struct wl_interface zwp_relative_pointer_manager_v1_interface = {
- "zwp_relative_pointer_manager_v1", 1,
- 2, zwp_relative_pointer_manager_v1_requests,
- 0, NULL,
-};
-
-static const struct wl_message zwp_relative_pointer_v1_requests[] = {
- { "destroy", "", relative_pointer_unstable_v1_types + 0 },
-};
-
-static const struct wl_message zwp_relative_pointer_v1_events[] = {
- { "relative_motion", "uuffff", relative_pointer_unstable_v1_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface zwp_relative_pointer_v1_interface = {
- "zwp_relative_pointer_v1", 1,
- 1, zwp_relative_pointer_v1_requests,
- 1, zwp_relative_pointer_v1_events,
-};
-
diff --git a/pkg/glfw/wayland-headers/relative-pointer-unstable-v1-client-protocol.h b/pkg/glfw/wayland-headers/relative-pointer-unstable-v1-client-protocol.h
deleted file mode 100644
index 5c79482f9..000000000
--- a/pkg/glfw/wayland-headers/relative-pointer-unstable-v1-client-protocol.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-#ifndef RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H
-#define RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H
-
-#include
-#include
-#include "wayland-client.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @page page_relative_pointer_unstable_v1 The relative_pointer_unstable_v1 protocol
- * protocol for relative pointer motion events
- *
- * @section page_desc_relative_pointer_unstable_v1 Description
- *
- * This protocol specifies a set of interfaces used for making clients able to
- * receive relative pointer events not obstructed by barriers (such as the
- * monitor edge or other pointer barriers).
- *
- * To start receiving relative pointer events, a client must first bind the
- * global interface "wp_relative_pointer_manager" which, if a compositor
- * supports relative pointer motion events, is exposed by the registry. After
- * having created the relative pointer manager proxy object, the client uses
- * it to create the actual relative pointer object using the
- * "get_relative_pointer" request given a wl_pointer. The relative pointer
- * motion events will then, when applicable, be transmitted via the proxy of
- * the newly created relative pointer object. See the documentation of the
- * relative pointer interface for more details.
- *
- * Warning! The protocol described in this file is experimental and backward
- * incompatible changes may be made. Backward compatible changes may be added
- * together with the corresponding interface version bump. Backward
- * incompatible changes are done by bumping the version number in the protocol
- * and interface names and resetting the interface version. Once the protocol
- * is to be declared stable, the 'z' prefix and the version number in the
- * protocol and interface names are removed and the interface version number is
- * reset.
- *
- * @section page_ifaces_relative_pointer_unstable_v1 Interfaces
- * - @subpage page_iface_zwp_relative_pointer_manager_v1 - get relative pointer objects
- * - @subpage page_iface_zwp_relative_pointer_v1 - relative pointer object
- * @section page_copyright_relative_pointer_unstable_v1 Copyright
- *
- *
- * Copyright © 2014 Jonas Ådahl
- * Copyright © 2015 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- */
-struct wl_pointer;
-struct zwp_relative_pointer_manager_v1;
-struct zwp_relative_pointer_v1;
-
-#ifndef ZWP_RELATIVE_POINTER_MANAGER_V1_INTERFACE
-#define ZWP_RELATIVE_POINTER_MANAGER_V1_INTERFACE
-/**
- * @page page_iface_zwp_relative_pointer_manager_v1 zwp_relative_pointer_manager_v1
- * @section page_iface_zwp_relative_pointer_manager_v1_desc Description
- *
- * A global interface used for getting the relative pointer object for a
- * given pointer.
- * @section page_iface_zwp_relative_pointer_manager_v1_api API
- * See @ref iface_zwp_relative_pointer_manager_v1.
- */
-/**
- * @defgroup iface_zwp_relative_pointer_manager_v1 The zwp_relative_pointer_manager_v1 interface
- *
- * A global interface used for getting the relative pointer object for a
- * given pointer.
- */
-extern const struct wl_interface zwp_relative_pointer_manager_v1_interface;
-#endif
-#ifndef ZWP_RELATIVE_POINTER_V1_INTERFACE
-#define ZWP_RELATIVE_POINTER_V1_INTERFACE
-/**
- * @page page_iface_zwp_relative_pointer_v1 zwp_relative_pointer_v1
- * @section page_iface_zwp_relative_pointer_v1_desc Description
- *
- * A wp_relative_pointer object is an extension to the wl_pointer interface
- * used for emitting relative pointer events. It shares the same focus as
- * wl_pointer objects of the same seat and will only emit events when it has
- * focus.
- * @section page_iface_zwp_relative_pointer_v1_api API
- * See @ref iface_zwp_relative_pointer_v1.
- */
-/**
- * @defgroup iface_zwp_relative_pointer_v1 The zwp_relative_pointer_v1 interface
- *
- * A wp_relative_pointer object is an extension to the wl_pointer interface
- * used for emitting relative pointer events. It shares the same focus as
- * wl_pointer objects of the same seat and will only emit events when it has
- * focus.
- */
-extern const struct wl_interface zwp_relative_pointer_v1_interface;
-#endif
-
-#define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY 0
-#define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER 1
-
-
-/**
- * @ingroup iface_zwp_relative_pointer_manager_v1
- */
-#define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_zwp_relative_pointer_manager_v1
- */
-#define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER_SINCE_VERSION 1
-
-/** @ingroup iface_zwp_relative_pointer_manager_v1 */
-static inline void
-zwp_relative_pointer_manager_v1_set_user_data(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) zwp_relative_pointer_manager_v1, user_data);
-}
-
-/** @ingroup iface_zwp_relative_pointer_manager_v1 */
-static inline void *
-zwp_relative_pointer_manager_v1_get_user_data(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) zwp_relative_pointer_manager_v1);
-}
-
-static inline uint32_t
-zwp_relative_pointer_manager_v1_get_version(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1);
-}
-
-/**
- * @ingroup iface_zwp_relative_pointer_manager_v1
- *
- * Used by the client to notify the server that it will no longer use this
- * relative pointer manager object.
- */
-static inline void
-zwp_relative_pointer_manager_v1_destroy(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_manager_v1,
- ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_zwp_relative_pointer_manager_v1
- *
- * Create a relative pointer interface given a wl_pointer object. See the
- * wp_relative_pointer interface for more details.
- */
-static inline struct zwp_relative_pointer_v1 *
-zwp_relative_pointer_manager_v1_get_relative_pointer(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, struct wl_pointer *pointer)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_manager_v1,
- ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER, &zwp_relative_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1), 0, NULL, pointer);
-
- return (struct zwp_relative_pointer_v1 *) id;
-}
-
-/**
- * @ingroup iface_zwp_relative_pointer_v1
- * @struct zwp_relative_pointer_v1_listener
- */
-struct zwp_relative_pointer_v1_listener {
- /**
- * relative pointer motion
- *
- * Relative x/y pointer motion from the pointer of the seat
- * associated with this object.
- *
- * A relative motion is in the same dimension as regular wl_pointer
- * motion events, except they do not represent an absolute
- * position. For example, moving a pointer from (x, y) to (x', y')
- * would have the equivalent relative motion (x' - x, y' - y). If a
- * pointer motion caused the absolute pointer position to be
- * clipped by for example the edge of the monitor, the relative
- * motion is unaffected by the clipping and will represent the
- * unclipped motion.
- *
- * This event also contains non-accelerated motion deltas. The
- * non-accelerated delta is, when applicable, the regular pointer
- * motion delta as it was before having applied motion acceleration
- * and other transformations such as normalization.
- *
- * Note that the non-accelerated delta does not represent 'raw'
- * events as they were read from some device. Pointer motion
- * acceleration is device- and configuration-specific and
- * non-accelerated deltas and accelerated deltas may have the same
- * value on some devices.
- *
- * Relative motions are not coupled to wl_pointer.motion events,
- * and can be sent in combination with such events, but also
- * independently. There may also be scenarios where
- * wl_pointer.motion is sent, but there is no relative motion. The
- * order of an absolute and relative motion event originating from
- * the same physical motion is not guaranteed.
- *
- * If the client needs button events or focus state, it can receive
- * them from a wl_pointer object of the same seat that the
- * wp_relative_pointer object is associated with.
- * @param utime_hi high 32 bits of a 64 bit timestamp with microsecond granularity
- * @param utime_lo low 32 bits of a 64 bit timestamp with microsecond granularity
- * @param dx the x component of the motion vector
- * @param dy the y component of the motion vector
- * @param dx_unaccel the x component of the unaccelerated motion vector
- * @param dy_unaccel the y component of the unaccelerated motion vector
- */
- void (*relative_motion)(void *data,
- struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
- uint32_t utime_hi,
- uint32_t utime_lo,
- wl_fixed_t dx,
- wl_fixed_t dy,
- wl_fixed_t dx_unaccel,
- wl_fixed_t dy_unaccel);
-};
-
-/**
- * @ingroup iface_zwp_relative_pointer_v1
- */
-static inline int
-zwp_relative_pointer_v1_add_listener(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
- const struct zwp_relative_pointer_v1_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) zwp_relative_pointer_v1,
- (void (**)(void)) listener, data);
-}
-
-#define ZWP_RELATIVE_POINTER_V1_DESTROY 0
-
-/**
- * @ingroup iface_zwp_relative_pointer_v1
- */
-#define ZWP_RELATIVE_POINTER_V1_RELATIVE_MOTION_SINCE_VERSION 1
-
-/**
- * @ingroup iface_zwp_relative_pointer_v1
- */
-#define ZWP_RELATIVE_POINTER_V1_DESTROY_SINCE_VERSION 1
-
-/** @ingroup iface_zwp_relative_pointer_v1 */
-static inline void
-zwp_relative_pointer_v1_set_user_data(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) zwp_relative_pointer_v1, user_data);
-}
-
-/** @ingroup iface_zwp_relative_pointer_v1 */
-static inline void *
-zwp_relative_pointer_v1_get_user_data(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) zwp_relative_pointer_v1);
-}
-
-static inline uint32_t
-zwp_relative_pointer_v1_get_version(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_v1);
-}
-
-/**
- * @ingroup iface_zwp_relative_pointer_v1
- */
-static inline void
-zwp_relative_pointer_v1_destroy(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_v1,
- ZWP_RELATIVE_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pkg/glfw/wayland-headers/viewporter-client-protocol-code.h b/pkg/glfw/wayland-headers/viewporter-client-protocol-code.h
deleted file mode 100644
index d6858580e..000000000
--- a/pkg/glfw/wayland-headers/viewporter-client-protocol-code.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-/*
- * Copyright © 2013-2016 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include
-#include
-#include
-#include "wayland-util.h"
-
-#ifndef __has_attribute
-# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
-#endif
-
-#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
-#define WL_PRIVATE __attribute__ ((visibility("hidden")))
-#else
-#define WL_PRIVATE
-#endif
-
-extern const struct wl_interface wl_surface_interface;
-extern const struct wl_interface wp_viewport_interface;
-
-static const struct wl_interface *viewporter_types[] = {
- NULL,
- NULL,
- NULL,
- NULL,
- &wp_viewport_interface,
- &wl_surface_interface,
-};
-
-static const struct wl_message wp_viewporter_requests[] = {
- { "destroy", "", viewporter_types + 0 },
- { "get_viewport", "no", viewporter_types + 4 },
-};
-
-WL_PRIVATE const struct wl_interface wp_viewporter_interface = {
- "wp_viewporter", 1,
- 2, wp_viewporter_requests,
- 0, NULL,
-};
-
-static const struct wl_message wp_viewport_requests[] = {
- { "destroy", "", viewporter_types + 0 },
- { "set_source", "ffff", viewporter_types + 0 },
- { "set_destination", "ii", viewporter_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wp_viewport_interface = {
- "wp_viewport", 1,
- 3, wp_viewport_requests,
- 0, NULL,
-};
-
diff --git a/pkg/glfw/wayland-headers/viewporter-client-protocol.h b/pkg/glfw/wayland-headers/viewporter-client-protocol.h
deleted file mode 100644
index afe60ef59..000000000
--- a/pkg/glfw/wayland-headers/viewporter-client-protocol.h
+++ /dev/null
@@ -1,398 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-#ifndef VIEWPORTER_CLIENT_PROTOCOL_H
-#define VIEWPORTER_CLIENT_PROTOCOL_H
-
-#include
-#include
-#include "wayland-client.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @page page_viewporter The viewporter protocol
- * @section page_ifaces_viewporter Interfaces
- * - @subpage page_iface_wp_viewporter - surface cropping and scaling
- * - @subpage page_iface_wp_viewport - crop and scale interface to a wl_surface
- * @section page_copyright_viewporter Copyright
- *
- *
- * Copyright © 2013-2016 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- */
-struct wl_surface;
-struct wp_viewport;
-struct wp_viewporter;
-
-#ifndef WP_VIEWPORTER_INTERFACE
-#define WP_VIEWPORTER_INTERFACE
-/**
- * @page page_iface_wp_viewporter wp_viewporter
- * @section page_iface_wp_viewporter_desc Description
- *
- * The global interface exposing surface cropping and scaling
- * capabilities is used to instantiate an interface extension for a
- * wl_surface object. This extended interface will then allow
- * cropping and scaling the surface contents, effectively
- * disconnecting the direct relationship between the buffer and the
- * surface size.
- * @section page_iface_wp_viewporter_api API
- * See @ref iface_wp_viewporter.
- */
-/**
- * @defgroup iface_wp_viewporter The wp_viewporter interface
- *
- * The global interface exposing surface cropping and scaling
- * capabilities is used to instantiate an interface extension for a
- * wl_surface object. This extended interface will then allow
- * cropping and scaling the surface contents, effectively
- * disconnecting the direct relationship between the buffer and the
- * surface size.
- */
-extern const struct wl_interface wp_viewporter_interface;
-#endif
-#ifndef WP_VIEWPORT_INTERFACE
-#define WP_VIEWPORT_INTERFACE
-/**
- * @page page_iface_wp_viewport wp_viewport
- * @section page_iface_wp_viewport_desc Description
- *
- * An additional interface to a wl_surface object, which allows the
- * client to specify the cropping and scaling of the surface
- * contents.
- *
- * This interface works with two concepts: the source rectangle (src_x,
- * src_y, src_width, src_height), and the destination size (dst_width,
- * dst_height). The contents of the source rectangle are scaled to the
- * destination size, and content outside the source rectangle is ignored.
- * This state is double-buffered, and is applied on the next
- * wl_surface.commit.
- *
- * The two parts of crop and scale state are independent: the source
- * rectangle, and the destination size. Initially both are unset, that
- * is, no scaling is applied. The whole of the current wl_buffer is
- * used as the source, and the surface size is as defined in
- * wl_surface.attach.
- *
- * If the destination size is set, it causes the surface size to become
- * dst_width, dst_height. The source (rectangle) is scaled to exactly
- * this size. This overrides whatever the attached wl_buffer size is,
- * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
- * has no content and therefore no size. Otherwise, the size is always
- * at least 1x1 in surface local coordinates.
- *
- * If the source rectangle is set, it defines what area of the wl_buffer is
- * taken as the source. If the source rectangle is set and the destination
- * size is not set, then src_width and src_height must be integers, and the
- * surface size becomes the source rectangle size. This results in cropping
- * without scaling. If src_width or src_height are not integers and
- * destination size is not set, the bad_size protocol error is raised when
- * the surface state is applied.
- *
- * The coordinate transformations from buffer pixel coordinates up to
- * the surface-local coordinates happen in the following order:
- * 1. buffer_transform (wl_surface.set_buffer_transform)
- * 2. buffer_scale (wl_surface.set_buffer_scale)
- * 3. crop and scale (wp_viewport.set*)
- * This means, that the source rectangle coordinates of crop and scale
- * are given in the coordinates after the buffer transform and scale,
- * i.e. in the coordinates that would be the surface-local coordinates
- * if the crop and scale was not applied.
- *
- * If src_x or src_y are negative, the bad_value protocol error is raised.
- * Otherwise, if the source rectangle is partially or completely outside of
- * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
- * when the surface state is applied. A NULL wl_buffer does not raise the
- * out_of_buffer error.
- *
- * If the wl_surface associated with the wp_viewport is destroyed,
- * all wp_viewport requests except 'destroy' raise the protocol error
- * no_surface.
- *
- * If the wp_viewport object is destroyed, the crop and scale
- * state is removed from the wl_surface. The change will be applied
- * on the next wl_surface.commit.
- * @section page_iface_wp_viewport_api API
- * See @ref iface_wp_viewport.
- */
-/**
- * @defgroup iface_wp_viewport The wp_viewport interface
- *
- * An additional interface to a wl_surface object, which allows the
- * client to specify the cropping and scaling of the surface
- * contents.
- *
- * This interface works with two concepts: the source rectangle (src_x,
- * src_y, src_width, src_height), and the destination size (dst_width,
- * dst_height). The contents of the source rectangle are scaled to the
- * destination size, and content outside the source rectangle is ignored.
- * This state is double-buffered, and is applied on the next
- * wl_surface.commit.
- *
- * The two parts of crop and scale state are independent: the source
- * rectangle, and the destination size. Initially both are unset, that
- * is, no scaling is applied. The whole of the current wl_buffer is
- * used as the source, and the surface size is as defined in
- * wl_surface.attach.
- *
- * If the destination size is set, it causes the surface size to become
- * dst_width, dst_height. The source (rectangle) is scaled to exactly
- * this size. This overrides whatever the attached wl_buffer size is,
- * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
- * has no content and therefore no size. Otherwise, the size is always
- * at least 1x1 in surface local coordinates.
- *
- * If the source rectangle is set, it defines what area of the wl_buffer is
- * taken as the source. If the source rectangle is set and the destination
- * size is not set, then src_width and src_height must be integers, and the
- * surface size becomes the source rectangle size. This results in cropping
- * without scaling. If src_width or src_height are not integers and
- * destination size is not set, the bad_size protocol error is raised when
- * the surface state is applied.
- *
- * The coordinate transformations from buffer pixel coordinates up to
- * the surface-local coordinates happen in the following order:
- * 1. buffer_transform (wl_surface.set_buffer_transform)
- * 2. buffer_scale (wl_surface.set_buffer_scale)
- * 3. crop and scale (wp_viewport.set*)
- * This means, that the source rectangle coordinates of crop and scale
- * are given in the coordinates after the buffer transform and scale,
- * i.e. in the coordinates that would be the surface-local coordinates
- * if the crop and scale was not applied.
- *
- * If src_x or src_y are negative, the bad_value protocol error is raised.
- * Otherwise, if the source rectangle is partially or completely outside of
- * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
- * when the surface state is applied. A NULL wl_buffer does not raise the
- * out_of_buffer error.
- *
- * If the wl_surface associated with the wp_viewport is destroyed,
- * all wp_viewport requests except 'destroy' raise the protocol error
- * no_surface.
- *
- * If the wp_viewport object is destroyed, the crop and scale
- * state is removed from the wl_surface. The change will be applied
- * on the next wl_surface.commit.
- */
-extern const struct wl_interface wp_viewport_interface;
-#endif
-
-#ifndef WP_VIEWPORTER_ERROR_ENUM
-#define WP_VIEWPORTER_ERROR_ENUM
-enum wp_viewporter_error {
- /**
- * the surface already has a viewport object associated
- */
- WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS = 0,
-};
-#endif /* WP_VIEWPORTER_ERROR_ENUM */
-
-#define WP_VIEWPORTER_DESTROY 0
-#define WP_VIEWPORTER_GET_VIEWPORT 1
-
-
-/**
- * @ingroup iface_wp_viewporter
- */
-#define WP_VIEWPORTER_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_wp_viewporter
- */
-#define WP_VIEWPORTER_GET_VIEWPORT_SINCE_VERSION 1
-
-/** @ingroup iface_wp_viewporter */
-static inline void
-wp_viewporter_set_user_data(struct wp_viewporter *wp_viewporter, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wp_viewporter, user_data);
-}
-
-/** @ingroup iface_wp_viewporter */
-static inline void *
-wp_viewporter_get_user_data(struct wp_viewporter *wp_viewporter)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wp_viewporter);
-}
-
-static inline uint32_t
-wp_viewporter_get_version(struct wp_viewporter *wp_viewporter)
-{
- return wl_proxy_get_version((struct wl_proxy *) wp_viewporter);
-}
-
-/**
- * @ingroup iface_wp_viewporter
- *
- * Informs the server that the client will not be using this
- * protocol object anymore. This does not affect any other objects,
- * wp_viewport objects included.
- */
-static inline void
-wp_viewporter_destroy(struct wp_viewporter *wp_viewporter)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter,
- WP_VIEWPORTER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_wp_viewporter
- *
- * Instantiate an interface extension for the given wl_surface to
- * crop and scale its content. If the given wl_surface already has
- * a wp_viewport object associated, the viewport_exists
- * protocol error is raised.
- */
-static inline struct wp_viewport *
-wp_viewporter_get_viewport(struct wp_viewporter *wp_viewporter, struct wl_surface *surface)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter,
- WP_VIEWPORTER_GET_VIEWPORT, &wp_viewport_interface, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), 0, NULL, surface);
-
- return (struct wp_viewport *) id;
-}
-
-#ifndef WP_VIEWPORT_ERROR_ENUM
-#define WP_VIEWPORT_ERROR_ENUM
-enum wp_viewport_error {
- /**
- * negative or zero values in width or height
- */
- WP_VIEWPORT_ERROR_BAD_VALUE = 0,
- /**
- * destination size is not integer
- */
- WP_VIEWPORT_ERROR_BAD_SIZE = 1,
- /**
- * source rectangle extends outside of the content area
- */
- WP_VIEWPORT_ERROR_OUT_OF_BUFFER = 2,
- /**
- * the wl_surface was destroyed
- */
- WP_VIEWPORT_ERROR_NO_SURFACE = 3,
-};
-#endif /* WP_VIEWPORT_ERROR_ENUM */
-
-#define WP_VIEWPORT_DESTROY 0
-#define WP_VIEWPORT_SET_SOURCE 1
-#define WP_VIEWPORT_SET_DESTINATION 2
-
-
-/**
- * @ingroup iface_wp_viewport
- */
-#define WP_VIEWPORT_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_wp_viewport
- */
-#define WP_VIEWPORT_SET_SOURCE_SINCE_VERSION 1
-/**
- * @ingroup iface_wp_viewport
- */
-#define WP_VIEWPORT_SET_DESTINATION_SINCE_VERSION 1
-
-/** @ingroup iface_wp_viewport */
-static inline void
-wp_viewport_set_user_data(struct wp_viewport *wp_viewport, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wp_viewport, user_data);
-}
-
-/** @ingroup iface_wp_viewport */
-static inline void *
-wp_viewport_get_user_data(struct wp_viewport *wp_viewport)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wp_viewport);
-}
-
-static inline uint32_t
-wp_viewport_get_version(struct wp_viewport *wp_viewport)
-{
- return wl_proxy_get_version((struct wl_proxy *) wp_viewport);
-}
-
-/**
- * @ingroup iface_wp_viewport
- *
- * The associated wl_surface's crop and scale state is removed.
- * The change is applied on the next wl_surface.commit.
- */
-static inline void
-wp_viewport_destroy(struct wp_viewport *wp_viewport)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport,
- WP_VIEWPORT_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_wp_viewport
- *
- * Set the source rectangle of the associated wl_surface. See
- * wp_viewport for the description, and relation to the wl_buffer
- * size.
- *
- * If all of x, y, width and height are -1.0, the source rectangle is
- * unset instead. Any other set of values where width or height are zero
- * or negative, or x or y are negative, raise the bad_value protocol
- * error.
- *
- * The crop and scale state is double-buffered state, and will be
- * applied on the next wl_surface.commit.
- */
-static inline void
-wp_viewport_set_source(struct wp_viewport *wp_viewport, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport,
- WP_VIEWPORT_SET_SOURCE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, x, y, width, height);
-}
-
-/**
- * @ingroup iface_wp_viewport
- *
- * Set the destination size of the associated wl_surface. See
- * wp_viewport for the description, and relation to the wl_buffer
- * size.
- *
- * If width is -1 and height is -1, the destination size is unset
- * instead. Any other pair of values for width and height that
- * contains zero or negative values raises the bad_value protocol
- * error.
- *
- * The crop and scale state is double-buffered state, and will be
- * applied on the next wl_surface.commit.
- */
-static inline void
-wp_viewport_set_destination(struct wp_viewport *wp_viewport, int32_t width, int32_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport,
- WP_VIEWPORT_SET_DESTINATION, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, width, height);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pkg/glfw/wayland-headers/wayland-client-protocol-code.h b/pkg/glfw/wayland-headers/wayland-client-protocol-code.h
deleted file mode 100644
index 7ea8e7c66..000000000
--- a/pkg/glfw/wayland-headers/wayland-client-protocol-code.h
+++ /dev/null
@@ -1,525 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2010-2011 Intel Corporation
- * Copyright © 2012-2013 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include
-#include
-#include
-#include "wayland-util.h"
-
-#ifndef __has_attribute
-# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
-#endif
-
-#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
-#define WL_PRIVATE __attribute__ ((visibility("hidden")))
-#else
-#define WL_PRIVATE
-#endif
-
-extern const struct wl_interface wl_buffer_interface;
-extern const struct wl_interface wl_callback_interface;
-extern const struct wl_interface wl_data_device_interface;
-extern const struct wl_interface wl_data_offer_interface;
-extern const struct wl_interface wl_data_source_interface;
-extern const struct wl_interface wl_keyboard_interface;
-extern const struct wl_interface wl_output_interface;
-extern const struct wl_interface wl_pointer_interface;
-extern const struct wl_interface wl_region_interface;
-extern const struct wl_interface wl_registry_interface;
-extern const struct wl_interface wl_seat_interface;
-extern const struct wl_interface wl_shell_surface_interface;
-extern const struct wl_interface wl_shm_pool_interface;
-extern const struct wl_interface wl_subsurface_interface;
-extern const struct wl_interface wl_surface_interface;
-extern const struct wl_interface wl_touch_interface;
-
-static const struct wl_interface *wayland_types[] = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- &wl_callback_interface,
- &wl_registry_interface,
- &wl_surface_interface,
- &wl_region_interface,
- &wl_buffer_interface,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- &wl_shm_pool_interface,
- NULL,
- NULL,
- &wl_data_source_interface,
- &wl_surface_interface,
- &wl_surface_interface,
- NULL,
- &wl_data_source_interface,
- NULL,
- &wl_data_offer_interface,
- NULL,
- &wl_surface_interface,
- NULL,
- NULL,
- &wl_data_offer_interface,
- &wl_data_offer_interface,
- &wl_data_source_interface,
- &wl_data_device_interface,
- &wl_seat_interface,
- &wl_shell_surface_interface,
- &wl_surface_interface,
- &wl_seat_interface,
- NULL,
- &wl_seat_interface,
- NULL,
- NULL,
- &wl_surface_interface,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- &wl_output_interface,
- &wl_seat_interface,
- NULL,
- &wl_surface_interface,
- NULL,
- NULL,
- NULL,
- &wl_output_interface,
- &wl_buffer_interface,
- NULL,
- NULL,
- &wl_callback_interface,
- &wl_region_interface,
- &wl_region_interface,
- &wl_output_interface,
- &wl_output_interface,
- &wl_pointer_interface,
- &wl_keyboard_interface,
- &wl_touch_interface,
- NULL,
- &wl_surface_interface,
- NULL,
- NULL,
- NULL,
- &wl_surface_interface,
- NULL,
- NULL,
- NULL,
- &wl_surface_interface,
- NULL,
- &wl_surface_interface,
- NULL,
- NULL,
- &wl_surface_interface,
- NULL,
- NULL,
- &wl_surface_interface,
- NULL,
- NULL,
- NULL,
- &wl_subsurface_interface,
- &wl_surface_interface,
- &wl_surface_interface,
- &wl_surface_interface,
- &wl_surface_interface,
-};
-
-static const struct wl_message wl_display_requests[] = {
- { "sync", "n", wayland_types + 8 },
- { "get_registry", "n", wayland_types + 9 },
-};
-
-static const struct wl_message wl_display_events[] = {
- { "error", "ous", wayland_types + 0 },
- { "delete_id", "u", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_display_interface = {
- "wl_display", 1,
- 2, wl_display_requests,
- 2, wl_display_events,
-};
-
-static const struct wl_message wl_registry_requests[] = {
- { "bind", "usun", wayland_types + 0 },
-};
-
-static const struct wl_message wl_registry_events[] = {
- { "global", "usu", wayland_types + 0 },
- { "global_remove", "u", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_registry_interface = {
- "wl_registry", 1,
- 1, wl_registry_requests,
- 2, wl_registry_events,
-};
-
-static const struct wl_message wl_callback_events[] = {
- { "done", "u", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_callback_interface = {
- "wl_callback", 1,
- 0, NULL,
- 1, wl_callback_events,
-};
-
-static const struct wl_message wl_compositor_requests[] = {
- { "create_surface", "n", wayland_types + 10 },
- { "create_region", "n", wayland_types + 11 },
-};
-
-WL_PRIVATE const struct wl_interface wl_compositor_interface = {
- "wl_compositor", 6,
- 2, wl_compositor_requests,
- 0, NULL,
-};
-
-static const struct wl_message wl_shm_pool_requests[] = {
- { "create_buffer", "niiiiu", wayland_types + 12 },
- { "destroy", "", wayland_types + 0 },
- { "resize", "i", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_shm_pool_interface = {
- "wl_shm_pool", 1,
- 3, wl_shm_pool_requests,
- 0, NULL,
-};
-
-static const struct wl_message wl_shm_requests[] = {
- { "create_pool", "nhi", wayland_types + 18 },
-};
-
-static const struct wl_message wl_shm_events[] = {
- { "format", "u", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_shm_interface = {
- "wl_shm", 1,
- 1, wl_shm_requests,
- 1, wl_shm_events,
-};
-
-static const struct wl_message wl_buffer_requests[] = {
- { "destroy", "", wayland_types + 0 },
-};
-
-static const struct wl_message wl_buffer_events[] = {
- { "release", "", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_buffer_interface = {
- "wl_buffer", 1,
- 1, wl_buffer_requests,
- 1, wl_buffer_events,
-};
-
-static const struct wl_message wl_data_offer_requests[] = {
- { "accept", "u?s", wayland_types + 0 },
- { "receive", "sh", wayland_types + 0 },
- { "destroy", "", wayland_types + 0 },
- { "finish", "3", wayland_types + 0 },
- { "set_actions", "3uu", wayland_types + 0 },
-};
-
-static const struct wl_message wl_data_offer_events[] = {
- { "offer", "s", wayland_types + 0 },
- { "source_actions", "3u", wayland_types + 0 },
- { "action", "3u", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_data_offer_interface = {
- "wl_data_offer", 3,
- 5, wl_data_offer_requests,
- 3, wl_data_offer_events,
-};
-
-static const struct wl_message wl_data_source_requests[] = {
- { "offer", "s", wayland_types + 0 },
- { "destroy", "", wayland_types + 0 },
- { "set_actions", "3u", wayland_types + 0 },
-};
-
-static const struct wl_message wl_data_source_events[] = {
- { "target", "?s", wayland_types + 0 },
- { "send", "sh", wayland_types + 0 },
- { "cancelled", "", wayland_types + 0 },
- { "dnd_drop_performed", "3", wayland_types + 0 },
- { "dnd_finished", "3", wayland_types + 0 },
- { "action", "3u", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_data_source_interface = {
- "wl_data_source", 3,
- 3, wl_data_source_requests,
- 6, wl_data_source_events,
-};
-
-static const struct wl_message wl_data_device_requests[] = {
- { "start_drag", "?oo?ou", wayland_types + 21 },
- { "set_selection", "?ou", wayland_types + 25 },
- { "release", "2", wayland_types + 0 },
-};
-
-static const struct wl_message wl_data_device_events[] = {
- { "data_offer", "n", wayland_types + 27 },
- { "enter", "uoff?o", wayland_types + 28 },
- { "leave", "", wayland_types + 0 },
- { "motion", "uff", wayland_types + 0 },
- { "drop", "", wayland_types + 0 },
- { "selection", "?o", wayland_types + 33 },
-};
-
-WL_PRIVATE const struct wl_interface wl_data_device_interface = {
- "wl_data_device", 3,
- 3, wl_data_device_requests,
- 6, wl_data_device_events,
-};
-
-static const struct wl_message wl_data_device_manager_requests[] = {
- { "create_data_source", "n", wayland_types + 34 },
- { "get_data_device", "no", wayland_types + 35 },
-};
-
-WL_PRIVATE const struct wl_interface wl_data_device_manager_interface = {
- "wl_data_device_manager", 3,
- 2, wl_data_device_manager_requests,
- 0, NULL,
-};
-
-static const struct wl_message wl_shell_requests[] = {
- { "get_shell_surface", "no", wayland_types + 37 },
-};
-
-WL_PRIVATE const struct wl_interface wl_shell_interface = {
- "wl_shell", 1,
- 1, wl_shell_requests,
- 0, NULL,
-};
-
-static const struct wl_message wl_shell_surface_requests[] = {
- { "pong", "u", wayland_types + 0 },
- { "move", "ou", wayland_types + 39 },
- { "resize", "ouu", wayland_types + 41 },
- { "set_toplevel", "", wayland_types + 0 },
- { "set_transient", "oiiu", wayland_types + 44 },
- { "set_fullscreen", "uu?o", wayland_types + 48 },
- { "set_popup", "ouoiiu", wayland_types + 51 },
- { "set_maximized", "?o", wayland_types + 57 },
- { "set_title", "s", wayland_types + 0 },
- { "set_class", "s", wayland_types + 0 },
-};
-
-static const struct wl_message wl_shell_surface_events[] = {
- { "ping", "u", wayland_types + 0 },
- { "configure", "uii", wayland_types + 0 },
- { "popup_done", "", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_shell_surface_interface = {
- "wl_shell_surface", 1,
- 10, wl_shell_surface_requests,
- 3, wl_shell_surface_events,
-};
-
-static const struct wl_message wl_surface_requests[] = {
- { "destroy", "", wayland_types + 0 },
- { "attach", "?oii", wayland_types + 58 },
- { "damage", "iiii", wayland_types + 0 },
- { "frame", "n", wayland_types + 61 },
- { "set_opaque_region", "?o", wayland_types + 62 },
- { "set_input_region", "?o", wayland_types + 63 },
- { "commit", "", wayland_types + 0 },
- { "set_buffer_transform", "2i", wayland_types + 0 },
- { "set_buffer_scale", "3i", wayland_types + 0 },
- { "damage_buffer", "4iiii", wayland_types + 0 },
- { "offset", "5ii", wayland_types + 0 },
-};
-
-static const struct wl_message wl_surface_events[] = {
- { "enter", "o", wayland_types + 64 },
- { "leave", "o", wayland_types + 65 },
- { "preferred_buffer_scale", "6i", wayland_types + 0 },
- { "preferred_buffer_transform", "6u", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_surface_interface = {
- "wl_surface", 6,
- 11, wl_surface_requests,
- 4, wl_surface_events,
-};
-
-static const struct wl_message wl_seat_requests[] = {
- { "get_pointer", "n", wayland_types + 66 },
- { "get_keyboard", "n", wayland_types + 67 },
- { "get_touch", "n", wayland_types + 68 },
- { "release", "5", wayland_types + 0 },
-};
-
-static const struct wl_message wl_seat_events[] = {
- { "capabilities", "u", wayland_types + 0 },
- { "name", "2s", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_seat_interface = {
- "wl_seat", 9,
- 4, wl_seat_requests,
- 2, wl_seat_events,
-};
-
-static const struct wl_message wl_pointer_requests[] = {
- { "set_cursor", "u?oii", wayland_types + 69 },
- { "release", "3", wayland_types + 0 },
-};
-
-static const struct wl_message wl_pointer_events[] = {
- { "enter", "uoff", wayland_types + 73 },
- { "leave", "uo", wayland_types + 77 },
- { "motion", "uff", wayland_types + 0 },
- { "button", "uuuu", wayland_types + 0 },
- { "axis", "uuf", wayland_types + 0 },
- { "frame", "5", wayland_types + 0 },
- { "axis_source", "5u", wayland_types + 0 },
- { "axis_stop", "5uu", wayland_types + 0 },
- { "axis_discrete", "5ui", wayland_types + 0 },
- { "axis_value120", "8ui", wayland_types + 0 },
- { "axis_relative_direction", "9uu", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_pointer_interface = {
- "wl_pointer", 9,
- 2, wl_pointer_requests,
- 11, wl_pointer_events,
-};
-
-static const struct wl_message wl_keyboard_requests[] = {
- { "release", "3", wayland_types + 0 },
-};
-
-static const struct wl_message wl_keyboard_events[] = {
- { "keymap", "uhu", wayland_types + 0 },
- { "enter", "uoa", wayland_types + 79 },
- { "leave", "uo", wayland_types + 82 },
- { "key", "uuuu", wayland_types + 0 },
- { "modifiers", "uuuuu", wayland_types + 0 },
- { "repeat_info", "4ii", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_keyboard_interface = {
- "wl_keyboard", 9,
- 1, wl_keyboard_requests,
- 6, wl_keyboard_events,
-};
-
-static const struct wl_message wl_touch_requests[] = {
- { "release", "3", wayland_types + 0 },
-};
-
-static const struct wl_message wl_touch_events[] = {
- { "down", "uuoiff", wayland_types + 84 },
- { "up", "uui", wayland_types + 0 },
- { "motion", "uiff", wayland_types + 0 },
- { "frame", "", wayland_types + 0 },
- { "cancel", "", wayland_types + 0 },
- { "shape", "6iff", wayland_types + 0 },
- { "orientation", "6if", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_touch_interface = {
- "wl_touch", 9,
- 1, wl_touch_requests,
- 7, wl_touch_events,
-};
-
-static const struct wl_message wl_output_requests[] = {
- { "release", "3", wayland_types + 0 },
-};
-
-static const struct wl_message wl_output_events[] = {
- { "geometry", "iiiiissi", wayland_types + 0 },
- { "mode", "uiii", wayland_types + 0 },
- { "done", "2", wayland_types + 0 },
- { "scale", "2i", wayland_types + 0 },
- { "name", "4s", wayland_types + 0 },
- { "description", "4s", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_output_interface = {
- "wl_output", 4,
- 1, wl_output_requests,
- 6, wl_output_events,
-};
-
-static const struct wl_message wl_region_requests[] = {
- { "destroy", "", wayland_types + 0 },
- { "add", "iiii", wayland_types + 0 },
- { "subtract", "iiii", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_region_interface = {
- "wl_region", 1,
- 3, wl_region_requests,
- 0, NULL,
-};
-
-static const struct wl_message wl_subcompositor_requests[] = {
- { "destroy", "", wayland_types + 0 },
- { "get_subsurface", "noo", wayland_types + 90 },
-};
-
-WL_PRIVATE const struct wl_interface wl_subcompositor_interface = {
- "wl_subcompositor", 1,
- 2, wl_subcompositor_requests,
- 0, NULL,
-};
-
-static const struct wl_message wl_subsurface_requests[] = {
- { "destroy", "", wayland_types + 0 },
- { "set_position", "ii", wayland_types + 0 },
- { "place_above", "o", wayland_types + 93 },
- { "place_below", "o", wayland_types + 94 },
- { "set_sync", "", wayland_types + 0 },
- { "set_desync", "", wayland_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface wl_subsurface_interface = {
- "wl_subsurface", 1,
- 6, wl_subsurface_requests,
- 0, NULL,
-};
-
diff --git a/pkg/glfw/wayland-headers/wayland-client-protocol.h b/pkg/glfw/wayland-headers/wayland-client-protocol.h
deleted file mode 100644
index 764c5958c..000000000
--- a/pkg/glfw/wayland-headers/wayland-client-protocol.h
+++ /dev/null
@@ -1,6236 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-#ifndef WAYLAND_CLIENT_PROTOCOL_H
-#define WAYLAND_CLIENT_PROTOCOL_H
-
-#include
-#include
-#include "wayland-client.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @page page_wayland The wayland protocol
- * @section page_ifaces_wayland Interfaces
- * - @subpage page_iface_wl_display - core global object
- * - @subpage page_iface_wl_registry - global registry object
- * - @subpage page_iface_wl_callback - callback object
- * - @subpage page_iface_wl_compositor - the compositor singleton
- * - @subpage page_iface_wl_shm_pool - a shared memory pool
- * - @subpage page_iface_wl_shm - shared memory support
- * - @subpage page_iface_wl_buffer - content for a wl_surface
- * - @subpage page_iface_wl_data_offer - offer to transfer data
- * - @subpage page_iface_wl_data_source - offer to transfer data
- * - @subpage page_iface_wl_data_device - data transfer device
- * - @subpage page_iface_wl_data_device_manager - data transfer interface
- * - @subpage page_iface_wl_shell - create desktop-style surfaces
- * - @subpage page_iface_wl_shell_surface - desktop-style metadata interface
- * - @subpage page_iface_wl_surface - an onscreen surface
- * - @subpage page_iface_wl_seat - group of input devices
- * - @subpage page_iface_wl_pointer - pointer input device
- * - @subpage page_iface_wl_keyboard - keyboard input device
- * - @subpage page_iface_wl_touch - touchscreen input device
- * - @subpage page_iface_wl_output - compositor output region
- * - @subpage page_iface_wl_region - region interface
- * - @subpage page_iface_wl_subcompositor - sub-surface compositing
- * - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface
- * @section page_copyright_wayland Copyright
- *
- *
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2010-2011 Intel Corporation
- * Copyright © 2012-2013 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-struct wl_buffer;
-struct wl_callback;
-struct wl_compositor;
-struct wl_data_device;
-struct wl_data_device_manager;
-struct wl_data_offer;
-struct wl_data_source;
-struct wl_display;
-struct wl_keyboard;
-struct wl_output;
-struct wl_pointer;
-struct wl_region;
-struct wl_registry;
-struct wl_seat;
-struct wl_shell;
-struct wl_shell_surface;
-struct wl_shm;
-struct wl_shm_pool;
-struct wl_subcompositor;
-struct wl_subsurface;
-struct wl_surface;
-struct wl_touch;
-
-#ifndef WL_DISPLAY_INTERFACE
-#define WL_DISPLAY_INTERFACE
-/**
- * @page page_iface_wl_display wl_display
- * @section page_iface_wl_display_desc Description
- *
- * The core global object. This is a special singleton object. It
- * is used for internal Wayland protocol features.
- * @section page_iface_wl_display_api API
- * See @ref iface_wl_display.
- */
-/**
- * @defgroup iface_wl_display The wl_display interface
- *
- * The core global object. This is a special singleton object. It
- * is used for internal Wayland protocol features.
- */
-extern const struct wl_interface wl_display_interface;
-#endif
-#ifndef WL_REGISTRY_INTERFACE
-#define WL_REGISTRY_INTERFACE
-/**
- * @page page_iface_wl_registry wl_registry
- * @section page_iface_wl_registry_desc Description
- *
- * The singleton global registry object. The server has a number of
- * global objects that are available to all clients. These objects
- * typically represent an actual object in the server (for example,
- * an input device) or they are singleton objects that provide
- * extension functionality.
- *
- * When a client creates a registry object, the registry object
- * will emit a global event for each global currently in the
- * registry. Globals come and go as a result of device or
- * monitor hotplugs, reconfiguration or other events, and the
- * registry will send out global and global_remove events to
- * keep the client up to date with the changes. To mark the end
- * of the initial burst of events, the client can use the
- * wl_display.sync request immediately after calling
- * wl_display.get_registry.
- *
- * A client can bind to a global object by using the bind
- * request. This creates a client-side handle that lets the object
- * emit events to the client and lets the client invoke requests on
- * the object.
- * @section page_iface_wl_registry_api API
- * See @ref iface_wl_registry.
- */
-/**
- * @defgroup iface_wl_registry The wl_registry interface
- *
- * The singleton global registry object. The server has a number of
- * global objects that are available to all clients. These objects
- * typically represent an actual object in the server (for example,
- * an input device) or they are singleton objects that provide
- * extension functionality.
- *
- * When a client creates a registry object, the registry object
- * will emit a global event for each global currently in the
- * registry. Globals come and go as a result of device or
- * monitor hotplugs, reconfiguration or other events, and the
- * registry will send out global and global_remove events to
- * keep the client up to date with the changes. To mark the end
- * of the initial burst of events, the client can use the
- * wl_display.sync request immediately after calling
- * wl_display.get_registry.
- *
- * A client can bind to a global object by using the bind
- * request. This creates a client-side handle that lets the object
- * emit events to the client and lets the client invoke requests on
- * the object.
- */
-extern const struct wl_interface wl_registry_interface;
-#endif
-#ifndef WL_CALLBACK_INTERFACE
-#define WL_CALLBACK_INTERFACE
-/**
- * @page page_iface_wl_callback wl_callback
- * @section page_iface_wl_callback_desc Description
- *
- * Clients can handle the 'done' event to get notified when
- * the related request is done.
- *
- * Note, because wl_callback objects are created from multiple independent
- * factory interfaces, the wl_callback interface is frozen at version 1.
- * @section page_iface_wl_callback_api API
- * See @ref iface_wl_callback.
- */
-/**
- * @defgroup iface_wl_callback The wl_callback interface
- *
- * Clients can handle the 'done' event to get notified when
- * the related request is done.
- *
- * Note, because wl_callback objects are created from multiple independent
- * factory interfaces, the wl_callback interface is frozen at version 1.
- */
-extern const struct wl_interface wl_callback_interface;
-#endif
-#ifndef WL_COMPOSITOR_INTERFACE
-#define WL_COMPOSITOR_INTERFACE
-/**
- * @page page_iface_wl_compositor wl_compositor
- * @section page_iface_wl_compositor_desc Description
- *
- * A compositor. This object is a singleton global. The
- * compositor is in charge of combining the contents of multiple
- * surfaces into one displayable output.
- * @section page_iface_wl_compositor_api API
- * See @ref iface_wl_compositor.
- */
-/**
- * @defgroup iface_wl_compositor The wl_compositor interface
- *
- * A compositor. This object is a singleton global. The
- * compositor is in charge of combining the contents of multiple
- * surfaces into one displayable output.
- */
-extern const struct wl_interface wl_compositor_interface;
-#endif
-#ifndef WL_SHM_POOL_INTERFACE
-#define WL_SHM_POOL_INTERFACE
-/**
- * @page page_iface_wl_shm_pool wl_shm_pool
- * @section page_iface_wl_shm_pool_desc Description
- *
- * The wl_shm_pool object encapsulates a piece of memory shared
- * between the compositor and client. Through the wl_shm_pool
- * object, the client can allocate shared memory wl_buffer objects.
- * All objects created through the same pool share the same
- * underlying mapped memory. Reusing the mapped memory avoids the
- * setup/teardown overhead and is useful when interactively resizing
- * a surface or for many small buffers.
- * @section page_iface_wl_shm_pool_api API
- * See @ref iface_wl_shm_pool.
- */
-/**
- * @defgroup iface_wl_shm_pool The wl_shm_pool interface
- *
- * The wl_shm_pool object encapsulates a piece of memory shared
- * between the compositor and client. Through the wl_shm_pool
- * object, the client can allocate shared memory wl_buffer objects.
- * All objects created through the same pool share the same
- * underlying mapped memory. Reusing the mapped memory avoids the
- * setup/teardown overhead and is useful when interactively resizing
- * a surface or for many small buffers.
- */
-extern const struct wl_interface wl_shm_pool_interface;
-#endif
-#ifndef WL_SHM_INTERFACE
-#define WL_SHM_INTERFACE
-/**
- * @page page_iface_wl_shm wl_shm
- * @section page_iface_wl_shm_desc Description
- *
- * A singleton global object that provides support for shared
- * memory.
- *
- * Clients can create wl_shm_pool objects using the create_pool
- * request.
- *
- * On binding the wl_shm object one or more format events
- * are emitted to inform clients about the valid pixel formats
- * that can be used for buffers.
- * @section page_iface_wl_shm_api API
- * See @ref iface_wl_shm.
- */
-/**
- * @defgroup iface_wl_shm The wl_shm interface
- *
- * A singleton global object that provides support for shared
- * memory.
- *
- * Clients can create wl_shm_pool objects using the create_pool
- * request.
- *
- * On binding the wl_shm object one or more format events
- * are emitted to inform clients about the valid pixel formats
- * that can be used for buffers.
- */
-extern const struct wl_interface wl_shm_interface;
-#endif
-#ifndef WL_BUFFER_INTERFACE
-#define WL_BUFFER_INTERFACE
-/**
- * @page page_iface_wl_buffer wl_buffer
- * @section page_iface_wl_buffer_desc Description
- *
- * A buffer provides the content for a wl_surface. Buffers are
- * created through factory interfaces such as wl_shm, wp_linux_buffer_params
- * (from the linux-dmabuf protocol extension) or similar. It has a width and
- * a height and can be attached to a wl_surface, but the mechanism by which a
- * client provides and updates the contents is defined by the buffer factory
- * interface.
- *
- * If the buffer uses a format that has an alpha channel, the alpha channel
- * is assumed to be premultiplied in the color channels unless otherwise
- * specified.
- *
- * Note, because wl_buffer objects are created from multiple independent
- * factory interfaces, the wl_buffer interface is frozen at version 1.
- * @section page_iface_wl_buffer_api API
- * See @ref iface_wl_buffer.
- */
-/**
- * @defgroup iface_wl_buffer The wl_buffer interface
- *
- * A buffer provides the content for a wl_surface. Buffers are
- * created through factory interfaces such as wl_shm, wp_linux_buffer_params
- * (from the linux-dmabuf protocol extension) or similar. It has a width and
- * a height and can be attached to a wl_surface, but the mechanism by which a
- * client provides and updates the contents is defined by the buffer factory
- * interface.
- *
- * If the buffer uses a format that has an alpha channel, the alpha channel
- * is assumed to be premultiplied in the color channels unless otherwise
- * specified.
- *
- * Note, because wl_buffer objects are created from multiple independent
- * factory interfaces, the wl_buffer interface is frozen at version 1.
- */
-extern const struct wl_interface wl_buffer_interface;
-#endif
-#ifndef WL_DATA_OFFER_INTERFACE
-#define WL_DATA_OFFER_INTERFACE
-/**
- * @page page_iface_wl_data_offer wl_data_offer
- * @section page_iface_wl_data_offer_desc Description
- *
- * A wl_data_offer represents a piece of data offered for transfer
- * by another client (the source client). It is used by the
- * copy-and-paste and drag-and-drop mechanisms. The offer
- * describes the different mime types that the data can be
- * converted to and provides the mechanism for transferring the
- * data directly from the source client.
- * @section page_iface_wl_data_offer_api API
- * See @ref iface_wl_data_offer.
- */
-/**
- * @defgroup iface_wl_data_offer The wl_data_offer interface
- *
- * A wl_data_offer represents a piece of data offered for transfer
- * by another client (the source client). It is used by the
- * copy-and-paste and drag-and-drop mechanisms. The offer
- * describes the different mime types that the data can be
- * converted to and provides the mechanism for transferring the
- * data directly from the source client.
- */
-extern const struct wl_interface wl_data_offer_interface;
-#endif
-#ifndef WL_DATA_SOURCE_INTERFACE
-#define WL_DATA_SOURCE_INTERFACE
-/**
- * @page page_iface_wl_data_source wl_data_source
- * @section page_iface_wl_data_source_desc Description
- *
- * The wl_data_source object is the source side of a wl_data_offer.
- * It is created by the source client in a data transfer and
- * provides a way to describe the offered data and a way to respond
- * to requests to transfer the data.
- * @section page_iface_wl_data_source_api API
- * See @ref iface_wl_data_source.
- */
-/**
- * @defgroup iface_wl_data_source The wl_data_source interface
- *
- * The wl_data_source object is the source side of a wl_data_offer.
- * It is created by the source client in a data transfer and
- * provides a way to describe the offered data and a way to respond
- * to requests to transfer the data.
- */
-extern const struct wl_interface wl_data_source_interface;
-#endif
-#ifndef WL_DATA_DEVICE_INTERFACE
-#define WL_DATA_DEVICE_INTERFACE
-/**
- * @page page_iface_wl_data_device wl_data_device
- * @section page_iface_wl_data_device_desc Description
- *
- * There is one wl_data_device per seat which can be obtained
- * from the global wl_data_device_manager singleton.
- *
- * A wl_data_device provides access to inter-client data transfer
- * mechanisms such as copy-and-paste and drag-and-drop.
- * @section page_iface_wl_data_device_api API
- * See @ref iface_wl_data_device.
- */
-/**
- * @defgroup iface_wl_data_device The wl_data_device interface
- *
- * There is one wl_data_device per seat which can be obtained
- * from the global wl_data_device_manager singleton.
- *
- * A wl_data_device provides access to inter-client data transfer
- * mechanisms such as copy-and-paste and drag-and-drop.
- */
-extern const struct wl_interface wl_data_device_interface;
-#endif
-#ifndef WL_DATA_DEVICE_MANAGER_INTERFACE
-#define WL_DATA_DEVICE_MANAGER_INTERFACE
-/**
- * @page page_iface_wl_data_device_manager wl_data_device_manager
- * @section page_iface_wl_data_device_manager_desc Description
- *
- * The wl_data_device_manager is a singleton global object that
- * provides access to inter-client data transfer mechanisms such as
- * copy-and-paste and drag-and-drop. These mechanisms are tied to
- * a wl_seat and this interface lets a client get a wl_data_device
- * corresponding to a wl_seat.
- *
- * Depending on the version bound, the objects created from the bound
- * wl_data_device_manager object will have different requirements for
- * functioning properly. See wl_data_source.set_actions,
- * wl_data_offer.accept and wl_data_offer.finish for details.
- * @section page_iface_wl_data_device_manager_api API
- * See @ref iface_wl_data_device_manager.
- */
-/**
- * @defgroup iface_wl_data_device_manager The wl_data_device_manager interface
- *
- * The wl_data_device_manager is a singleton global object that
- * provides access to inter-client data transfer mechanisms such as
- * copy-and-paste and drag-and-drop. These mechanisms are tied to
- * a wl_seat and this interface lets a client get a wl_data_device
- * corresponding to a wl_seat.
- *
- * Depending on the version bound, the objects created from the bound
- * wl_data_device_manager object will have different requirements for
- * functioning properly. See wl_data_source.set_actions,
- * wl_data_offer.accept and wl_data_offer.finish for details.
- */
-extern const struct wl_interface wl_data_device_manager_interface;
-#endif
-#ifndef WL_SHELL_INTERFACE
-#define WL_SHELL_INTERFACE
-/**
- * @page page_iface_wl_shell wl_shell
- * @section page_iface_wl_shell_desc Description
- *
- * This interface is implemented by servers that provide
- * desktop-style user interfaces.
- *
- * It allows clients to associate a wl_shell_surface with
- * a basic surface.
- *
- * Note! This protocol is deprecated and not intended for production use.
- * For desktop-style user interfaces, use xdg_shell. Compositors and clients
- * should not implement this interface.
- * @section page_iface_wl_shell_api API
- * See @ref iface_wl_shell.
- */
-/**
- * @defgroup iface_wl_shell The wl_shell interface
- *
- * This interface is implemented by servers that provide
- * desktop-style user interfaces.
- *
- * It allows clients to associate a wl_shell_surface with
- * a basic surface.
- *
- * Note! This protocol is deprecated and not intended for production use.
- * For desktop-style user interfaces, use xdg_shell. Compositors and clients
- * should not implement this interface.
- */
-extern const struct wl_interface wl_shell_interface;
-#endif
-#ifndef WL_SHELL_SURFACE_INTERFACE
-#define WL_SHELL_SURFACE_INTERFACE
-/**
- * @page page_iface_wl_shell_surface wl_shell_surface
- * @section page_iface_wl_shell_surface_desc Description
- *
- * An interface that may be implemented by a wl_surface, for
- * implementations that provide a desktop-style user interface.
- *
- * It provides requests to treat surfaces like toplevel, fullscreen
- * or popup windows, move, resize or maximize them, associate
- * metadata like title and class, etc.
- *
- * On the server side the object is automatically destroyed when
- * the related wl_surface is destroyed. On the client side,
- * wl_shell_surface_destroy() must be called before destroying
- * the wl_surface object.
- * @section page_iface_wl_shell_surface_api API
- * See @ref iface_wl_shell_surface.
- */
-/**
- * @defgroup iface_wl_shell_surface The wl_shell_surface interface
- *
- * An interface that may be implemented by a wl_surface, for
- * implementations that provide a desktop-style user interface.
- *
- * It provides requests to treat surfaces like toplevel, fullscreen
- * or popup windows, move, resize or maximize them, associate
- * metadata like title and class, etc.
- *
- * On the server side the object is automatically destroyed when
- * the related wl_surface is destroyed. On the client side,
- * wl_shell_surface_destroy() must be called before destroying
- * the wl_surface object.
- */
-extern const struct wl_interface wl_shell_surface_interface;
-#endif
-#ifndef WL_SURFACE_INTERFACE
-#define WL_SURFACE_INTERFACE
-/**
- * @page page_iface_wl_surface wl_surface
- * @section page_iface_wl_surface_desc Description
- *
- * A surface is a rectangular area that may be displayed on zero
- * or more outputs, and shown any number of times at the compositor's
- * discretion. They can present wl_buffers, receive user input, and
- * define a local coordinate system.
- *
- * The size of a surface (and relative positions on it) is described
- * in surface-local coordinates, which may differ from the buffer
- * coordinates of the pixel content, in case a buffer_transform
- * or a buffer_scale is used.
- *
- * A surface without a "role" is fairly useless: a compositor does
- * not know where, when or how to present it. The role is the
- * purpose of a wl_surface. Examples of roles are a cursor for a
- * pointer (as set by wl_pointer.set_cursor), a drag icon
- * (wl_data_device.start_drag), a sub-surface
- * (wl_subcompositor.get_subsurface), and a window as defined by a
- * shell protocol (e.g. wl_shell.get_shell_surface).
- *
- * A surface can have only one role at a time. Initially a
- * wl_surface does not have a role. Once a wl_surface is given a
- * role, it is set permanently for the whole lifetime of the
- * wl_surface object. Giving the current role again is allowed,
- * unless explicitly forbidden by the relevant interface
- * specification.
- *
- * Surface roles are given by requests in other interfaces such as
- * wl_pointer.set_cursor. The request should explicitly mention
- * that this request gives a role to a wl_surface. Often, this
- * request also creates a new protocol object that represents the
- * role and adds additional functionality to wl_surface. When a
- * client wants to destroy a wl_surface, they must destroy this role
- * object before the wl_surface, otherwise a defunct_role_object error is
- * sent.
- *
- * Destroying the role object does not remove the role from the
- * wl_surface, but it may stop the wl_surface from "playing the role".
- * For instance, if a wl_subsurface object is destroyed, the wl_surface
- * it was created for will be unmapped and forget its position and
- * z-order. It is allowed to create a wl_subsurface for the same
- * wl_surface again, but it is not allowed to use the wl_surface as
- * a cursor (cursor is a different role than sub-surface, and role
- * switching is not allowed).
- * @section page_iface_wl_surface_api API
- * See @ref iface_wl_surface.
- */
-/**
- * @defgroup iface_wl_surface The wl_surface interface
- *
- * A surface is a rectangular area that may be displayed on zero
- * or more outputs, and shown any number of times at the compositor's
- * discretion. They can present wl_buffers, receive user input, and
- * define a local coordinate system.
- *
- * The size of a surface (and relative positions on it) is described
- * in surface-local coordinates, which may differ from the buffer
- * coordinates of the pixel content, in case a buffer_transform
- * or a buffer_scale is used.
- *
- * A surface without a "role" is fairly useless: a compositor does
- * not know where, when or how to present it. The role is the
- * purpose of a wl_surface. Examples of roles are a cursor for a
- * pointer (as set by wl_pointer.set_cursor), a drag icon
- * (wl_data_device.start_drag), a sub-surface
- * (wl_subcompositor.get_subsurface), and a window as defined by a
- * shell protocol (e.g. wl_shell.get_shell_surface).
- *
- * A surface can have only one role at a time. Initially a
- * wl_surface does not have a role. Once a wl_surface is given a
- * role, it is set permanently for the whole lifetime of the
- * wl_surface object. Giving the current role again is allowed,
- * unless explicitly forbidden by the relevant interface
- * specification.
- *
- * Surface roles are given by requests in other interfaces such as
- * wl_pointer.set_cursor. The request should explicitly mention
- * that this request gives a role to a wl_surface. Often, this
- * request also creates a new protocol object that represents the
- * role and adds additional functionality to wl_surface. When a
- * client wants to destroy a wl_surface, they must destroy this role
- * object before the wl_surface, otherwise a defunct_role_object error is
- * sent.
- *
- * Destroying the role object does not remove the role from the
- * wl_surface, but it may stop the wl_surface from "playing the role".
- * For instance, if a wl_subsurface object is destroyed, the wl_surface
- * it was created for will be unmapped and forget its position and
- * z-order. It is allowed to create a wl_subsurface for the same
- * wl_surface again, but it is not allowed to use the wl_surface as
- * a cursor (cursor is a different role than sub-surface, and role
- * switching is not allowed).
- */
-extern const struct wl_interface wl_surface_interface;
-#endif
-#ifndef WL_SEAT_INTERFACE
-#define WL_SEAT_INTERFACE
-/**
- * @page page_iface_wl_seat wl_seat
- * @section page_iface_wl_seat_desc Description
- *
- * A seat is a group of keyboards, pointer and touch devices. This
- * object is published as a global during start up, or when such a
- * device is hot plugged. A seat typically has a pointer and
- * maintains a keyboard focus and a pointer focus.
- * @section page_iface_wl_seat_api API
- * See @ref iface_wl_seat.
- */
-/**
- * @defgroup iface_wl_seat The wl_seat interface
- *
- * A seat is a group of keyboards, pointer and touch devices. This
- * object is published as a global during start up, or when such a
- * device is hot plugged. A seat typically has a pointer and
- * maintains a keyboard focus and a pointer focus.
- */
-extern const struct wl_interface wl_seat_interface;
-#endif
-#ifndef WL_POINTER_INTERFACE
-#define WL_POINTER_INTERFACE
-/**
- * @page page_iface_wl_pointer wl_pointer
- * @section page_iface_wl_pointer_desc Description
- *
- * The wl_pointer interface represents one or more input devices,
- * such as mice, which control the pointer location and pointer_focus
- * of a seat.
- *
- * The wl_pointer interface generates motion, enter and leave
- * events for the surfaces that the pointer is located over,
- * and button and axis events for button presses, button releases
- * and scrolling.
- * @section page_iface_wl_pointer_api API
- * See @ref iface_wl_pointer.
- */
-/**
- * @defgroup iface_wl_pointer The wl_pointer interface
- *
- * The wl_pointer interface represents one or more input devices,
- * such as mice, which control the pointer location and pointer_focus
- * of a seat.
- *
- * The wl_pointer interface generates motion, enter and leave
- * events for the surfaces that the pointer is located over,
- * and button and axis events for button presses, button releases
- * and scrolling.
- */
-extern const struct wl_interface wl_pointer_interface;
-#endif
-#ifndef WL_KEYBOARD_INTERFACE
-#define WL_KEYBOARD_INTERFACE
-/**
- * @page page_iface_wl_keyboard wl_keyboard
- * @section page_iface_wl_keyboard_desc Description
- *
- * The wl_keyboard interface represents one or more keyboards
- * associated with a seat.
- * @section page_iface_wl_keyboard_api API
- * See @ref iface_wl_keyboard.
- */
-/**
- * @defgroup iface_wl_keyboard The wl_keyboard interface
- *
- * The wl_keyboard interface represents one or more keyboards
- * associated with a seat.
- */
-extern const struct wl_interface wl_keyboard_interface;
-#endif
-#ifndef WL_TOUCH_INTERFACE
-#define WL_TOUCH_INTERFACE
-/**
- * @page page_iface_wl_touch wl_touch
- * @section page_iface_wl_touch_desc Description
- *
- * The wl_touch interface represents a touchscreen
- * associated with a seat.
- *
- * Touch interactions can consist of one or more contacts.
- * For each contact, a series of events is generated, starting
- * with a down event, followed by zero or more motion events,
- * and ending with an up event. Events relating to the same
- * contact point can be identified by the ID of the sequence.
- * @section page_iface_wl_touch_api API
- * See @ref iface_wl_touch.
- */
-/**
- * @defgroup iface_wl_touch The wl_touch interface
- *
- * The wl_touch interface represents a touchscreen
- * associated with a seat.
- *
- * Touch interactions can consist of one or more contacts.
- * For each contact, a series of events is generated, starting
- * with a down event, followed by zero or more motion events,
- * and ending with an up event. Events relating to the same
- * contact point can be identified by the ID of the sequence.
- */
-extern const struct wl_interface wl_touch_interface;
-#endif
-#ifndef WL_OUTPUT_INTERFACE
-#define WL_OUTPUT_INTERFACE
-/**
- * @page page_iface_wl_output wl_output
- * @section page_iface_wl_output_desc Description
- *
- * An output describes part of the compositor geometry. The
- * compositor works in the 'compositor coordinate system' and an
- * output corresponds to a rectangular area in that space that is
- * actually visible. This typically corresponds to a monitor that
- * displays part of the compositor space. This object is published
- * as global during start up, or when a monitor is hotplugged.
- * @section page_iface_wl_output_api API
- * See @ref iface_wl_output.
- */
-/**
- * @defgroup iface_wl_output The wl_output interface
- *
- * An output describes part of the compositor geometry. The
- * compositor works in the 'compositor coordinate system' and an
- * output corresponds to a rectangular area in that space that is
- * actually visible. This typically corresponds to a monitor that
- * displays part of the compositor space. This object is published
- * as global during start up, or when a monitor is hotplugged.
- */
-extern const struct wl_interface wl_output_interface;
-#endif
-#ifndef WL_REGION_INTERFACE
-#define WL_REGION_INTERFACE
-/**
- * @page page_iface_wl_region wl_region
- * @section page_iface_wl_region_desc Description
- *
- * A region object describes an area.
- *
- * Region objects are used to describe the opaque and input
- * regions of a surface.
- * @section page_iface_wl_region_api API
- * See @ref iface_wl_region.
- */
-/**
- * @defgroup iface_wl_region The wl_region interface
- *
- * A region object describes an area.
- *
- * Region objects are used to describe the opaque and input
- * regions of a surface.
- */
-extern const struct wl_interface wl_region_interface;
-#endif
-#ifndef WL_SUBCOMPOSITOR_INTERFACE
-#define WL_SUBCOMPOSITOR_INTERFACE
-/**
- * @page page_iface_wl_subcompositor wl_subcompositor
- * @section page_iface_wl_subcompositor_desc Description
- *
- * The global interface exposing sub-surface compositing capabilities.
- * A wl_surface, that has sub-surfaces associated, is called the
- * parent surface. Sub-surfaces can be arbitrarily nested and create
- * a tree of sub-surfaces.
- *
- * The root surface in a tree of sub-surfaces is the main
- * surface. The main surface cannot be a sub-surface, because
- * sub-surfaces must always have a parent.
- *
- * A main surface with its sub-surfaces forms a (compound) window.
- * For window management purposes, this set of wl_surface objects is
- * to be considered as a single window, and it should also behave as
- * such.
- *
- * The aim of sub-surfaces is to offload some of the compositing work
- * within a window from clients to the compositor. A prime example is
- * a video player with decorations and video in separate wl_surface
- * objects. This should allow the compositor to pass YUV video buffer
- * processing to dedicated overlay hardware when possible.
- * @section page_iface_wl_subcompositor_api API
- * See @ref iface_wl_subcompositor.
- */
-/**
- * @defgroup iface_wl_subcompositor The wl_subcompositor interface
- *
- * The global interface exposing sub-surface compositing capabilities.
- * A wl_surface, that has sub-surfaces associated, is called the
- * parent surface. Sub-surfaces can be arbitrarily nested and create
- * a tree of sub-surfaces.
- *
- * The root surface in a tree of sub-surfaces is the main
- * surface. The main surface cannot be a sub-surface, because
- * sub-surfaces must always have a parent.
- *
- * A main surface with its sub-surfaces forms a (compound) window.
- * For window management purposes, this set of wl_surface objects is
- * to be considered as a single window, and it should also behave as
- * such.
- *
- * The aim of sub-surfaces is to offload some of the compositing work
- * within a window from clients to the compositor. A prime example is
- * a video player with decorations and video in separate wl_surface
- * objects. This should allow the compositor to pass YUV video buffer
- * processing to dedicated overlay hardware when possible.
- */
-extern const struct wl_interface wl_subcompositor_interface;
-#endif
-#ifndef WL_SUBSURFACE_INTERFACE
-#define WL_SUBSURFACE_INTERFACE
-/**
- * @page page_iface_wl_subsurface wl_subsurface
- * @section page_iface_wl_subsurface_desc Description
- *
- * An additional interface to a wl_surface object, which has been
- * made a sub-surface. A sub-surface has one parent surface. A
- * sub-surface's size and position are not limited to that of the parent.
- * Particularly, a sub-surface is not automatically clipped to its
- * parent's area.
- *
- * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
- * and the parent surface is mapped. The order of which one happens
- * first is irrelevant. A sub-surface is hidden if the parent becomes
- * hidden, or if a NULL wl_buffer is applied. These rules apply
- * recursively through the tree of surfaces.
- *
- * The behaviour of a wl_surface.commit request on a sub-surface
- * depends on the sub-surface's mode. The possible modes are
- * synchronized and desynchronized, see methods
- * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
- * mode caches the wl_surface state to be applied when the parent's
- * state gets applied, and desynchronized mode applies the pending
- * wl_surface state directly. A sub-surface is initially in the
- * synchronized mode.
- *
- * Sub-surfaces also have another kind of state, which is managed by
- * wl_subsurface requests, as opposed to wl_surface requests. This
- * state includes the sub-surface position relative to the parent
- * surface (wl_subsurface.set_position), and the stacking order of
- * the parent and its sub-surfaces (wl_subsurface.place_above and
- * .place_below). This state is applied when the parent surface's
- * wl_surface state is applied, regardless of the sub-surface's mode.
- * As the exception, set_sync and set_desync are effective immediately.
- *
- * The main surface can be thought to be always in desynchronized mode,
- * since it does not have a parent in the sub-surfaces sense.
- *
- * Even if a sub-surface is in desynchronized mode, it will behave as
- * in synchronized mode, if its parent surface behaves as in
- * synchronized mode. This rule is applied recursively throughout the
- * tree of surfaces. This means, that one can set a sub-surface into
- * synchronized mode, and then assume that all its child and grand-child
- * sub-surfaces are synchronized, too, without explicitly setting them.
- *
- * Destroying a sub-surface takes effect immediately. If you need to
- * synchronize the removal of a sub-surface to the parent surface update,
- * unmap the sub-surface first by attaching a NULL wl_buffer, update parent,
- * and then destroy the sub-surface.
- *
- * If the parent wl_surface object is destroyed, the sub-surface is
- * unmapped.
- * @section page_iface_wl_subsurface_api API
- * See @ref iface_wl_subsurface.
- */
-/**
- * @defgroup iface_wl_subsurface The wl_subsurface interface
- *
- * An additional interface to a wl_surface object, which has been
- * made a sub-surface. A sub-surface has one parent surface. A
- * sub-surface's size and position are not limited to that of the parent.
- * Particularly, a sub-surface is not automatically clipped to its
- * parent's area.
- *
- * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
- * and the parent surface is mapped. The order of which one happens
- * first is irrelevant. A sub-surface is hidden if the parent becomes
- * hidden, or if a NULL wl_buffer is applied. These rules apply
- * recursively through the tree of surfaces.
- *
- * The behaviour of a wl_surface.commit request on a sub-surface
- * depends on the sub-surface's mode. The possible modes are
- * synchronized and desynchronized, see methods
- * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
- * mode caches the wl_surface state to be applied when the parent's
- * state gets applied, and desynchronized mode applies the pending
- * wl_surface state directly. A sub-surface is initially in the
- * synchronized mode.
- *
- * Sub-surfaces also have another kind of state, which is managed by
- * wl_subsurface requests, as opposed to wl_surface requests. This
- * state includes the sub-surface position relative to the parent
- * surface (wl_subsurface.set_position), and the stacking order of
- * the parent and its sub-surfaces (wl_subsurface.place_above and
- * .place_below). This state is applied when the parent surface's
- * wl_surface state is applied, regardless of the sub-surface's mode.
- * As the exception, set_sync and set_desync are effective immediately.
- *
- * The main surface can be thought to be always in desynchronized mode,
- * since it does not have a parent in the sub-surfaces sense.
- *
- * Even if a sub-surface is in desynchronized mode, it will behave as
- * in synchronized mode, if its parent surface behaves as in
- * synchronized mode. This rule is applied recursively throughout the
- * tree of surfaces. This means, that one can set a sub-surface into
- * synchronized mode, and then assume that all its child and grand-child
- * sub-surfaces are synchronized, too, without explicitly setting them.
- *
- * Destroying a sub-surface takes effect immediately. If you need to
- * synchronize the removal of a sub-surface to the parent surface update,
- * unmap the sub-surface first by attaching a NULL wl_buffer, update parent,
- * and then destroy the sub-surface.
- *
- * If the parent wl_surface object is destroyed, the sub-surface is
- * unmapped.
- */
-extern const struct wl_interface wl_subsurface_interface;
-#endif
-
-#ifndef WL_DISPLAY_ERROR_ENUM
-#define WL_DISPLAY_ERROR_ENUM
-/**
- * @ingroup iface_wl_display
- * global error values
- *
- * These errors are global and can be emitted in response to any
- * server request.
- */
-enum wl_display_error {
- /**
- * server couldn't find object
- */
- WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
- /**
- * method doesn't exist on the specified interface or malformed request
- */
- WL_DISPLAY_ERROR_INVALID_METHOD = 1,
- /**
- * server is out of memory
- */
- WL_DISPLAY_ERROR_NO_MEMORY = 2,
- /**
- * implementation error in compositor
- */
- WL_DISPLAY_ERROR_IMPLEMENTATION = 3,
-};
-#endif /* WL_DISPLAY_ERROR_ENUM */
-
-/**
- * @ingroup iface_wl_display
- * @struct wl_display_listener
- */
-struct wl_display_listener {
- /**
- * fatal error event
- *
- * The error event is sent out when a fatal (non-recoverable)
- * error has occurred. The object_id argument is the object where
- * the error occurred, most often in response to a request to that
- * object. The code identifies the error and is defined by the
- * object interface. As such, each interface defines its own set of
- * error codes. The message is a brief description of the error,
- * for (debugging) convenience.
- * @param object_id object where the error occurred
- * @param code error code
- * @param message error description
- */
- void (*error)(void *data,
- struct wl_display *wl_display,
- void *object_id,
- uint32_t code,
- const char *message);
- /**
- * acknowledge object ID deletion
- *
- * This event is used internally by the object ID management
- * logic. When a client deletes an object that it had created, the
- * server will send this event to acknowledge that it has seen the
- * delete request. When the client receives this event, it will
- * know that it can safely reuse the object ID.
- * @param id deleted object ID
- */
- void (*delete_id)(void *data,
- struct wl_display *wl_display,
- uint32_t id);
-};
-
-/**
- * @ingroup iface_wl_display
- */
-static inline int
-wl_display_add_listener(struct wl_display *wl_display,
- const struct wl_display_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_display,
- (void (**)(void)) listener, data);
-}
-
-#define WL_DISPLAY_SYNC 0
-#define WL_DISPLAY_GET_REGISTRY 1
-
-/**
- * @ingroup iface_wl_display
- */
-#define WL_DISPLAY_ERROR_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_display
- */
-#define WL_DISPLAY_DELETE_ID_SINCE_VERSION 1
-
-/**
- * @ingroup iface_wl_display
- */
-#define WL_DISPLAY_SYNC_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_display
- */
-#define WL_DISPLAY_GET_REGISTRY_SINCE_VERSION 1
-
-/** @ingroup iface_wl_display */
-static inline void
-wl_display_set_user_data(struct wl_display *wl_display, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_display, user_data);
-}
-
-/** @ingroup iface_wl_display */
-static inline void *
-wl_display_get_user_data(struct wl_display *wl_display)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_display);
-}
-
-static inline uint32_t
-wl_display_get_version(struct wl_display *wl_display)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_display);
-}
-
-/**
- * @ingroup iface_wl_display
- *
- * The sync request asks the server to emit the 'done' event
- * on the returned wl_callback object. Since requests are
- * handled in-order and events are delivered in-order, this can
- * be used as a barrier to ensure all previous requests and the
- * resulting events have been handled.
- *
- * The object returned by this request will be destroyed by the
- * compositor after the callback is fired and as such the client must not
- * attempt to use it after that point.
- *
- * The callback_data passed in the callback is the event serial.
- */
-static inline struct wl_callback *
-wl_display_sync(struct wl_display *wl_display)
-{
- struct wl_proxy *callback;
-
- callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_display,
- WL_DISPLAY_SYNC, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL);
-
- return (struct wl_callback *) callback;
-}
-
-/**
- * @ingroup iface_wl_display
- *
- * This request creates a registry object that allows the client
- * to list and bind the global objects available from the
- * compositor.
- *
- * It should be noted that the server side resources consumed in
- * response to a get_registry request can only be released when the
- * client disconnects, not when the client side proxy is destroyed.
- * Therefore, clients should invoke get_registry as infrequently as
- * possible to avoid wasting memory.
- */
-static inline struct wl_registry *
-wl_display_get_registry(struct wl_display *wl_display)
-{
- struct wl_proxy *registry;
-
- registry = wl_proxy_marshal_flags((struct wl_proxy *) wl_display,
- WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL);
-
- return (struct wl_registry *) registry;
-}
-
-/**
- * @ingroup iface_wl_registry
- * @struct wl_registry_listener
- */
-struct wl_registry_listener {
- /**
- * announce global object
- *
- * Notify the client of global objects.
- *
- * The event notifies the client that a global object with the
- * given name is now available, and it implements the given version
- * of the given interface.
- * @param name numeric name of the global object
- * @param interface interface implemented by the object
- * @param version interface version
- */
- void (*global)(void *data,
- struct wl_registry *wl_registry,
- uint32_t name,
- const char *interface,
- uint32_t version);
- /**
- * announce removal of global object
- *
- * Notify the client of removed global objects.
- *
- * This event notifies the client that the global identified by
- * name is no longer available. If the client bound to the global
- * using the bind request, the client should now destroy that
- * object.
- *
- * The object remains valid and requests to the object will be
- * ignored until the client destroys it, to avoid races between the
- * global going away and a client sending a request to it.
- * @param name numeric name of the global object
- */
- void (*global_remove)(void *data,
- struct wl_registry *wl_registry,
- uint32_t name);
-};
-
-/**
- * @ingroup iface_wl_registry
- */
-static inline int
-wl_registry_add_listener(struct wl_registry *wl_registry,
- const struct wl_registry_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_registry,
- (void (**)(void)) listener, data);
-}
-
-#define WL_REGISTRY_BIND 0
-
-/**
- * @ingroup iface_wl_registry
- */
-#define WL_REGISTRY_GLOBAL_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_registry
- */
-#define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION 1
-
-/**
- * @ingroup iface_wl_registry
- */
-#define WL_REGISTRY_BIND_SINCE_VERSION 1
-
-/** @ingroup iface_wl_registry */
-static inline void
-wl_registry_set_user_data(struct wl_registry *wl_registry, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_registry, user_data);
-}
-
-/** @ingroup iface_wl_registry */
-static inline void *
-wl_registry_get_user_data(struct wl_registry *wl_registry)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_registry);
-}
-
-static inline uint32_t
-wl_registry_get_version(struct wl_registry *wl_registry)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_registry);
-}
-
-/** @ingroup iface_wl_registry */
-static inline void
-wl_registry_destroy(struct wl_registry *wl_registry)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_registry);
-}
-
-/**
- * @ingroup iface_wl_registry
- *
- * Binds a new, client-created object to the server using the
- * specified name as the identifier.
- */
-static inline void *
-wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_registry,
- WL_REGISTRY_BIND, interface, version, 0, name, interface->name, version, NULL);
-
- return (void *) id;
-}
-
-/**
- * @ingroup iface_wl_callback
- * @struct wl_callback_listener
- */
-struct wl_callback_listener {
- /**
- * done event
- *
- * Notify the client when the related request is done.
- * @param callback_data request-specific data for the callback
- */
- void (*done)(void *data,
- struct wl_callback *wl_callback,
- uint32_t callback_data);
-};
-
-/**
- * @ingroup iface_wl_callback
- */
-static inline int
-wl_callback_add_listener(struct wl_callback *wl_callback,
- const struct wl_callback_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_callback,
- (void (**)(void)) listener, data);
-}
-
-/**
- * @ingroup iface_wl_callback
- */
-#define WL_CALLBACK_DONE_SINCE_VERSION 1
-
-
-/** @ingroup iface_wl_callback */
-static inline void
-wl_callback_set_user_data(struct wl_callback *wl_callback, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_callback, user_data);
-}
-
-/** @ingroup iface_wl_callback */
-static inline void *
-wl_callback_get_user_data(struct wl_callback *wl_callback)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_callback);
-}
-
-static inline uint32_t
-wl_callback_get_version(struct wl_callback *wl_callback)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_callback);
-}
-
-/** @ingroup iface_wl_callback */
-static inline void
-wl_callback_destroy(struct wl_callback *wl_callback)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_callback);
-}
-
-#define WL_COMPOSITOR_CREATE_SURFACE 0
-#define WL_COMPOSITOR_CREATE_REGION 1
-
-
-/**
- * @ingroup iface_wl_compositor
- */
-#define WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_compositor
- */
-#define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1
-
-/** @ingroup iface_wl_compositor */
-static inline void
-wl_compositor_set_user_data(struct wl_compositor *wl_compositor, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_compositor, user_data);
-}
-
-/** @ingroup iface_wl_compositor */
-static inline void *
-wl_compositor_get_user_data(struct wl_compositor *wl_compositor)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_compositor);
-}
-
-static inline uint32_t
-wl_compositor_get_version(struct wl_compositor *wl_compositor)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_compositor);
-}
-
-/** @ingroup iface_wl_compositor */
-static inline void
-wl_compositor_destroy(struct wl_compositor *wl_compositor)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_compositor);
-}
-
-/**
- * @ingroup iface_wl_compositor
- *
- * Ask the compositor to create a new surface.
- */
-static inline struct wl_surface *
-wl_compositor_create_surface(struct wl_compositor *wl_compositor)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor,
- WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL);
-
- return (struct wl_surface *) id;
-}
-
-/**
- * @ingroup iface_wl_compositor
- *
- * Ask the compositor to create a new region.
- */
-static inline struct wl_region *
-wl_compositor_create_region(struct wl_compositor *wl_compositor)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor,
- WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL);
-
- return (struct wl_region *) id;
-}
-
-#define WL_SHM_POOL_CREATE_BUFFER 0
-#define WL_SHM_POOL_DESTROY 1
-#define WL_SHM_POOL_RESIZE 2
-
-
-/**
- * @ingroup iface_wl_shm_pool
- */
-#define WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shm_pool
- */
-#define WL_SHM_POOL_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shm_pool
- */
-#define WL_SHM_POOL_RESIZE_SINCE_VERSION 1
-
-/** @ingroup iface_wl_shm_pool */
-static inline void
-wl_shm_pool_set_user_data(struct wl_shm_pool *wl_shm_pool, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_shm_pool, user_data);
-}
-
-/** @ingroup iface_wl_shm_pool */
-static inline void *
-wl_shm_pool_get_user_data(struct wl_shm_pool *wl_shm_pool)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_shm_pool);
-}
-
-static inline uint32_t
-wl_shm_pool_get_version(struct wl_shm_pool *wl_shm_pool)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_shm_pool);
-}
-
-/**
- * @ingroup iface_wl_shm_pool
- *
- * Create a wl_buffer object from the pool.
- *
- * The buffer is created offset bytes into the pool and has
- * width and height as specified. The stride argument specifies
- * the number of bytes from the beginning of one row to the beginning
- * of the next. The format is the pixel format of the buffer and
- * must be one of those advertised through the wl_shm.format event.
- *
- * A buffer will keep a reference to the pool it was created from
- * so it is valid to destroy the pool immediately after creating
- * a buffer from it.
- */
-static inline struct wl_buffer *
-wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool,
- WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, NULL, offset, width, height, stride, format);
-
- return (struct wl_buffer *) id;
-}
-
-/**
- * @ingroup iface_wl_shm_pool
- *
- * Destroy the shared memory pool.
- *
- * The mmapped memory will be released when all
- * buffers that have been created from this pool
- * are gone.
- */
-static inline void
-wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool,
- WL_SHM_POOL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_wl_shm_pool
- *
- * This request will cause the server to remap the backing memory
- * for the pool from the file descriptor passed when the pool was
- * created, but using the new size. This request can only be
- * used to make the pool bigger.
- *
- * This request only changes the amount of bytes that are mmapped
- * by the server and does not touch the file corresponding to the
- * file descriptor passed at creation time. It is the client's
- * responsibility to ensure that the file is at least as big as
- * the new pool size.
- */
-static inline void
-wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool,
- WL_SHM_POOL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, size);
-}
-
-#ifndef WL_SHM_ERROR_ENUM
-#define WL_SHM_ERROR_ENUM
-/**
- * @ingroup iface_wl_shm
- * wl_shm error values
- *
- * These errors can be emitted in response to wl_shm requests.
- */
-enum wl_shm_error {
- /**
- * buffer format is not known
- */
- WL_SHM_ERROR_INVALID_FORMAT = 0,
- /**
- * invalid size or stride during pool or buffer creation
- */
- WL_SHM_ERROR_INVALID_STRIDE = 1,
- /**
- * mmapping the file descriptor failed
- */
- WL_SHM_ERROR_INVALID_FD = 2,
-};
-#endif /* WL_SHM_ERROR_ENUM */
-
-#ifndef WL_SHM_FORMAT_ENUM
-#define WL_SHM_FORMAT_ENUM
-/**
- * @ingroup iface_wl_shm
- * pixel formats
- *
- * This describes the memory layout of an individual pixel.
- *
- * All renderers should support argb8888 and xrgb8888 but any other
- * formats are optional and may not be supported by the particular
- * renderer in use.
- *
- * The drm format codes match the macros defined in drm_fourcc.h, except
- * argb8888 and xrgb8888. The formats actually supported by the compositor
- * will be reported by the format event.
- *
- * For all wl_shm formats and unless specified in another protocol
- * extension, pre-multiplied alpha is used for pixel values.
- */
-enum wl_shm_format {
- /**
- * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_ARGB8888 = 0,
- /**
- * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_XRGB8888 = 1,
- /**
- * 8-bit color index format, [7:0] C
- */
- WL_SHM_FORMAT_C8 = 0x20203843,
- /**
- * 8-bit RGB format, [7:0] R:G:B 3:3:2
- */
- WL_SHM_FORMAT_RGB332 = 0x38424752,
- /**
- * 8-bit BGR format, [7:0] B:G:R 2:3:3
- */
- WL_SHM_FORMAT_BGR233 = 0x38524742,
- /**
- * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian
- */
- WL_SHM_FORMAT_XRGB4444 = 0x32315258,
- /**
- * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian
- */
- WL_SHM_FORMAT_XBGR4444 = 0x32314258,
- /**
- * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian
- */
- WL_SHM_FORMAT_RGBX4444 = 0x32315852,
- /**
- * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian
- */
- WL_SHM_FORMAT_BGRX4444 = 0x32315842,
- /**
- * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian
- */
- WL_SHM_FORMAT_ARGB4444 = 0x32315241,
- /**
- * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian
- */
- WL_SHM_FORMAT_ABGR4444 = 0x32314241,
- /**
- * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian
- */
- WL_SHM_FORMAT_RGBA4444 = 0x32314152,
- /**
- * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian
- */
- WL_SHM_FORMAT_BGRA4444 = 0x32314142,
- /**
- * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian
- */
- WL_SHM_FORMAT_XRGB1555 = 0x35315258,
- /**
- * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian
- */
- WL_SHM_FORMAT_XBGR1555 = 0x35314258,
- /**
- * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian
- */
- WL_SHM_FORMAT_RGBX5551 = 0x35315852,
- /**
- * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian
- */
- WL_SHM_FORMAT_BGRX5551 = 0x35315842,
- /**
- * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian
- */
- WL_SHM_FORMAT_ARGB1555 = 0x35315241,
- /**
- * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian
- */
- WL_SHM_FORMAT_ABGR1555 = 0x35314241,
- /**
- * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian
- */
- WL_SHM_FORMAT_RGBA5551 = 0x35314152,
- /**
- * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian
- */
- WL_SHM_FORMAT_BGRA5551 = 0x35314142,
- /**
- * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian
- */
- WL_SHM_FORMAT_RGB565 = 0x36314752,
- /**
- * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian
- */
- WL_SHM_FORMAT_BGR565 = 0x36314742,
- /**
- * 24-bit RGB format, [23:0] R:G:B little endian
- */
- WL_SHM_FORMAT_RGB888 = 0x34324752,
- /**
- * 24-bit BGR format, [23:0] B:G:R little endian
- */
- WL_SHM_FORMAT_BGR888 = 0x34324742,
- /**
- * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_XBGR8888 = 0x34324258,
- /**
- * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_RGBX8888 = 0x34325852,
- /**
- * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_BGRX8888 = 0x34325842,
- /**
- * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_ABGR8888 = 0x34324241,
- /**
- * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_RGBA8888 = 0x34324152,
- /**
- * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_BGRA8888 = 0x34324142,
- /**
- * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian
- */
- WL_SHM_FORMAT_XRGB2101010 = 0x30335258,
- /**
- * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian
- */
- WL_SHM_FORMAT_XBGR2101010 = 0x30334258,
- /**
- * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian
- */
- WL_SHM_FORMAT_RGBX1010102 = 0x30335852,
- /**
- * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian
- */
- WL_SHM_FORMAT_BGRX1010102 = 0x30335842,
- /**
- * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian
- */
- WL_SHM_FORMAT_ARGB2101010 = 0x30335241,
- /**
- * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian
- */
- WL_SHM_FORMAT_ABGR2101010 = 0x30334241,
- /**
- * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian
- */
- WL_SHM_FORMAT_RGBA1010102 = 0x30334152,
- /**
- * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian
- */
- WL_SHM_FORMAT_BGRA1010102 = 0x30334142,
- /**
- * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_YUYV = 0x56595559,
- /**
- * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_YVYU = 0x55595659,
- /**
- * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_UYVY = 0x59565955,
- /**
- * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_VYUY = 0x59555956,
- /**
- * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_AYUV = 0x56555941,
- /**
- * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane
- */
- WL_SHM_FORMAT_NV12 = 0x3231564e,
- /**
- * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane
- */
- WL_SHM_FORMAT_NV21 = 0x3132564e,
- /**
- * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane
- */
- WL_SHM_FORMAT_NV16 = 0x3631564e,
- /**
- * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane
- */
- WL_SHM_FORMAT_NV61 = 0x3136564e,
- /**
- * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes
- */
- WL_SHM_FORMAT_YUV410 = 0x39565559,
- /**
- * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes
- */
- WL_SHM_FORMAT_YVU410 = 0x39555659,
- /**
- * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes
- */
- WL_SHM_FORMAT_YUV411 = 0x31315559,
- /**
- * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes
- */
- WL_SHM_FORMAT_YVU411 = 0x31315659,
- /**
- * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes
- */
- WL_SHM_FORMAT_YUV420 = 0x32315559,
- /**
- * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes
- */
- WL_SHM_FORMAT_YVU420 = 0x32315659,
- /**
- * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes
- */
- WL_SHM_FORMAT_YUV422 = 0x36315559,
- /**
- * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes
- */
- WL_SHM_FORMAT_YVU422 = 0x36315659,
- /**
- * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes
- */
- WL_SHM_FORMAT_YUV444 = 0x34325559,
- /**
- * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes
- */
- WL_SHM_FORMAT_YVU444 = 0x34325659,
- /**
- * [7:0] R
- */
- WL_SHM_FORMAT_R8 = 0x20203852,
- /**
- * [15:0] R little endian
- */
- WL_SHM_FORMAT_R16 = 0x20363152,
- /**
- * [15:0] R:G 8:8 little endian
- */
- WL_SHM_FORMAT_RG88 = 0x38384752,
- /**
- * [15:0] G:R 8:8 little endian
- */
- WL_SHM_FORMAT_GR88 = 0x38385247,
- /**
- * [31:0] R:G 16:16 little endian
- */
- WL_SHM_FORMAT_RG1616 = 0x32334752,
- /**
- * [31:0] G:R 16:16 little endian
- */
- WL_SHM_FORMAT_GR1616 = 0x32335247,
- /**
- * [63:0] x:R:G:B 16:16:16:16 little endian
- */
- WL_SHM_FORMAT_XRGB16161616F = 0x48345258,
- /**
- * [63:0] x:B:G:R 16:16:16:16 little endian
- */
- WL_SHM_FORMAT_XBGR16161616F = 0x48344258,
- /**
- * [63:0] A:R:G:B 16:16:16:16 little endian
- */
- WL_SHM_FORMAT_ARGB16161616F = 0x48345241,
- /**
- * [63:0] A:B:G:R 16:16:16:16 little endian
- */
- WL_SHM_FORMAT_ABGR16161616F = 0x48344241,
- /**
- * [31:0] X:Y:Cb:Cr 8:8:8:8 little endian
- */
- WL_SHM_FORMAT_XYUV8888 = 0x56555958,
- /**
- * [23:0] Cr:Cb:Y 8:8:8 little endian
- */
- WL_SHM_FORMAT_VUY888 = 0x34325556,
- /**
- * Y followed by U then V, 10:10:10. Non-linear modifier only
- */
- WL_SHM_FORMAT_VUY101010 = 0x30335556,
- /**
- * [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels
- */
- WL_SHM_FORMAT_Y210 = 0x30313259,
- /**
- * [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels
- */
- WL_SHM_FORMAT_Y212 = 0x32313259,
- /**
- * [63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels
- */
- WL_SHM_FORMAT_Y216 = 0x36313259,
- /**
- * [31:0] A:Cr:Y:Cb 2:10:10:10 little endian
- */
- WL_SHM_FORMAT_Y410 = 0x30313459,
- /**
- * [63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian
- */
- WL_SHM_FORMAT_Y412 = 0x32313459,
- /**
- * [63:0] A:Cr:Y:Cb 16:16:16:16 little endian
- */
- WL_SHM_FORMAT_Y416 = 0x36313459,
- /**
- * [31:0] X:Cr:Y:Cb 2:10:10:10 little endian
- */
- WL_SHM_FORMAT_XVYU2101010 = 0x30335658,
- /**
- * [63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian
- */
- WL_SHM_FORMAT_XVYU12_16161616 = 0x36335658,
- /**
- * [63:0] X:Cr:Y:Cb 16:16:16:16 little endian
- */
- WL_SHM_FORMAT_XVYU16161616 = 0x38345658,
- /**
- * [63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian
- */
- WL_SHM_FORMAT_Y0L0 = 0x304c3059,
- /**
- * [63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian
- */
- WL_SHM_FORMAT_X0L0 = 0x304c3058,
- /**
- * [63:0] A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian
- */
- WL_SHM_FORMAT_Y0L2 = 0x324c3059,
- /**
- * [63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian
- */
- WL_SHM_FORMAT_X0L2 = 0x324c3058,
- WL_SHM_FORMAT_YUV420_8BIT = 0x38305559,
- WL_SHM_FORMAT_YUV420_10BIT = 0x30315559,
- WL_SHM_FORMAT_XRGB8888_A8 = 0x38415258,
- WL_SHM_FORMAT_XBGR8888_A8 = 0x38414258,
- WL_SHM_FORMAT_RGBX8888_A8 = 0x38415852,
- WL_SHM_FORMAT_BGRX8888_A8 = 0x38415842,
- WL_SHM_FORMAT_RGB888_A8 = 0x38413852,
- WL_SHM_FORMAT_BGR888_A8 = 0x38413842,
- WL_SHM_FORMAT_RGB565_A8 = 0x38413552,
- WL_SHM_FORMAT_BGR565_A8 = 0x38413542,
- /**
- * non-subsampled Cr:Cb plane
- */
- WL_SHM_FORMAT_NV24 = 0x3432564e,
- /**
- * non-subsampled Cb:Cr plane
- */
- WL_SHM_FORMAT_NV42 = 0x3234564e,
- /**
- * 2x1 subsampled Cr:Cb plane, 10 bit per channel
- */
- WL_SHM_FORMAT_P210 = 0x30313250,
- /**
- * 2x2 subsampled Cr:Cb plane 10 bits per channel
- */
- WL_SHM_FORMAT_P010 = 0x30313050,
- /**
- * 2x2 subsampled Cr:Cb plane 12 bits per channel
- */
- WL_SHM_FORMAT_P012 = 0x32313050,
- /**
- * 2x2 subsampled Cr:Cb plane 16 bits per channel
- */
- WL_SHM_FORMAT_P016 = 0x36313050,
- /**
- * [63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian
- */
- WL_SHM_FORMAT_AXBXGXRX106106106106 = 0x30314241,
- /**
- * 2x2 subsampled Cr:Cb plane
- */
- WL_SHM_FORMAT_NV15 = 0x3531564e,
- WL_SHM_FORMAT_Q410 = 0x30313451,
- WL_SHM_FORMAT_Q401 = 0x31303451,
- /**
- * [63:0] x:R:G:B 16:16:16:16 little endian
- */
- WL_SHM_FORMAT_XRGB16161616 = 0x38345258,
- /**
- * [63:0] x:B:G:R 16:16:16:16 little endian
- */
- WL_SHM_FORMAT_XBGR16161616 = 0x38344258,
- /**
- * [63:0] A:R:G:B 16:16:16:16 little endian
- */
- WL_SHM_FORMAT_ARGB16161616 = 0x38345241,
- /**
- * [63:0] A:B:G:R 16:16:16:16 little endian
- */
- WL_SHM_FORMAT_ABGR16161616 = 0x38344241,
-};
-#endif /* WL_SHM_FORMAT_ENUM */
-
-/**
- * @ingroup iface_wl_shm
- * @struct wl_shm_listener
- */
-struct wl_shm_listener {
- /**
- * pixel format description
- *
- * Informs the client about a valid pixel format that can be used
- * for buffers. Known formats include argb8888 and xrgb8888.
- * @param format buffer pixel format
- */
- void (*format)(void *data,
- struct wl_shm *wl_shm,
- uint32_t format);
-};
-
-/**
- * @ingroup iface_wl_shm
- */
-static inline int
-wl_shm_add_listener(struct wl_shm *wl_shm,
- const struct wl_shm_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_shm,
- (void (**)(void)) listener, data);
-}
-
-#define WL_SHM_CREATE_POOL 0
-
-/**
- * @ingroup iface_wl_shm
- */
-#define WL_SHM_FORMAT_SINCE_VERSION 1
-
-/**
- * @ingroup iface_wl_shm
- */
-#define WL_SHM_CREATE_POOL_SINCE_VERSION 1
-
-/** @ingroup iface_wl_shm */
-static inline void
-wl_shm_set_user_data(struct wl_shm *wl_shm, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_shm, user_data);
-}
-
-/** @ingroup iface_wl_shm */
-static inline void *
-wl_shm_get_user_data(struct wl_shm *wl_shm)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_shm);
-}
-
-static inline uint32_t
-wl_shm_get_version(struct wl_shm *wl_shm)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_shm);
-}
-
-/** @ingroup iface_wl_shm */
-static inline void
-wl_shm_destroy(struct wl_shm *wl_shm)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_shm);
-}
-
-/**
- * @ingroup iface_wl_shm
- *
- * Create a new wl_shm_pool object.
- *
- * The pool can be used to create shared memory based buffer
- * objects. The server will mmap size bytes of the passed file
- * descriptor, to use as backing memory for the pool.
- */
-static inline struct wl_shm_pool *
-wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm,
- WL_SHM_CREATE_POOL, &wl_shm_pool_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm), 0, NULL, fd, size);
-
- return (struct wl_shm_pool *) id;
-}
-
-/**
- * @ingroup iface_wl_buffer
- * @struct wl_buffer_listener
- */
-struct wl_buffer_listener {
- /**
- * compositor releases buffer
- *
- * Sent when this wl_buffer is no longer used by the compositor.
- * The client is now free to reuse or destroy this buffer and its
- * backing storage.
- *
- * If a client receives a release event before the frame callback
- * requested in the same wl_surface.commit that attaches this
- * wl_buffer to a surface, then the client is immediately free to
- * reuse the buffer and its backing storage, and does not need a
- * second buffer for the next surface content update. Typically
- * this is possible, when the compositor maintains a copy of the
- * wl_surface contents, e.g. as a GL texture. This is an important
- * optimization for GL(ES) compositors with wl_shm clients.
- */
- void (*release)(void *data,
- struct wl_buffer *wl_buffer);
-};
-
-/**
- * @ingroup iface_wl_buffer
- */
-static inline int
-wl_buffer_add_listener(struct wl_buffer *wl_buffer,
- const struct wl_buffer_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_buffer,
- (void (**)(void)) listener, data);
-}
-
-#define WL_BUFFER_DESTROY 0
-
-/**
- * @ingroup iface_wl_buffer
- */
-#define WL_BUFFER_RELEASE_SINCE_VERSION 1
-
-/**
- * @ingroup iface_wl_buffer
- */
-#define WL_BUFFER_DESTROY_SINCE_VERSION 1
-
-/** @ingroup iface_wl_buffer */
-static inline void
-wl_buffer_set_user_data(struct wl_buffer *wl_buffer, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_buffer, user_data);
-}
-
-/** @ingroup iface_wl_buffer */
-static inline void *
-wl_buffer_get_user_data(struct wl_buffer *wl_buffer)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_buffer);
-}
-
-static inline uint32_t
-wl_buffer_get_version(struct wl_buffer *wl_buffer)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_buffer);
-}
-
-/**
- * @ingroup iface_wl_buffer
- *
- * Destroy a buffer. If and how you need to release the backing
- * storage is defined by the buffer factory interface.
- *
- * For possible side-effects to a surface, see wl_surface.attach.
- */
-static inline void
-wl_buffer_destroy(struct wl_buffer *wl_buffer)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_buffer,
- WL_BUFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_buffer), WL_MARSHAL_FLAG_DESTROY);
-}
-
-#ifndef WL_DATA_OFFER_ERROR_ENUM
-#define WL_DATA_OFFER_ERROR_ENUM
-enum wl_data_offer_error {
- /**
- * finish request was called untimely
- */
- WL_DATA_OFFER_ERROR_INVALID_FINISH = 0,
- /**
- * action mask contains invalid values
- */
- WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1,
- /**
- * action argument has an invalid value
- */
- WL_DATA_OFFER_ERROR_INVALID_ACTION = 2,
- /**
- * offer doesn't accept this request
- */
- WL_DATA_OFFER_ERROR_INVALID_OFFER = 3,
-};
-#endif /* WL_DATA_OFFER_ERROR_ENUM */
-
-/**
- * @ingroup iface_wl_data_offer
- * @struct wl_data_offer_listener
- */
-struct wl_data_offer_listener {
- /**
- * advertise offered mime type
- *
- * Sent immediately after creating the wl_data_offer object. One
- * event per offered mime type.
- * @param mime_type offered mime type
- */
- void (*offer)(void *data,
- struct wl_data_offer *wl_data_offer,
- const char *mime_type);
- /**
- * notify the source-side available actions
- *
- * This event indicates the actions offered by the data source.
- * It will be sent immediately after creating the wl_data_offer
- * object, or anytime the source side changes its offered actions
- * through wl_data_source.set_actions.
- * @param source_actions actions offered by the data source
- * @since 3
- */
- void (*source_actions)(void *data,
- struct wl_data_offer *wl_data_offer,
- uint32_t source_actions);
- /**
- * notify the selected action
- *
- * This event indicates the action selected by the compositor
- * after matching the source/destination side actions. Only one
- * action (or none) will be offered here.
- *
- * This event can be emitted multiple times during the
- * drag-and-drop operation in response to destination side action
- * changes through wl_data_offer.set_actions.
- *
- * This event will no longer be emitted after wl_data_device.drop
- * happened on the drag-and-drop destination, the client must honor
- * the last action received, or the last preferred one set through
- * wl_data_offer.set_actions when handling an "ask" action.
- *
- * Compositors may also change the selected action on the fly,
- * mainly in response to keyboard modifier changes during the
- * drag-and-drop operation.
- *
- * The most recent action received is always the valid one. Prior
- * to receiving wl_data_device.drop, the chosen action may change
- * (e.g. due to keyboard modifiers being pressed). At the time of
- * receiving wl_data_device.drop the drag-and-drop destination must
- * honor the last action received.
- *
- * Action changes may still happen after wl_data_device.drop,
- * especially on "ask" actions, where the drag-and-drop destination
- * may choose another action afterwards. Action changes happening
- * at this stage are always the result of inter-client negotiation,
- * the compositor shall no longer be able to induce a different
- * action.
- *
- * Upon "ask" actions, it is expected that the drag-and-drop
- * destination may potentially choose a different action and/or
- * mime type, based on wl_data_offer.source_actions and finally
- * chosen by the user (e.g. popping up a menu with the available
- * options). The final wl_data_offer.set_actions and
- * wl_data_offer.accept requests must happen before the call to
- * wl_data_offer.finish.
- * @param dnd_action action selected by the compositor
- * @since 3
- */
- void (*action)(void *data,
- struct wl_data_offer *wl_data_offer,
- uint32_t dnd_action);
-};
-
-/**
- * @ingroup iface_wl_data_offer
- */
-static inline int
-wl_data_offer_add_listener(struct wl_data_offer *wl_data_offer,
- const struct wl_data_offer_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_data_offer,
- (void (**)(void)) listener, data);
-}
-
-#define WL_DATA_OFFER_ACCEPT 0
-#define WL_DATA_OFFER_RECEIVE 1
-#define WL_DATA_OFFER_DESTROY 2
-#define WL_DATA_OFFER_FINISH 3
-#define WL_DATA_OFFER_SET_ACTIONS 4
-
-/**
- * @ingroup iface_wl_data_offer
- */
-#define WL_DATA_OFFER_OFFER_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_offer
- */
-#define WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION 3
-/**
- * @ingroup iface_wl_data_offer
- */
-#define WL_DATA_OFFER_ACTION_SINCE_VERSION 3
-
-/**
- * @ingroup iface_wl_data_offer
- */
-#define WL_DATA_OFFER_ACCEPT_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_offer
- */
-#define WL_DATA_OFFER_RECEIVE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_offer
- */
-#define WL_DATA_OFFER_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_offer
- */
-#define WL_DATA_OFFER_FINISH_SINCE_VERSION 3
-/**
- * @ingroup iface_wl_data_offer
- */
-#define WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION 3
-
-/** @ingroup iface_wl_data_offer */
-static inline void
-wl_data_offer_set_user_data(struct wl_data_offer *wl_data_offer, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_data_offer, user_data);
-}
-
-/** @ingroup iface_wl_data_offer */
-static inline void *
-wl_data_offer_get_user_data(struct wl_data_offer *wl_data_offer)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_data_offer);
-}
-
-static inline uint32_t
-wl_data_offer_get_version(struct wl_data_offer *wl_data_offer)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_data_offer);
-}
-
-/**
- * @ingroup iface_wl_data_offer
- *
- * Indicate that the client can accept the given mime type, or
- * NULL for not accepted.
- *
- * For objects of version 2 or older, this request is used by the
- * client to give feedback whether the client can receive the given
- * mime type, or NULL if none is accepted; the feedback does not
- * determine whether the drag-and-drop operation succeeds or not.
- *
- * For objects of version 3 or newer, this request determines the
- * final result of the drag-and-drop operation. If the end result
- * is that no mime types were accepted, the drag-and-drop operation
- * will be cancelled and the corresponding drag source will receive
- * wl_data_source.cancelled. Clients may still use this event in
- * conjunction with wl_data_source.action for feedback.
- */
-static inline void
-wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
- WL_DATA_OFFER_ACCEPT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, serial, mime_type);
-}
-
-/**
- * @ingroup iface_wl_data_offer
- *
- * To transfer the offered data, the client issues this request
- * and indicates the mime type it wants to receive. The transfer
- * happens through the passed file descriptor (typically created
- * with the pipe system call). The source client writes the data
- * in the mime type representation requested and then closes the
- * file descriptor.
- *
- * The receiving client reads from the read end of the pipe until
- * EOF and then closes its end, at which point the transfer is
- * complete.
- *
- * This request may happen multiple times for different mime types,
- * both before and after wl_data_device.drop. Drag-and-drop destination
- * clients may preemptively fetch data or examine it more closely to
- * determine acceptance.
- */
-static inline void
-wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
- WL_DATA_OFFER_RECEIVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, mime_type, fd);
-}
-
-/**
- * @ingroup iface_wl_data_offer
- *
- * Destroy the data offer.
- */
-static inline void
-wl_data_offer_destroy(struct wl_data_offer *wl_data_offer)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
- WL_DATA_OFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_wl_data_offer
- *
- * Notifies the compositor that the drag destination successfully
- * finished the drag-and-drop operation.
- *
- * Upon receiving this request, the compositor will emit
- * wl_data_source.dnd_finished on the drag source client.
- *
- * It is a client error to perform other requests than
- * wl_data_offer.destroy after this one. It is also an error to perform
- * this request after a NULL mime type has been set in
- * wl_data_offer.accept or no action was received through
- * wl_data_offer.action.
- *
- * If wl_data_offer.finish request is received for a non drag and drop
- * operation, the invalid_finish protocol error is raised.
- */
-static inline void
-wl_data_offer_finish(struct wl_data_offer *wl_data_offer)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
- WL_DATA_OFFER_FINISH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0);
-}
-
-/**
- * @ingroup iface_wl_data_offer
- *
- * Sets the actions that the destination side client supports for
- * this operation. This request may trigger the emission of
- * wl_data_source.action and wl_data_offer.action events if the compositor
- * needs to change the selected action.
- *
- * This request can be called multiple times throughout the
- * drag-and-drop operation, typically in response to wl_data_device.enter
- * or wl_data_device.motion events.
- *
- * This request determines the final result of the drag-and-drop
- * operation. If the end result is that no action is accepted,
- * the drag source will receive wl_data_source.cancelled.
- *
- * The dnd_actions argument must contain only values expressed in the
- * wl_data_device_manager.dnd_actions enum, and the preferred_action
- * argument must only contain one of those values set, otherwise it
- * will result in a protocol error.
- *
- * While managing an "ask" action, the destination drag-and-drop client
- * may perform further wl_data_offer.receive requests, and is expected
- * to perform one last wl_data_offer.set_actions request with a preferred
- * action other than "ask" (and optionally wl_data_offer.accept) before
- * requesting wl_data_offer.finish, in order to convey the action selected
- * by the user. If the preferred action is not in the
- * wl_data_offer.source_actions mask, an error will be raised.
- *
- * If the "ask" action is dismissed (e.g. user cancellation), the client
- * is expected to perform wl_data_offer.destroy right away.
- *
- * This request can only be made on drag-and-drop offers, a protocol error
- * will be raised otherwise.
- */
-static inline void
-wl_data_offer_set_actions(struct wl_data_offer *wl_data_offer, uint32_t dnd_actions, uint32_t preferred_action)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
- WL_DATA_OFFER_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, dnd_actions, preferred_action);
-}
-
-#ifndef WL_DATA_SOURCE_ERROR_ENUM
-#define WL_DATA_SOURCE_ERROR_ENUM
-enum wl_data_source_error {
- /**
- * action mask contains invalid values
- */
- WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0,
- /**
- * source doesn't accept this request
- */
- WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1,
-};
-#endif /* WL_DATA_SOURCE_ERROR_ENUM */
-
-/**
- * @ingroup iface_wl_data_source
- * @struct wl_data_source_listener
- */
-struct wl_data_source_listener {
- /**
- * a target accepts an offered mime type
- *
- * Sent when a target accepts pointer_focus or motion events. If
- * a target does not accept any of the offered types, type is NULL.
- *
- * Used for feedback during drag-and-drop.
- * @param mime_type mime type accepted by the target
- */
- void (*target)(void *data,
- struct wl_data_source *wl_data_source,
- const char *mime_type);
- /**
- * send the data
- *
- * Request for data from the client. Send the data as the
- * specified mime type over the passed file descriptor, then close
- * it.
- * @param mime_type mime type for the data
- * @param fd file descriptor for the data
- */
- void (*send)(void *data,
- struct wl_data_source *wl_data_source,
- const char *mime_type,
- int32_t fd);
- /**
- * selection was cancelled
- *
- * This data source is no longer valid. There are several reasons
- * why this could happen:
- *
- * - The data source has been replaced by another data source. -
- * The drag-and-drop operation was performed, but the drop
- * destination did not accept any of the mime types offered through
- * wl_data_source.target. - The drag-and-drop operation was
- * performed, but the drop destination did not select any of the
- * actions present in the mask offered through
- * wl_data_source.action. - The drag-and-drop operation was
- * performed but didn't happen over a surface. - The compositor
- * cancelled the drag-and-drop operation (e.g. compositor dependent
- * timeouts to avoid stale drag-and-drop transfers).
- *
- * The client should clean up and destroy this data source.
- *
- * For objects of version 2 or older, wl_data_source.cancelled will
- * only be emitted if the data source was replaced by another data
- * source.
- */
- void (*cancelled)(void *data,
- struct wl_data_source *wl_data_source);
- /**
- * the drag-and-drop operation physically finished
- *
- * The user performed the drop action. This event does not
- * indicate acceptance, wl_data_source.cancelled may still be
- * emitted afterwards if the drop destination does not accept any
- * mime type.
- *
- * However, this event might however not be received if the
- * compositor cancelled the drag-and-drop operation before this
- * event could happen.
- *
- * Note that the data_source may still be used in the future and
- * should not be destroyed here.
- * @since 3
- */
- void (*dnd_drop_performed)(void *data,
- struct wl_data_source *wl_data_source);
- /**
- * the drag-and-drop operation concluded
- *
- * The drop destination finished interoperating with this data
- * source, so the client is now free to destroy this data source
- * and free all associated data.
- *
- * If the action used to perform the operation was "move", the
- * source can now delete the transferred data.
- * @since 3
- */
- void (*dnd_finished)(void *data,
- struct wl_data_source *wl_data_source);
- /**
- * notify the selected action
- *
- * This event indicates the action selected by the compositor
- * after matching the source/destination side actions. Only one
- * action (or none) will be offered here.
- *
- * This event can be emitted multiple times during the
- * drag-and-drop operation, mainly in response to destination side
- * changes through wl_data_offer.set_actions, and as the data
- * device enters/leaves surfaces.
- *
- * It is only possible to receive this event after
- * wl_data_source.dnd_drop_performed if the drag-and-drop operation
- * ended in an "ask" action, in which case the final
- * wl_data_source.action event will happen immediately before
- * wl_data_source.dnd_finished.
- *
- * Compositors may also change the selected action on the fly,
- * mainly in response to keyboard modifier changes during the
- * drag-and-drop operation.
- *
- * The most recent action received is always the valid one. The
- * chosen action may change alongside negotiation (e.g. an "ask"
- * action can turn into a "move" operation), so the effects of the
- * final action must always be applied in
- * wl_data_offer.dnd_finished.
- *
- * Clients can trigger cursor surface changes from this point, so
- * they reflect the current action.
- * @param dnd_action action selected by the compositor
- * @since 3
- */
- void (*action)(void *data,
- struct wl_data_source *wl_data_source,
- uint32_t dnd_action);
-};
-
-/**
- * @ingroup iface_wl_data_source
- */
-static inline int
-wl_data_source_add_listener(struct wl_data_source *wl_data_source,
- const struct wl_data_source_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_data_source,
- (void (**)(void)) listener, data);
-}
-
-#define WL_DATA_SOURCE_OFFER 0
-#define WL_DATA_SOURCE_DESTROY 1
-#define WL_DATA_SOURCE_SET_ACTIONS 2
-
-/**
- * @ingroup iface_wl_data_source
- */
-#define WL_DATA_SOURCE_TARGET_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_source
- */
-#define WL_DATA_SOURCE_SEND_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_source
- */
-#define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_source
- */
-#define WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION 3
-/**
- * @ingroup iface_wl_data_source
- */
-#define WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION 3
-/**
- * @ingroup iface_wl_data_source
- */
-#define WL_DATA_SOURCE_ACTION_SINCE_VERSION 3
-
-/**
- * @ingroup iface_wl_data_source
- */
-#define WL_DATA_SOURCE_OFFER_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_source
- */
-#define WL_DATA_SOURCE_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_source
- */
-#define WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION 3
-
-/** @ingroup iface_wl_data_source */
-static inline void
-wl_data_source_set_user_data(struct wl_data_source *wl_data_source, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_data_source, user_data);
-}
-
-/** @ingroup iface_wl_data_source */
-static inline void *
-wl_data_source_get_user_data(struct wl_data_source *wl_data_source)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_data_source);
-}
-
-static inline uint32_t
-wl_data_source_get_version(struct wl_data_source *wl_data_source)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_data_source);
-}
-
-/**
- * @ingroup iface_wl_data_source
- *
- * This request adds a mime type to the set of mime types
- * advertised to targets. Can be called several times to offer
- * multiple types.
- */
-static inline void
-wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source,
- WL_DATA_SOURCE_OFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, mime_type);
-}
-
-/**
- * @ingroup iface_wl_data_source
- *
- * Destroy the data source.
- */
-static inline void
-wl_data_source_destroy(struct wl_data_source *wl_data_source)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source,
- WL_DATA_SOURCE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_wl_data_source
- *
- * Sets the actions that the source side client supports for this
- * operation. This request may trigger wl_data_source.action and
- * wl_data_offer.action events if the compositor needs to change the
- * selected action.
- *
- * The dnd_actions argument must contain only values expressed in the
- * wl_data_device_manager.dnd_actions enum, otherwise it will result
- * in a protocol error.
- *
- * This request must be made once only, and can only be made on sources
- * used in drag-and-drop, so it must be performed before
- * wl_data_device.start_drag. Attempting to use the source other than
- * for drag-and-drop will raise a protocol error.
- */
-static inline void
-wl_data_source_set_actions(struct wl_data_source *wl_data_source, uint32_t dnd_actions)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source,
- WL_DATA_SOURCE_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, dnd_actions);
-}
-
-#ifndef WL_DATA_DEVICE_ERROR_ENUM
-#define WL_DATA_DEVICE_ERROR_ENUM
-enum wl_data_device_error {
- /**
- * given wl_surface has another role
- */
- WL_DATA_DEVICE_ERROR_ROLE = 0,
-};
-#endif /* WL_DATA_DEVICE_ERROR_ENUM */
-
-/**
- * @ingroup iface_wl_data_device
- * @struct wl_data_device_listener
- */
-struct wl_data_device_listener {
- /**
- * introduce a new wl_data_offer
- *
- * The data_offer event introduces a new wl_data_offer object,
- * which will subsequently be used in either the data_device.enter
- * event (for drag-and-drop) or the data_device.selection event
- * (for selections). Immediately following the
- * data_device.data_offer event, the new data_offer object will
- * send out data_offer.offer events to describe the mime types it
- * offers.
- * @param id the new data_offer object
- */
- void (*data_offer)(void *data,
- struct wl_data_device *wl_data_device,
- struct wl_data_offer *id);
- /**
- * initiate drag-and-drop session
- *
- * This event is sent when an active drag-and-drop pointer enters
- * a surface owned by the client. The position of the pointer at
- * enter time is provided by the x and y arguments, in
- * surface-local coordinates.
- * @param serial serial number of the enter event
- * @param surface client surface entered
- * @param x surface-local x coordinate
- * @param y surface-local y coordinate
- * @param id source data_offer object
- */
- void (*enter)(void *data,
- struct wl_data_device *wl_data_device,
- uint32_t serial,
- struct wl_surface *surface,
- wl_fixed_t x,
- wl_fixed_t y,
- struct wl_data_offer *id);
- /**
- * end drag-and-drop session
- *
- * This event is sent when the drag-and-drop pointer leaves the
- * surface and the session ends. The client must destroy the
- * wl_data_offer introduced at enter time at this point.
- */
- void (*leave)(void *data,
- struct wl_data_device *wl_data_device);
- /**
- * drag-and-drop session motion
- *
- * This event is sent when the drag-and-drop pointer moves within
- * the currently focused surface. The new position of the pointer
- * is provided by the x and y arguments, in surface-local
- * coordinates.
- * @param time timestamp with millisecond granularity
- * @param x surface-local x coordinate
- * @param y surface-local y coordinate
- */
- void (*motion)(void *data,
- struct wl_data_device *wl_data_device,
- uint32_t time,
- wl_fixed_t x,
- wl_fixed_t y);
- /**
- * end drag-and-drop session successfully
- *
- * The event is sent when a drag-and-drop operation is ended
- * because the implicit grab is removed.
- *
- * The drag-and-drop destination is expected to honor the last
- * action received through wl_data_offer.action, if the resulting
- * action is "copy" or "move", the destination can still perform
- * wl_data_offer.receive requests, and is expected to end all
- * transfers with a wl_data_offer.finish request.
- *
- * If the resulting action is "ask", the action will not be
- * considered final. The drag-and-drop destination is expected to
- * perform one last wl_data_offer.set_actions request, or
- * wl_data_offer.destroy in order to cancel the operation.
- */
- void (*drop)(void *data,
- struct wl_data_device *wl_data_device);
- /**
- * advertise new selection
- *
- * The selection event is sent out to notify the client of a new
- * wl_data_offer for the selection for this device. The
- * data_device.data_offer and the data_offer.offer events are sent
- * out immediately before this event to introduce the data offer
- * object. The selection event is sent to a client immediately
- * before receiving keyboard focus and when a new selection is set
- * while the client has keyboard focus. The data_offer is valid
- * until a new data_offer or NULL is received or until the client
- * loses keyboard focus. Switching surface with keyboard focus
- * within the same client doesn't mean a new selection will be
- * sent. The client must destroy the previous selection data_offer,
- * if any, upon receiving this event.
- * @param id selection data_offer object
- */
- void (*selection)(void *data,
- struct wl_data_device *wl_data_device,
- struct wl_data_offer *id);
-};
-
-/**
- * @ingroup iface_wl_data_device
- */
-static inline int
-wl_data_device_add_listener(struct wl_data_device *wl_data_device,
- const struct wl_data_device_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_data_device,
- (void (**)(void)) listener, data);
-}
-
-#define WL_DATA_DEVICE_START_DRAG 0
-#define WL_DATA_DEVICE_SET_SELECTION 1
-#define WL_DATA_DEVICE_RELEASE 2
-
-/**
- * @ingroup iface_wl_data_device
- */
-#define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_device
- */
-#define WL_DATA_DEVICE_ENTER_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_device
- */
-#define WL_DATA_DEVICE_LEAVE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_device
- */
-#define WL_DATA_DEVICE_MOTION_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_device
- */
-#define WL_DATA_DEVICE_DROP_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_device
- */
-#define WL_DATA_DEVICE_SELECTION_SINCE_VERSION 1
-
-/**
- * @ingroup iface_wl_data_device
- */
-#define WL_DATA_DEVICE_START_DRAG_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_device
- */
-#define WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_device
- */
-#define WL_DATA_DEVICE_RELEASE_SINCE_VERSION 2
-
-/** @ingroup iface_wl_data_device */
-static inline void
-wl_data_device_set_user_data(struct wl_data_device *wl_data_device, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_data_device, user_data);
-}
-
-/** @ingroup iface_wl_data_device */
-static inline void *
-wl_data_device_get_user_data(struct wl_data_device *wl_data_device)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device);
-}
-
-static inline uint32_t
-wl_data_device_get_version(struct wl_data_device *wl_data_device)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_data_device);
-}
-
-/** @ingroup iface_wl_data_device */
-static inline void
-wl_data_device_destroy(struct wl_data_device *wl_data_device)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_data_device);
-}
-
-/**
- * @ingroup iface_wl_data_device
- *
- * This request asks the compositor to start a drag-and-drop
- * operation on behalf of the client.
- *
- * The source argument is the data source that provides the data
- * for the eventual data transfer. If source is NULL, enter, leave
- * and motion events are sent only to the client that initiated the
- * drag and the client is expected to handle the data passing
- * internally. If source is destroyed, the drag-and-drop session will be
- * cancelled.
- *
- * The origin surface is the surface where the drag originates and
- * the client must have an active implicit grab that matches the
- * serial.
- *
- * The icon surface is an optional (can be NULL) surface that
- * provides an icon to be moved around with the cursor. Initially,
- * the top-left corner of the icon surface is placed at the cursor
- * hotspot, but subsequent wl_surface.attach request can move the
- * relative position. Attach requests must be confirmed with
- * wl_surface.commit as usual. The icon surface is given the role of
- * a drag-and-drop icon. If the icon surface already has another role,
- * it raises a protocol error.
- *
- * The input region is ignored for wl_surfaces with the role of a
- * drag-and-drop icon.
- */
-static inline void
-wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device,
- WL_DATA_DEVICE_START_DRAG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, origin, icon, serial);
-}
-
-/**
- * @ingroup iface_wl_data_device
- *
- * This request asks the compositor to set the selection
- * to the data from the source on behalf of the client.
- *
- * To unset the selection, set the source to NULL.
- */
-static inline void
-wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device,
- WL_DATA_DEVICE_SET_SELECTION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, serial);
-}
-
-/**
- * @ingroup iface_wl_data_device
- *
- * This request destroys the data device.
- */
-static inline void
-wl_data_device_release(struct wl_data_device *wl_data_device)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device,
- WL_DATA_DEVICE_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), WL_MARSHAL_FLAG_DESTROY);
-}
-
-#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
-#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
-/**
- * @ingroup iface_wl_data_device_manager
- * drag and drop actions
- *
- * This is a bitmask of the available/preferred actions in a
- * drag-and-drop operation.
- *
- * In the compositor, the selected action is a result of matching the
- * actions offered by the source and destination sides. "action" events
- * with a "none" action will be sent to both source and destination if
- * there is no match. All further checks will effectively happen on
- * (source actions ∩ destination actions).
- *
- * In addition, compositors may also pick different actions in
- * reaction to key modifiers being pressed. One common design that
- * is used in major toolkits (and the behavior recommended for
- * compositors) is:
- *
- * - If no modifiers are pressed, the first match (in bit order)
- * will be used.
- * - Pressing Shift selects "move", if enabled in the mask.
- * - Pressing Control selects "copy", if enabled in the mask.
- *
- * Behavior beyond that is considered implementation-dependent.
- * Compositors may for example bind other modifiers (like Alt/Meta)
- * or drags initiated with other buttons than BTN_LEFT to specific
- * actions (e.g. "ask").
- */
-enum wl_data_device_manager_dnd_action {
- /**
- * no action
- */
- WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0,
- /**
- * copy action
- */
- WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1,
- /**
- * move action
- */
- WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2,
- /**
- * ask action
- */
- WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4,
-};
-#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */
-
-#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE 0
-#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE 1
-
-
-/**
- * @ingroup iface_wl_data_device_manager
- */
-#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_data_device_manager
- */
-#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1
-
-/** @ingroup iface_wl_data_device_manager */
-static inline void
-wl_data_device_manager_set_user_data(struct wl_data_device_manager *wl_data_device_manager, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_data_device_manager, user_data);
-}
-
-/** @ingroup iface_wl_data_device_manager */
-static inline void *
-wl_data_device_manager_get_user_data(struct wl_data_device_manager *wl_data_device_manager)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device_manager);
-}
-
-static inline uint32_t
-wl_data_device_manager_get_version(struct wl_data_device_manager *wl_data_device_manager)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager);
-}
-
-/** @ingroup iface_wl_data_device_manager */
-static inline void
-wl_data_device_manager_destroy(struct wl_data_device_manager *wl_data_device_manager)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_data_device_manager);
-}
-
-/**
- * @ingroup iface_wl_data_device_manager
- *
- * Create a new data source.
- */
-static inline struct wl_data_source *
-wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data_device_manager)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager,
- WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL);
-
- return (struct wl_data_source *) id;
-}
-
-/**
- * @ingroup iface_wl_data_device_manager
- *
- * Create a new data device for a given seat.
- */
-static inline struct wl_data_device *
-wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_device_manager, struct wl_seat *seat)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager,
- WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL, seat);
-
- return (struct wl_data_device *) id;
-}
-
-#ifndef WL_SHELL_ERROR_ENUM
-#define WL_SHELL_ERROR_ENUM
-enum wl_shell_error {
- /**
- * given wl_surface has another role
- */
- WL_SHELL_ERROR_ROLE = 0,
-};
-#endif /* WL_SHELL_ERROR_ENUM */
-
-#define WL_SHELL_GET_SHELL_SURFACE 0
-
-
-/**
- * @ingroup iface_wl_shell
- */
-#define WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1
-
-/** @ingroup iface_wl_shell */
-static inline void
-wl_shell_set_user_data(struct wl_shell *wl_shell, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_shell, user_data);
-}
-
-/** @ingroup iface_wl_shell */
-static inline void *
-wl_shell_get_user_data(struct wl_shell *wl_shell)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_shell);
-}
-
-static inline uint32_t
-wl_shell_get_version(struct wl_shell *wl_shell)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_shell);
-}
-
-/** @ingroup iface_wl_shell */
-static inline void
-wl_shell_destroy(struct wl_shell *wl_shell)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_shell);
-}
-
-/**
- * @ingroup iface_wl_shell
- *
- * Create a shell surface for an existing surface. This gives
- * the wl_surface the role of a shell surface. If the wl_surface
- * already has another role, it raises a protocol error.
- *
- * Only one shell surface can be associated with a given surface.
- */
-static inline struct wl_shell_surface *
-wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shell,
- WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_shell), 0, NULL, surface);
-
- return (struct wl_shell_surface *) id;
-}
-
-#ifndef WL_SHELL_SURFACE_RESIZE_ENUM
-#define WL_SHELL_SURFACE_RESIZE_ENUM
-/**
- * @ingroup iface_wl_shell_surface
- * edge values for resizing
- *
- * These values are used to indicate which edge of a surface
- * is being dragged in a resize operation. The server may
- * use this information to adapt its behavior, e.g. choose
- * an appropriate cursor image.
- */
-enum wl_shell_surface_resize {
- /**
- * no edge
- */
- WL_SHELL_SURFACE_RESIZE_NONE = 0,
- /**
- * top edge
- */
- WL_SHELL_SURFACE_RESIZE_TOP = 1,
- /**
- * bottom edge
- */
- WL_SHELL_SURFACE_RESIZE_BOTTOM = 2,
- /**
- * left edge
- */
- WL_SHELL_SURFACE_RESIZE_LEFT = 4,
- /**
- * top and left edges
- */
- WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5,
- /**
- * bottom and left edges
- */
- WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6,
- /**
- * right edge
- */
- WL_SHELL_SURFACE_RESIZE_RIGHT = 8,
- /**
- * top and right edges
- */
- WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9,
- /**
- * bottom and right edges
- */
- WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10,
-};
-#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
-
-#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
-#define WL_SHELL_SURFACE_TRANSIENT_ENUM
-/**
- * @ingroup iface_wl_shell_surface
- * details of transient behaviour
- *
- * These flags specify details of the expected behaviour
- * of transient surfaces. Used in the set_transient request.
- */
-enum wl_shell_surface_transient {
- /**
- * do not set keyboard focus
- */
- WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1,
-};
-#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
-
-#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
-#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
-/**
- * @ingroup iface_wl_shell_surface
- * different method to set the surface fullscreen
- *
- * Hints to indicate to the compositor how to deal with a conflict
- * between the dimensions of the surface and the dimensions of the
- * output. The compositor is free to ignore this parameter.
- */
-enum wl_shell_surface_fullscreen_method {
- /**
- * no preference, apply default policy
- */
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0,
- /**
- * scale, preserve the surface's aspect ratio and center on output
- */
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1,
- /**
- * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch
- */
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2,
- /**
- * no upscaling, center on output and add black borders to compensate size mismatch
- */
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3,
-};
-#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
-
-/**
- * @ingroup iface_wl_shell_surface
- * @struct wl_shell_surface_listener
- */
-struct wl_shell_surface_listener {
- /**
- * ping client
- *
- * Ping a client to check if it is receiving events and sending
- * requests. A client is expected to reply with a pong request.
- * @param serial serial number of the ping
- */
- void (*ping)(void *data,
- struct wl_shell_surface *wl_shell_surface,
- uint32_t serial);
- /**
- * suggest resize
- *
- * The configure event asks the client to resize its surface.
- *
- * The size is a hint, in the sense that the client is free to
- * ignore it if it doesn't resize, pick a smaller size (to satisfy
- * aspect ratio or resize in steps of NxM pixels).
- *
- * The edges parameter provides a hint about how the surface was
- * resized. The client may use this information to decide how to
- * adjust its content to the new size (e.g. a scrolling area might
- * adjust its content position to leave the viewable content
- * unmoved).
- *
- * The client is free to dismiss all but the last configure event
- * it received.
- *
- * The width and height arguments specify the size of the window in
- * surface-local coordinates.
- * @param edges how the surface was resized
- * @param width new width of the surface
- * @param height new height of the surface
- */
- void (*configure)(void *data,
- struct wl_shell_surface *wl_shell_surface,
- uint32_t edges,
- int32_t width,
- int32_t height);
- /**
- * popup interaction is done
- *
- * The popup_done event is sent out when a popup grab is broken,
- * that is, when the user clicks a surface that doesn't belong to
- * the client owning the popup surface.
- */
- void (*popup_done)(void *data,
- struct wl_shell_surface *wl_shell_surface);
-};
-
-/**
- * @ingroup iface_wl_shell_surface
- */
-static inline int
-wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface,
- const struct wl_shell_surface_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_shell_surface,
- (void (**)(void)) listener, data);
-}
-
-#define WL_SHELL_SURFACE_PONG 0
-#define WL_SHELL_SURFACE_MOVE 1
-#define WL_SHELL_SURFACE_RESIZE 2
-#define WL_SHELL_SURFACE_SET_TOPLEVEL 3
-#define WL_SHELL_SURFACE_SET_TRANSIENT 4
-#define WL_SHELL_SURFACE_SET_FULLSCREEN 5
-#define WL_SHELL_SURFACE_SET_POPUP 6
-#define WL_SHELL_SURFACE_SET_MAXIMIZED 7
-#define WL_SHELL_SURFACE_SET_TITLE 8
-#define WL_SHELL_SURFACE_SET_CLASS 9
-
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_PING_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION 1
-
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_PONG_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_MOVE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_RESIZE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_shell_surface
- */
-#define WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION 1
-
-/** @ingroup iface_wl_shell_surface */
-static inline void
-wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_shell_surface, user_data);
-}
-
-/** @ingroup iface_wl_shell_surface */
-static inline void *
-wl_shell_surface_get_user_data(struct wl_shell_surface *wl_shell_surface)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_shell_surface);
-}
-
-static inline uint32_t
-wl_shell_surface_get_version(struct wl_shell_surface *wl_shell_surface)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_shell_surface);
-}
-
-/** @ingroup iface_wl_shell_surface */
-static inline void
-wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_shell_surface);
-}
-
-/**
- * @ingroup iface_wl_shell_surface
- *
- * A client must respond to a ping event with a pong request or
- * the client may be deemed unresponsive.
- */
-static inline void
-wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, serial);
-}
-
-/**
- * @ingroup iface_wl_shell_surface
- *
- * Start a pointer-driven move of the surface.
- *
- * This request must be used in response to a button press event.
- * The server may ignore move requests depending on the state of
- * the surface (e.g. fullscreen or maximized).
- */
-static inline void
-wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial);
-}
-
-/**
- * @ingroup iface_wl_shell_surface
- *
- * Start a pointer-driven resizing of the surface.
- *
- * This request must be used in response to a button press event.
- * The server may ignore resize requests depending on the state of
- * the surface (e.g. fullscreen or maximized).
- */
-static inline void
-wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, edges);
-}
-
-/**
- * @ingroup iface_wl_shell_surface
- *
- * Map the surface as a toplevel surface.
- *
- * A toplevel surface is not fullscreen, maximized or transient.
- */
-static inline void
-wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_TOPLEVEL, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0);
-}
-
-/**
- * @ingroup iface_wl_shell_surface
- *
- * Map the surface relative to an existing surface.
- *
- * The x and y arguments specify the location of the upper left
- * corner of the surface relative to the upper left corner of the
- * parent surface, in surface-local coordinates.
- *
- * The flags argument controls details of the transient behaviour.
- */
-static inline void
-wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_TRANSIENT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, parent, x, y, flags);
-}
-
-/**
- * @ingroup iface_wl_shell_surface
- *
- * Map the surface as a fullscreen surface.
- *
- * If an output parameter is given then the surface will be made
- * fullscreen on that output. If the client does not specify the
- * output then the compositor will apply its policy - usually
- * choosing the output on which the surface has the biggest surface
- * area.
- *
- * The client may specify a method to resolve a size conflict
- * between the output size and the surface size - this is provided
- * through the method parameter.
- *
- * The framerate parameter is used only when the method is set
- * to "driver", to indicate the preferred framerate. A value of 0
- * indicates that the client does not care about framerate. The
- * framerate is specified in mHz, that is framerate of 60000 is 60Hz.
- *
- * A method of "scale" or "driver" implies a scaling operation of
- * the surface, either via a direct scaling operation or a change of
- * the output mode. This will override any kind of output scaling, so
- * that mapping a surface with a buffer size equal to the mode can
- * fill the screen independent of buffer_scale.
- *
- * A method of "fill" means we don't scale up the buffer, however
- * any output scale is applied. This means that you may run into
- * an edge case where the application maps a buffer with the same
- * size of the output mode but buffer_scale 1 (thus making a
- * surface larger than the output). In this case it is allowed to
- * downscale the results to fit the screen.
- *
- * The compositor must reply to this request with a configure event
- * with the dimensions for the output on which the surface will
- * be made fullscreen.
- */
-static inline void
-wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, method, framerate, output);
-}
-
-/**
- * @ingroup iface_wl_shell_surface
- *
- * Map the surface as a popup.
- *
- * A popup surface is a transient surface with an added pointer
- * grab.
- *
- * An existing implicit grab will be changed to owner-events mode,
- * and the popup grab will continue after the implicit grab ends
- * (i.e. releasing the mouse button does not cause the popup to
- * be unmapped).
- *
- * The popup grab continues until the window is destroyed or a
- * mouse button is pressed in any other client's window. A click
- * in any of the client's surfaces is reported as normal, however,
- * clicks in other clients' surfaces will be discarded and trigger
- * the callback.
- *
- * The x and y arguments specify the location of the upper left
- * corner of the surface relative to the upper left corner of the
- * parent surface, in surface-local coordinates.
- */
-static inline void
-wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, parent, x, y, flags);
-}
-
-/**
- * @ingroup iface_wl_shell_surface
- *
- * Map the surface as a maximized surface.
- *
- * If an output parameter is given then the surface will be
- * maximized on that output. If the client does not specify the
- * output then the compositor will apply its policy - usually
- * choosing the output on which the surface has the biggest surface
- * area.
- *
- * The compositor will reply with a configure event telling
- * the expected new surface size. The operation is completed
- * on the next buffer attach to this surface.
- *
- * A maximized surface typically fills the entire output it is
- * bound to, except for desktop elements such as panels. This is
- * the main difference between a maximized shell surface and a
- * fullscreen shell surface.
- *
- * The details depend on the compositor implementation.
- */
-static inline void
-wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, output);
-}
-
-/**
- * @ingroup iface_wl_shell_surface
- *
- * Set a short title for the surface.
- *
- * This string may be used to identify the surface in a task bar,
- * window list, or other user interface elements provided by the
- * compositor.
- *
- * The string must be encoded in UTF-8.
- */
-static inline void
-wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, title);
-}
-
-/**
- * @ingroup iface_wl_shell_surface
- *
- * Set a class for the surface.
- *
- * The surface class identifies the general class of applications
- * to which the surface belongs. A common convention is to use the
- * file name (or the full path if it is a non-standard location) of
- * the application's .desktop file as the class.
- */
-static inline void
-wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_CLASS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, class_);
-}
-
-#ifndef WL_SURFACE_ERROR_ENUM
-#define WL_SURFACE_ERROR_ENUM
-/**
- * @ingroup iface_wl_surface
- * wl_surface error values
- *
- * These errors can be emitted in response to wl_surface requests.
- */
-enum wl_surface_error {
- /**
- * buffer scale value is invalid
- */
- WL_SURFACE_ERROR_INVALID_SCALE = 0,
- /**
- * buffer transform value is invalid
- */
- WL_SURFACE_ERROR_INVALID_TRANSFORM = 1,
- /**
- * buffer size is invalid
- */
- WL_SURFACE_ERROR_INVALID_SIZE = 2,
- /**
- * buffer offset is invalid
- */
- WL_SURFACE_ERROR_INVALID_OFFSET = 3,
- /**
- * surface was destroyed before its role object
- */
- WL_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 4,
-};
-#endif /* WL_SURFACE_ERROR_ENUM */
-
-/**
- * @ingroup iface_wl_surface
- * @struct wl_surface_listener
- */
-struct wl_surface_listener {
- /**
- * surface enters an output
- *
- * This is emitted whenever a surface's creation, movement, or
- * resizing results in some part of it being within the scanout
- * region of an output.
- *
- * Note that a surface may be overlapping with zero or more
- * outputs.
- * @param output output entered by the surface
- */
- void (*enter)(void *data,
- struct wl_surface *wl_surface,
- struct wl_output *output);
- /**
- * surface leaves an output
- *
- * This is emitted whenever a surface's creation, movement, or
- * resizing results in it no longer having any part of it within
- * the scanout region of an output.
- *
- * Clients should not use the number of outputs the surface is on
- * for frame throttling purposes. The surface might be hidden even
- * if no leave event has been sent, and the compositor might expect
- * new surface content updates even if no enter event has been
- * sent. The frame event should be used instead.
- * @param output output left by the surface
- */
- void (*leave)(void *data,
- struct wl_surface *wl_surface,
- struct wl_output *output);
- /**
- * preferred buffer scale for the surface
- *
- * This event indicates the preferred buffer scale for this
- * surface. It is sent whenever the compositor's preference
- * changes.
- *
- * It is intended that scaling aware clients use this event to
- * scale their content and use wl_surface.set_buffer_scale to
- * indicate the scale they have rendered with. This allows clients
- * to supply a higher detail buffer.
- * @param factor preferred scaling factor
- * @since 6
- */
- void (*preferred_buffer_scale)(void *data,
- struct wl_surface *wl_surface,
- int32_t factor);
- /**
- * preferred buffer transform for the surface
- *
- * This event indicates the preferred buffer transform for this
- * surface. It is sent whenever the compositor's preference
- * changes.
- *
- * It is intended that transform aware clients use this event to
- * apply the transform to their content and use
- * wl_surface.set_buffer_transform to indicate the transform they
- * have rendered with.
- * @param transform preferred transform
- * @since 6
- */
- void (*preferred_buffer_transform)(void *data,
- struct wl_surface *wl_surface,
- uint32_t transform);
-};
-
-/**
- * @ingroup iface_wl_surface
- */
-static inline int
-wl_surface_add_listener(struct wl_surface *wl_surface,
- const struct wl_surface_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_surface,
- (void (**)(void)) listener, data);
-}
-
-#define WL_SURFACE_DESTROY 0
-#define WL_SURFACE_ATTACH 1
-#define WL_SURFACE_DAMAGE 2
-#define WL_SURFACE_FRAME 3
-#define WL_SURFACE_SET_OPAQUE_REGION 4
-#define WL_SURFACE_SET_INPUT_REGION 5
-#define WL_SURFACE_COMMIT 6
-#define WL_SURFACE_SET_BUFFER_TRANSFORM 7
-#define WL_SURFACE_SET_BUFFER_SCALE 8
-#define WL_SURFACE_DAMAGE_BUFFER 9
-#define WL_SURFACE_OFFSET 10
-
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_ENTER_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_LEAVE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION 6
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_PREFERRED_BUFFER_TRANSFORM_SINCE_VERSION 6
-
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_ATTACH_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_DAMAGE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_FRAME_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_COMMIT_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION 2
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION 3
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION 4
-/**
- * @ingroup iface_wl_surface
- */
-#define WL_SURFACE_OFFSET_SINCE_VERSION 5
-
-/** @ingroup iface_wl_surface */
-static inline void
-wl_surface_set_user_data(struct wl_surface *wl_surface, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_surface, user_data);
-}
-
-/** @ingroup iface_wl_surface */
-static inline void *
-wl_surface_get_user_data(struct wl_surface *wl_surface)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_surface);
-}
-
-static inline uint32_t
-wl_surface_get_version(struct wl_surface *wl_surface)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_surface);
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * Deletes the surface and invalidates its object ID.
- */
-static inline void
-wl_surface_destroy(struct wl_surface *wl_surface)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * Set a buffer as the content of this surface.
- *
- * The new size of the surface is calculated based on the buffer
- * size transformed by the inverse buffer_transform and the
- * inverse buffer_scale. This means that at commit time the supplied
- * buffer size must be an integer multiple of the buffer_scale. If
- * that's not the case, an invalid_size error is sent.
- *
- * The x and y arguments specify the location of the new pending
- * buffer's upper left corner, relative to the current buffer's upper
- * left corner, in surface-local coordinates. In other words, the
- * x and y, combined with the new surface size define in which
- * directions the surface's size changes. Setting anything other than 0
- * as x and y arguments is discouraged, and should instead be replaced
- * with using the separate wl_surface.offset request.
- *
- * When the bound wl_surface version is 5 or higher, passing any
- * non-zero x or y is a protocol violation, and will result in an
- * 'invalid_offset' error being raised. The x and y arguments are ignored
- * and do not change the pending state. To achieve equivalent semantics,
- * use wl_surface.offset.
- *
- * Surface contents are double-buffered state, see wl_surface.commit.
- *
- * The initial surface contents are void; there is no content.
- * wl_surface.attach assigns the given wl_buffer as the pending
- * wl_buffer. wl_surface.commit makes the pending wl_buffer the new
- * surface contents, and the size of the surface becomes the size
- * calculated from the wl_buffer, as described above. After commit,
- * there is no pending buffer until the next attach.
- *
- * Committing a pending wl_buffer allows the compositor to read the
- * pixels in the wl_buffer. The compositor may access the pixels at
- * any time after the wl_surface.commit request. When the compositor
- * will not access the pixels anymore, it will send the
- * wl_buffer.release event. Only after receiving wl_buffer.release,
- * the client may reuse the wl_buffer. A wl_buffer that has been
- * attached and then replaced by another attach instead of committed
- * will not receive a release event, and is not used by the
- * compositor.
- *
- * If a pending wl_buffer has been committed to more than one wl_surface,
- * the delivery of wl_buffer.release events becomes undefined. A well
- * behaved client should not rely on wl_buffer.release events in this
- * case. Alternatively, a client could create multiple wl_buffer objects
- * from the same backing storage or use wp_linux_buffer_release.
- *
- * Destroying the wl_buffer after wl_buffer.release does not change
- * the surface contents. Destroying the wl_buffer before wl_buffer.release
- * is allowed as long as the underlying buffer storage isn't re-used (this
- * can happen e.g. on client process termination). However, if the client
- * destroys the wl_buffer before receiving the wl_buffer.release event and
- * mutates the underlying buffer storage, the surface contents become
- * undefined immediately.
- *
- * If wl_surface.attach is sent with a NULL wl_buffer, the
- * following wl_surface.commit will remove the surface content.
- */
-static inline void
-wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, buffer, x, y);
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * This request is used to describe the regions where the pending
- * buffer is different from the current surface contents, and where
- * the surface therefore needs to be repainted. The compositor
- * ignores the parts of the damage that fall outside of the surface.
- *
- * Damage is double-buffered state, see wl_surface.commit.
- *
- * The damage rectangle is specified in surface-local coordinates,
- * where x and y specify the upper left corner of the damage rectangle.
- *
- * The initial value for pending damage is empty: no damage.
- * wl_surface.damage adds pending damage: the new pending damage
- * is the union of old pending damage and the given rectangle.
- *
- * wl_surface.commit assigns pending damage as the current damage,
- * and clears pending damage. The server will clear the current
- * damage as it repaints the surface.
- *
- * Note! New clients should not use this request. Instead damage can be
- * posted with wl_surface.damage_buffer which uses buffer coordinates
- * instead of surface coordinates.
- */
-static inline void
-wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_DAMAGE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height);
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * Request a notification when it is a good time to start drawing a new
- * frame, by creating a frame callback. This is useful for throttling
- * redrawing operations, and driving animations.
- *
- * When a client is animating on a wl_surface, it can use the 'frame'
- * request to get notified when it is a good time to draw and commit the
- * next frame of animation. If the client commits an update earlier than
- * that, it is likely that some updates will not make it to the display,
- * and the client is wasting resources by drawing too often.
- *
- * The frame request will take effect on the next wl_surface.commit.
- * The notification will only be posted for one frame unless
- * requested again. For a wl_surface, the notifications are posted in
- * the order the frame requests were committed.
- *
- * The server must send the notifications so that a client
- * will not send excessive updates, while still allowing
- * the highest possible update rate for clients that wait for the reply
- * before drawing again. The server should give some time for the client
- * to draw and commit after sending the frame callback events to let it
- * hit the next output refresh.
- *
- * A server should avoid signaling the frame callbacks if the
- * surface is not visible in any way, e.g. the surface is off-screen,
- * or completely obscured by other opaque surfaces.
- *
- * The object returned by this request will be destroyed by the
- * compositor after the callback is fired and as such the client must not
- * attempt to use it after that point.
- *
- * The callback_data passed in the callback is the current time, in
- * milliseconds, with an undefined base.
- */
-static inline struct wl_callback *
-wl_surface_frame(struct wl_surface *wl_surface)
-{
- struct wl_proxy *callback;
-
- callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_FRAME, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, NULL);
-
- return (struct wl_callback *) callback;
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * This request sets the region of the surface that contains
- * opaque content.
- *
- * The opaque region is an optimization hint for the compositor
- * that lets it optimize the redrawing of content behind opaque
- * regions. Setting an opaque region is not required for correct
- * behaviour, but marking transparent content as opaque will result
- * in repaint artifacts.
- *
- * The opaque region is specified in surface-local coordinates.
- *
- * The compositor ignores the parts of the opaque region that fall
- * outside of the surface.
- *
- * Opaque region is double-buffered state, see wl_surface.commit.
- *
- * wl_surface.set_opaque_region changes the pending opaque region.
- * wl_surface.commit copies the pending region to the current region.
- * Otherwise, the pending and current regions are never changed.
- *
- * The initial value for an opaque region is empty. Setting the pending
- * opaque region has copy semantics, and the wl_region object can be
- * destroyed immediately. A NULL wl_region causes the pending opaque
- * region to be set to empty.
- */
-static inline void
-wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_SET_OPAQUE_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region);
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * This request sets the region of the surface that can receive
- * pointer and touch events.
- *
- * Input events happening outside of this region will try the next
- * surface in the server surface stack. The compositor ignores the
- * parts of the input region that fall outside of the surface.
- *
- * The input region is specified in surface-local coordinates.
- *
- * Input region is double-buffered state, see wl_surface.commit.
- *
- * wl_surface.set_input_region changes the pending input region.
- * wl_surface.commit copies the pending region to the current region.
- * Otherwise the pending and current regions are never changed,
- * except cursor and icon surfaces are special cases, see
- * wl_pointer.set_cursor and wl_data_device.start_drag.
- *
- * The initial value for an input region is infinite. That means the
- * whole surface will accept input. Setting the pending input region
- * has copy semantics, and the wl_region object can be destroyed
- * immediately. A NULL wl_region causes the input region to be set
- * to infinite.
- */
-static inline void
-wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_SET_INPUT_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region);
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * Surface state (input, opaque, and damage regions, attached buffers,
- * etc.) is double-buffered. Protocol requests modify the pending state,
- * as opposed to the current state in use by the compositor. A commit
- * request atomically applies all pending state, replacing the current
- * state. After commit, the new pending state is as documented for each
- * related request.
- *
- * On commit, a pending wl_buffer is applied first, and all other state
- * second. This means that all coordinates in double-buffered state are
- * relative to the new wl_buffer coming into use, except for
- * wl_surface.attach itself. If there is no pending wl_buffer, the
- * coordinates are relative to the current surface contents.
- *
- * All requests that need a commit to become effective are documented
- * to affect double-buffered state.
- *
- * Other interfaces may add further double-buffered surface state.
- */
-static inline void
-wl_surface_commit(struct wl_surface *wl_surface)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0);
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * This request sets an optional transformation on how the compositor
- * interprets the contents of the buffer attached to the surface. The
- * accepted values for the transform parameter are the values for
- * wl_output.transform.
- *
- * Buffer transform is double-buffered state, see wl_surface.commit.
- *
- * A newly created surface has its buffer transformation set to normal.
- *
- * wl_surface.set_buffer_transform changes the pending buffer
- * transformation. wl_surface.commit copies the pending buffer
- * transformation to the current one. Otherwise, the pending and current
- * values are never changed.
- *
- * The purpose of this request is to allow clients to render content
- * according to the output transform, thus permitting the compositor to
- * use certain optimizations even if the display is rotated. Using
- * hardware overlays and scanning out a client buffer for fullscreen
- * surfaces are examples of such optimizations. Those optimizations are
- * highly dependent on the compositor implementation, so the use of this
- * request should be considered on a case-by-case basis.
- *
- * Note that if the transform value includes 90 or 270 degree rotation,
- * the width of the buffer will become the surface height and the height
- * of the buffer will become the surface width.
- *
- * If transform is not one of the values from the
- * wl_output.transform enum the invalid_transform protocol error
- * is raised.
- */
-static inline void
-wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_SET_BUFFER_TRANSFORM, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, transform);
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * This request sets an optional scaling factor on how the compositor
- * interprets the contents of the buffer attached to the window.
- *
- * Buffer scale is double-buffered state, see wl_surface.commit.
- *
- * A newly created surface has its buffer scale set to 1.
- *
- * wl_surface.set_buffer_scale changes the pending buffer scale.
- * wl_surface.commit copies the pending buffer scale to the current one.
- * Otherwise, the pending and current values are never changed.
- *
- * The purpose of this request is to allow clients to supply higher
- * resolution buffer data for use on high resolution outputs. It is
- * intended that you pick the same buffer scale as the scale of the
- * output that the surface is displayed on. This means the compositor
- * can avoid scaling when rendering the surface on that output.
- *
- * Note that if the scale is larger than 1, then you have to attach
- * a buffer that is larger (by a factor of scale in each dimension)
- * than the desired surface size.
- *
- * If scale is not positive the invalid_scale protocol error is
- * raised.
- */
-static inline void
-wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_SET_BUFFER_SCALE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, scale);
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * This request is used to describe the regions where the pending
- * buffer is different from the current surface contents, and where
- * the surface therefore needs to be repainted. The compositor
- * ignores the parts of the damage that fall outside of the surface.
- *
- * Damage is double-buffered state, see wl_surface.commit.
- *
- * The damage rectangle is specified in buffer coordinates,
- * where x and y specify the upper left corner of the damage rectangle.
- *
- * The initial value for pending damage is empty: no damage.
- * wl_surface.damage_buffer adds pending damage: the new pending
- * damage is the union of old pending damage and the given rectangle.
- *
- * wl_surface.commit assigns pending damage as the current damage,
- * and clears pending damage. The server will clear the current
- * damage as it repaints the surface.
- *
- * This request differs from wl_surface.damage in only one way - it
- * takes damage in buffer coordinates instead of surface-local
- * coordinates. While this generally is more intuitive than surface
- * coordinates, it is especially desirable when using wp_viewport
- * or when a drawing library (like EGL) is unaware of buffer scale
- * and buffer transform.
- *
- * Note: Because buffer transformation changes and damage requests may
- * be interleaved in the protocol stream, it is impossible to determine
- * the actual mapping between surface and buffer damage until
- * wl_surface.commit time. Therefore, compositors wishing to take both
- * kinds of damage into account will have to accumulate damage from the
- * two requests separately and only transform from one to the other
- * after receiving the wl_surface.commit.
- */
-static inline void
-wl_surface_damage_buffer(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_DAMAGE_BUFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height);
-}
-
-/**
- * @ingroup iface_wl_surface
- *
- * The x and y arguments specify the location of the new pending
- * buffer's upper left corner, relative to the current buffer's upper
- * left corner, in surface-local coordinates. In other words, the
- * x and y, combined with the new surface size define in which
- * directions the surface's size changes.
- *
- * Surface location offset is double-buffered state, see
- * wl_surface.commit.
- *
- * This request is semantically equivalent to and the replaces the x and y
- * arguments in the wl_surface.attach request in wl_surface versions prior
- * to 5. See wl_surface.attach for details.
- */
-static inline void
-wl_surface_offset(struct wl_surface *wl_surface, int32_t x, int32_t y)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
- WL_SURFACE_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y);
-}
-
-#ifndef WL_SEAT_CAPABILITY_ENUM
-#define WL_SEAT_CAPABILITY_ENUM
-/**
- * @ingroup iface_wl_seat
- * seat capability bitmask
- *
- * This is a bitmask of capabilities this seat has; if a member is
- * set, then it is present on the seat.
- */
-enum wl_seat_capability {
- /**
- * the seat has pointer devices
- */
- WL_SEAT_CAPABILITY_POINTER = 1,
- /**
- * the seat has one or more keyboards
- */
- WL_SEAT_CAPABILITY_KEYBOARD = 2,
- /**
- * the seat has touch devices
- */
- WL_SEAT_CAPABILITY_TOUCH = 4,
-};
-#endif /* WL_SEAT_CAPABILITY_ENUM */
-
-#ifndef WL_SEAT_ERROR_ENUM
-#define WL_SEAT_ERROR_ENUM
-/**
- * @ingroup iface_wl_seat
- * wl_seat error values
- *
- * These errors can be emitted in response to wl_seat requests.
- */
-enum wl_seat_error {
- /**
- * get_pointer, get_keyboard or get_touch called on seat without the matching capability
- */
- WL_SEAT_ERROR_MISSING_CAPABILITY = 0,
-};
-#endif /* WL_SEAT_ERROR_ENUM */
-
-/**
- * @ingroup iface_wl_seat
- * @struct wl_seat_listener
- */
-struct wl_seat_listener {
- /**
- * seat capabilities changed
- *
- * This is emitted whenever a seat gains or loses the pointer,
- * keyboard or touch capabilities. The argument is a capability
- * enum containing the complete set of capabilities this seat has.
- *
- * When the pointer capability is added, a client may create a
- * wl_pointer object using the wl_seat.get_pointer request. This
- * object will receive pointer events until the capability is
- * removed in the future.
- *
- * When the pointer capability is removed, a client should destroy
- * the wl_pointer objects associated with the seat where the
- * capability was removed, using the wl_pointer.release request. No
- * further pointer events will be received on these objects.
- *
- * In some compositors, if a seat regains the pointer capability
- * and a client has a previously obtained wl_pointer object of
- * version 4 or less, that object may start sending pointer events
- * again. This behavior is considered a misinterpretation of the
- * intended behavior and must not be relied upon by the client.
- * wl_pointer objects of version 5 or later must not send events if
- * created before the most recent event notifying the client of an
- * added pointer capability.
- *
- * The above behavior also applies to wl_keyboard and wl_touch with
- * the keyboard and touch capabilities, respectively.
- * @param capabilities capabilities of the seat
- */
- void (*capabilities)(void *data,
- struct wl_seat *wl_seat,
- uint32_t capabilities);
- /**
- * unique identifier for this seat
- *
- * In a multi-seat configuration the seat name can be used by
- * clients to help identify which physical devices the seat
- * represents.
- *
- * The seat name is a UTF-8 string with no convention defined for
- * its contents. Each name is unique among all wl_seat globals. The
- * name is only guaranteed to be unique for the current compositor
- * instance.
- *
- * The same seat names are used for all clients. Thus, the name can
- * be shared across processes to refer to a specific wl_seat
- * global.
- *
- * The name event is sent after binding to the seat global. This
- * event is only sent once per seat object, and the name does not
- * change over the lifetime of the wl_seat global.
- *
- * Compositors may re-use the same seat name if the wl_seat global
- * is destroyed and re-created later.
- * @param name seat identifier
- * @since 2
- */
- void (*name)(void *data,
- struct wl_seat *wl_seat,
- const char *name);
-};
-
-/**
- * @ingroup iface_wl_seat
- */
-static inline int
-wl_seat_add_listener(struct wl_seat *wl_seat,
- const struct wl_seat_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_seat,
- (void (**)(void)) listener, data);
-}
-
-#define WL_SEAT_GET_POINTER 0
-#define WL_SEAT_GET_KEYBOARD 1
-#define WL_SEAT_GET_TOUCH 2
-#define WL_SEAT_RELEASE 3
-
-/**
- * @ingroup iface_wl_seat
- */
-#define WL_SEAT_CAPABILITIES_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_seat
- */
-#define WL_SEAT_NAME_SINCE_VERSION 2
-
-/**
- * @ingroup iface_wl_seat
- */
-#define WL_SEAT_GET_POINTER_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_seat
- */
-#define WL_SEAT_GET_KEYBOARD_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_seat
- */
-#define WL_SEAT_GET_TOUCH_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_seat
- */
-#define WL_SEAT_RELEASE_SINCE_VERSION 5
-
-/** @ingroup iface_wl_seat */
-static inline void
-wl_seat_set_user_data(struct wl_seat *wl_seat, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_seat, user_data);
-}
-
-/** @ingroup iface_wl_seat */
-static inline void *
-wl_seat_get_user_data(struct wl_seat *wl_seat)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_seat);
-}
-
-static inline uint32_t
-wl_seat_get_version(struct wl_seat *wl_seat)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_seat);
-}
-
-/** @ingroup iface_wl_seat */
-static inline void
-wl_seat_destroy(struct wl_seat *wl_seat)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_seat);
-}
-
-/**
- * @ingroup iface_wl_seat
- *
- * The ID provided will be initialized to the wl_pointer interface
- * for this seat.
- *
- * This request only takes effect if the seat has the pointer
- * capability, or has had the pointer capability in the past.
- * It is a protocol violation to issue this request on a seat that has
- * never had the pointer capability. The missing_capability error will
- * be sent in this case.
- */
-static inline struct wl_pointer *
-wl_seat_get_pointer(struct wl_seat *wl_seat)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
- WL_SEAT_GET_POINTER, &wl_pointer_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL);
-
- return (struct wl_pointer *) id;
-}
-
-/**
- * @ingroup iface_wl_seat
- *
- * The ID provided will be initialized to the wl_keyboard interface
- * for this seat.
- *
- * This request only takes effect if the seat has the keyboard
- * capability, or has had the keyboard capability in the past.
- * It is a protocol violation to issue this request on a seat that has
- * never had the keyboard capability. The missing_capability error will
- * be sent in this case.
- */
-static inline struct wl_keyboard *
-wl_seat_get_keyboard(struct wl_seat *wl_seat)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
- WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL);
-
- return (struct wl_keyboard *) id;
-}
-
-/**
- * @ingroup iface_wl_seat
- *
- * The ID provided will be initialized to the wl_touch interface
- * for this seat.
- *
- * This request only takes effect if the seat has the touch
- * capability, or has had the touch capability in the past.
- * It is a protocol violation to issue this request on a seat that has
- * never had the touch capability. The missing_capability error will
- * be sent in this case.
- */
-static inline struct wl_touch *
-wl_seat_get_touch(struct wl_seat *wl_seat)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
- WL_SEAT_GET_TOUCH, &wl_touch_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL);
-
- return (struct wl_touch *) id;
-}
-
-/**
- * @ingroup iface_wl_seat
- *
- * Using this request a client can tell the server that it is not going to
- * use the seat object anymore.
- */
-static inline void
-wl_seat_release(struct wl_seat *wl_seat)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
- WL_SEAT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_seat), WL_MARSHAL_FLAG_DESTROY);
-}
-
-#ifndef WL_POINTER_ERROR_ENUM
-#define WL_POINTER_ERROR_ENUM
-enum wl_pointer_error {
- /**
- * given wl_surface has another role
- */
- WL_POINTER_ERROR_ROLE = 0,
-};
-#endif /* WL_POINTER_ERROR_ENUM */
-
-#ifndef WL_POINTER_BUTTON_STATE_ENUM
-#define WL_POINTER_BUTTON_STATE_ENUM
-/**
- * @ingroup iface_wl_pointer
- * physical button state
- *
- * Describes the physical state of a button that produced the button
- * event.
- */
-enum wl_pointer_button_state {
- /**
- * the button is not pressed
- */
- WL_POINTER_BUTTON_STATE_RELEASED = 0,
- /**
- * the button is pressed
- */
- WL_POINTER_BUTTON_STATE_PRESSED = 1,
-};
-#endif /* WL_POINTER_BUTTON_STATE_ENUM */
-
-#ifndef WL_POINTER_AXIS_ENUM
-#define WL_POINTER_AXIS_ENUM
-/**
- * @ingroup iface_wl_pointer
- * axis types
- *
- * Describes the axis types of scroll events.
- */
-enum wl_pointer_axis {
- /**
- * vertical axis
- */
- WL_POINTER_AXIS_VERTICAL_SCROLL = 0,
- /**
- * horizontal axis
- */
- WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
-};
-#endif /* WL_POINTER_AXIS_ENUM */
-
-#ifndef WL_POINTER_AXIS_SOURCE_ENUM
-#define WL_POINTER_AXIS_SOURCE_ENUM
-/**
- * @ingroup iface_wl_pointer
- * axis source types
- *
- * Describes the source types for axis events. This indicates to the
- * client how an axis event was physically generated; a client may
- * adjust the user interface accordingly. For example, scroll events
- * from a "finger" source may be in a smooth coordinate space with
- * kinetic scrolling whereas a "wheel" source may be in discrete steps
- * of a number of lines.
- *
- * The "continuous" axis source is a device generating events in a
- * continuous coordinate space, but using something other than a
- * finger. One example for this source is button-based scrolling where
- * the vertical motion of a device is converted to scroll events while
- * a button is held down.
- *
- * The "wheel tilt" axis source indicates that the actual device is a
- * wheel but the scroll event is not caused by a rotation but a
- * (usually sideways) tilt of the wheel.
- */
-enum wl_pointer_axis_source {
- /**
- * a physical wheel rotation
- */
- WL_POINTER_AXIS_SOURCE_WHEEL = 0,
- /**
- * finger on a touch surface
- */
- WL_POINTER_AXIS_SOURCE_FINGER = 1,
- /**
- * continuous coordinate space
- */
- WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2,
- /**
- * a physical wheel tilt
- * @since 6
- */
- WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3,
-};
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6
-#endif /* WL_POINTER_AXIS_SOURCE_ENUM */
-
-#ifndef WL_POINTER_AXIS_RELATIVE_DIRECTION_ENUM
-#define WL_POINTER_AXIS_RELATIVE_DIRECTION_ENUM
-/**
- * @ingroup iface_wl_pointer
- * axis relative direction
- *
- * This specifies the direction of the physical motion that caused a
- * wl_pointer.axis event, relative to the wl_pointer.axis direction.
- */
-enum wl_pointer_axis_relative_direction {
- /**
- * physical motion matches axis direction
- */
- WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL = 0,
- /**
- * physical motion is the inverse of the axis direction
- */
- WL_POINTER_AXIS_RELATIVE_DIRECTION_INVERTED = 1,
-};
-#endif /* WL_POINTER_AXIS_RELATIVE_DIRECTION_ENUM */
-
-/**
- * @ingroup iface_wl_pointer
- * @struct wl_pointer_listener
- */
-struct wl_pointer_listener {
- /**
- * enter event
- *
- * Notification that this seat's pointer is focused on a certain
- * surface.
- *
- * When a seat's focus enters a surface, the pointer image is
- * undefined and a client should respond to this event by setting
- * an appropriate pointer image with the set_cursor request.
- * @param serial serial number of the enter event
- * @param surface surface entered by the pointer
- * @param surface_x surface-local x coordinate
- * @param surface_y surface-local y coordinate
- */
- void (*enter)(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t serial,
- struct wl_surface *surface,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y);
- /**
- * leave event
- *
- * Notification that this seat's pointer is no longer focused on
- * a certain surface.
- *
- * The leave notification is sent before the enter notification for
- * the new focus.
- * @param serial serial number of the leave event
- * @param surface surface left by the pointer
- */
- void (*leave)(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t serial,
- struct wl_surface *surface);
- /**
- * pointer motion event
- *
- * Notification of pointer location change. The arguments
- * surface_x and surface_y are the location relative to the focused
- * surface.
- * @param time timestamp with millisecond granularity
- * @param surface_x surface-local x coordinate
- * @param surface_y surface-local y coordinate
- */
- void (*motion)(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t time,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y);
- /**
- * pointer button event
- *
- * Mouse button click and release notifications.
- *
- * The location of the click is given by the last motion or enter
- * event. The time argument is a timestamp with millisecond
- * granularity, with an undefined base.
- *
- * The button is a button code as defined in the Linux kernel's
- * linux/input-event-codes.h header file, e.g. BTN_LEFT.
- *
- * Any 16-bit button code value is reserved for future additions to
- * the kernel's event code list. All other button codes above
- * 0xFFFF are currently undefined but may be used in future
- * versions of this protocol.
- * @param serial serial number of the button event
- * @param time timestamp with millisecond granularity
- * @param button button that produced the event
- * @param state physical state of the button
- */
- void (*button)(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t serial,
- uint32_t time,
- uint32_t button,
- uint32_t state);
- /**
- * axis event
- *
- * Scroll and other axis notifications.
- *
- * For scroll events (vertical and horizontal scroll axes), the
- * value parameter is the length of a vector along the specified
- * axis in a coordinate space identical to those of motion events,
- * representing a relative movement along the specified axis.
- *
- * For devices that support movements non-parallel to axes multiple
- * axis events will be emitted.
- *
- * When applicable, for example for touch pads, the server can
- * choose to emit scroll events where the motion vector is
- * equivalent to a motion event vector.
- *
- * When applicable, a client can transform its content relative to
- * the scroll distance.
- * @param time timestamp with millisecond granularity
- * @param axis axis type
- * @param value length of vector in surface-local coordinate space
- */
- void (*axis)(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t time,
- uint32_t axis,
- wl_fixed_t value);
- /**
- * end of a pointer event sequence
- *
- * Indicates the end of a set of events that logically belong
- * together. A client is expected to accumulate the data in all
- * events within the frame before proceeding.
- *
- * All wl_pointer events before a wl_pointer.frame event belong
- * logically together. For example, in a diagonal scroll motion the
- * compositor will send an optional wl_pointer.axis_source event,
- * two wl_pointer.axis events (horizontal and vertical) and finally
- * a wl_pointer.frame event. The client may use this information to
- * calculate a diagonal vector for scrolling.
- *
- * When multiple wl_pointer.axis events occur within the same
- * frame, the motion vector is the combined motion of all events.
- * When a wl_pointer.axis and a wl_pointer.axis_stop event occur
- * within the same frame, this indicates that axis movement in one
- * axis has stopped but continues in the other axis. When multiple
- * wl_pointer.axis_stop events occur within the same frame, this
- * indicates that these axes stopped in the same instance.
- *
- * A wl_pointer.frame event is sent for every logical event group,
- * even if the group only contains a single wl_pointer event.
- * Specifically, a client may get a sequence: motion, frame,
- * button, frame, axis, frame, axis_stop, frame.
- *
- * The wl_pointer.enter and wl_pointer.leave events are logical
- * events generated by the compositor and not the hardware. These
- * events are also grouped by a wl_pointer.frame. When a pointer
- * moves from one surface to another, a compositor should group the
- * wl_pointer.leave event within the same wl_pointer.frame.
- * However, a client must not rely on wl_pointer.leave and
- * wl_pointer.enter being in the same wl_pointer.frame.
- * Compositor-specific policies may require the wl_pointer.leave
- * and wl_pointer.enter event being split across multiple
- * wl_pointer.frame groups.
- * @since 5
- */
- void (*frame)(void *data,
- struct wl_pointer *wl_pointer);
- /**
- * axis source event
- *
- * Source information for scroll and other axes.
- *
- * This event does not occur on its own. It is sent before a
- * wl_pointer.frame event and carries the source information for
- * all events within that frame.
- *
- * The source specifies how this event was generated. If the source
- * is wl_pointer.axis_source.finger, a wl_pointer.axis_stop event
- * will be sent when the user lifts the finger off the device.
- *
- * If the source is wl_pointer.axis_source.wheel,
- * wl_pointer.axis_source.wheel_tilt or
- * wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event
- * may or may not be sent. Whether a compositor sends an axis_stop
- * event for these sources is hardware-specific and
- * implementation-dependent; clients must not rely on receiving an
- * axis_stop event for these scroll sources and should treat scroll
- * sequences from these scroll sources as unterminated by default.
- *
- * This event is optional. If the source is unknown for a
- * particular axis event sequence, no event is sent. Only one
- * wl_pointer.axis_source event is permitted per frame.
- *
- * The order of wl_pointer.axis_discrete and wl_pointer.axis_source
- * is not guaranteed.
- * @param axis_source source of the axis event
- * @since 5
- */
- void (*axis_source)(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t axis_source);
- /**
- * axis stop event
- *
- * Stop notification for scroll and other axes.
- *
- * For some wl_pointer.axis_source types, a wl_pointer.axis_stop
- * event is sent to notify a client that the axis sequence has
- * terminated. This enables the client to implement kinetic
- * scrolling. See the wl_pointer.axis_source documentation for
- * information on when this event may be generated.
- *
- * Any wl_pointer.axis events with the same axis_source after this
- * event should be considered as the start of a new axis motion.
- *
- * The timestamp is to be interpreted identical to the timestamp in
- * the wl_pointer.axis event. The timestamp value may be the same
- * as a preceding wl_pointer.axis event.
- * @param time timestamp with millisecond granularity
- * @param axis the axis stopped with this event
- * @since 5
- */
- void (*axis_stop)(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t time,
- uint32_t axis);
- /**
- * axis click event
- *
- * Discrete step information for scroll and other axes.
- *
- * This event carries the axis value of the wl_pointer.axis event
- * in discrete steps (e.g. mouse wheel clicks).
- *
- * This event is deprecated with wl_pointer version 8 - this event
- * is not sent to clients supporting version 8 or later.
- *
- * This event does not occur on its own, it is coupled with a
- * wl_pointer.axis event that represents this axis value on a
- * continuous scale. The protocol guarantees that each
- * axis_discrete event is always followed by exactly one axis event
- * with the same axis number within the same wl_pointer.frame. Note
- * that the protocol allows for other events to occur between the
- * axis_discrete and its coupled axis event, including other
- * axis_discrete or axis events. A wl_pointer.frame must not
- * contain more than one axis_discrete event per axis type.
- *
- * This event is optional; continuous scrolling devices like
- * two-finger scrolling on touchpads do not have discrete steps and
- * do not generate this event.
- *
- * The discrete value carries the directional information. e.g. a
- * value of -2 is two steps towards the negative direction of this
- * axis.
- *
- * The axis number is identical to the axis number in the
- * associated axis event.
- *
- * The order of wl_pointer.axis_discrete and wl_pointer.axis_source
- * is not guaranteed.
- * @param axis axis type
- * @param discrete number of steps
- * @since 5
- */
- void (*axis_discrete)(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t axis,
- int32_t discrete);
- /**
- * axis high-resolution scroll event
- *
- * Discrete high-resolution scroll information.
- *
- * This event carries high-resolution wheel scroll information,
- * with each multiple of 120 representing one logical scroll step
- * (a wheel detent). For example, an axis_value120 of 30 is one
- * quarter of a logical scroll step in the positive direction, a
- * value120 of -240 are two logical scroll steps in the negative
- * direction within the same hardware event. Clients that rely on
- * discrete scrolling should accumulate the value120 to multiples
- * of 120 before processing the event.
- *
- * The value120 must not be zero.
- *
- * This event replaces the wl_pointer.axis_discrete event in
- * clients supporting wl_pointer version 8 or later.
- *
- * Where a wl_pointer.axis_source event occurs in the same
- * wl_pointer.frame, the axis source applies to this event.
- *
- * The order of wl_pointer.axis_value120 and wl_pointer.axis_source
- * is not guaranteed.
- * @param axis axis type
- * @param value120 scroll distance as fraction of 120
- * @since 8
- */
- void (*axis_value120)(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t axis,
- int32_t value120);
- /**
- * axis relative physical direction event
- *
- * Relative directional information of the entity causing the
- * axis motion.
- *
- * For a wl_pointer.axis event, the
- * wl_pointer.axis_relative_direction event specifies the movement
- * direction of the entity causing the wl_pointer.axis event. For
- * example: - if a user's fingers on a touchpad move down and this
- * causes a wl_pointer.axis vertical_scroll down event, the
- * physical direction is 'identical' - if a user's fingers on a
- * touchpad move down and this causes a wl_pointer.axis
- * vertical_scroll up scroll up event ('natural scrolling'), the
- * physical direction is 'inverted'.
- *
- * A client may use this information to adjust scroll motion of
- * components. Specifically, enabling natural scrolling causes the
- * content to change direction compared to traditional scrolling.
- * Some widgets like volume control sliders should usually match
- * the physical direction regardless of whether natural scrolling
- * is active. This event enables clients to match the scroll
- * direction of a widget to the physical direction.
- *
- * This event does not occur on its own, it is coupled with a
- * wl_pointer.axis event that represents this axis value. The
- * protocol guarantees that each axis_relative_direction event is
- * always followed by exactly one axis event with the same axis
- * number within the same wl_pointer.frame. Note that the protocol
- * allows for other events to occur between the
- * axis_relative_direction and its coupled axis event.
- *
- * The axis number is identical to the axis number in the
- * associated axis event.
- *
- * The order of wl_pointer.axis_relative_direction,
- * wl_pointer.axis_discrete and wl_pointer.axis_source is not
- * guaranteed.
- * @param axis axis type
- * @param direction physical direction relative to axis motion
- * @since 9
- */
- void (*axis_relative_direction)(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t axis,
- uint32_t direction);
-};
-
-/**
- * @ingroup iface_wl_pointer
- */
-static inline int
-wl_pointer_add_listener(struct wl_pointer *wl_pointer,
- const struct wl_pointer_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_pointer,
- (void (**)(void)) listener, data);
-}
-
-#define WL_POINTER_SET_CURSOR 0
-#define WL_POINTER_RELEASE 1
-
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_ENTER_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_LEAVE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_MOTION_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_BUTTON_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_AXIS_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_FRAME_SINCE_VERSION 5
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_AXIS_SOURCE_SINCE_VERSION 5
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_AXIS_STOP_SINCE_VERSION 5
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_AXIS_DISCRETE_SINCE_VERSION 5
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_AXIS_VALUE120_SINCE_VERSION 8
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION 9
-
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_SET_CURSOR_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_pointer
- */
-#define WL_POINTER_RELEASE_SINCE_VERSION 3
-
-/** @ingroup iface_wl_pointer */
-static inline void
-wl_pointer_set_user_data(struct wl_pointer *wl_pointer, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_pointer, user_data);
-}
-
-/** @ingroup iface_wl_pointer */
-static inline void *
-wl_pointer_get_user_data(struct wl_pointer *wl_pointer)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_pointer);
-}
-
-static inline uint32_t
-wl_pointer_get_version(struct wl_pointer *wl_pointer)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_pointer);
-}
-
-/** @ingroup iface_wl_pointer */
-static inline void
-wl_pointer_destroy(struct wl_pointer *wl_pointer)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_pointer);
-}
-
-/**
- * @ingroup iface_wl_pointer
- *
- * Set the pointer surface, i.e., the surface that contains the
- * pointer image (cursor). This request gives the surface the role
- * of a cursor. If the surface already has another role, it raises
- * a protocol error.
- *
- * The cursor actually changes only if the pointer
- * focus for this device is one of the requesting client's surfaces
- * or the surface parameter is the current pointer surface. If
- * there was a previous surface set with this request it is
- * replaced. If surface is NULL, the pointer image is hidden.
- *
- * The parameters hotspot_x and hotspot_y define the position of
- * the pointer surface relative to the pointer location. Its
- * top-left corner is always at (x, y) - (hotspot_x, hotspot_y),
- * where (x, y) are the coordinates of the pointer location, in
- * surface-local coordinates.
- *
- * On surface.attach requests to the pointer surface, hotspot_x
- * and hotspot_y are decremented by the x and y parameters
- * passed to the request. Attach must be confirmed by
- * wl_surface.commit as usual.
- *
- * The hotspot can also be updated by passing the currently set
- * pointer surface to this request with new values for hotspot_x
- * and hotspot_y.
- *
- * The input region is ignored for wl_surfaces with the role of
- * a cursor. When the use as a cursor ends, the wl_surface is
- * unmapped.
- *
- * The serial parameter must match the latest wl_pointer.enter
- * serial number sent to the client. Otherwise the request will be
- * ignored.
- */
-static inline void
-wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer,
- WL_POINTER_SET_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), 0, serial, surface, hotspot_x, hotspot_y);
-}
-
-/**
- * @ingroup iface_wl_pointer
- *
- * Using this request a client can tell the server that it is not going to
- * use the pointer object anymore.
- *
- * This request destroys the pointer proxy object, so clients must not call
- * wl_pointer_destroy() after using this request.
- */
-static inline void
-wl_pointer_release(struct wl_pointer *wl_pointer)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer,
- WL_POINTER_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), WL_MARSHAL_FLAG_DESTROY);
-}
-
-#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM
-#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM
-/**
- * @ingroup iface_wl_keyboard
- * keyboard mapping format
- *
- * This specifies the format of the keymap provided to the
- * client with the wl_keyboard.keymap event.
- */
-enum wl_keyboard_keymap_format {
- /**
- * no keymap; client must understand how to interpret the raw keycode
- */
- WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0,
- /**
- * libxkbcommon compatible, null-terminated string; to determine the xkb keycode, clients must add 8 to the key event keycode
- */
- WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1,
-};
-#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
-
-#ifndef WL_KEYBOARD_KEY_STATE_ENUM
-#define WL_KEYBOARD_KEY_STATE_ENUM
-/**
- * @ingroup iface_wl_keyboard
- * physical key state
- *
- * Describes the physical state of a key that produced the key event.
- */
-enum wl_keyboard_key_state {
- /**
- * key is not pressed
- */
- WL_KEYBOARD_KEY_STATE_RELEASED = 0,
- /**
- * key is pressed
- */
- WL_KEYBOARD_KEY_STATE_PRESSED = 1,
-};
-#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
-
-/**
- * @ingroup iface_wl_keyboard
- * @struct wl_keyboard_listener
- */
-struct wl_keyboard_listener {
- /**
- * keyboard mapping
- *
- * This event provides a file descriptor to the client which can
- * be memory-mapped in read-only mode to provide a keyboard mapping
- * description.
- *
- * From version 7 onwards, the fd must be mapped with MAP_PRIVATE
- * by the recipient, as MAP_SHARED may fail.
- * @param format keymap format
- * @param fd keymap file descriptor
- * @param size keymap size, in bytes
- */
- void (*keymap)(void *data,
- struct wl_keyboard *wl_keyboard,
- uint32_t format,
- int32_t fd,
- uint32_t size);
- /**
- * enter event
- *
- * Notification that this seat's keyboard focus is on a certain
- * surface.
- *
- * The compositor must send the wl_keyboard.modifiers event after
- * this event.
- * @param serial serial number of the enter event
- * @param surface surface gaining keyboard focus
- * @param keys the currently pressed keys
- */
- void (*enter)(void *data,
- struct wl_keyboard *wl_keyboard,
- uint32_t serial,
- struct wl_surface *surface,
- struct wl_array *keys);
- /**
- * leave event
- *
- * Notification that this seat's keyboard focus is no longer on a
- * certain surface.
- *
- * The leave notification is sent before the enter notification for
- * the new focus.
- *
- * After this event client must assume that all keys, including
- * modifiers, are lifted and also it must stop key repeating if
- * there's some going on.
- * @param serial serial number of the leave event
- * @param surface surface that lost keyboard focus
- */
- void (*leave)(void *data,
- struct wl_keyboard *wl_keyboard,
- uint32_t serial,
- struct wl_surface *surface);
- /**
- * key event
- *
- * A key was pressed or released. The time argument is a
- * timestamp with millisecond granularity, with an undefined base.
- *
- * The key is a platform-specific key code that can be interpreted
- * by feeding it to the keyboard mapping (see the keymap event).
- *
- * If this event produces a change in modifiers, then the resulting
- * wl_keyboard.modifiers event must be sent after this event.
- * @param serial serial number of the key event
- * @param time timestamp with millisecond granularity
- * @param key key that produced the event
- * @param state physical state of the key
- */
- void (*key)(void *data,
- struct wl_keyboard *wl_keyboard,
- uint32_t serial,
- uint32_t time,
- uint32_t key,
- uint32_t state);
- /**
- * modifier and group state
- *
- * Notifies clients that the modifier and/or group state has
- * changed, and it should update its local state.
- * @param serial serial number of the modifiers event
- * @param mods_depressed depressed modifiers
- * @param mods_latched latched modifiers
- * @param mods_locked locked modifiers
- * @param group keyboard layout
- */
- void (*modifiers)(void *data,
- struct wl_keyboard *wl_keyboard,
- uint32_t serial,
- uint32_t mods_depressed,
- uint32_t mods_latched,
- uint32_t mods_locked,
- uint32_t group);
- /**
- * repeat rate and delay
- *
- * Informs the client about the keyboard's repeat rate and delay.
- *
- * This event is sent as soon as the wl_keyboard object has been
- * created, and is guaranteed to be received by the client before
- * any key press event.
- *
- * Negative values for either rate or delay are illegal. A rate of
- * zero will disable any repeating (regardless of the value of
- * delay).
- *
- * This event can be sent later on as well with a new value if
- * necessary, so clients should continue listening for the event
- * past the creation of wl_keyboard.
- * @param rate the rate of repeating keys in characters per second
- * @param delay delay in milliseconds since key down until repeating starts
- * @since 4
- */
- void (*repeat_info)(void *data,
- struct wl_keyboard *wl_keyboard,
- int32_t rate,
- int32_t delay);
-};
-
-/**
- * @ingroup iface_wl_keyboard
- */
-static inline int
-wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard,
- const struct wl_keyboard_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_keyboard,
- (void (**)(void)) listener, data);
-}
-
-#define WL_KEYBOARD_RELEASE 0
-
-/**
- * @ingroup iface_wl_keyboard
- */
-#define WL_KEYBOARD_KEYMAP_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_keyboard
- */
-#define WL_KEYBOARD_ENTER_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_keyboard
- */
-#define WL_KEYBOARD_LEAVE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_keyboard
- */
-#define WL_KEYBOARD_KEY_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_keyboard
- */
-#define WL_KEYBOARD_MODIFIERS_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_keyboard
- */
-#define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 4
-
-/**
- * @ingroup iface_wl_keyboard
- */
-#define WL_KEYBOARD_RELEASE_SINCE_VERSION 3
-
-/** @ingroup iface_wl_keyboard */
-static inline void
-wl_keyboard_set_user_data(struct wl_keyboard *wl_keyboard, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_keyboard, user_data);
-}
-
-/** @ingroup iface_wl_keyboard */
-static inline void *
-wl_keyboard_get_user_data(struct wl_keyboard *wl_keyboard)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_keyboard);
-}
-
-static inline uint32_t
-wl_keyboard_get_version(struct wl_keyboard *wl_keyboard)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_keyboard);
-}
-
-/** @ingroup iface_wl_keyboard */
-static inline void
-wl_keyboard_destroy(struct wl_keyboard *wl_keyboard)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_keyboard);
-}
-
-/**
- * @ingroup iface_wl_keyboard
- */
-static inline void
-wl_keyboard_release(struct wl_keyboard *wl_keyboard)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_keyboard,
- WL_KEYBOARD_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_keyboard), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_wl_touch
- * @struct wl_touch_listener
- */
-struct wl_touch_listener {
- /**
- * touch down event and beginning of a touch sequence
- *
- * A new touch point has appeared on the surface. This touch
- * point is assigned a unique ID. Future events from this touch
- * point reference this ID. The ID ceases to be valid after a touch
- * up event and may be reused in the future.
- * @param serial serial number of the touch down event
- * @param time timestamp with millisecond granularity
- * @param surface surface touched
- * @param id the unique ID of this touch point
- * @param x surface-local x coordinate
- * @param y surface-local y coordinate
- */
- void (*down)(void *data,
- struct wl_touch *wl_touch,
- uint32_t serial,
- uint32_t time,
- struct wl_surface *surface,
- int32_t id,
- wl_fixed_t x,
- wl_fixed_t y);
- /**
- * end of a touch event sequence
- *
- * The touch point has disappeared. No further events will be
- * sent for this touch point and the touch point's ID is released
- * and may be reused in a future touch down event.
- * @param serial serial number of the touch up event
- * @param time timestamp with millisecond granularity
- * @param id the unique ID of this touch point
- */
- void (*up)(void *data,
- struct wl_touch *wl_touch,
- uint32_t serial,
- uint32_t time,
- int32_t id);
- /**
- * update of touch point coordinates
- *
- * A touch point has changed coordinates.
- * @param time timestamp with millisecond granularity
- * @param id the unique ID of this touch point
- * @param x surface-local x coordinate
- * @param y surface-local y coordinate
- */
- void (*motion)(void *data,
- struct wl_touch *wl_touch,
- uint32_t time,
- int32_t id,
- wl_fixed_t x,
- wl_fixed_t y);
- /**
- * end of touch frame event
- *
- * Indicates the end of a set of events that logically belong
- * together. A client is expected to accumulate the data in all
- * events within the frame before proceeding.
- *
- * A wl_touch.frame terminates at least one event but otherwise no
- * guarantee is provided about the set of events within a frame. A
- * client must assume that any state not updated in a frame is
- * unchanged from the previously known state.
- */
- void (*frame)(void *data,
- struct wl_touch *wl_touch);
- /**
- * touch session cancelled
- *
- * Sent if the compositor decides the touch stream is a global
- * gesture. No further events are sent to the clients from that
- * particular gesture. Touch cancellation applies to all touch
- * points currently active on this client's surface. The client is
- * responsible for finalizing the touch points, future touch points
- * on this surface may reuse the touch point ID.
- */
- void (*cancel)(void *data,
- struct wl_touch *wl_touch);
- /**
- * update shape of touch point
- *
- * Sent when a touchpoint has changed its shape.
- *
- * This event does not occur on its own. It is sent before a
- * wl_touch.frame event and carries the new shape information for
- * any previously reported, or new touch points of that frame.
- *
- * Other events describing the touch point such as wl_touch.down,
- * wl_touch.motion or wl_touch.orientation may be sent within the
- * same wl_touch.frame. A client should treat these events as a
- * single logical touch point update. The order of wl_touch.shape,
- * wl_touch.orientation and wl_touch.motion is not guaranteed. A
- * wl_touch.down event is guaranteed to occur before the first
- * wl_touch.shape event for this touch ID but both events may occur
- * within the same wl_touch.frame.
- *
- * A touchpoint shape is approximated by an ellipse through the
- * major and minor axis length. The major axis length describes the
- * longer diameter of the ellipse, while the minor axis length
- * describes the shorter diameter. Major and minor are orthogonal
- * and both are specified in surface-local coordinates. The center
- * of the ellipse is always at the touchpoint location as reported
- * by wl_touch.down or wl_touch.move.
- *
- * This event is only sent by the compositor if the touch device
- * supports shape reports. The client has to make reasonable
- * assumptions about the shape if it did not receive this event.
- * @param id the unique ID of this touch point
- * @param major length of the major axis in surface-local coordinates
- * @param minor length of the minor axis in surface-local coordinates
- * @since 6
- */
- void (*shape)(void *data,
- struct wl_touch *wl_touch,
- int32_t id,
- wl_fixed_t major,
- wl_fixed_t minor);
- /**
- * update orientation of touch point
- *
- * Sent when a touchpoint has changed its orientation.
- *
- * This event does not occur on its own. It is sent before a
- * wl_touch.frame event and carries the new shape information for
- * any previously reported, or new touch points of that frame.
- *
- * Other events describing the touch point such as wl_touch.down,
- * wl_touch.motion or wl_touch.shape may be sent within the same
- * wl_touch.frame. A client should treat these events as a single
- * logical touch point update. The order of wl_touch.shape,
- * wl_touch.orientation and wl_touch.motion is not guaranteed. A
- * wl_touch.down event is guaranteed to occur before the first
- * wl_touch.orientation event for this touch ID but both events may
- * occur within the same wl_touch.frame.
- *
- * The orientation describes the clockwise angle of a touchpoint's
- * major axis to the positive surface y-axis and is normalized to
- * the -180 to +180 degree range. The granularity of orientation
- * depends on the touch device, some devices only support binary
- * rotation values between 0 and 90 degrees.
- *
- * This event is only sent by the compositor if the touch device
- * supports orientation reports.
- * @param id the unique ID of this touch point
- * @param orientation angle between major axis and positive surface y-axis in degrees
- * @since 6
- */
- void (*orientation)(void *data,
- struct wl_touch *wl_touch,
- int32_t id,
- wl_fixed_t orientation);
-};
-
-/**
- * @ingroup iface_wl_touch
- */
-static inline int
-wl_touch_add_listener(struct wl_touch *wl_touch,
- const struct wl_touch_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_touch,
- (void (**)(void)) listener, data);
-}
-
-#define WL_TOUCH_RELEASE 0
-
-/**
- * @ingroup iface_wl_touch
- */
-#define WL_TOUCH_DOWN_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_touch
- */
-#define WL_TOUCH_UP_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_touch
- */
-#define WL_TOUCH_MOTION_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_touch
- */
-#define WL_TOUCH_FRAME_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_touch
- */
-#define WL_TOUCH_CANCEL_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_touch
- */
-#define WL_TOUCH_SHAPE_SINCE_VERSION 6
-/**
- * @ingroup iface_wl_touch
- */
-#define WL_TOUCH_ORIENTATION_SINCE_VERSION 6
-
-/**
- * @ingroup iface_wl_touch
- */
-#define WL_TOUCH_RELEASE_SINCE_VERSION 3
-
-/** @ingroup iface_wl_touch */
-static inline void
-wl_touch_set_user_data(struct wl_touch *wl_touch, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_touch, user_data);
-}
-
-/** @ingroup iface_wl_touch */
-static inline void *
-wl_touch_get_user_data(struct wl_touch *wl_touch)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_touch);
-}
-
-static inline uint32_t
-wl_touch_get_version(struct wl_touch *wl_touch)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_touch);
-}
-
-/** @ingroup iface_wl_touch */
-static inline void
-wl_touch_destroy(struct wl_touch *wl_touch)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_touch);
-}
-
-/**
- * @ingroup iface_wl_touch
- */
-static inline void
-wl_touch_release(struct wl_touch *wl_touch)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_touch,
- WL_TOUCH_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_touch), WL_MARSHAL_FLAG_DESTROY);
-}
-
-#ifndef WL_OUTPUT_SUBPIXEL_ENUM
-#define WL_OUTPUT_SUBPIXEL_ENUM
-/**
- * @ingroup iface_wl_output
- * subpixel geometry information
- *
- * This enumeration describes how the physical
- * pixels on an output are laid out.
- */
-enum wl_output_subpixel {
- /**
- * unknown geometry
- */
- WL_OUTPUT_SUBPIXEL_UNKNOWN = 0,
- /**
- * no geometry
- */
- WL_OUTPUT_SUBPIXEL_NONE = 1,
- /**
- * horizontal RGB
- */
- WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2,
- /**
- * horizontal BGR
- */
- WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3,
- /**
- * vertical RGB
- */
- WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4,
- /**
- * vertical BGR
- */
- WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5,
-};
-#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
-
-#ifndef WL_OUTPUT_TRANSFORM_ENUM
-#define WL_OUTPUT_TRANSFORM_ENUM
-/**
- * @ingroup iface_wl_output
- * transform from framebuffer to output
- *
- * This describes the transform that a compositor will apply to a
- * surface to compensate for the rotation or mirroring of an
- * output device.
- *
- * The flipped values correspond to an initial flip around a
- * vertical axis followed by rotation.
- *
- * The purpose is mainly to allow clients to render accordingly and
- * tell the compositor, so that for fullscreen surfaces, the
- * compositor will still be able to scan out directly from client
- * surfaces.
- */
-enum wl_output_transform {
- /**
- * no transform
- */
- WL_OUTPUT_TRANSFORM_NORMAL = 0,
- /**
- * 90 degrees counter-clockwise
- */
- WL_OUTPUT_TRANSFORM_90 = 1,
- /**
- * 180 degrees counter-clockwise
- */
- WL_OUTPUT_TRANSFORM_180 = 2,
- /**
- * 270 degrees counter-clockwise
- */
- WL_OUTPUT_TRANSFORM_270 = 3,
- /**
- * 180 degree flip around a vertical axis
- */
- WL_OUTPUT_TRANSFORM_FLIPPED = 4,
- /**
- * flip and rotate 90 degrees counter-clockwise
- */
- WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5,
- /**
- * flip and rotate 180 degrees counter-clockwise
- */
- WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6,
- /**
- * flip and rotate 270 degrees counter-clockwise
- */
- WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7,
-};
-#endif /* WL_OUTPUT_TRANSFORM_ENUM */
-
-#ifndef WL_OUTPUT_MODE_ENUM
-#define WL_OUTPUT_MODE_ENUM
-/**
- * @ingroup iface_wl_output
- * mode information
- *
- * These flags describe properties of an output mode.
- * They are used in the flags bitfield of the mode event.
- */
-enum wl_output_mode {
- /**
- * indicates this is the current mode
- */
- WL_OUTPUT_MODE_CURRENT = 0x1,
- /**
- * indicates this is the preferred mode
- */
- WL_OUTPUT_MODE_PREFERRED = 0x2,
-};
-#endif /* WL_OUTPUT_MODE_ENUM */
-
-/**
- * @ingroup iface_wl_output
- * @struct wl_output_listener
- */
-struct wl_output_listener {
- /**
- * properties of the output
- *
- * The geometry event describes geometric properties of the
- * output. The event is sent when binding to the output object and
- * whenever any of the properties change.
- *
- * The physical size can be set to zero if it doesn't make sense
- * for this output (e.g. for projectors or virtual outputs).
- *
- * The geometry event will be followed by a done event (starting
- * from version 2).
- *
- * Note: wl_output only advertises partial information about the
- * output position and identification. Some compositors, for
- * instance those not implementing a desktop-style output layout or
- * those exposing virtual outputs, might fake this information.
- * Instead of using x and y, clients should use
- * xdg_output.logical_position. Instead of using make and model,
- * clients should use name and description.
- * @param x x position within the global compositor space
- * @param y y position within the global compositor space
- * @param physical_width width in millimeters of the output
- * @param physical_height height in millimeters of the output
- * @param subpixel subpixel orientation of the output
- * @param make textual description of the manufacturer
- * @param model textual description of the model
- * @param transform transform that maps framebuffer to output
- */
- void (*geometry)(void *data,
- struct wl_output *wl_output,
- int32_t x,
- int32_t y,
- int32_t physical_width,
- int32_t physical_height,
- int32_t subpixel,
- const char *make,
- const char *model,
- int32_t transform);
- /**
- * advertise available modes for the output
- *
- * The mode event describes an available mode for the output.
- *
- * The event is sent when binding to the output object and there
- * will always be one mode, the current mode. The event is sent
- * again if an output changes mode, for the mode that is now
- * current. In other words, the current mode is always the last
- * mode that was received with the current flag set.
- *
- * Non-current modes are deprecated. A compositor can decide to
- * only advertise the current mode and never send other modes.
- * Clients should not rely on non-current modes.
- *
- * The size of a mode is given in physical hardware units of the
- * output device. This is not necessarily the same as the output
- * size in the global compositor space. For instance, the output
- * may be scaled, as described in wl_output.scale, or transformed,
- * as described in wl_output.transform. Clients willing to retrieve
- * the output size in the global compositor space should use
- * xdg_output.logical_size instead.
- *
- * The vertical refresh rate can be set to zero if it doesn't make
- * sense for this output (e.g. for virtual outputs).
- *
- * The mode event will be followed by a done event (starting from
- * version 2).
- *
- * Clients should not use the refresh rate to schedule frames.
- * Instead, they should use the wl_surface.frame event or the
- * presentation-time protocol.
- *
- * Note: this information is not always meaningful for all outputs.
- * Some compositors, such as those exposing virtual outputs, might
- * fake the refresh rate or the size.
- * @param flags bitfield of mode flags
- * @param width width of the mode in hardware units
- * @param height height of the mode in hardware units
- * @param refresh vertical refresh rate in mHz
- */
- void (*mode)(void *data,
- struct wl_output *wl_output,
- uint32_t flags,
- int32_t width,
- int32_t height,
- int32_t refresh);
- /**
- * sent all information about output
- *
- * This event is sent after all other properties have been sent
- * after binding to the output object and after any other property
- * changes done after that. This allows changes to the output
- * properties to be seen as atomic, even if they happen via
- * multiple events.
- * @since 2
- */
- void (*done)(void *data,
- struct wl_output *wl_output);
- /**
- * output scaling properties
- *
- * This event contains scaling geometry information that is not
- * in the geometry event. It may be sent after binding the output
- * object or if the output scale changes later. If it is not sent,
- * the client should assume a scale of 1.
- *
- * A scale larger than 1 means that the compositor will
- * automatically scale surface buffers by this amount when
- * rendering. This is used for very high resolution displays where
- * applications rendering at the native resolution would be too
- * small to be legible.
- *
- * It is intended that scaling aware clients track the current
- * output of a surface, and if it is on a scaled output it should
- * use wl_surface.set_buffer_scale with the scale of the output.
- * That way the compositor can avoid scaling the surface, and the
- * client can supply a higher detail image.
- *
- * The scale event will be followed by a done event.
- * @param factor scaling factor of output
- * @since 2
- */
- void (*scale)(void *data,
- struct wl_output *wl_output,
- int32_t factor);
- /**
- * name of this output
- *
- * Many compositors will assign user-friendly names to their
- * outputs, show them to the user, allow the user to refer to an
- * output, etc. The client may wish to know this name as well to
- * offer the user similar behaviors.
- *
- * The name is a UTF-8 string with no convention defined for its
- * contents. Each name is unique among all wl_output globals. The
- * name is only guaranteed to be unique for the compositor
- * instance.
- *
- * The same output name is used for all clients for a given
- * wl_output global. Thus, the name can be shared across processes
- * to refer to a specific wl_output global.
- *
- * The name is not guaranteed to be persistent across sessions,
- * thus cannot be used to reliably identify an output in e.g.
- * configuration files.
- *
- * Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc.
- * However, do not assume that the name is a reflection of an
- * underlying DRM connector, X11 connection, etc.
- *
- * The name event is sent after binding the output object. This
- * event is only sent once per output object, and the name does not
- * change over the lifetime of the wl_output global.
- *
- * Compositors may re-use the same output name if the wl_output
- * global is destroyed and re-created later. Compositors should
- * avoid re-using the same name if possible.
- *
- * The name event will be followed by a done event.
- * @param name output name
- * @since 4
- */
- void (*name)(void *data,
- struct wl_output *wl_output,
- const char *name);
- /**
- * human-readable description of this output
- *
- * Many compositors can produce human-readable descriptions of
- * their outputs. The client may wish to know this description as
- * well, e.g. for output selection purposes.
- *
- * The description is a UTF-8 string with no convention defined for
- * its contents. The description is not guaranteed to be unique
- * among all wl_output globals. Examples might include 'Foocorp 11"
- * Display' or 'Virtual X11 output via :1'.
- *
- * The description event is sent after binding the output object
- * and whenever the description changes. The description is
- * optional, and may not be sent at all.
- *
- * The description event will be followed by a done event.
- * @param description output description
- * @since 4
- */
- void (*description)(void *data,
- struct wl_output *wl_output,
- const char *description);
-};
-
-/**
- * @ingroup iface_wl_output
- */
-static inline int
-wl_output_add_listener(struct wl_output *wl_output,
- const struct wl_output_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) wl_output,
- (void (**)(void)) listener, data);
-}
-
-#define WL_OUTPUT_RELEASE 0
-
-/**
- * @ingroup iface_wl_output
- */
-#define WL_OUTPUT_GEOMETRY_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_output
- */
-#define WL_OUTPUT_MODE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_output
- */
-#define WL_OUTPUT_DONE_SINCE_VERSION 2
-/**
- * @ingroup iface_wl_output
- */
-#define WL_OUTPUT_SCALE_SINCE_VERSION 2
-/**
- * @ingroup iface_wl_output
- */
-#define WL_OUTPUT_NAME_SINCE_VERSION 4
-/**
- * @ingroup iface_wl_output
- */
-#define WL_OUTPUT_DESCRIPTION_SINCE_VERSION 4
-
-/**
- * @ingroup iface_wl_output
- */
-#define WL_OUTPUT_RELEASE_SINCE_VERSION 3
-
-/** @ingroup iface_wl_output */
-static inline void
-wl_output_set_user_data(struct wl_output *wl_output, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_output, user_data);
-}
-
-/** @ingroup iface_wl_output */
-static inline void *
-wl_output_get_user_data(struct wl_output *wl_output)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_output);
-}
-
-static inline uint32_t
-wl_output_get_version(struct wl_output *wl_output)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_output);
-}
-
-/** @ingroup iface_wl_output */
-static inline void
-wl_output_destroy(struct wl_output *wl_output)
-{
- wl_proxy_destroy((struct wl_proxy *) wl_output);
-}
-
-/**
- * @ingroup iface_wl_output
- *
- * Using this request a client can tell the server that it is not going to
- * use the output object anymore.
- */
-static inline void
-wl_output_release(struct wl_output *wl_output)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_output,
- WL_OUTPUT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_output), WL_MARSHAL_FLAG_DESTROY);
-}
-
-#define WL_REGION_DESTROY 0
-#define WL_REGION_ADD 1
-#define WL_REGION_SUBTRACT 2
-
-
-/**
- * @ingroup iface_wl_region
- */
-#define WL_REGION_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_region
- */
-#define WL_REGION_ADD_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_region
- */
-#define WL_REGION_SUBTRACT_SINCE_VERSION 1
-
-/** @ingroup iface_wl_region */
-static inline void
-wl_region_set_user_data(struct wl_region *wl_region, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_region, user_data);
-}
-
-/** @ingroup iface_wl_region */
-static inline void *
-wl_region_get_user_data(struct wl_region *wl_region)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_region);
-}
-
-static inline uint32_t
-wl_region_get_version(struct wl_region *wl_region)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_region);
-}
-
-/**
- * @ingroup iface_wl_region
- *
- * Destroy the region. This will invalidate the object ID.
- */
-static inline void
-wl_region_destroy(struct wl_region *wl_region)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_region,
- WL_REGION_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_wl_region
- *
- * Add the specified rectangle to the region.
- */
-static inline void
-wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_region,
- WL_REGION_ADD, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height);
-}
-
-/**
- * @ingroup iface_wl_region
- *
- * Subtract the specified rectangle from the region.
- */
-static inline void
-wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_region,
- WL_REGION_SUBTRACT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height);
-}
-
-#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM
-#define WL_SUBCOMPOSITOR_ERROR_ENUM
-enum wl_subcompositor_error {
- /**
- * the to-be sub-surface is invalid
- */
- WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0,
- /**
- * the to-be sub-surface parent is invalid
- */
- WL_SUBCOMPOSITOR_ERROR_BAD_PARENT = 1,
-};
-#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
-
-#define WL_SUBCOMPOSITOR_DESTROY 0
-#define WL_SUBCOMPOSITOR_GET_SUBSURFACE 1
-
-
-/**
- * @ingroup iface_wl_subcompositor
- */
-#define WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_subcompositor
- */
-#define WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION 1
-
-/** @ingroup iface_wl_subcompositor */
-static inline void
-wl_subcompositor_set_user_data(struct wl_subcompositor *wl_subcompositor, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_subcompositor, user_data);
-}
-
-/** @ingroup iface_wl_subcompositor */
-static inline void *
-wl_subcompositor_get_user_data(struct wl_subcompositor *wl_subcompositor)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_subcompositor);
-}
-
-static inline uint32_t
-wl_subcompositor_get_version(struct wl_subcompositor *wl_subcompositor)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_subcompositor);
-}
-
-/**
- * @ingroup iface_wl_subcompositor
- *
- * Informs the server that the client will not be using this
- * protocol object anymore. This does not affect any other
- * objects, wl_subsurface objects included.
- */
-static inline void
-wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor,
- WL_SUBCOMPOSITOR_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_wl_subcompositor
- *
- * Create a sub-surface interface for the given surface, and
- * associate it with the given parent surface. This turns a
- * plain wl_surface into a sub-surface.
- *
- * The to-be sub-surface must not already have another role, and it
- * must not have an existing wl_subsurface object. Otherwise the
- * bad_surface protocol error is raised.
- *
- * Adding sub-surfaces to a parent is a double-buffered operation on the
- * parent (see wl_surface.commit). The effect of adding a sub-surface
- * becomes visible on the next time the state of the parent surface is
- * applied.
- *
- * The parent surface must not be one of the child surface's descendants,
- * and the parent must be different from the child surface, otherwise the
- * bad_parent protocol error is raised.
- *
- * This request modifies the behaviour of wl_surface.commit request on
- * the sub-surface, see the documentation on wl_subsurface interface.
- */
-static inline struct wl_subsurface *
-wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface, struct wl_surface *parent)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor,
- WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), 0, NULL, surface, parent);
-
- return (struct wl_subsurface *) id;
-}
-
-#ifndef WL_SUBSURFACE_ERROR_ENUM
-#define WL_SUBSURFACE_ERROR_ENUM
-enum wl_subsurface_error {
- /**
- * wl_surface is not a sibling or the parent
- */
- WL_SUBSURFACE_ERROR_BAD_SURFACE = 0,
-};
-#endif /* WL_SUBSURFACE_ERROR_ENUM */
-
-#define WL_SUBSURFACE_DESTROY 0
-#define WL_SUBSURFACE_SET_POSITION 1
-#define WL_SUBSURFACE_PLACE_ABOVE 2
-#define WL_SUBSURFACE_PLACE_BELOW 3
-#define WL_SUBSURFACE_SET_SYNC 4
-#define WL_SUBSURFACE_SET_DESYNC 5
-
-
-/**
- * @ingroup iface_wl_subsurface
- */
-#define WL_SUBSURFACE_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_subsurface
- */
-#define WL_SUBSURFACE_SET_POSITION_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_subsurface
- */
-#define WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_subsurface
- */
-#define WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_subsurface
- */
-#define WL_SUBSURFACE_SET_SYNC_SINCE_VERSION 1
-/**
- * @ingroup iface_wl_subsurface
- */
-#define WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION 1
-
-/** @ingroup iface_wl_subsurface */
-static inline void
-wl_subsurface_set_user_data(struct wl_subsurface *wl_subsurface, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) wl_subsurface, user_data);
-}
-
-/** @ingroup iface_wl_subsurface */
-static inline void *
-wl_subsurface_get_user_data(struct wl_subsurface *wl_subsurface)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) wl_subsurface);
-}
-
-static inline uint32_t
-wl_subsurface_get_version(struct wl_subsurface *wl_subsurface)
-{
- return wl_proxy_get_version((struct wl_proxy *) wl_subsurface);
-}
-
-/**
- * @ingroup iface_wl_subsurface
- *
- * The sub-surface interface is removed from the wl_surface object
- * that was turned into a sub-surface with a
- * wl_subcompositor.get_subsurface request. The wl_surface's association
- * to the parent is deleted. The wl_surface is unmapped immediately.
- */
-static inline void
-wl_subsurface_destroy(struct wl_subsurface *wl_subsurface)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_wl_subsurface
- *
- * This schedules a sub-surface position change.
- * The sub-surface will be moved so that its origin (top left
- * corner pixel) will be at the location x, y of the parent surface
- * coordinate system. The coordinates are not restricted to the parent
- * surface area. Negative values are allowed.
- *
- * The scheduled coordinates will take effect whenever the state of the
- * parent surface is applied. When this happens depends on whether the
- * parent surface is in synchronized mode or not. See
- * wl_subsurface.set_sync and wl_subsurface.set_desync for details.
- *
- * If more than one set_position request is invoked by the client before
- * the commit of the parent surface, the position of a new request always
- * replaces the scheduled position from any previous request.
- *
- * The initial position is 0, 0.
- */
-static inline void
-wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_SET_POSITION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, x, y);
-}
-
-/**
- * @ingroup iface_wl_subsurface
- *
- * This sub-surface is taken from the stack, and put back just
- * above the reference surface, changing the z-order of the sub-surfaces.
- * The reference surface must be one of the sibling surfaces, or the
- * parent surface. Using any other surface, including this sub-surface,
- * will cause a protocol error.
- *
- * The z-order is double-buffered. Requests are handled in order and
- * applied immediately to a pending state. The final pending state is
- * copied to the active state the next time the state of the parent
- * surface is applied. When this happens depends on whether the parent
- * surface is in synchronized mode or not. See wl_subsurface.set_sync and
- * wl_subsurface.set_desync for details.
- *
- * A new sub-surface is initially added as the top-most in the stack
- * of its siblings and parent.
- */
-static inline void
-wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_PLACE_ABOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling);
-}
-
-/**
- * @ingroup iface_wl_subsurface
- *
- * The sub-surface is placed just below the reference surface.
- * See wl_subsurface.place_above.
- */
-static inline void
-wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_PLACE_BELOW, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling);
-}
-
-/**
- * @ingroup iface_wl_subsurface
- *
- * Change the commit behaviour of the sub-surface to synchronized
- * mode, also described as the parent dependent mode.
- *
- * In synchronized mode, wl_surface.commit on a sub-surface will
- * accumulate the committed state in a cache, but the state will
- * not be applied and hence will not change the compositor output.
- * The cached state is applied to the sub-surface immediately after
- * the parent surface's state is applied. This ensures atomic
- * updates of the parent and all its synchronized sub-surfaces.
- * Applying the cached state will invalidate the cache, so further
- * parent surface commits do not (re-)apply old state.
- *
- * See wl_subsurface for the recursive effect of this mode.
- */
-static inline void
-wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_SET_SYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0);
-}
-
-/**
- * @ingroup iface_wl_subsurface
- *
- * Change the commit behaviour of the sub-surface to desynchronized
- * mode, also described as independent or freely running mode.
- *
- * In desynchronized mode, wl_surface.commit on a sub-surface will
- * apply the pending state directly, without caching, as happens
- * normally with a wl_surface. Calling wl_surface.commit on the
- * parent surface has no effect on the sub-surface's wl_surface
- * state. This mode allows a sub-surface to be updated on its own.
- *
- * If cached state exists when wl_surface.commit is called in
- * desynchronized mode, the pending state is added to the cached
- * state, and applied as a whole. This invalidates the cache.
- *
- * Note: even if a sub-surface is set to desynchronized, a parent
- * sub-surface may override it to behave as synchronized. For details,
- * see wl_subsurface.
- *
- * If a surface's parent surface behaves as desynchronized, then
- * the cached state is applied on set_desync.
- */
-static inline void
-wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_SET_DESYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol-code.h
deleted file mode 100644
index ceece5a2b..000000000
--- a/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol-code.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-/*
- * Copyright © 2020 Aleix Pol Gonzalez
- * Copyright © 2020 Carlos Garnacho
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include
-#include
-#include
-#include "wayland-util.h"
-
-#ifndef __has_attribute
-# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
-#endif
-
-#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
-#define WL_PRIVATE __attribute__ ((visibility("hidden")))
-#else
-#define WL_PRIVATE
-#endif
-
-extern const struct wl_interface wl_seat_interface;
-extern const struct wl_interface wl_surface_interface;
-extern const struct wl_interface xdg_activation_token_v1_interface;
-
-static const struct wl_interface *xdg_activation_v1_types[] = {
- NULL,
- &xdg_activation_token_v1_interface,
- NULL,
- &wl_surface_interface,
- NULL,
- &wl_seat_interface,
- &wl_surface_interface,
-};
-
-static const struct wl_message xdg_activation_v1_requests[] = {
- { "destroy", "", xdg_activation_v1_types + 0 },
- { "get_activation_token", "n", xdg_activation_v1_types + 1 },
- { "activate", "so", xdg_activation_v1_types + 2 },
-};
-
-WL_PRIVATE const struct wl_interface xdg_activation_v1_interface = {
- "xdg_activation_v1", 1,
- 3, xdg_activation_v1_requests,
- 0, NULL,
-};
-
-static const struct wl_message xdg_activation_token_v1_requests[] = {
- { "set_serial", "uo", xdg_activation_v1_types + 4 },
- { "set_app_id", "s", xdg_activation_v1_types + 0 },
- { "set_surface", "o", xdg_activation_v1_types + 6 },
- { "commit", "", xdg_activation_v1_types + 0 },
- { "destroy", "", xdg_activation_v1_types + 0 },
-};
-
-static const struct wl_message xdg_activation_token_v1_events[] = {
- { "done", "s", xdg_activation_v1_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface xdg_activation_token_v1_interface = {
- "xdg_activation_token_v1", 1,
- 5, xdg_activation_token_v1_requests,
- 1, xdg_activation_token_v1_events,
-};
-
diff --git a/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol.h b/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol.h
deleted file mode 100644
index b26c548c9..000000000
--- a/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol.h
+++ /dev/null
@@ -1,415 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-#ifndef XDG_ACTIVATION_V1_CLIENT_PROTOCOL_H
-#define XDG_ACTIVATION_V1_CLIENT_PROTOCOL_H
-
-#include
-#include
-#include "wayland-client.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @page page_xdg_activation_v1 The xdg_activation_v1 protocol
- * Protocol for requesting activation of surfaces
- *
- * @section page_desc_xdg_activation_v1 Description
- *
- * The way for a client to pass focus to another toplevel is as follows.
- *
- * The client that intends to activate another toplevel uses the
- * xdg_activation_v1.get_activation_token request to get an activation token.
- * This token is then forwarded to the client, which is supposed to activate
- * one of its surfaces, through a separate band of communication.
- *
- * One established way of doing this is through the XDG_ACTIVATION_TOKEN
- * environment variable of a newly launched child process. The child process
- * should unset the environment variable again right after reading it out in
- * order to avoid propagating it to other child processes.
- *
- * Another established way exists for Applications implementing the D-Bus
- * interface org.freedesktop.Application, which should get their token under
- * activation-token on their platform_data.
- *
- * In general activation tokens may be transferred across clients through
- * means not described in this protocol.
- *
- * The client to be activated will then pass the token
- * it received to the xdg_activation_v1.activate request. The compositor can
- * then use this token to decide how to react to the activation request.
- *
- * The token the activating client gets may be ineffective either already at
- * the time it receives it, for example if it was not focused, for focus
- * stealing prevention. The activating client will have no way to discover
- * the validity of the token, and may still forward it to the to be activated
- * client.
- *
- * The created activation token may optionally get information attached to it
- * that can be used by the compositor to identify the application that we
- * intend to activate. This can for example be used to display a visual hint
- * about what application is being started.
- *
- * Warning! The protocol described in this file is currently in the testing
- * phase. Backward compatible changes may be added together with the
- * corresponding interface version bump. Backward incompatible changes can
- * only be done by creating a new major version of the extension.
- *
- * @section page_ifaces_xdg_activation_v1 Interfaces
- * - @subpage page_iface_xdg_activation_v1 - interface for activating surfaces
- * - @subpage page_iface_xdg_activation_token_v1 - an exported activation handle
- * @section page_copyright_xdg_activation_v1 Copyright
- *
- *
- * Copyright © 2020 Aleix Pol Gonzalez
- * Copyright © 2020 Carlos Garnacho
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- */
-struct wl_seat;
-struct wl_surface;
-struct xdg_activation_token_v1;
-struct xdg_activation_v1;
-
-#ifndef XDG_ACTIVATION_V1_INTERFACE
-#define XDG_ACTIVATION_V1_INTERFACE
-/**
- * @page page_iface_xdg_activation_v1 xdg_activation_v1
- * @section page_iface_xdg_activation_v1_desc Description
- *
- * A global interface used for informing the compositor about applications
- * being activated or started, or for applications to request to be
- * activated.
- * @section page_iface_xdg_activation_v1_api API
- * See @ref iface_xdg_activation_v1.
- */
-/**
- * @defgroup iface_xdg_activation_v1 The xdg_activation_v1 interface
- *
- * A global interface used for informing the compositor about applications
- * being activated or started, or for applications to request to be
- * activated.
- */
-extern const struct wl_interface xdg_activation_v1_interface;
-#endif
-#ifndef XDG_ACTIVATION_TOKEN_V1_INTERFACE
-#define XDG_ACTIVATION_TOKEN_V1_INTERFACE
-/**
- * @page page_iface_xdg_activation_token_v1 xdg_activation_token_v1
- * @section page_iface_xdg_activation_token_v1_desc Description
- *
- * An object for setting up a token and receiving a token handle that can
- * be passed as an activation token to another client.
- *
- * The object is created using the xdg_activation_v1.get_activation_token
- * request. This object should then be populated with the app_id, surface
- * and serial information and committed. The compositor shall then issue a
- * done event with the token. In case the request's parameters are invalid,
- * the compositor will provide an invalid token.
- * @section page_iface_xdg_activation_token_v1_api API
- * See @ref iface_xdg_activation_token_v1.
- */
-/**
- * @defgroup iface_xdg_activation_token_v1 The xdg_activation_token_v1 interface
- *
- * An object for setting up a token and receiving a token handle that can
- * be passed as an activation token to another client.
- *
- * The object is created using the xdg_activation_v1.get_activation_token
- * request. This object should then be populated with the app_id, surface
- * and serial information and committed. The compositor shall then issue a
- * done event with the token. In case the request's parameters are invalid,
- * the compositor will provide an invalid token.
- */
-extern const struct wl_interface xdg_activation_token_v1_interface;
-#endif
-
-#define XDG_ACTIVATION_V1_DESTROY 0
-#define XDG_ACTIVATION_V1_GET_ACTIVATION_TOKEN 1
-#define XDG_ACTIVATION_V1_ACTIVATE 2
-
-
-/**
- * @ingroup iface_xdg_activation_v1
- */
-#define XDG_ACTIVATION_V1_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_activation_v1
- */
-#define XDG_ACTIVATION_V1_GET_ACTIVATION_TOKEN_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_activation_v1
- */
-#define XDG_ACTIVATION_V1_ACTIVATE_SINCE_VERSION 1
-
-/** @ingroup iface_xdg_activation_v1 */
-static inline void
-xdg_activation_v1_set_user_data(struct xdg_activation_v1 *xdg_activation_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) xdg_activation_v1, user_data);
-}
-
-/** @ingroup iface_xdg_activation_v1 */
-static inline void *
-xdg_activation_v1_get_user_data(struct xdg_activation_v1 *xdg_activation_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) xdg_activation_v1);
-}
-
-static inline uint32_t
-xdg_activation_v1_get_version(struct xdg_activation_v1 *xdg_activation_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1);
-}
-
-/**
- * @ingroup iface_xdg_activation_v1
- *
- * Notify the compositor that the xdg_activation object will no longer be
- * used.
- *
- * The child objects created via this interface are unaffected and should
- * be destroyed separately.
- */
-static inline void
-xdg_activation_v1_destroy(struct xdg_activation_v1 *xdg_activation_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_v1,
- XDG_ACTIVATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_xdg_activation_v1
- *
- * Creates an xdg_activation_token_v1 object that will provide
- * the initiating client with a unique token for this activation. This
- * token should be offered to the clients to be activated.
- */
-static inline struct xdg_activation_token_v1 *
-xdg_activation_v1_get_activation_token(struct xdg_activation_v1 *xdg_activation_v1)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_v1,
- XDG_ACTIVATION_V1_GET_ACTIVATION_TOKEN, &xdg_activation_token_v1_interface, wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1), 0, NULL);
-
- return (struct xdg_activation_token_v1 *) id;
-}
-
-/**
- * @ingroup iface_xdg_activation_v1
- *
- * Requests surface activation. It's up to the compositor to display
- * this information as desired, for example by placing the surface above
- * the rest.
- *
- * The compositor may know who requested this by checking the activation
- * token and might decide not to follow through with the activation if it's
- * considered unwanted.
- *
- * Compositors can ignore unknown activation tokens when an invalid
- * token is passed.
- */
-static inline void
-xdg_activation_v1_activate(struct xdg_activation_v1 *xdg_activation_v1, const char *token, struct wl_surface *surface)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_v1,
- XDG_ACTIVATION_V1_ACTIVATE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1), 0, token, surface);
-}
-
-#ifndef XDG_ACTIVATION_TOKEN_V1_ERROR_ENUM
-#define XDG_ACTIVATION_TOKEN_V1_ERROR_ENUM
-enum xdg_activation_token_v1_error {
- /**
- * The token has already been used previously
- */
- XDG_ACTIVATION_TOKEN_V1_ERROR_ALREADY_USED = 0,
-};
-#endif /* XDG_ACTIVATION_TOKEN_V1_ERROR_ENUM */
-
-/**
- * @ingroup iface_xdg_activation_token_v1
- * @struct xdg_activation_token_v1_listener
- */
-struct xdg_activation_token_v1_listener {
- /**
- * the exported activation token
- *
- * The 'done' event contains the unique token of this activation
- * request and notifies that the provider is done.
- * @param token the exported activation token
- */
- void (*done)(void *data,
- struct xdg_activation_token_v1 *xdg_activation_token_v1,
- const char *token);
-};
-
-/**
- * @ingroup iface_xdg_activation_token_v1
- */
-static inline int
-xdg_activation_token_v1_add_listener(struct xdg_activation_token_v1 *xdg_activation_token_v1,
- const struct xdg_activation_token_v1_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) xdg_activation_token_v1,
- (void (**)(void)) listener, data);
-}
-
-#define XDG_ACTIVATION_TOKEN_V1_SET_SERIAL 0
-#define XDG_ACTIVATION_TOKEN_V1_SET_APP_ID 1
-#define XDG_ACTIVATION_TOKEN_V1_SET_SURFACE 2
-#define XDG_ACTIVATION_TOKEN_V1_COMMIT 3
-#define XDG_ACTIVATION_TOKEN_V1_DESTROY 4
-
-/**
- * @ingroup iface_xdg_activation_token_v1
- */
-#define XDG_ACTIVATION_TOKEN_V1_DONE_SINCE_VERSION 1
-
-/**
- * @ingroup iface_xdg_activation_token_v1
- */
-#define XDG_ACTIVATION_TOKEN_V1_SET_SERIAL_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_activation_token_v1
- */
-#define XDG_ACTIVATION_TOKEN_V1_SET_APP_ID_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_activation_token_v1
- */
-#define XDG_ACTIVATION_TOKEN_V1_SET_SURFACE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_activation_token_v1
- */
-#define XDG_ACTIVATION_TOKEN_V1_COMMIT_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_activation_token_v1
- */
-#define XDG_ACTIVATION_TOKEN_V1_DESTROY_SINCE_VERSION 1
-
-/** @ingroup iface_xdg_activation_token_v1 */
-static inline void
-xdg_activation_token_v1_set_user_data(struct xdg_activation_token_v1 *xdg_activation_token_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) xdg_activation_token_v1, user_data);
-}
-
-/** @ingroup iface_xdg_activation_token_v1 */
-static inline void *
-xdg_activation_token_v1_get_user_data(struct xdg_activation_token_v1 *xdg_activation_token_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) xdg_activation_token_v1);
-}
-
-static inline uint32_t
-xdg_activation_token_v1_get_version(struct xdg_activation_token_v1 *xdg_activation_token_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1);
-}
-
-/**
- * @ingroup iface_xdg_activation_token_v1
- *
- * Provides information about the seat and serial event that requested the
- * token.
- *
- * The serial can come from an input or focus event. For instance, if a
- * click triggers the launch of a third-party client, the launcher client
- * should send a set_serial request with the serial and seat from the
- * wl_pointer.button event.
- *
- * Some compositors might refuse to activate toplevels when the token
- * doesn't have a valid and recent enough event serial.
- *
- * Must be sent before commit. This information is optional.
- */
-static inline void
-xdg_activation_token_v1_set_serial(struct xdg_activation_token_v1 *xdg_activation_token_v1, uint32_t serial, struct wl_seat *seat)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1,
- XDG_ACTIVATION_TOKEN_V1_SET_SERIAL, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0, serial, seat);
-}
-
-/**
- * @ingroup iface_xdg_activation_token_v1
- *
- * The requesting client can specify an app_id to associate the token
- * being created with it.
- *
- * Must be sent before commit. This information is optional.
- */
-static inline void
-xdg_activation_token_v1_set_app_id(struct xdg_activation_token_v1 *xdg_activation_token_v1, const char *app_id)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1,
- XDG_ACTIVATION_TOKEN_V1_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0, app_id);
-}
-
-/**
- * @ingroup iface_xdg_activation_token_v1
- *
- * This request sets the surface requesting the activation. Note, this is
- * different from the surface that will be activated.
- *
- * Some compositors might refuse to activate toplevels when the token
- * doesn't have a requesting surface.
- *
- * Must be sent before commit. This information is optional.
- */
-static inline void
-xdg_activation_token_v1_set_surface(struct xdg_activation_token_v1 *xdg_activation_token_v1, struct wl_surface *surface)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1,
- XDG_ACTIVATION_TOKEN_V1_SET_SURFACE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0, surface);
-}
-
-/**
- * @ingroup iface_xdg_activation_token_v1
- *
- * Requests an activation token based on the different parameters that
- * have been offered through set_serial, set_surface and set_app_id.
- */
-static inline void
-xdg_activation_token_v1_commit(struct xdg_activation_token_v1 *xdg_activation_token_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1,
- XDG_ACTIVATION_TOKEN_V1_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0);
-}
-
-/**
- * @ingroup iface_xdg_activation_token_v1
- *
- * Notify the compositor that the xdg_activation_token_v1 object will no
- * longer be used. The received token stays valid.
- */
-static inline void
-xdg_activation_token_v1_destroy(struct xdg_activation_token_v1 *xdg_activation_token_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1,
- XDG_ACTIVATION_TOKEN_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol-code.h
deleted file mode 100644
index 85496afa3..000000000
--- a/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol-code.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-/*
- * Copyright © 2018 Simon Ser
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include
-#include
-#include
-#include "wayland-util.h"
-
-#ifndef __has_attribute
-# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
-#endif
-
-#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
-#define WL_PRIVATE __attribute__ ((visibility("hidden")))
-#else
-#define WL_PRIVATE
-#endif
-
-extern const struct wl_interface xdg_toplevel_interface;
-extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
-
-static const struct wl_interface *xdg_decoration_unstable_v1_types[] = {
- NULL,
- &zxdg_toplevel_decoration_v1_interface,
- &xdg_toplevel_interface,
-};
-
-static const struct wl_message zxdg_decoration_manager_v1_requests[] = {
- { "destroy", "", xdg_decoration_unstable_v1_types + 0 },
- { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 },
-};
-
-WL_PRIVATE const struct wl_interface zxdg_decoration_manager_v1_interface = {
- "zxdg_decoration_manager_v1", 1,
- 2, zxdg_decoration_manager_v1_requests,
- 0, NULL,
-};
-
-static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = {
- { "destroy", "", xdg_decoration_unstable_v1_types + 0 },
- { "set_mode", "u", xdg_decoration_unstable_v1_types + 0 },
- { "unset_mode", "", xdg_decoration_unstable_v1_types + 0 },
-};
-
-static const struct wl_message zxdg_toplevel_decoration_v1_events[] = {
- { "configure", "u", xdg_decoration_unstable_v1_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface zxdg_toplevel_decoration_v1_interface = {
- "zxdg_toplevel_decoration_v1", 1,
- 3, zxdg_toplevel_decoration_v1_requests,
- 1, zxdg_toplevel_decoration_v1_events,
-};
-
diff --git a/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol.h b/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol.h
deleted file mode 100644
index 1aa6a0db1..000000000
--- a/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol.h
+++ /dev/null
@@ -1,378 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-#ifndef XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H
-#define XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H
-
-#include
-#include
-#include "wayland-client.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @page page_xdg_decoration_unstable_v1 The xdg_decoration_unstable_v1 protocol
- * @section page_ifaces_xdg_decoration_unstable_v1 Interfaces
- * - @subpage page_iface_zxdg_decoration_manager_v1 - window decoration manager
- * - @subpage page_iface_zxdg_toplevel_decoration_v1 - decoration object for a toplevel surface
- * @section page_copyright_xdg_decoration_unstable_v1 Copyright
- *
- *
- * Copyright © 2018 Simon Ser
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- */
-struct xdg_toplevel;
-struct zxdg_decoration_manager_v1;
-struct zxdg_toplevel_decoration_v1;
-
-#ifndef ZXDG_DECORATION_MANAGER_V1_INTERFACE
-#define ZXDG_DECORATION_MANAGER_V1_INTERFACE
-/**
- * @page page_iface_zxdg_decoration_manager_v1 zxdg_decoration_manager_v1
- * @section page_iface_zxdg_decoration_manager_v1_desc Description
- *
- * This interface allows a compositor to announce support for server-side
- * decorations.
- *
- * A window decoration is a set of window controls as deemed appropriate by
- * the party managing them, such as user interface components used to move,
- * resize and change a window's state.
- *
- * A client can use this protocol to request being decorated by a supporting
- * compositor.
- *
- * If compositor and client do not negotiate the use of a server-side
- * decoration using this protocol, clients continue to self-decorate as they
- * see fit.
- *
- * Warning! The protocol described in this file is experimental and
- * backward incompatible changes may be made. Backward compatible changes
- * may be added together with the corresponding interface version bump.
- * Backward incompatible changes are done by bumping the version number in
- * the protocol and interface names and resetting the interface version.
- * Once the protocol is to be declared stable, the 'z' prefix and the
- * version number in the protocol and interface names are removed and the
- * interface version number is reset.
- * @section page_iface_zxdg_decoration_manager_v1_api API
- * See @ref iface_zxdg_decoration_manager_v1.
- */
-/**
- * @defgroup iface_zxdg_decoration_manager_v1 The zxdg_decoration_manager_v1 interface
- *
- * This interface allows a compositor to announce support for server-side
- * decorations.
- *
- * A window decoration is a set of window controls as deemed appropriate by
- * the party managing them, such as user interface components used to move,
- * resize and change a window's state.
- *
- * A client can use this protocol to request being decorated by a supporting
- * compositor.
- *
- * If compositor and client do not negotiate the use of a server-side
- * decoration using this protocol, clients continue to self-decorate as they
- * see fit.
- *
- * Warning! The protocol described in this file is experimental and
- * backward incompatible changes may be made. Backward compatible changes
- * may be added together with the corresponding interface version bump.
- * Backward incompatible changes are done by bumping the version number in
- * the protocol and interface names and resetting the interface version.
- * Once the protocol is to be declared stable, the 'z' prefix and the
- * version number in the protocol and interface names are removed and the
- * interface version number is reset.
- */
-extern const struct wl_interface zxdg_decoration_manager_v1_interface;
-#endif
-#ifndef ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE
-#define ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE
-/**
- * @page page_iface_zxdg_toplevel_decoration_v1 zxdg_toplevel_decoration_v1
- * @section page_iface_zxdg_toplevel_decoration_v1_desc Description
- *
- * The decoration object allows the compositor to toggle server-side window
- * decorations for a toplevel surface. The client can request to switch to
- * another mode.
- *
- * The xdg_toplevel_decoration object must be destroyed before its
- * xdg_toplevel.
- * @section page_iface_zxdg_toplevel_decoration_v1_api API
- * See @ref iface_zxdg_toplevel_decoration_v1.
- */
-/**
- * @defgroup iface_zxdg_toplevel_decoration_v1 The zxdg_toplevel_decoration_v1 interface
- *
- * The decoration object allows the compositor to toggle server-side window
- * decorations for a toplevel surface. The client can request to switch to
- * another mode.
- *
- * The xdg_toplevel_decoration object must be destroyed before its
- * xdg_toplevel.
- */
-extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
-#endif
-
-#define ZXDG_DECORATION_MANAGER_V1_DESTROY 0
-#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION 1
-
-
-/**
- * @ingroup iface_zxdg_decoration_manager_v1
- */
-#define ZXDG_DECORATION_MANAGER_V1_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_zxdg_decoration_manager_v1
- */
-#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION_SINCE_VERSION 1
-
-/** @ingroup iface_zxdg_decoration_manager_v1 */
-static inline void
-zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data);
-}
-
-/** @ingroup iface_zxdg_decoration_manager_v1 */
-static inline void *
-zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1);
-}
-
-static inline uint32_t
-zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1);
-}
-
-/**
- * @ingroup iface_zxdg_decoration_manager_v1
- *
- * Destroy the decoration manager. This doesn't destroy objects created
- * with the manager.
- */
-static inline void
-zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1,
- ZXDG_DECORATION_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_zxdg_decoration_manager_v1
- *
- * Create a new decoration object associated with the given toplevel.
- *
- * Creating an xdg_toplevel_decoration from an xdg_toplevel which has a
- * buffer attached or committed is a client error, and any attempts by a
- * client to attach or manipulate a buffer prior to the first
- * xdg_toplevel_decoration.configure event must also be treated as
- * errors.
- */
-static inline struct zxdg_toplevel_decoration_v1 *
-zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1,
- ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, &zxdg_toplevel_decoration_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), 0, NULL, toplevel);
-
- return (struct zxdg_toplevel_decoration_v1 *) id;
-}
-
-#ifndef ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM
-#define ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM
-enum zxdg_toplevel_decoration_v1_error {
- /**
- * xdg_toplevel has a buffer attached before configure
- */
- ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0,
- /**
- * xdg_toplevel already has a decoration object
- */
- ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1,
- /**
- * xdg_toplevel destroyed before the decoration object
- */
- ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2,
-};
-#endif /* ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM */
-
-#ifndef ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM
-#define ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM
-/**
- * @ingroup iface_zxdg_toplevel_decoration_v1
- * window decoration modes
- *
- * These values describe window decoration modes.
- */
-enum zxdg_toplevel_decoration_v1_mode {
- /**
- * no server-side window decoration
- */
- ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1,
- /**
- * server-side window decoration
- */
- ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2,
-};
-#endif /* ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM */
-
-/**
- * @ingroup iface_zxdg_toplevel_decoration_v1
- * @struct zxdg_toplevel_decoration_v1_listener
- */
-struct zxdg_toplevel_decoration_v1_listener {
- /**
- * suggest a surface change
- *
- * The configure event asks the client to change its decoration
- * mode. The configured state should not be applied immediately.
- * Clients must send an ack_configure in response to this event.
- * See xdg_surface.configure and xdg_surface.ack_configure for
- * details.
- *
- * A configure event can be sent at any time. The specified mode
- * must be obeyed by the client.
- * @param mode the decoration mode
- */
- void (*configure)(void *data,
- struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
- uint32_t mode);
-};
-
-/**
- * @ingroup iface_zxdg_toplevel_decoration_v1
- */
-static inline int
-zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
- const struct zxdg_toplevel_decoration_v1_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1,
- (void (**)(void)) listener, data);
-}
-
-#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY 0
-#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE 1
-#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE 2
-
-/**
- * @ingroup iface_zxdg_toplevel_decoration_v1
- */
-#define ZXDG_TOPLEVEL_DECORATION_V1_CONFIGURE_SINCE_VERSION 1
-
-/**
- * @ingroup iface_zxdg_toplevel_decoration_v1
- */
-#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_zxdg_toplevel_decoration_v1
- */
-#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE_SINCE_VERSION 1
-/**
- * @ingroup iface_zxdg_toplevel_decoration_v1
- */
-#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE_SINCE_VERSION 1
-
-/** @ingroup iface_zxdg_toplevel_decoration_v1 */
-static inline void
-zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data);
-}
-
-/** @ingroup iface_zxdg_toplevel_decoration_v1 */
-static inline void *
-zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1);
-}
-
-static inline uint32_t
-zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
-{
- return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1);
-}
-
-/**
- * @ingroup iface_zxdg_toplevel_decoration_v1
- *
- * Switch back to a mode without any server-side decorations at the next
- * commit.
- */
-static inline void
-zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1,
- ZXDG_TOPLEVEL_DECORATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_zxdg_toplevel_decoration_v1
- *
- * Set the toplevel surface decoration mode. This informs the compositor
- * that the client prefers the provided decoration mode.
- *
- * After requesting a decoration mode, the compositor will respond by
- * emitting an xdg_surface.configure event. The client should then update
- * its content, drawing it without decorations if the received mode is
- * server-side decorations. The client must also acknowledge the configure
- * when committing the new content (see xdg_surface.ack_configure).
- *
- * The compositor can decide not to use the client's mode and enforce a
- * different mode instead.
- *
- * Clients whose decoration mode depend on the xdg_toplevel state may send
- * a set_mode request in response to an xdg_surface.configure event and wait
- * for the next xdg_surface.configure event to prevent unwanted state.
- * Such clients are responsible for preventing configure loops and must
- * make sure not to send multiple successive set_mode requests with the
- * same decoration mode.
- */
-static inline void
-zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1,
- ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0, mode);
-}
-
-/**
- * @ingroup iface_zxdg_toplevel_decoration_v1
- *
- * Unset the toplevel surface decoration mode. This informs the compositor
- * that the client doesn't prefer a particular decoration mode.
- *
- * This request has the same semantics as set_mode.
- */
-static inline void
-zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1,
- ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pkg/glfw/wayland-headers/xdg-shell-client-protocol-code.h b/pkg/glfw/wayland-headers/xdg-shell-client-protocol-code.h
deleted file mode 100644
index d698c2ca5..000000000
--- a/pkg/glfw/wayland-headers/xdg-shell-client-protocol-code.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-/*
- * Copyright © 2008-2013 Kristian Høgsberg
- * Copyright © 2013 Rafael Antognolli
- * Copyright © 2013 Jasper St. Pierre
- * Copyright © 2010-2013 Intel Corporation
- * Copyright © 2015-2017 Samsung Electronics Co., Ltd
- * Copyright © 2015-2017 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include
-#include
-#include
-#include "wayland-util.h"
-
-#ifndef __has_attribute
-# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
-#endif
-
-#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
-#define WL_PRIVATE __attribute__ ((visibility("hidden")))
-#else
-#define WL_PRIVATE
-#endif
-
-extern const struct wl_interface wl_output_interface;
-extern const struct wl_interface wl_seat_interface;
-extern const struct wl_interface wl_surface_interface;
-extern const struct wl_interface xdg_popup_interface;
-extern const struct wl_interface xdg_positioner_interface;
-extern const struct wl_interface xdg_surface_interface;
-extern const struct wl_interface xdg_toplevel_interface;
-
-static const struct wl_interface *xdg_shell_types[] = {
- NULL,
- NULL,
- NULL,
- NULL,
- &xdg_positioner_interface,
- &xdg_surface_interface,
- &wl_surface_interface,
- &xdg_toplevel_interface,
- &xdg_popup_interface,
- &xdg_surface_interface,
- &xdg_positioner_interface,
- &xdg_toplevel_interface,
- &wl_seat_interface,
- NULL,
- NULL,
- NULL,
- &wl_seat_interface,
- NULL,
- &wl_seat_interface,
- NULL,
- NULL,
- &wl_output_interface,
- &wl_seat_interface,
- NULL,
- &xdg_positioner_interface,
- NULL,
-};
-
-static const struct wl_message xdg_wm_base_requests[] = {
- { "destroy", "", xdg_shell_types + 0 },
- { "create_positioner", "n", xdg_shell_types + 4 },
- { "get_xdg_surface", "no", xdg_shell_types + 5 },
- { "pong", "u", xdg_shell_types + 0 },
-};
-
-static const struct wl_message xdg_wm_base_events[] = {
- { "ping", "u", xdg_shell_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
- "xdg_wm_base", 6,
- 4, xdg_wm_base_requests,
- 1, xdg_wm_base_events,
-};
-
-static const struct wl_message xdg_positioner_requests[] = {
- { "destroy", "", xdg_shell_types + 0 },
- { "set_size", "ii", xdg_shell_types + 0 },
- { "set_anchor_rect", "iiii", xdg_shell_types + 0 },
- { "set_anchor", "u", xdg_shell_types + 0 },
- { "set_gravity", "u", xdg_shell_types + 0 },
- { "set_constraint_adjustment", "u", xdg_shell_types + 0 },
- { "set_offset", "ii", xdg_shell_types + 0 },
- { "set_reactive", "3", xdg_shell_types + 0 },
- { "set_parent_size", "3ii", xdg_shell_types + 0 },
- { "set_parent_configure", "3u", xdg_shell_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
- "xdg_positioner", 6,
- 10, xdg_positioner_requests,
- 0, NULL,
-};
-
-static const struct wl_message xdg_surface_requests[] = {
- { "destroy", "", xdg_shell_types + 0 },
- { "get_toplevel", "n", xdg_shell_types + 7 },
- { "get_popup", "n?oo", xdg_shell_types + 8 },
- { "set_window_geometry", "iiii", xdg_shell_types + 0 },
- { "ack_configure", "u", xdg_shell_types + 0 },
-};
-
-static const struct wl_message xdg_surface_events[] = {
- { "configure", "u", xdg_shell_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface xdg_surface_interface = {
- "xdg_surface", 6,
- 5, xdg_surface_requests,
- 1, xdg_surface_events,
-};
-
-static const struct wl_message xdg_toplevel_requests[] = {
- { "destroy", "", xdg_shell_types + 0 },
- { "set_parent", "?o", xdg_shell_types + 11 },
- { "set_title", "s", xdg_shell_types + 0 },
- { "set_app_id", "s", xdg_shell_types + 0 },
- { "show_window_menu", "ouii", xdg_shell_types + 12 },
- { "move", "ou", xdg_shell_types + 16 },
- { "resize", "ouu", xdg_shell_types + 18 },
- { "set_max_size", "ii", xdg_shell_types + 0 },
- { "set_min_size", "ii", xdg_shell_types + 0 },
- { "set_maximized", "", xdg_shell_types + 0 },
- { "unset_maximized", "", xdg_shell_types + 0 },
- { "set_fullscreen", "?o", xdg_shell_types + 21 },
- { "unset_fullscreen", "", xdg_shell_types + 0 },
- { "set_minimized", "", xdg_shell_types + 0 },
-};
-
-static const struct wl_message xdg_toplevel_events[] = {
- { "configure", "iia", xdg_shell_types + 0 },
- { "close", "", xdg_shell_types + 0 },
- { "configure_bounds", "4ii", xdg_shell_types + 0 },
- { "wm_capabilities", "5a", xdg_shell_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
- "xdg_toplevel", 6,
- 14, xdg_toplevel_requests,
- 4, xdg_toplevel_events,
-};
-
-static const struct wl_message xdg_popup_requests[] = {
- { "destroy", "", xdg_shell_types + 0 },
- { "grab", "ou", xdg_shell_types + 22 },
- { "reposition", "3ou", xdg_shell_types + 24 },
-};
-
-static const struct wl_message xdg_popup_events[] = {
- { "configure", "iiii", xdg_shell_types + 0 },
- { "popup_done", "", xdg_shell_types + 0 },
- { "repositioned", "3u", xdg_shell_types + 0 },
-};
-
-WL_PRIVATE const struct wl_interface xdg_popup_interface = {
- "xdg_popup", 6,
- 3, xdg_popup_requests,
- 3, xdg_popup_events,
-};
-
diff --git a/pkg/glfw/wayland-headers/xdg-shell-client-protocol.h b/pkg/glfw/wayland-headers/xdg-shell-client-protocol.h
deleted file mode 100644
index 1e5a9664b..000000000
--- a/pkg/glfw/wayland-headers/xdg-shell-client-protocol.h
+++ /dev/null
@@ -1,2307 +0,0 @@
-/* Generated by wayland-scanner 1.23.1 */
-
-#ifndef XDG_SHELL_CLIENT_PROTOCOL_H
-#define XDG_SHELL_CLIENT_PROTOCOL_H
-
-#include
-#include
-#include "wayland-client.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @page page_xdg_shell The xdg_shell protocol
- * @section page_ifaces_xdg_shell Interfaces
- * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces
- * - @subpage page_iface_xdg_positioner - child surface positioner
- * - @subpage page_iface_xdg_surface - desktop user interface surface base interface
- * - @subpage page_iface_xdg_toplevel - toplevel surface
- * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus
- * @section page_copyright_xdg_shell Copyright
- *
- *
- * Copyright © 2008-2013 Kristian Høgsberg
- * Copyright © 2013 Rafael Antognolli
- * Copyright © 2013 Jasper St. Pierre
- * Copyright © 2010-2013 Intel Corporation
- * Copyright © 2015-2017 Samsung Electronics Co., Ltd
- * Copyright © 2015-2017 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- */
-struct wl_output;
-struct wl_seat;
-struct wl_surface;
-struct xdg_popup;
-struct xdg_positioner;
-struct xdg_surface;
-struct xdg_toplevel;
-struct xdg_wm_base;
-
-#ifndef XDG_WM_BASE_INTERFACE
-#define XDG_WM_BASE_INTERFACE
-/**
- * @page page_iface_xdg_wm_base xdg_wm_base
- * @section page_iface_xdg_wm_base_desc Description
- *
- * The xdg_wm_base interface is exposed as a global object enabling clients
- * to turn their wl_surfaces into windows in a desktop environment. It
- * defines the basic functionality needed for clients and the compositor to
- * create windows that can be dragged, resized, maximized, etc, as well as
- * creating transient windows such as popup menus.
- * @section page_iface_xdg_wm_base_api API
- * See @ref iface_xdg_wm_base.
- */
-/**
- * @defgroup iface_xdg_wm_base The xdg_wm_base interface
- *
- * The xdg_wm_base interface is exposed as a global object enabling clients
- * to turn their wl_surfaces into windows in a desktop environment. It
- * defines the basic functionality needed for clients and the compositor to
- * create windows that can be dragged, resized, maximized, etc, as well as
- * creating transient windows such as popup menus.
- */
-extern const struct wl_interface xdg_wm_base_interface;
-#endif
-#ifndef XDG_POSITIONER_INTERFACE
-#define XDG_POSITIONER_INTERFACE
-/**
- * @page page_iface_xdg_positioner xdg_positioner
- * @section page_iface_xdg_positioner_desc Description
- *
- * The xdg_positioner provides a collection of rules for the placement of a
- * child surface relative to a parent surface. Rules can be defined to ensure
- * the child surface remains within the visible area's borders, and to
- * specify how the child surface changes its position, such as sliding along
- * an axis, or flipping around a rectangle. These positioner-created rules are
- * constrained by the requirement that a child surface must intersect with or
- * be at least partially adjacent to its parent surface.
- *
- * See the various requests for details about possible rules.
- *
- * At the time of the request, the compositor makes a copy of the rules
- * specified by the xdg_positioner. Thus, after the request is complete the
- * xdg_positioner object can be destroyed or reused; further changes to the
- * object will have no effect on previous usages.
- *
- * For an xdg_positioner object to be considered complete, it must have a
- * non-zero size set by set_size, and a non-zero anchor rectangle set by
- * set_anchor_rect. Passing an incomplete xdg_positioner object when
- * positioning a surface raises an invalid_positioner error.
- * @section page_iface_xdg_positioner_api API
- * See @ref iface_xdg_positioner.
- */
-/**
- * @defgroup iface_xdg_positioner The xdg_positioner interface
- *
- * The xdg_positioner provides a collection of rules for the placement of a
- * child surface relative to a parent surface. Rules can be defined to ensure
- * the child surface remains within the visible area's borders, and to
- * specify how the child surface changes its position, such as sliding along
- * an axis, or flipping around a rectangle. These positioner-created rules are
- * constrained by the requirement that a child surface must intersect with or
- * be at least partially adjacent to its parent surface.
- *
- * See the various requests for details about possible rules.
- *
- * At the time of the request, the compositor makes a copy of the rules
- * specified by the xdg_positioner. Thus, after the request is complete the
- * xdg_positioner object can be destroyed or reused; further changes to the
- * object will have no effect on previous usages.
- *
- * For an xdg_positioner object to be considered complete, it must have a
- * non-zero size set by set_size, and a non-zero anchor rectangle set by
- * set_anchor_rect. Passing an incomplete xdg_positioner object when
- * positioning a surface raises an invalid_positioner error.
- */
-extern const struct wl_interface xdg_positioner_interface;
-#endif
-#ifndef XDG_SURFACE_INTERFACE
-#define XDG_SURFACE_INTERFACE
-/**
- * @page page_iface_xdg_surface xdg_surface
- * @section page_iface_xdg_surface_desc Description
- *
- * An interface that may be implemented by a wl_surface, for
- * implementations that provide a desktop-style user interface.
- *
- * It provides a base set of functionality required to construct user
- * interface elements requiring management by the compositor, such as
- * toplevel windows, menus, etc. The types of functionality are split into
- * xdg_surface roles.
- *
- * Creating an xdg_surface does not set the role for a wl_surface. In order
- * to map an xdg_surface, the client must create a role-specific object
- * using, e.g., get_toplevel, get_popup. The wl_surface for any given
- * xdg_surface can have at most one role, and may not be assigned any role
- * not based on xdg_surface.
- *
- * A role must be assigned before any other requests are made to the
- * xdg_surface object.
- *
- * The client must call wl_surface.commit on the corresponding wl_surface
- * for the xdg_surface state to take effect.
- *
- * Creating an xdg_surface from a wl_surface which has a buffer attached or
- * committed is a client error, and any attempts by a client to attach or
- * manipulate a buffer prior to the first xdg_surface.configure call must
- * also be treated as errors.
- *
- * After creating a role-specific object and setting it up, the client must
- * perform an initial commit without any buffer attached. The compositor
- * will reply with initial wl_surface state such as
- * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
- * event. The client must acknowledge it and is then allowed to attach a
- * buffer to map the surface.
- *
- * Mapping an xdg_surface-based role surface is defined as making it
- * possible for the surface to be shown by the compositor. Note that
- * a mapped surface is not guaranteed to be visible once it is mapped.
- *
- * For an xdg_surface to be mapped by the compositor, the following
- * conditions must be met:
- * (1) the client has assigned an xdg_surface-based role to the surface
- * (2) the client has set and committed the xdg_surface state and the
- * role-dependent state to the surface
- * (3) the client has committed a buffer to the surface
- *
- * A newly-unmapped surface is considered to have met condition (1) out
- * of the 3 required conditions for mapping a surface if its role surface
- * has not been destroyed, i.e. the client must perform the initial commit
- * again before attaching a buffer.
- * @section page_iface_xdg_surface_api API
- * See @ref iface_xdg_surface.
- */
-/**
- * @defgroup iface_xdg_surface The xdg_surface interface
- *
- * An interface that may be implemented by a wl_surface, for
- * implementations that provide a desktop-style user interface.
- *
- * It provides a base set of functionality required to construct user
- * interface elements requiring management by the compositor, such as
- * toplevel windows, menus, etc. The types of functionality are split into
- * xdg_surface roles.
- *
- * Creating an xdg_surface does not set the role for a wl_surface. In order
- * to map an xdg_surface, the client must create a role-specific object
- * using, e.g., get_toplevel, get_popup. The wl_surface for any given
- * xdg_surface can have at most one role, and may not be assigned any role
- * not based on xdg_surface.
- *
- * A role must be assigned before any other requests are made to the
- * xdg_surface object.
- *
- * The client must call wl_surface.commit on the corresponding wl_surface
- * for the xdg_surface state to take effect.
- *
- * Creating an xdg_surface from a wl_surface which has a buffer attached or
- * committed is a client error, and any attempts by a client to attach or
- * manipulate a buffer prior to the first xdg_surface.configure call must
- * also be treated as errors.
- *
- * After creating a role-specific object and setting it up, the client must
- * perform an initial commit without any buffer attached. The compositor
- * will reply with initial wl_surface state such as
- * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
- * event. The client must acknowledge it and is then allowed to attach a
- * buffer to map the surface.
- *
- * Mapping an xdg_surface-based role surface is defined as making it
- * possible for the surface to be shown by the compositor. Note that
- * a mapped surface is not guaranteed to be visible once it is mapped.
- *
- * For an xdg_surface to be mapped by the compositor, the following
- * conditions must be met:
- * (1) the client has assigned an xdg_surface-based role to the surface
- * (2) the client has set and committed the xdg_surface state and the
- * role-dependent state to the surface
- * (3) the client has committed a buffer to the surface
- *
- * A newly-unmapped surface is considered to have met condition (1) out
- * of the 3 required conditions for mapping a surface if its role surface
- * has not been destroyed, i.e. the client must perform the initial commit
- * again before attaching a buffer.
- */
-extern const struct wl_interface xdg_surface_interface;
-#endif
-#ifndef XDG_TOPLEVEL_INTERFACE
-#define XDG_TOPLEVEL_INTERFACE
-/**
- * @page page_iface_xdg_toplevel xdg_toplevel
- * @section page_iface_xdg_toplevel_desc Description
- *
- * This interface defines an xdg_surface role which allows a surface to,
- * among other things, set window-like properties such as maximize,
- * fullscreen, and minimize, set application-specific metadata like title and
- * id, and well as trigger user interactive operations such as interactive
- * resize and move.
- *
- * Unmapping an xdg_toplevel means that the surface cannot be shown
- * by the compositor until it is explicitly mapped again.
- * All active operations (e.g., move, resize) are canceled and all
- * attributes (e.g. title, state, stacking, ...) are discarded for
- * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
- * the state it had right after xdg_surface.get_toplevel. The client
- * can re-map the toplevel by perfoming a commit without any buffer
- * attached, waiting for a configure event and handling it as usual (see
- * xdg_surface description).
- *
- * Attaching a null buffer to a toplevel unmaps the surface.
- * @section page_iface_xdg_toplevel_api API
- * See @ref iface_xdg_toplevel.
- */
-/**
- * @defgroup iface_xdg_toplevel The xdg_toplevel interface
- *
- * This interface defines an xdg_surface role which allows a surface to,
- * among other things, set window-like properties such as maximize,
- * fullscreen, and minimize, set application-specific metadata like title and
- * id, and well as trigger user interactive operations such as interactive
- * resize and move.
- *
- * Unmapping an xdg_toplevel means that the surface cannot be shown
- * by the compositor until it is explicitly mapped again.
- * All active operations (e.g., move, resize) are canceled and all
- * attributes (e.g. title, state, stacking, ...) are discarded for
- * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
- * the state it had right after xdg_surface.get_toplevel. The client
- * can re-map the toplevel by perfoming a commit without any buffer
- * attached, waiting for a configure event and handling it as usual (see
- * xdg_surface description).
- *
- * Attaching a null buffer to a toplevel unmaps the surface.
- */
-extern const struct wl_interface xdg_toplevel_interface;
-#endif
-#ifndef XDG_POPUP_INTERFACE
-#define XDG_POPUP_INTERFACE
-/**
- * @page page_iface_xdg_popup xdg_popup
- * @section page_iface_xdg_popup_desc Description
- *
- * A popup surface is a short-lived, temporary surface. It can be used to
- * implement for example menus, popovers, tooltips and other similar user
- * interface concepts.
- *
- * A popup can be made to take an explicit grab. See xdg_popup.grab for
- * details.
- *
- * When the popup is dismissed, a popup_done event will be sent out, and at
- * the same time the surface will be unmapped. See the xdg_popup.popup_done
- * event for details.
- *
- * Explicitly destroying the xdg_popup object will also dismiss the popup and
- * unmap the surface. Clients that want to dismiss the popup when another
- * surface of their own is clicked should dismiss the popup using the destroy
- * request.
- *
- * A newly created xdg_popup will be stacked on top of all previously created
- * xdg_popup surfaces associated with the same xdg_toplevel.
- *
- * The parent of an xdg_popup must be mapped (see the xdg_surface
- * description) before the xdg_popup itself.
- *
- * The client must call wl_surface.commit on the corresponding wl_surface
- * for the xdg_popup state to take effect.
- * @section page_iface_xdg_popup_api API
- * See @ref iface_xdg_popup.
- */
-/**
- * @defgroup iface_xdg_popup The xdg_popup interface
- *
- * A popup surface is a short-lived, temporary surface. It can be used to
- * implement for example menus, popovers, tooltips and other similar user
- * interface concepts.
- *
- * A popup can be made to take an explicit grab. See xdg_popup.grab for
- * details.
- *
- * When the popup is dismissed, a popup_done event will be sent out, and at
- * the same time the surface will be unmapped. See the xdg_popup.popup_done
- * event for details.
- *
- * Explicitly destroying the xdg_popup object will also dismiss the popup and
- * unmap the surface. Clients that want to dismiss the popup when another
- * surface of their own is clicked should dismiss the popup using the destroy
- * request.
- *
- * A newly created xdg_popup will be stacked on top of all previously created
- * xdg_popup surfaces associated with the same xdg_toplevel.
- *
- * The parent of an xdg_popup must be mapped (see the xdg_surface
- * description) before the xdg_popup itself.
- *
- * The client must call wl_surface.commit on the corresponding wl_surface
- * for the xdg_popup state to take effect.
- */
-extern const struct wl_interface xdg_popup_interface;
-#endif
-
-#ifndef XDG_WM_BASE_ERROR_ENUM
-#define XDG_WM_BASE_ERROR_ENUM
-enum xdg_wm_base_error {
- /**
- * given wl_surface has another role
- */
- XDG_WM_BASE_ERROR_ROLE = 0,
- /**
- * xdg_wm_base was destroyed before children
- */
- XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1,
- /**
- * the client tried to map or destroy a non-topmost popup
- */
- XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2,
- /**
- * the client specified an invalid popup parent surface
- */
- XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3,
- /**
- * the client provided an invalid surface state
- */
- XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4,
- /**
- * the client provided an invalid positioner
- */
- XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5,
- /**
- * the client didn’t respond to a ping event in time
- */
- XDG_WM_BASE_ERROR_UNRESPONSIVE = 6,
-};
-#endif /* XDG_WM_BASE_ERROR_ENUM */
-
-/**
- * @ingroup iface_xdg_wm_base
- * @struct xdg_wm_base_listener
- */
-struct xdg_wm_base_listener {
- /**
- * check if the client is alive
- *
- * The ping event asks the client if it's still alive. Pass the
- * serial specified in the event back to the compositor by sending
- * a "pong" request back with the specified serial. See
- * xdg_wm_base.pong.
- *
- * Compositors can use this to determine if the client is still
- * alive. It's unspecified what will happen if the client doesn't
- * respond to the ping request, or in what timeframe. Clients
- * should try to respond in a reasonable amount of time. The
- * “unresponsive” error is provided for compositors that wish
- * to disconnect unresponsive clients.
- *
- * A compositor is free to ping in any way it wants, but a client
- * must always respond to any xdg_wm_base object it created.
- * @param serial pass this to the pong request
- */
- void (*ping)(void *data,
- struct xdg_wm_base *xdg_wm_base,
- uint32_t serial);
-};
-
-/**
- * @ingroup iface_xdg_wm_base
- */
-static inline int
-xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base,
- const struct xdg_wm_base_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base,
- (void (**)(void)) listener, data);
-}
-
-#define XDG_WM_BASE_DESTROY 0
-#define XDG_WM_BASE_CREATE_POSITIONER 1
-#define XDG_WM_BASE_GET_XDG_SURFACE 2
-#define XDG_WM_BASE_PONG 3
-
-/**
- * @ingroup iface_xdg_wm_base
- */
-#define XDG_WM_BASE_PING_SINCE_VERSION 1
-
-/**
- * @ingroup iface_xdg_wm_base
- */
-#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_wm_base
- */
-#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_wm_base
- */
-#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_wm_base
- */
-#define XDG_WM_BASE_PONG_SINCE_VERSION 1
-
-/** @ingroup iface_xdg_wm_base */
-static inline void
-xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data);
-}
-
-/** @ingroup iface_xdg_wm_base */
-static inline void *
-xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base);
-}
-
-static inline uint32_t
-xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base)
-{
- return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base);
-}
-
-/**
- * @ingroup iface_xdg_wm_base
- *
- * Destroy this xdg_wm_base object.
- *
- * Destroying a bound xdg_wm_base object while there are surfaces
- * still alive created by this xdg_wm_base object instance is illegal
- * and will result in a defunct_surfaces error.
- */
-static inline void
-xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
- XDG_WM_BASE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_xdg_wm_base
- *
- * Create a positioner object. A positioner object is used to position
- * surfaces relative to some parent surface. See the interface description
- * and xdg_surface.get_popup for details.
- */
-static inline struct xdg_positioner *
-xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
- XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL);
-
- return (struct xdg_positioner *) id;
-}
-
-/**
- * @ingroup iface_xdg_wm_base
- *
- * This creates an xdg_surface for the given surface. While xdg_surface
- * itself is not a role, the corresponding surface may only be assigned
- * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is
- * illegal to create an xdg_surface for a wl_surface which already has an
- * assigned role and this will result in a role error.
- *
- * This creates an xdg_surface for the given surface. An xdg_surface is
- * used as basis to define a role to a given surface, such as xdg_toplevel
- * or xdg_popup. It also manages functionality shared between xdg_surface
- * based surface roles.
- *
- * See the documentation of xdg_surface for more details about what an
- * xdg_surface is and how it is used.
- */
-static inline struct xdg_surface *
-xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
- XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL, surface);
-
- return (struct xdg_surface *) id;
-}
-
-/**
- * @ingroup iface_xdg_wm_base
- *
- * A client must respond to a ping event with a pong request or
- * the client may be deemed unresponsive. See xdg_wm_base.ping
- * and xdg_wm_base.error.unresponsive.
- */
-static inline void
-xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
- XDG_WM_BASE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, serial);
-}
-
-#ifndef XDG_POSITIONER_ERROR_ENUM
-#define XDG_POSITIONER_ERROR_ENUM
-enum xdg_positioner_error {
- /**
- * invalid input provided
- */
- XDG_POSITIONER_ERROR_INVALID_INPUT = 0,
-};
-#endif /* XDG_POSITIONER_ERROR_ENUM */
-
-#ifndef XDG_POSITIONER_ANCHOR_ENUM
-#define XDG_POSITIONER_ANCHOR_ENUM
-enum xdg_positioner_anchor {
- XDG_POSITIONER_ANCHOR_NONE = 0,
- XDG_POSITIONER_ANCHOR_TOP = 1,
- XDG_POSITIONER_ANCHOR_BOTTOM = 2,
- XDG_POSITIONER_ANCHOR_LEFT = 3,
- XDG_POSITIONER_ANCHOR_RIGHT = 4,
- XDG_POSITIONER_ANCHOR_TOP_LEFT = 5,
- XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6,
- XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7,
- XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8,
-};
-#endif /* XDG_POSITIONER_ANCHOR_ENUM */
-
-#ifndef XDG_POSITIONER_GRAVITY_ENUM
-#define XDG_POSITIONER_GRAVITY_ENUM
-enum xdg_positioner_gravity {
- XDG_POSITIONER_GRAVITY_NONE = 0,
- XDG_POSITIONER_GRAVITY_TOP = 1,
- XDG_POSITIONER_GRAVITY_BOTTOM = 2,
- XDG_POSITIONER_GRAVITY_LEFT = 3,
- XDG_POSITIONER_GRAVITY_RIGHT = 4,
- XDG_POSITIONER_GRAVITY_TOP_LEFT = 5,
- XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6,
- XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7,
- XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8,
-};
-#endif /* XDG_POSITIONER_GRAVITY_ENUM */
-
-#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM
-#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM
-/**
- * @ingroup iface_xdg_positioner
- * constraint adjustments
- *
- * The constraint adjustment value define ways the compositor will adjust
- * the position of the surface, if the unadjusted position would result
- * in the surface being partly constrained.
- *
- * Whether a surface is considered 'constrained' is left to the compositor
- * to determine. For example, the surface may be partly outside the
- * compositor's defined 'work area', thus necessitating the child surface's
- * position be adjusted until it is entirely inside the work area.
- *
- * The adjustments can be combined, according to a defined precedence: 1)
- * Flip, 2) Slide, 3) Resize.
- */
-enum xdg_positioner_constraint_adjustment {
- /**
- * don't move the child surface when constrained
- *
- * Don't alter the surface position even if it is constrained on
- * some axis, for example partially outside the edge of an output.
- */
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0,
- /**
- * move along the x axis until unconstrained
- *
- * Slide the surface along the x axis until it is no longer
- * constrained.
- *
- * First try to slide towards the direction of the gravity on the x
- * axis until either the edge in the opposite direction of the
- * gravity is unconstrained or the edge in the direction of the
- * gravity is constrained.
- *
- * Then try to slide towards the opposite direction of the gravity
- * on the x axis until either the edge in the direction of the
- * gravity is unconstrained or the edge in the opposite direction
- * of the gravity is constrained.
- */
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1,
- /**
- * move along the y axis until unconstrained
- *
- * Slide the surface along the y axis until it is no longer
- * constrained.
- *
- * First try to slide towards the direction of the gravity on the y
- * axis until either the edge in the opposite direction of the
- * gravity is unconstrained or the edge in the direction of the
- * gravity is constrained.
- *
- * Then try to slide towards the opposite direction of the gravity
- * on the y axis until either the edge in the direction of the
- * gravity is unconstrained or the edge in the opposite direction
- * of the gravity is constrained.
- */
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2,
- /**
- * invert the anchor and gravity on the x axis
- *
- * Invert the anchor and gravity on the x axis if the surface is
- * constrained on the x axis. For example, if the left edge of the
- * surface is constrained, the gravity is 'left' and the anchor is
- * 'left', change the gravity to 'right' and the anchor to 'right'.
- *
- * If the adjusted position also ends up being constrained, the
- * resulting position of the flip_x adjustment will be the one
- * before the adjustment.
- */
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4,
- /**
- * invert the anchor and gravity on the y axis
- *
- * Invert the anchor and gravity on the y axis if the surface is
- * constrained on the y axis. For example, if the bottom edge of
- * the surface is constrained, the gravity is 'bottom' and the
- * anchor is 'bottom', change the gravity to 'top' and the anchor
- * to 'top'.
- *
- * The adjusted position is calculated given the original anchor
- * rectangle and offset, but with the new flipped anchor and
- * gravity values.
- *
- * If the adjusted position also ends up being constrained, the
- * resulting position of the flip_y adjustment will be the one
- * before the adjustment.
- */
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8,
- /**
- * horizontally resize the surface
- *
- * Resize the surface horizontally so that it is completely
- * unconstrained.
- */
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16,
- /**
- * vertically resize the surface
- *
- * Resize the surface vertically so that it is completely
- * unconstrained.
- */
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32,
-};
-#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */
-
-#define XDG_POSITIONER_DESTROY 0
-#define XDG_POSITIONER_SET_SIZE 1
-#define XDG_POSITIONER_SET_ANCHOR_RECT 2
-#define XDG_POSITIONER_SET_ANCHOR 3
-#define XDG_POSITIONER_SET_GRAVITY 4
-#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5
-#define XDG_POSITIONER_SET_OFFSET 6
-#define XDG_POSITIONER_SET_REACTIVE 7
-#define XDG_POSITIONER_SET_PARENT_SIZE 8
-#define XDG_POSITIONER_SET_PARENT_CONFIGURE 9
-
-
-/**
- * @ingroup iface_xdg_positioner
- */
-#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_positioner
- */
-#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_positioner
- */
-#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_positioner
- */
-#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_positioner
- */
-#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_positioner
- */
-#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_positioner
- */
-#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_positioner
- */
-#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3
-/**
- * @ingroup iface_xdg_positioner
- */
-#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3
-/**
- * @ingroup iface_xdg_positioner
- */
-#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3
-
-/** @ingroup iface_xdg_positioner */
-static inline void
-xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data);
-}
-
-/** @ingroup iface_xdg_positioner */
-static inline void *
-xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner);
-}
-
-static inline uint32_t
-xdg_positioner_get_version(struct xdg_positioner *xdg_positioner)
-{
- return wl_proxy_get_version((struct wl_proxy *) xdg_positioner);
-}
-
-/**
- * @ingroup iface_xdg_positioner
- *
- * Notify the compositor that the xdg_positioner will no longer be used.
- */
-static inline void
-xdg_positioner_destroy(struct xdg_positioner *xdg_positioner)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
- XDG_POSITIONER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_xdg_positioner
- *
- * Set the size of the surface that is to be positioned with the positioner
- * object. The size is in surface-local coordinates and corresponds to the
- * window geometry. See xdg_surface.set_window_geometry.
- *
- * If a zero or negative size is set the invalid_input error is raised.
- */
-static inline void
-xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
- XDG_POSITIONER_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, width, height);
-}
-
-/**
- * @ingroup iface_xdg_positioner
- *
- * Specify the anchor rectangle within the parent surface that the child
- * surface will be placed relative to. The rectangle is relative to the
- * window geometry as defined by xdg_surface.set_window_geometry of the
- * parent surface.
- *
- * When the xdg_positioner object is used to position a child surface, the
- * anchor rectangle may not extend outside the window geometry of the
- * positioned child's parent surface.
- *
- * If a negative size is set the invalid_input error is raised.
- */
-static inline void
-xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
- XDG_POSITIONER_SET_ANCHOR_RECT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y, width, height);
-}
-
-/**
- * @ingroup iface_xdg_positioner
- *
- * Defines the anchor point for the anchor rectangle. The specified anchor
- * is used derive an anchor point that the child surface will be
- * positioned relative to. If a corner anchor is set (e.g. 'top_left' or
- * 'bottom_right'), the anchor point will be at the specified corner;
- * otherwise, the derived anchor point will be centered on the specified
- * edge, or in the center of the anchor rectangle if no edge is specified.
- */
-static inline void
-xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
- XDG_POSITIONER_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, anchor);
-}
-
-/**
- * @ingroup iface_xdg_positioner
- *
- * Defines in what direction a surface should be positioned, relative to
- * the anchor point of the parent surface. If a corner gravity is
- * specified (e.g. 'bottom_right' or 'top_left'), then the child surface
- * will be placed towards the specified gravity; otherwise, the child
- * surface will be centered over the anchor point on any axis that had no
- * gravity specified. If the gravity is not in the ‘gravity’ enum, an
- * invalid_input error is raised.
- */
-static inline void
-xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
- XDG_POSITIONER_SET_GRAVITY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, gravity);
-}
-
-/**
- * @ingroup iface_xdg_positioner
- *
- * Specify how the window should be positioned if the originally intended
- * position caused the surface to be constrained, meaning at least
- * partially outside positioning boundaries set by the compositor. The
- * adjustment is set by constructing a bitmask describing the adjustment to
- * be made when the surface is constrained on that axis.
- *
- * If no bit for one axis is set, the compositor will assume that the child
- * surface should not change its position on that axis when constrained.
- *
- * If more than one bit for one axis is set, the order of how adjustments
- * are applied is specified in the corresponding adjustment descriptions.
- *
- * The default adjustment is none.
- */
-static inline void
-xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
- XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, constraint_adjustment);
-}
-
-/**
- * @ingroup iface_xdg_positioner
- *
- * Specify the surface position offset relative to the position of the
- * anchor on the anchor rectangle and the anchor on the surface. For
- * example if the anchor of the anchor rectangle is at (x, y), the surface
- * has the gravity bottom|right, and the offset is (ox, oy), the calculated
- * surface position will be (x + ox, y + oy). The offset position of the
- * surface is the one used for constraint testing. See
- * set_constraint_adjustment.
- *
- * An example use case is placing a popup menu on top of a user interface
- * element, while aligning the user interface element of the parent surface
- * with some user interface element placed somewhere in the popup surface.
- */
-static inline void
-xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
- XDG_POSITIONER_SET_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y);
-}
-
-/**
- * @ingroup iface_xdg_positioner
- *
- * When set reactive, the surface is reconstrained if the conditions used
- * for constraining changed, e.g. the parent window moved.
- *
- * If the conditions changed and the popup was reconstrained, an
- * xdg_popup.configure event is sent with updated geometry, followed by an
- * xdg_surface.configure event.
- */
-static inline void
-xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
- XDG_POSITIONER_SET_REACTIVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0);
-}
-
-/**
- * @ingroup iface_xdg_positioner
- *
- * Set the parent window geometry the compositor should use when
- * positioning the popup. The compositor may use this information to
- * determine the future state the popup should be constrained using. If
- * this doesn't match the dimension of the parent the popup is eventually
- * positioned against, the behavior is undefined.
- *
- * The arguments are given in the surface-local coordinate space.
- */
-static inline void
-xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
- XDG_POSITIONER_SET_PARENT_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, parent_width, parent_height);
-}
-
-/**
- * @ingroup iface_xdg_positioner
- *
- * Set the serial of an xdg_surface.configure event this positioner will be
- * used in response to. The compositor may use this information together
- * with set_parent_size to determine what future state the popup should be
- * constrained using.
- */
-static inline void
-xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
- XDG_POSITIONER_SET_PARENT_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, serial);
-}
-
-#ifndef XDG_SURFACE_ERROR_ENUM
-#define XDG_SURFACE_ERROR_ENUM
-enum xdg_surface_error {
- /**
- * Surface was not fully constructed
- */
- XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1,
- /**
- * Surface was already constructed
- */
- XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2,
- /**
- * Attaching a buffer to an unconfigured surface
- */
- XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3,
- /**
- * Invalid serial number when acking a configure event
- */
- XDG_SURFACE_ERROR_INVALID_SERIAL = 4,
- /**
- * Width or height was zero or negative
- */
- XDG_SURFACE_ERROR_INVALID_SIZE = 5,
- /**
- * Surface was destroyed before its role object
- */
- XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6,
-};
-#endif /* XDG_SURFACE_ERROR_ENUM */
-
-/**
- * @ingroup iface_xdg_surface
- * @struct xdg_surface_listener
- */
-struct xdg_surface_listener {
- /**
- * suggest a surface change
- *
- * The configure event marks the end of a configure sequence. A
- * configure sequence is a set of one or more events configuring
- * the state of the xdg_surface, including the final
- * xdg_surface.configure event.
- *
- * Where applicable, xdg_surface surface roles will during a
- * configure sequence extend this event as a latched state sent as
- * events before the xdg_surface.configure event. Such events
- * should be considered to make up a set of atomically applied
- * configuration states, where the xdg_surface.configure commits
- * the accumulated state.
- *
- * Clients should arrange their surface for the new states, and
- * then send an ack_configure request with the serial sent in this
- * configure event at some point before committing the new surface.
- *
- * If the client receives multiple configure events before it can
- * respond to one, it is free to discard all but the last event it
- * received.
- * @param serial serial of the configure event
- */
- void (*configure)(void *data,
- struct xdg_surface *xdg_surface,
- uint32_t serial);
-};
-
-/**
- * @ingroup iface_xdg_surface
- */
-static inline int
-xdg_surface_add_listener(struct xdg_surface *xdg_surface,
- const struct xdg_surface_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) xdg_surface,
- (void (**)(void)) listener, data);
-}
-
-#define XDG_SURFACE_DESTROY 0
-#define XDG_SURFACE_GET_TOPLEVEL 1
-#define XDG_SURFACE_GET_POPUP 2
-#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3
-#define XDG_SURFACE_ACK_CONFIGURE 4
-
-/**
- * @ingroup iface_xdg_surface
- */
-#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1
-
-/**
- * @ingroup iface_xdg_surface
- */
-#define XDG_SURFACE_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_surface
- */
-#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_surface
- */
-#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_surface
- */
-#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_surface
- */
-#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1
-
-/** @ingroup iface_xdg_surface */
-static inline void
-xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data);
-}
-
-/** @ingroup iface_xdg_surface */
-static inline void *
-xdg_surface_get_user_data(struct xdg_surface *xdg_surface)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface);
-}
-
-static inline uint32_t
-xdg_surface_get_version(struct xdg_surface *xdg_surface)
-{
- return wl_proxy_get_version((struct wl_proxy *) xdg_surface);
-}
-
-/**
- * @ingroup iface_xdg_surface
- *
- * Destroy the xdg_surface object. An xdg_surface must only be destroyed
- * after its role object has been destroyed, otherwise
- * a defunct_role_object error is raised.
- */
-static inline void
-xdg_surface_destroy(struct xdg_surface *xdg_surface)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
- XDG_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_xdg_surface
- *
- * This creates an xdg_toplevel object for the given xdg_surface and gives
- * the associated wl_surface the xdg_toplevel role.
- *
- * See the documentation of xdg_toplevel for more details about what an
- * xdg_toplevel is and how it is used.
- */
-static inline struct xdg_toplevel *
-xdg_surface_get_toplevel(struct xdg_surface *xdg_surface)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
- XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL);
-
- return (struct xdg_toplevel *) id;
-}
-
-/**
- * @ingroup iface_xdg_surface
- *
- * This creates an xdg_popup object for the given xdg_surface and gives
- * the associated wl_surface the xdg_popup role.
- *
- * If null is passed as a parent, a parent surface must be specified using
- * some other protocol, before committing the initial state.
- *
- * See the documentation of xdg_popup for more details about what an
- * xdg_popup is and how it is used.
- */
-static inline struct xdg_popup *
-xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner)
-{
- struct wl_proxy *id;
-
- id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
- XDG_SURFACE_GET_POPUP, &xdg_popup_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL, parent, positioner);
-
- return (struct xdg_popup *) id;
-}
-
-/**
- * @ingroup iface_xdg_surface
- *
- * The window geometry of a surface is its "visible bounds" from the
- * user's perspective. Client-side decorations often have invisible
- * portions like drop-shadows which should be ignored for the
- * purposes of aligning, placing and constraining windows.
- *
- * The window geometry is double buffered, and will be applied at the
- * time wl_surface.commit of the corresponding wl_surface is called.
- *
- * When maintaining a position, the compositor should treat the (x, y)
- * coordinate of the window geometry as the top left corner of the window.
- * A client changing the (x, y) window geometry coordinate should in
- * general not alter the position of the window.
- *
- * Once the window geometry of the surface is set, it is not possible to
- * unset it, and it will remain the same until set_window_geometry is
- * called again, even if a new subsurface or buffer is attached.
- *
- * If never set, the value is the full bounds of the surface,
- * including any subsurfaces. This updates dynamically on every
- * commit. This unset is meant for extremely simple clients.
- *
- * The arguments are given in the surface-local coordinate space of
- * the wl_surface associated with this xdg_surface, and may extend outside
- * of the wl_surface itself to mark parts of the subsurface tree as part of
- * the window geometry.
- *
- * When applied, the effective window geometry will be the set window
- * geometry clamped to the bounding rectangle of the combined
- * geometry of the surface of the xdg_surface and the associated
- * subsurfaces.
- *
- * The effective geometry will not be recalculated unless a new call to
- * set_window_geometry is done and the new pending surface state is
- * subsequently applied.
- *
- * The width and height of the effective window geometry must be
- * greater than zero. Setting an invalid size will raise an
- * invalid_size error.
- */
-static inline void
-xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
- XDG_SURFACE_SET_WINDOW_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, x, y, width, height);
-}
-
-/**
- * @ingroup iface_xdg_surface
- *
- * When a configure event is received, if a client commits the
- * surface in response to the configure event, then the client
- * must make an ack_configure request sometime before the commit
- * request, passing along the serial of the configure event.
- *
- * For instance, for toplevel surfaces the compositor might use this
- * information to move a surface to the top left only when the client has
- * drawn itself for the maximized or fullscreen state.
- *
- * If the client receives multiple configure events before it
- * can respond to one, it only has to ack the last configure event.
- * Acking a configure event that was never sent raises an invalid_serial
- * error.
- *
- * A client is not required to commit immediately after sending
- * an ack_configure request - it may even ack_configure several times
- * before its next surface commit.
- *
- * A client may send multiple ack_configure requests before committing, but
- * only the last request sent before a commit indicates which configure
- * event the client really is responding to.
- *
- * Sending an ack_configure request consumes the serial number sent with
- * the request, as well as serial numbers sent by all configure events
- * sent on this xdg_surface prior to the configure event referenced by
- * the committed serial.
- *
- * It is an error to issue multiple ack_configure requests referencing a
- * serial from the same configure event, or to issue an ack_configure
- * request referencing a serial from a configure event issued before the
- * event identified by the last ack_configure request for the same
- * xdg_surface. Doing so will raise an invalid_serial error.
- */
-static inline void
-xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
- XDG_SURFACE_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, serial);
-}
-
-#ifndef XDG_TOPLEVEL_ERROR_ENUM
-#define XDG_TOPLEVEL_ERROR_ENUM
-enum xdg_toplevel_error {
- /**
- * provided value is not a valid variant of the resize_edge enum
- */
- XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0,
- /**
- * invalid parent toplevel
- */
- XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1,
- /**
- * client provided an invalid min or max size
- */
- XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2,
-};
-#endif /* XDG_TOPLEVEL_ERROR_ENUM */
-
-#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM
-#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM
-/**
- * @ingroup iface_xdg_toplevel
- * edge values for resizing
- *
- * These values are used to indicate which edge of a surface
- * is being dragged in a resize operation.
- */
-enum xdg_toplevel_resize_edge {
- XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0,
- XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1,
- XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2,
- XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4,
- XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5,
- XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6,
- XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8,
- XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9,
- XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10,
-};
-#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */
-
-#ifndef XDG_TOPLEVEL_STATE_ENUM
-#define XDG_TOPLEVEL_STATE_ENUM
-/**
- * @ingroup iface_xdg_toplevel
- * types of state on the surface
- *
- * The different state values used on the surface. This is designed for
- * state values like maximized, fullscreen. It is paired with the
- * configure event to ensure that both the client and the compositor
- * setting the state can be synchronized.
- *
- * States set in this way are double-buffered. They will get applied on
- * the next commit.
- */
-enum xdg_toplevel_state {
- /**
- * the surface is maximized
- * the surface is maximized
- *
- * The surface is maximized. The window geometry specified in the
- * configure event must be obeyed by the client, or the
- * xdg_wm_base.invalid_surface_state error is raised.
- *
- * The client should draw without shadow or other decoration
- * outside of the window geometry.
- */
- XDG_TOPLEVEL_STATE_MAXIMIZED = 1,
- /**
- * the surface is fullscreen
- * the surface is fullscreen
- *
- * The surface is fullscreen. The window geometry specified in
- * the configure event is a maximum; the client cannot resize
- * beyond it. For a surface to cover the whole fullscreened area,
- * the geometry dimensions must be obeyed by the client. For more
- * details, see xdg_toplevel.set_fullscreen.
- */
- XDG_TOPLEVEL_STATE_FULLSCREEN = 2,
- /**
- * the surface is being resized
- * the surface is being resized
- *
- * The surface is being resized. The window geometry specified in
- * the configure event is a maximum; the client cannot resize
- * beyond it. Clients that have aspect ratio or cell sizing
- * configuration can use a smaller size, however.
- */
- XDG_TOPLEVEL_STATE_RESIZING = 3,
- /**
- * the surface is now activated
- * the surface is now activated
- *
- * Client window decorations should be painted as if the window
- * is active. Do not assume this means that the window actually has
- * keyboard or pointer focus.
- */
- XDG_TOPLEVEL_STATE_ACTIVATED = 4,
- /**
- * the surface’s left edge is tiled
- *
- * The window is currently in a tiled layout and the left edge is
- * considered to be adjacent to another part of the tiling grid.
- * @since 2
- */
- XDG_TOPLEVEL_STATE_TILED_LEFT = 5,
- /**
- * the surface’s right edge is tiled
- *
- * The window is currently in a tiled layout and the right edge
- * is considered to be adjacent to another part of the tiling grid.
- * @since 2
- */
- XDG_TOPLEVEL_STATE_TILED_RIGHT = 6,
- /**
- * the surface’s top edge is tiled
- *
- * The window is currently in a tiled layout and the top edge is
- * considered to be adjacent to another part of the tiling grid.
- * @since 2
- */
- XDG_TOPLEVEL_STATE_TILED_TOP = 7,
- /**
- * the surface’s bottom edge is tiled
- *
- * The window is currently in a tiled layout and the bottom edge
- * is considered to be adjacent to another part of the tiling grid.
- * @since 2
- */
- XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8,
- /**
- * surface repaint is suspended
- *
- * The surface is currently not ordinarily being repainted; for
- * example because its content is occluded by another window, or
- * its outputs are switched off due to screen locking.
- * @since 6
- */
- XDG_TOPLEVEL_STATE_SUSPENDED = 9,
-};
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6
-#endif /* XDG_TOPLEVEL_STATE_ENUM */
-
-#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM
-#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM
-enum xdg_toplevel_wm_capabilities {
- /**
- * show_window_menu is available
- */
- XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1,
- /**
- * set_maximized and unset_maximized are available
- */
- XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2,
- /**
- * set_fullscreen and unset_fullscreen are available
- */
- XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3,
- /**
- * set_minimized is available
- */
- XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4,
-};
-#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */
-
-/**
- * @ingroup iface_xdg_toplevel
- * @struct xdg_toplevel_listener
- */
-struct xdg_toplevel_listener {
- /**
- * suggest a surface change
- *
- * This configure event asks the client to resize its toplevel
- * surface or to change its state. The configured state should not
- * be applied immediately. See xdg_surface.configure for details.
- *
- * The width and height arguments specify a hint to the window
- * about how its surface should be resized in window geometry
- * coordinates. See set_window_geometry.
- *
- * If the width or height arguments are zero, it means the client
- * should decide its own window dimension. This may happen when the
- * compositor needs to configure the state of the surface but
- * doesn't have any information about any previous or expected
- * dimension.
- *
- * The states listed in the event specify how the width/height
- * arguments should be interpreted, and possibly how it should be
- * drawn.
- *
- * Clients must send an ack_configure in response to this event.
- * See xdg_surface.configure and xdg_surface.ack_configure for
- * details.
- */
- void (*configure)(void *data,
- struct xdg_toplevel *xdg_toplevel,
- int32_t width,
- int32_t height,
- struct wl_array *states);
- /**
- * surface wants to be closed
- *
- * The close event is sent by the compositor when the user wants
- * the surface to be closed. This should be equivalent to the user
- * clicking the close button in client-side decorations, if your
- * application has any.
- *
- * This is only a request that the user intends to close the
- * window. The client may choose to ignore this request, or show a
- * dialog to ask the user to save their data, etc.
- */
- void (*close)(void *data,
- struct xdg_toplevel *xdg_toplevel);
- /**
- * recommended window geometry bounds
- *
- * The configure_bounds event may be sent prior to a
- * xdg_toplevel.configure event to communicate the bounds a window
- * geometry size is recommended to constrain to.
- *
- * The passed width and height are in surface coordinate space. If
- * width and height are 0, it means bounds is unknown and
- * equivalent to as if no configure_bounds event was ever sent for
- * this surface.
- *
- * The bounds can for example correspond to the size of a monitor
- * excluding any panels or other shell components, so that a
- * surface isn't created in a way that it cannot fit.
- *
- * The bounds may change at any point, and in such a case, a new
- * xdg_toplevel.configure_bounds will be sent, followed by
- * xdg_toplevel.configure and xdg_surface.configure.
- * @since 4
- */
- void (*configure_bounds)(void *data,
- struct xdg_toplevel *xdg_toplevel,
- int32_t width,
- int32_t height);
- /**
- * compositor capabilities
- *
- * This event advertises the capabilities supported by the
- * compositor. If a capability isn't supported, clients should hide
- * or disable the UI elements that expose this functionality. For
- * instance, if the compositor doesn't advertise support for
- * minimized toplevels, a button triggering the set_minimized
- * request should not be displayed.
- *
- * The compositor will ignore requests it doesn't support. For
- * instance, a compositor which doesn't advertise support for
- * minimized will ignore set_minimized requests.
- *
- * Compositors must send this event once before the first
- * xdg_surface.configure event. When the capabilities change,
- * compositors must send this event again and then send an
- * xdg_surface.configure event.
- *
- * The configured state should not be applied immediately. See
- * xdg_surface.configure for details.
- *
- * The capabilities are sent as an array of 32-bit unsigned
- * integers in native endianness.
- * @param capabilities array of 32-bit capabilities
- * @since 5
- */
- void (*wm_capabilities)(void *data,
- struct xdg_toplevel *xdg_toplevel,
- struct wl_array *capabilities);
-};
-
-/**
- * @ingroup iface_xdg_toplevel
- */
-static inline int
-xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel,
- const struct xdg_toplevel_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel,
- (void (**)(void)) listener, data);
-}
-
-#define XDG_TOPLEVEL_DESTROY 0
-#define XDG_TOPLEVEL_SET_PARENT 1
-#define XDG_TOPLEVEL_SET_TITLE 2
-#define XDG_TOPLEVEL_SET_APP_ID 3
-#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4
-#define XDG_TOPLEVEL_MOVE 5
-#define XDG_TOPLEVEL_RESIZE 6
-#define XDG_TOPLEVEL_SET_MAX_SIZE 7
-#define XDG_TOPLEVEL_SET_MIN_SIZE 8
-#define XDG_TOPLEVEL_SET_MAXIMIZED 9
-#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10
-#define XDG_TOPLEVEL_SET_FULLSCREEN 11
-#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12
-#define XDG_TOPLEVEL_SET_MINIMIZED 13
-
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5
-
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_toplevel
- */
-#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1
-
-/** @ingroup iface_xdg_toplevel */
-static inline void
-xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data);
-}
-
-/** @ingroup iface_xdg_toplevel */
-static inline void *
-xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel);
-}
-
-static inline uint32_t
-xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel)
-{
- return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * This request destroys the role surface and unmaps the surface;
- * see "Unmapping" behavior in interface section for details.
- */
-static inline void
-xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Set the "parent" of this surface. This surface should be stacked
- * above the parent surface and all other ancestor surfaces.
- *
- * Parent surfaces should be set on dialogs, toolboxes, or other
- * "auxiliary" surfaces, so that the parent is raised when the dialog
- * is raised.
- *
- * Setting a null parent for a child surface unsets its parent. Setting
- * a null parent for a surface which currently has no parent is a no-op.
- *
- * Only mapped surfaces can have child surfaces. Setting a parent which
- * is not mapped is equivalent to setting a null parent. If a surface
- * becomes unmapped, its children's parent is set to the parent of
- * the now-unmapped surface. If the now-unmapped surface has no parent,
- * its children's parent is unset. If the now-unmapped surface becomes
- * mapped again, its parent-child relationship is not restored.
- *
- * The parent toplevel must not be one of the child toplevel's
- * descendants, and the parent must be different from the child toplevel,
- * otherwise the invalid_parent protocol error is raised.
- */
-static inline void
-xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_SET_PARENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, parent);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Set a short title for the surface.
- *
- * This string may be used to identify the surface in a task bar,
- * window list, or other user interface elements provided by the
- * compositor.
- *
- * The string must be encoded in UTF-8.
- */
-static inline void
-xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, title);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Set an application identifier for the surface.
- *
- * The app ID identifies the general class of applications to which
- * the surface belongs. The compositor can use this to group multiple
- * surfaces together, or to determine how to launch a new application.
- *
- * For D-Bus activatable applications, the app ID is used as the D-Bus
- * service name.
- *
- * The compositor shell will try to group application surfaces together
- * by their app ID. As a best practice, it is suggested to select app
- * ID's that match the basename of the application's .desktop file.
- * For example, "org.freedesktop.FooViewer" where the .desktop file is
- * "org.freedesktop.FooViewer.desktop".
- *
- * Like other properties, a set_app_id request can be sent after the
- * xdg_toplevel has been mapped to update the property.
- *
- * See the desktop-entry specification [0] for more details on
- * application identifiers and how they relate to well-known D-Bus
- * names and .desktop files.
- *
- * [0] https://standards.freedesktop.org/desktop-entry-spec/
- */
-static inline void
-xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, app_id);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Clients implementing client-side decorations might want to show
- * a context menu when right-clicking on the decorations, giving the
- * user a menu that they can use to maximize or minimize the window.
- *
- * This request asks the compositor to pop up such a window menu at
- * the given position, relative to the local surface coordinates of
- * the parent surface. There are no guarantees as to what menu items
- * the window menu contains, or even if a window menu will be drawn
- * at all.
- *
- * This request must be used in response to some sort of user action
- * like a button press, key press, or touch down event.
- */
-static inline void
-xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_SHOW_WINDOW_MENU, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, x, y);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Start an interactive, user-driven move of the surface.
- *
- * This request must be used in response to some sort of user action
- * like a button press, key press, or touch down event. The passed
- * serial is used to determine the type of interactive move (touch,
- * pointer, etc).
- *
- * The server may ignore move requests depending on the state of
- * the surface (e.g. fullscreen or maximized), or if the passed serial
- * is no longer valid.
- *
- * If triggered, the surface will lose the focus of the device
- * (wl_pointer, wl_touch, etc) used for the move. It is up to the
- * compositor to visually indicate that the move is taking place, such as
- * updating a pointer cursor, during the move. There is no guarantee
- * that the device focus will return when the move is completed.
- */
-static inline void
-xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Start a user-driven, interactive resize of the surface.
- *
- * This request must be used in response to some sort of user action
- * like a button press, key press, or touch down event. The passed
- * serial is used to determine the type of interactive resize (touch,
- * pointer, etc).
- *
- * The server may ignore resize requests depending on the state of
- * the surface (e.g. fullscreen or maximized).
- *
- * If triggered, the client will receive configure events with the
- * "resize" state enum value and the expected sizes. See the "resize"
- * enum value for more details about what is required. The client
- * must also acknowledge configure events using "ack_configure". After
- * the resize is completed, the client will receive another "configure"
- * event without the resize state.
- *
- * If triggered, the surface also will lose the focus of the device
- * (wl_pointer, wl_touch, etc) used for the resize. It is up to the
- * compositor to visually indicate that the resize is taking place,
- * such as updating a pointer cursor, during the resize. There is no
- * guarantee that the device focus will return when the resize is
- * completed.
- *
- * The edges parameter specifies how the surface should be resized, and
- * is one of the values of the resize_edge enum. Values not matching
- * a variant of the enum will cause the invalid_resize_edge protocol error.
- * The compositor may use this information to update the surface position
- * for example when dragging the top left corner. The compositor may also
- * use this information to adapt its behavior, e.g. choose an appropriate
- * cursor image.
- */
-static inline void
-xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, edges);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Set a maximum size for the window.
- *
- * The client can specify a maximum size so that the compositor does
- * not try to configure the window beyond this size.
- *
- * The width and height arguments are in window geometry coordinates.
- * See xdg_surface.set_window_geometry.
- *
- * Values set in this way are double-buffered. They will get applied
- * on the next commit.
- *
- * The compositor can use this information to allow or disallow
- * different states like maximize or fullscreen and draw accurate
- * animations.
- *
- * Similarly, a tiling window manager may use this information to
- * place and resize client windows in a more effective way.
- *
- * The client should not rely on the compositor to obey the maximum
- * size. The compositor may decide to ignore the values set by the
- * client and request a larger size.
- *
- * If never set, or a value of zero in the request, means that the
- * client has no expected maximum size in the given dimension.
- * As a result, a client wishing to reset the maximum size
- * to an unspecified state can use zero for width and height in the
- * request.
- *
- * Requesting a maximum size to be smaller than the minimum size of
- * a surface is illegal and will result in an invalid_size error.
- *
- * The width and height must be greater than or equal to zero. Using
- * strictly negative values for width or height will result in a
- * invalid_size error.
- */
-static inline void
-xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_SET_MAX_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Set a minimum size for the window.
- *
- * The client can specify a minimum size so that the compositor does
- * not try to configure the window below this size.
- *
- * The width and height arguments are in window geometry coordinates.
- * See xdg_surface.set_window_geometry.
- *
- * Values set in this way are double-buffered. They will get applied
- * on the next commit.
- *
- * The compositor can use this information to allow or disallow
- * different states like maximize or fullscreen and draw accurate
- * animations.
- *
- * Similarly, a tiling window manager may use this information to
- * place and resize client windows in a more effective way.
- *
- * The client should not rely on the compositor to obey the minimum
- * size. The compositor may decide to ignore the values set by the
- * client and request a smaller size.
- *
- * If never set, or a value of zero in the request, means that the
- * client has no expected minimum size in the given dimension.
- * As a result, a client wishing to reset the minimum size
- * to an unspecified state can use zero for width and height in the
- * request.
- *
- * Requesting a minimum size to be larger than the maximum size of
- * a surface is illegal and will result in an invalid_size error.
- *
- * The width and height must be greater than or equal to zero. Using
- * strictly negative values for width and height will result in a
- * invalid_size error.
- */
-static inline void
-xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_SET_MIN_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Maximize the surface.
- *
- * After requesting that the surface should be maximized, the compositor
- * will respond by emitting a configure event. Whether this configure
- * actually sets the window maximized is subject to compositor policies.
- * The client must then update its content, drawing in the configured
- * state. The client must also acknowledge the configure when committing
- * the new content (see ack_configure).
- *
- * It is up to the compositor to decide how and where to maximize the
- * surface, for example which output and what region of the screen should
- * be used.
- *
- * If the surface was already maximized, the compositor will still emit
- * a configure event with the "maximized" state.
- *
- * If the surface is in a fullscreen state, this request has no direct
- * effect. It may alter the state the surface is returned to when
- * unmaximized unless overridden by the compositor.
- */
-static inline void
-xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Unmaximize the surface.
- *
- * After requesting that the surface should be unmaximized, the compositor
- * will respond by emitting a configure event. Whether this actually
- * un-maximizes the window is subject to compositor policies.
- * If available and applicable, the compositor will include the window
- * geometry dimensions the window had prior to being maximized in the
- * configure event. The client must then update its content, drawing it in
- * the configured state. The client must also acknowledge the configure
- * when committing the new content (see ack_configure).
- *
- * It is up to the compositor to position the surface after it was
- * unmaximized; usually the position the surface had before maximizing, if
- * applicable.
- *
- * If the surface was already not maximized, the compositor will still
- * emit a configure event without the "maximized" state.
- *
- * If the surface is in a fullscreen state, this request has no direct
- * effect. It may alter the state the surface is returned to when
- * unmaximized unless overridden by the compositor.
- */
-static inline void
-xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_UNSET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Make the surface fullscreen.
- *
- * After requesting that the surface should be fullscreened, the
- * compositor will respond by emitting a configure event. Whether the
- * client is actually put into a fullscreen state is subject to compositor
- * policies. The client must also acknowledge the configure when
- * committing the new content (see ack_configure).
- *
- * The output passed by the request indicates the client's preference as
- * to which display it should be set fullscreen on. If this value is NULL,
- * it's up to the compositor to choose which display will be used to map
- * this surface.
- *
- * If the surface doesn't cover the whole output, the compositor will
- * position the surface in the center of the output and compensate with
- * with border fill covering the rest of the output. The content of the
- * border fill is undefined, but should be assumed to be in some way that
- * attempts to blend into the surrounding area (e.g. solid black).
- *
- * If the fullscreened surface is not opaque, the compositor must make
- * sure that other screen content not part of the same surface tree (made
- * up of subsurfaces, popups or similarly coupled surfaces) are not
- * visible below the fullscreened surface.
- */
-static inline void
-xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, output);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Make the surface no longer fullscreen.
- *
- * After requesting that the surface should be unfullscreened, the
- * compositor will respond by emitting a configure event.
- * Whether this actually removes the fullscreen state of the client is
- * subject to compositor policies.
- *
- * Making a surface unfullscreen sets states for the surface based on the following:
- * * the state(s) it may have had before becoming fullscreen
- * * any state(s) decided by the compositor
- * * any state(s) requested by the client while the surface was fullscreen
- *
- * The compositor may include the previous window geometry dimensions in
- * the configure event, if applicable.
- *
- * The client must also acknowledge the configure when committing the new
- * content (see ack_configure).
- */
-static inline void
-xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_UNSET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
-}
-
-/**
- * @ingroup iface_xdg_toplevel
- *
- * Request that the compositor minimize your surface. There is no
- * way to know if the surface is currently minimized, nor is there
- * any way to unset minimization on this surface.
- *
- * If you are looking to throttle redrawing when minimized, please
- * instead use the wl_surface.frame event for this, as this will
- * also work with live previews on windows in Alt-Tab, Expose or
- * similar compositor features.
- */
-static inline void
-xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
- XDG_TOPLEVEL_SET_MINIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
-}
-
-#ifndef XDG_POPUP_ERROR_ENUM
-#define XDG_POPUP_ERROR_ENUM
-enum xdg_popup_error {
- /**
- * tried to grab after being mapped
- */
- XDG_POPUP_ERROR_INVALID_GRAB = 0,
-};
-#endif /* XDG_POPUP_ERROR_ENUM */
-
-/**
- * @ingroup iface_xdg_popup
- * @struct xdg_popup_listener
- */
-struct xdg_popup_listener {
- /**
- * configure the popup surface
- *
- * This event asks the popup surface to configure itself given
- * the configuration. The configured state should not be applied
- * immediately. See xdg_surface.configure for details.
- *
- * The x and y arguments represent the position the popup was
- * placed at given the xdg_positioner rule, relative to the upper
- * left corner of the window geometry of the parent surface.
- *
- * For version 2 or older, the configure event for an xdg_popup is
- * only ever sent once for the initial configuration. Starting with
- * version 3, it may be sent again if the popup is setup with an
- * xdg_positioner with set_reactive requested, or in response to
- * xdg_popup.reposition requests.
- * @param x x position relative to parent surface window geometry
- * @param y y position relative to parent surface window geometry
- * @param width window geometry width
- * @param height window geometry height
- */
- void (*configure)(void *data,
- struct xdg_popup *xdg_popup,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height);
- /**
- * popup interaction is done
- *
- * The popup_done event is sent out when a popup is dismissed by
- * the compositor. The client should destroy the xdg_popup object
- * at this point.
- */
- void (*popup_done)(void *data,
- struct xdg_popup *xdg_popup);
- /**
- * signal the completion of a repositioned request
- *
- * The repositioned event is sent as part of a popup
- * configuration sequence, together with xdg_popup.configure and
- * lastly xdg_surface.configure to notify the completion of a
- * reposition request.
- *
- * The repositioned event is to notify about the completion of a
- * xdg_popup.reposition request. The token argument is the token
- * passed in the xdg_popup.reposition request.
- *
- * Immediately after this event is emitted, xdg_popup.configure and
- * xdg_surface.configure will be sent with the updated size and
- * position, as well as a new configure serial.
- *
- * The client should optionally update the content of the popup,
- * but must acknowledge the new popup configuration for the new
- * position to take effect. See xdg_surface.ack_configure for
- * details.
- * @param token reposition request token
- * @since 3
- */
- void (*repositioned)(void *data,
- struct xdg_popup *xdg_popup,
- uint32_t token);
-};
-
-/**
- * @ingroup iface_xdg_popup
- */
-static inline int
-xdg_popup_add_listener(struct xdg_popup *xdg_popup,
- const struct xdg_popup_listener *listener, void *data)
-{
- return wl_proxy_add_listener((struct wl_proxy *) xdg_popup,
- (void (**)(void)) listener, data);
-}
-
-#define XDG_POPUP_DESTROY 0
-#define XDG_POPUP_GRAB 1
-#define XDG_POPUP_REPOSITION 2
-
-/**
- * @ingroup iface_xdg_popup
- */
-#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_popup
- */
-#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_popup
- */
-#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3
-
-/**
- * @ingroup iface_xdg_popup
- */
-#define XDG_POPUP_DESTROY_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_popup
- */
-#define XDG_POPUP_GRAB_SINCE_VERSION 1
-/**
- * @ingroup iface_xdg_popup
- */
-#define XDG_POPUP_REPOSITION_SINCE_VERSION 3
-
-/** @ingroup iface_xdg_popup */
-static inline void
-xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data)
-{
- wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data);
-}
-
-/** @ingroup iface_xdg_popup */
-static inline void *
-xdg_popup_get_user_data(struct xdg_popup *xdg_popup)
-{
- return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup);
-}
-
-static inline uint32_t
-xdg_popup_get_version(struct xdg_popup *xdg_popup)
-{
- return wl_proxy_get_version((struct wl_proxy *) xdg_popup);
-}
-
-/**
- * @ingroup iface_xdg_popup
- *
- * This destroys the popup. Explicitly destroying the xdg_popup
- * object will also dismiss the popup, and unmap the surface.
- *
- * If this xdg_popup is not the "topmost" popup, the
- * xdg_wm_base.not_the_topmost_popup protocol error will be sent.
- */
-static inline void
-xdg_popup_destroy(struct xdg_popup *xdg_popup)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup,
- XDG_POPUP_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), WL_MARSHAL_FLAG_DESTROY);
-}
-
-/**
- * @ingroup iface_xdg_popup
- *
- * This request makes the created popup take an explicit grab. An explicit
- * grab will be dismissed when the user dismisses the popup, or when the
- * client destroys the xdg_popup. This can be done by the user clicking
- * outside the surface, using the keyboard, or even locking the screen
- * through closing the lid or a timeout.
- *
- * If the compositor denies the grab, the popup will be immediately
- * dismissed.
- *
- * This request must be used in response to some sort of user action like a
- * button press, key press, or touch down event. The serial number of the
- * event should be passed as 'serial'.
- *
- * The parent of a grabbing popup must either be an xdg_toplevel surface or
- * another xdg_popup with an explicit grab. If the parent is another
- * xdg_popup it means that the popups are nested, with this popup now being
- * the topmost popup.
- *
- * Nested popups must be destroyed in the reverse order they were created
- * in, e.g. the only popup you are allowed to destroy at all times is the
- * topmost one.
- *
- * When compositors choose to dismiss a popup, they may dismiss every
- * nested grabbing popup as well. When a compositor dismisses popups, it
- * will follow the same dismissing order as required from the client.
- *
- * If the topmost grabbing popup is destroyed, the grab will be returned to
- * the parent of the popup, if that parent previously had an explicit grab.
- *
- * If the parent is a grabbing popup which has already been dismissed, this
- * popup will be immediately dismissed. If the parent is a popup that did
- * not take an explicit grab, an error will be raised.
- *
- * During a popup grab, the client owning the grab will receive pointer
- * and touch events for all their surfaces as normal (similar to an
- * "owner-events" grab in X11 parlance), while the top most grabbing popup
- * will always have keyboard focus.
- */
-static inline void
-xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup,
- XDG_POPUP_GRAB, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, seat, serial);
-}
-
-/**
- * @ingroup iface_xdg_popup
- *
- * Reposition an already-mapped popup. The popup will be placed given the
- * details in the passed xdg_positioner object, and a
- * xdg_popup.repositioned followed by xdg_popup.configure and
- * xdg_surface.configure will be emitted in response. Any parameters set
- * by the previous positioner will be discarded.
- *
- * The passed token will be sent in the corresponding
- * xdg_popup.repositioned event. The new popup position will not take
- * effect until the corresponding configure event is acknowledged by the
- * client. See xdg_popup.repositioned for details. The token itself is
- * opaque, and has no other special meaning.
- *
- * If multiple reposition requests are sent, the compositor may skip all
- * but the last one.
- *
- * If the popup is repositioned in response to a configure event for its
- * parent, the client should send an xdg_positioner.set_parent_configure
- * and possibly an xdg_positioner.set_parent_size request to allow the
- * compositor to properly constrain the popup.
- *
- * If the popup is repositioned together with a parent that is being
- * resized, but not in response to a configure event, the client should
- * send an xdg_positioner.set_parent_size request.
- */
-static inline void
-xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token)
-{
- wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup,
- XDG_POPUP_REPOSITION, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, positioner, token);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pkg/macos/graphics/context.zig b/pkg/macos/graphics/context.zig
index d1c6c943f..77e4344e0 100644
--- a/pkg/macos/graphics/context.zig
+++ b/pkg/macos/graphics/context.zig
@@ -141,6 +141,22 @@ pub fn Context(comptime T: type) type {
@bitCast(rect),
);
}
+
+ pub fn scaleCTM(self: *T, sx: c.CGFloat, sy: c.CGFloat) void {
+ c.CGContextScaleCTM(
+ @ptrCast(self),
+ sx,
+ sy,
+ );
+ }
+
+ pub fn translateCTM(self: *T, tx: c.CGFloat, ty: c.CGFloat) void {
+ c.CGContextTranslateCTM(
+ @ptrCast(self),
+ tx,
+ ty,
+ );
+ }
};
}
diff --git a/pkg/opengl/Texture.zig b/pkg/opengl/Texture.zig
index 2c8e05eff..03e794855 100644
--- a/pkg/opengl/Texture.zig
+++ b/pkg/opengl/Texture.zig
@@ -92,6 +92,30 @@ pub const Format = enum(c_uint) {
_,
};
+/// Minification filter for textures.
+pub const MinFilter = enum(c_int) {
+ nearest = c.GL_NEAREST,
+ linear = c.GL_LINEAR,
+ nearest_mipmap_nearest = c.GL_NEAREST_MIPMAP_NEAREST,
+ linear_mipmap_nearest = c.GL_LINEAR_MIPMAP_NEAREST,
+ nearest_mipmap_linear = c.GL_NEAREST_MIPMAP_LINEAR,
+ linear_mipmap_linear = c.GL_LINEAR_MIPMAP_LINEAR,
+};
+
+/// Magnification filter for textures.
+pub const MagFilter = enum(c_int) {
+ nearest = c.GL_NEAREST,
+ linear = c.GL_LINEAR,
+};
+
+/// Texture coordinate wrapping mode.
+pub const Wrap = enum(c_int) {
+ clamp_to_edge = c.GL_CLAMP_TO_EDGE,
+ clamp_to_border = c.GL_CLAMP_TO_BORDER,
+ mirrored_repeat = c.GL_MIRRORED_REPEAT,
+ repeat = c.GL_REPEAT,
+};
+
/// Data type for texture images.
pub const DataType = enum(c_uint) {
UnsignedByte = c.GL_UNSIGNED_BYTE,
diff --git a/po/README_TRANSLATORS.md b/po/README_TRANSLATORS.md
index ca1e45faa..c02a5bd48 100644
--- a/po/README_TRANSLATORS.md
+++ b/po/README_TRANSLATORS.md
@@ -148,6 +148,18 @@ const locales = [_][]const u8{
You should then be able to run `zig build` and see your translations in action.
+Before opening a pull request with the new translation file, you should also add
+your locale to the `CODEOWNERS` file. Find the `# Localization` section near the
+bottom and add a line like so (where `xx_YY` is your locale):
+
+```diff
+ # Localization
+ /po/README_TRANSLATORS.md @ghostty-org/localization
+ /po/com.mitchellh.ghostty.pot @ghostty-org/localization
+ /po/zh_CN.UTF-8.po @ghostty-org/zh_CN
++/po/xx_YY.UTF-8.po @ghostty-org/xx_YY
+```
+
## Style Guide
These are general style guidelines for translations. Naturally, the specific
diff --git a/po/bg_BG.UTF-8.po b/po/bg_BG.UTF-8.po
new file mode 100644
index 000000000..84fd455e2
--- /dev/null
+++ b/po/bg_BG.UTF-8.po
@@ -0,0 +1,307 @@
+# Bulgarian translations for com.mitchellh.ghostty package.
+# Copyright (C) 2025 Mitchell Hashimoto
+# This file is distributed under the same license as the com.mitchellh.ghostty package.
+# Damyan Bogoev , 2025.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: com.mitchellh.ghostty\n"
+"Report-Msgid-Bugs-To: m@mitchellh.com\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
+"PO-Revision-Date: 2025-05-19 11:34+0300\n"
+"Last-Translator: Damyan Bogoev \n"
+"Language-Team: Bulgarian \n"
+"Language: bg\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:5
+msgid "Change Terminal Title"
+msgstr "Промяна на заглавието на терминала"
+
+#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:6
+msgid "Leave blank to restore the default title."
+msgstr "Оставете празно за възстановяване на заглавието по подразбиране."
+
+#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
+msgid "Cancel"
+msgstr "Отказ"
+
+#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:10
+msgid "OK"
+msgstr "ОК"
+
+#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
+msgid "Configuration Errors"
+msgstr "Грешки в конфигурацията"
+
+#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
+msgid ""
+"One or more configuration errors were found. Please review the errors below, "
+"and either reload your configuration or ignore these errors."
+msgstr ""
+"Открити са една или повече грешки в конфигурацията. Моля, прегледайте "
+"грешките по-долу и или презаредете конфигурацията си, или ги игнорирайте."
+
+#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
+msgid "Ignore"
+msgstr "Игнорирай"
+
+#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
+msgid "Reload Configuration"
+msgstr "Презареди конфигурацията"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:6
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:38
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:50
+msgid "Split Up"
+msgstr "Раздели нагоре"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:11
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:43
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:55
+msgid "Split Down"
+msgstr "Раздели надолу"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:16
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:48
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:60
+msgid "Split Left"
+msgstr "Раздели наляво"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:21
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:53
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:65
+msgid "Split Right"
+msgstr "Раздели надясно"
+
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr "Изпълни команда…"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
+msgid "Copy"
+msgstr "Копирай"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
+msgid "Paste"
+msgstr "Постави"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:18
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:73
+msgid "Clear"
+msgstr "Изчисти"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:23
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:78
+msgid "Reset"
+msgstr "Нулирай"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:30
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:42
+msgid "Split"
+msgstr "Раздели"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:33
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:45
+msgid "Change Title…"
+msgstr "Промени заглавие…"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:59
+msgid "Tab"
+msgstr "Раздел"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
+#: src/apprt/gtk/Window.zig:265
+msgid "New Tab"
+msgstr "Нов раздел"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:67
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:35
+msgid "Close Tab"
+msgstr "Затвори раздел"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:73
+msgid "Window"
+msgstr "Прозорец"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:76
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:18
+msgid "New Window"
+msgstr "Нов прозорец"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:81
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:23
+msgid "Close Window"
+msgstr "Затвори прозорец"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:89
+msgid "Config"
+msgstr "Конфигурация"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+msgid "Open Configuration"
+msgstr "Отвори конфигурацията"
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr "Командна палитра"
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+msgid "Terminal Inspector"
+msgstr "Инспектор на терминала"
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
+msgid "About Ghostty"
+msgstr "За Ghostty"
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
+msgid "Quit"
+msgstr "Изход"
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
+msgid "Authorize Clipboard Access"
+msgstr "Разрешаване на достъп до клипборда"
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
+msgid ""
+"An application is attempting to read from the clipboard. The current "
+"clipboard contents are shown below."
+msgstr ""
+"Приложение се опитва да чете от клипборда. Текущото съдържание на клипборда "
+"е показано по-долу."
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
+msgid "Deny"
+msgstr "Откажи"
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
+msgid "Allow"
+msgstr "Позволи"
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
+msgid ""
+"An application is attempting to write to the clipboard. The current "
+"clipboard contents are shown below."
+msgstr ""
+"Приложение се опитва да запише в клипборда. Текущото съдържание на клипборда "
+"е показано по-долу."
+
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
+msgid "Warning: Potentially Unsafe Paste"
+msgstr "Предупреждение: Потенциално опасно поставяне"
+
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
+msgid ""
+"Pasting this text into the terminal may be dangerous as it looks like some "
+"commands may be executed."
+msgstr ""
+"Поставянето на този текст в терминала може да е опасно, тъй като изглежда, "
+"че може да бъдат изпълнени някои команди."
+
+#: src/apprt/gtk/CloseDialog.zig:47
+msgid "Close"
+msgstr "Затвори"
+
+#: src/apprt/gtk/CloseDialog.zig:87
+msgid "Quit Ghostty?"
+msgstr "Изход от Ghostty?"
+
+#: src/apprt/gtk/CloseDialog.zig:88
+msgid "Close Window?"
+msgstr "Затваряне на прозореца?"
+
+#: src/apprt/gtk/CloseDialog.zig:89
+msgid "Close Tab?"
+msgstr "Затваряне на раздела?"
+
+#: src/apprt/gtk/CloseDialog.zig:90
+msgid "Close Split?"
+msgstr "Затваряне на разделянето?"
+
+#: src/apprt/gtk/CloseDialog.zig:96
+msgid "All terminal sessions will be terminated."
+msgstr "Всички терминални сесии ще бъдат прекратени."
+
+#: src/apprt/gtk/CloseDialog.zig:97
+msgid "All terminal sessions in this window will be terminated."
+msgstr "Всички терминални сесии в този прозорец ще бъдат прекратени."
+
+#: src/apprt/gtk/CloseDialog.zig:98
+msgid "All terminal sessions in this tab will be terminated."
+msgstr "Всички терминални сесии в този раздел ще бъдат прекратени."
+
+#: src/apprt/gtk/CloseDialog.zig:99
+msgid "The currently running process in this split will be terminated."
+msgstr "Текущият процес в това разделяне ще бъде прекратен."
+
+#: src/apprt/gtk/Surface.zig:1257
+msgid "Copied to clipboard"
+msgstr "Копирано в клипборда"
+
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Главно меню"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Преглед на отворените раздели"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr "Ново разделяне"
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Използвате дебъг версия на Ghostty! Производителността ще бъде намалена."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Конфигурацията е презаредена"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Разработчици на Ghostty"
+
+#: src/apprt/gtk/inspector.zig:144
+msgid "Ghostty: Terminal Inspector"
+msgstr "Ghostty: Инспектор на терминала"
diff --git a/po/ca_ES.UTF-8.po b/po/ca_ES.UTF-8.po
index 653439fa2..11bc99f57 100644
--- a/po/ca_ES.UTF-8.po
+++ b/po/ca_ES.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-20 08:07+0100\n"
"Last-Translator: Francesc Arpi \n"
"Language-Team: \n"
@@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Deixa en blanc per restaurar el títol per defecte."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Cancel·la"
@@ -35,10 +36,12 @@ msgid "OK"
msgstr "D'acord"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Errors de configuració"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -47,12 +50,14 @@ msgstr ""
"a continuació i torna a carregar la configuració o ignora aquests errors."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignora"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Carrega la configuració"
@@ -80,6 +85,10 @@ msgstr "Divideix a l'esquerra"
msgid "Split Right"
msgstr "Divideix a la dreta"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -87,7 +96,7 @@ msgstr "Copia"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Enganxa"
@@ -117,7 +126,7 @@ msgstr "Pestanya"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nova pestanya"
@@ -145,29 +154,36 @@ msgid "Config"
msgstr "Configuració"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Obre la configuració"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Inspector de terminal"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Sobre Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Surt"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Autoritza l'accés al porta-retalls"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -177,15 +193,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Denegar"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Permet"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -193,11 +224,11 @@ msgstr ""
"Una aplicació està intentant escriure al porta-retalls. El contingut actual "
"del porta-retalls es mostra a continuació."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Avís: Enganxament potencialment insegur"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -205,33 +236,6 @@ msgstr ""
"Enganxar aquest text al terminal pot ser perillós, ja que sembla que es "
"podrien executar algunes ordres."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Menú principal"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Mostra les pestanyes obertes"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Estàs executant una versió de depuració de Ghostty! El rendiment es veurà "
-"afectat."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "S'ha tornat a carregar la configuració"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Desenvolupadors de Ghostty"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Tanca"
@@ -268,10 +272,37 @@ msgstr "Totes les sessions del terminal en aquesta pestanya es tancaran."
msgid "The currently running process in this split will be terminated."
msgstr "El procés actualment en execució en aquesta divisió es tancarà."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Copiat al porta-retalls"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Menú principal"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Mostra les pestanyes obertes"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Estàs executant una versió de depuració de Ghostty! El rendiment es veurà "
+"afectat."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "S'ha tornat a carregar la configuració"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Desenvolupadors de Ghostty"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspector de terminal"
diff --git a/po/com.mitchellh.ghostty.pot b/po/com.mitchellh.ghostty.pot
index 7691f91b5..584f843b6 100644
--- a/po/com.mitchellh.ghostty.pot
+++ b/po/com.mitchellh.ghostty.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-06-28 17:01+0200\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -124,7 +124,7 @@ msgstr ""
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:263
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr ""
@@ -165,7 +165,7 @@ msgid "Terminal Inspector"
msgstr ""
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
-#: src/apprt/gtk/Window.zig:1036
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr ""
@@ -228,35 +228,6 @@ msgid ""
"commands may be executed."
msgstr ""
-#: src/apprt/gtk/Window.zig:216
-msgid "Main Menu"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:238
-msgid "View Open Tabs"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:264
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:327
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:773
-msgid "Reloaded the configuration"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:1017
-msgid "Ghostty Developers"
-msgstr ""
-
-#: src/apprt/gtk/inspector.zig:144
-msgid "Ghostty: Terminal Inspector"
-msgstr ""
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr ""
@@ -296,3 +267,32 @@ msgstr ""
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr ""
+
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr ""
+
+#: src/apprt/gtk/inspector.zig:144
+msgid "Ghostty: Terminal Inspector"
+msgstr ""
diff --git a/po/de_DE.UTF-8.po b/po/de_DE.UTF-8.po
index 2d3b96d81..fcca71101 100644
--- a/po/de_DE.UTF-8.po
+++ b/po/de_DE.UTF-8.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-06 14:57+0100\n"
"Last-Translator: Robin \n"
"Language-Team: German \n"
@@ -27,7 +27,8 @@ msgid "Leave blank to restore the default title."
msgstr "Leer lassen, um den Standardtitel wiederherzustellen."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Abbrechen"
@@ -36,22 +37,26 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr ""
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
msgstr ""
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr ""
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Konfiguration neu laden"
@@ -79,6 +84,10 @@ msgstr "Fenter nach links teilen"
msgid "Split Right"
msgstr "Fenster nach rechts teilen"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -86,7 +95,7 @@ msgstr "Kopieren"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Einfügen"
@@ -116,7 +125,7 @@ msgstr "Tab"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Neuer Tab"
@@ -144,29 +153,36 @@ msgid "Config"
msgstr "Konfiguration"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Konfiguration öffnen"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Terminalinspektor"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Über Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Beenden"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Zugriff auf die Zwischenablage gewähren"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -176,15 +192,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Nicht erlauben"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Erlauben"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -192,11 +223,11 @@ msgstr ""
"Eine Anwendung versucht in die Zwischenablage zu schreiben. Der aktuelle "
"Inhalt der Zwischenablage wird unten angezeigt."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Achtung: Möglicherweise unsicheres Einfügen"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -204,33 +235,6 @@ msgstr ""
"Diesen Text in das Terminal einzufügen könnte möglicherweise gefährlich "
"sein. Es scheint, dass Anweisungen ausgeführt werden könnten."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Hauptmenü"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Offene Tabs einblenden"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Du verwendest einen Debug Build von Ghostty! Die Leistung wird reduziert "
-"sein."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "Konfiguration wurde neu geladen"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Ghostty-Entwickler"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Schließen"
@@ -267,10 +271,37 @@ msgstr "Alle Terminalsitzungen in diesem Tab werden beendet."
msgid "The currently running process in this split will be terminated."
msgstr "Der aktuell laufende Prozess in diesem geteilten Fenster wird beendet."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "In die Zwischenablage kopiert"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Hauptmenü"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Offene Tabs einblenden"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Du verwendest einen Debug Build von Ghostty! Die Leistung wird reduziert "
+"sein."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Konfiguration wurde neu geladen"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Ghostty-Entwickler"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr ""
diff --git a/po/es_AR.UTF-8.po b/po/es_AR.UTF-8.po
index 3cd0625c8..9b3b68693 100644
--- a/po/es_AR.UTF-8.po
+++ b/po/es_AR.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-23 16:58+0800\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-05-19 20:17-0300\n"
"Last-Translator: Alan Moyano \n"
"Language-Team: Argentinian \n"
@@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Dejar en blanco para restaurar el título predeterminado."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Cancelar"
@@ -35,10 +36,12 @@ msgid "OK"
msgstr "Aceptar"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Errores de configuración"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -47,12 +50,14 @@ msgstr ""
"errores a continuación, y recargá tu configuración o ignorá estos errores."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignorar"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Recargar configuración"
@@ -91,7 +96,7 @@ msgstr "Copiar"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Pegar"
@@ -121,7 +126,7 @@ msgstr "Pestaña"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:255
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nueva pestaña"
@@ -162,7 +167,7 @@ msgid "Terminal Inspector"
msgstr "Inspector de la terminal"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
-#: src/apprt/gtk/Window.zig:1024
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Acerca de Ghostty"
@@ -172,10 +177,13 @@ msgstr "Salir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Autorizar acceso al portapapeles"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -185,15 +193,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Denegar"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Permitir"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -201,11 +224,11 @@ msgstr ""
"Una aplicación está intentando escribir en el portapapeles. El contenido "
"actual del portapapeles se muestra a continuación."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Advertencia: Pegado potencialmente inseguro"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -213,37 +236,6 @@ msgstr ""
"Pegar este texto en la terminal puede ser peligroso ya que parece que "
"algunos comandos podrían ejecutarse."
-#: src/apprt/gtk/Window.zig:208
-msgid "Main Menu"
-msgstr "Menú principal"
-
-#: src/apprt/gtk/Window.zig:229
-msgid "View Open Tabs"
-msgstr "Ver pestañas abiertas"
-
-#: src/apprt/gtk/Window.zig:256
-msgid "New Split"
-msgstr "Nueva división"
-
-#: src/apprt/gtk/Window.zig:319
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Estás ejecutando una versión de depuración de Ghostty. El rendimiento no "
-"será óptimo."
-
-#: src/apprt/gtk/Window.zig:765
-msgid "Reloaded the configuration"
-msgstr "Configuración recargada"
-
-#: src/apprt/gtk/Window.zig:1005
-msgid "Ghostty Developers"
-msgstr "Desarrolladores de Ghostty"
-
-#: src/apprt/gtk/inspector.zig:144
-msgid "Ghostty: Terminal Inspector"
-msgstr "Ghostty: Inspector de la terminal"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Cerrar"
@@ -280,6 +272,37 @@ msgstr "Todas las sesiones de terminal en esta pestaña serán terminadas."
msgid "The currently running process in this split will be terminated."
msgstr "El proceso actualmente en ejecución en esta división será terminado."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Copiado al portapapeles"
+
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Menú principal"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Ver pestañas abiertas"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr "Nueva división"
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Estás ejecutando una versión de depuración de Ghostty. El rendimiento no "
+"será óptimo."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Configuración recargada"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Desarrolladores de Ghostty"
+
+#: src/apprt/gtk/inspector.zig:144
+msgid "Ghostty: Terminal Inspector"
+msgstr "Ghostty: Inspector de la terminal"
diff --git a/po/es_BO.UTF-8.po b/po/es_BO.UTF-8.po
index 077b7dfa1..c89b53f61 100644
--- a/po/es_BO.UTF-8.po
+++ b/po/es_BO.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-28 17:46+0200\n"
"Last-Translator: Miguel Peredo \n"
"Language-Team: Spanish \n"
@@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Dejar en blanco para restaurar el título predeterminado."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Cancelar"
@@ -35,10 +36,12 @@ msgid "OK"
msgstr "Aceptar"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Errores de configuración"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -47,12 +50,14 @@ msgstr ""
"errores a continuación, y recargue su configuración o ignore estos errores."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignorar"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Recargar configuración"
@@ -80,6 +85,10 @@ msgstr "Dividir a la izquierda"
msgid "Split Right"
msgstr "Dividir a la derecha"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -87,7 +96,7 @@ msgstr "Copiar"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Pegar"
@@ -117,7 +126,7 @@ msgstr "Pestaña"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nueva pestaña"
@@ -145,29 +154,36 @@ msgid "Config"
msgstr "Configuración"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Abrir configuración"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Inspector de la terminal"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Acerca de Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Salir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Autorizar acceso al portapapeles"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -177,15 +193,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Denegar"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Permitir"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -193,11 +224,11 @@ msgstr ""
"Una aplicación está intentando escribir en el portapapeles. El contenido "
"actual del portapapeles se muestra a continuación."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Advertencia: Pegado potencialmente inseguro"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -205,33 +236,6 @@ msgstr ""
"Pegar este texto en la terminal puede ser peligroso ya que parece que "
"algunos comandos podrían ejecutarse."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Menú principal"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Ver pestañas abiertas"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Está ejecutando una versión de depuración de Ghostty. El rendimiento no "
-"será óptimo."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "Configuración recargada"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Desarrolladores de Ghostty"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Cerrar"
@@ -268,10 +272,37 @@ msgstr "Todas las sesiones de terminal en esta pestaña serán terminadas."
msgid "The currently running process in this split will be terminated."
msgstr "El proceso actualmente en ejecución en esta división será terminado."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Copiado al portapapeles"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Menú principal"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Ver pestañas abiertas"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Está ejecutando una versión de depuración de Ghostty. El rendimiento no "
+"será óptimo."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Configuración recargada"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Desarrolladores de Ghostty"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspector de la terminal"
diff --git a/po/fr_FR.UTF-8.po b/po/fr_FR.UTF-8.po
index aef0d96ac..2c227edaf 100644
--- a/po/fr_FR.UTF-8.po
+++ b/po/fr_FR.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-22 09:31+0100\n"
"Last-Translator: Kirwiisp \n"
"Language-Team: French \n"
@@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Laisser vide pour restaurer le titre par défaut."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Annuler"
@@ -35,10 +36,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Erreurs de configuration"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -48,12 +51,14 @@ msgstr ""
"erreurs."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignorer"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Recharger la configuration"
@@ -81,6 +86,10 @@ msgstr "Panneau à gauche"
msgid "Split Right"
msgstr "Panneau à droite"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -88,7 +97,7 @@ msgstr "Copier"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Coller"
@@ -118,7 +127,7 @@ msgstr "Onglet"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nouvel onglet"
@@ -146,29 +155,36 @@ msgid "Config"
msgstr "Config"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Ouvrir la configuration"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Inspecteur de terminal"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "À propos de Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Quitter"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Autoriser l'accès au presse-papiers"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -178,15 +194,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Refuser"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Autoriser"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -194,11 +225,11 @@ msgstr ""
"Une application essaie d'écrire dans le presse-papiers.Le contenu actuel du "
"presse-papiers est affiché ci-dessous."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Attention: Collage potentiellement dangereux"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -206,33 +237,6 @@ msgstr ""
"Coller ce texte dans le terminal pourrait être dangereux, il semblerait que "
"certaines commandes pourraient être exécutées."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Menu principal"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Voir les onglets ouverts"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Vous utilisez une version de débogage de Ghostty ! Les performances seront "
-"dégradées."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "Recharger la configuration"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Les développeurs de Ghostty"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Fermer"
@@ -269,10 +273,37 @@ msgstr "Toutes les sessions de cet onglet vont être arrêtées."
msgid "The currently running process in this split will be terminated."
msgstr "Le processus en cours dans ce panneau va être arrêté."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Copié dans le presse-papiers"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Menu principal"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Voir les onglets ouverts"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Vous utilisez une version de débogage de Ghostty ! Les performances seront "
+"dégradées."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Recharger la configuration"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Les développeurs de Ghostty"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspecteur"
diff --git a/po/ga_IE.UTF-8.po b/po/ga_IE.UTF-8.po
index 686d22d76..3c8018ca0 100644
--- a/po/ga_IE.UTF-8.po
+++ b/po/ga_IE.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-23 16:58+0800\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-06-29 21:15+0100\n"
"Last-Translator: Aindriú Mac Giolla Eoin \n"
"Language-Team: Irish \n"
@@ -27,7 +27,8 @@ msgid "Leave blank to restore the default title."
msgstr "Fág bán chun an teideal réamhshocraithe a athbhunú."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Cealaigh"
@@ -36,10 +37,12 @@ msgid "OK"
msgstr "Ceart go leor"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Earráidí cumraíochta"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -48,12 +51,14 @@ msgstr ""
"thíos, agus athlódáil do chumraíocht nó déan neamhaird de na hearráidí seo."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Déan neamhaird de"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Athlódáil cumraíocht"
@@ -92,7 +97,7 @@ msgstr "Cóipeáil"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Greamaigh"
@@ -122,7 +127,7 @@ msgstr "Táb"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:255
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Táb nua"
@@ -163,7 +168,7 @@ msgid "Terminal Inspector"
msgstr "Cigire teirminéil"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
-#: src/apprt/gtk/Window.zig:1024
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Maidir le Ghostty"
@@ -173,10 +178,13 @@ msgstr "Scoir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Údarú rochtain ar an ngearrthaisce"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -186,15 +194,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Diúltaigh"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Ceadaigh"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -202,11 +225,11 @@ msgstr ""
"Tá feidhmchlár ag iarraidh scríobh chuig an ngearrthaisce. Taispeántar ábhar "
"reatha an ghearrthaisce thíos."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Rabhadh: Greamaigh a d'fhéadfadh a bheith neamhshábháilte"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -214,36 +237,6 @@ msgstr ""
"D’fhéadfadh sé a bheith contúirteach an téacs seo a ghreamú isteach sa "
"teirminéal, toisc go d'fhéadfadh roinnt orduithe a fhorghníomhú."
-#: src/apprt/gtk/Window.zig:208
-msgid "Main Menu"
-msgstr "Príomh-Roghchlár"
-
-#: src/apprt/gtk/Window.zig:229
-msgid "View Open Tabs"
-msgstr "Féach ar na táib oscailte"
-
-#: src/apprt/gtk/Window.zig:256
-msgid "New Split"
-msgstr "Scoilt nua"
-
-#: src/apprt/gtk/Window.zig:319
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Tá leagan dífhabhtaithe de Ghostty á rith agat! Laghdófar an fheidhmíocht."
-
-#: src/apprt/gtk/Window.zig:765
-msgid "Reloaded the configuration"
-msgstr "Tá an chumraíocht athlódáilte"
-
-#: src/apprt/gtk/Window.zig:1005
-msgid "Ghostty Developers"
-msgstr "Forbróirí Ghostty"
-
-#: src/apprt/gtk/inspector.zig:144
-msgid "Ghostty: Terminal Inspector"
-msgstr "Ghostty: Cigire teirminéil"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Dún"
@@ -281,6 +274,36 @@ msgid "The currently running process in this split will be terminated."
msgstr ""
"Cuirfear deireadh leis an bpróiseas atá ar siúl faoi láthair sa scoilt seo."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Cóipeáilte chuig an ghearrthaisce"
+
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Príomh-Roghchlár"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Féach ar na táib oscailte"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr "Scoilt nua"
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Tá leagan dífhabhtaithe de Ghostty á rith agat! Laghdófar an fheidhmíocht."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Tá an chumraíocht athlódáilte"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Forbróirí Ghostty"
+
+#: src/apprt/gtk/inspector.zig:144
+msgid "Ghostty: Terminal Inspector"
+msgstr "Ghostty: Cigire teirminéil"
diff --git a/po/he_IL.UTF-8.po b/po/he_IL.UTF-8.po
new file mode 100644
index 000000000..7ca417908
--- /dev/null
+++ b/po/he_IL.UTF-8.po
@@ -0,0 +1,304 @@
+# Hebrew translations for com.mitchellh.ghostty.
+# Copyright (C) 2025 Mitchell Hashimoto
+# This file is distributed under the same license as the com.mitchellh.ghostty package.
+# Sl (Shahaf Levi), Sl's Repository Ltd , 2025.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: com.mitchellh.ghostty\n"
+"Report-Msgid-Bugs-To: m@mitchellh.com\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
+"PO-Revision-Date: 2025-03-13 00:00+0000\n"
+"Last-Translator: Sl (Shahaf Levi), Sl's Repository Ltd \n"
+"Language-Team: Hebrew \n"
+"Language: he\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:5
+msgid "Change Terminal Title"
+msgstr "שינוי כותרת המסוף"
+
+#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:6
+msgid "Leave blank to restore the default title."
+msgstr "השאר/י ריק כדי לשחזר את כותרת ברירת המחדל."
+
+#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
+msgid "Cancel"
+msgstr "ביטול"
+
+#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:10
+msgid "OK"
+msgstr "אישור"
+
+#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
+msgid "Configuration Errors"
+msgstr "שגיאות בהגדרות"
+
+#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
+msgid ""
+"One or more configuration errors were found. Please review the errors below, "
+"and either reload your configuration or ignore these errors."
+msgstr ""
+"נמצאו אחת או יותר שגיאות בהגדרות. אנא בדוק/י את השגיאות המופיעות מטה ולאחר "
+"מכן טען/י את ההגדרות מחדש או התעלם/י מהשגיאות."
+
+#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
+msgid "Ignore"
+msgstr "התעלמות"
+
+#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
+msgid "Reload Configuration"
+msgstr "טעינה מחדש של ההגדרות"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:6
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:38
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:50
+msgid "Split Up"
+msgstr "פיצול למעלה"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:11
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:43
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:55
+msgid "Split Down"
+msgstr "פיצול למטה"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:16
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:48
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:60
+msgid "Split Left"
+msgstr "פיצול שמאלה"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:21
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:53
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:65
+msgid "Split Right"
+msgstr "פיצול ימינה"
+
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr "הרץ/י פקודה…"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
+msgid "Copy"
+msgstr "העתקה"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
+msgid "Paste"
+msgstr "הדבקה"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:18
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:73
+msgid "Clear"
+msgstr "ניקוי"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:23
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:78
+msgid "Reset"
+msgstr "איפוס"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:30
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:42
+msgid "Split"
+msgstr "פיצול"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:33
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:45
+msgid "Change Title…"
+msgstr "שינוי כותרת…"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:59
+msgid "Tab"
+msgstr "כרטיסייה"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
+#: src/apprt/gtk/Window.zig:265
+msgid "New Tab"
+msgstr "כרטיסייה חדשה"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:67
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:35
+msgid "Close Tab"
+msgstr "סגור/י כרטיסייה"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:73
+msgid "Window"
+msgstr "חלון"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:76
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:18
+msgid "New Window"
+msgstr "חלון חדש"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:81
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:23
+msgid "Close Window"
+msgstr "סגור/י חלון"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:89
+msgid "Config"
+msgstr "הגדרות"
+
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+msgid "Open Configuration"
+msgstr "פתיחת ההגדרות"
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr "לוח פקודות"
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+msgid "Terminal Inspector"
+msgstr "בודק המסוף"
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
+msgid "About Ghostty"
+msgstr "אודות Ghostty"
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
+msgid "Quit"
+msgstr "יציאה"
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
+msgid "Authorize Clipboard Access"
+msgstr "אשר/י גישה ללוח ההעתקה"
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
+msgid ""
+"An application is attempting to read from the clipboard. The current "
+"clipboard contents are shown below."
+msgstr "יש אפליקציה שמנסה לקרוא מלוח ההעתקה. התוכן הנוכחי של הלוח מופיע למטה."
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
+msgid "Deny"
+msgstr "דחייה"
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
+msgid "Allow"
+msgstr "אישור"
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr "זכור/י את הבחירה עבור פיצול זה"
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr "טען/י את ההגדרות מחדש כדי להציג את הבקשה הזו שוב"
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
+msgid ""
+"An application is attempting to write to the clipboard. The current "
+"clipboard contents are shown below."
+msgstr ""
+"יש אפליקציה שמנסה לכתוב לתוך לוח ההעתקה. התוכן הנוכחי של הלוח מופיע למטה."
+
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
+msgid "Warning: Potentially Unsafe Paste"
+msgstr "אזהרה: ההדבקה עלולה להיות מסוכנת"
+
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
+msgid ""
+"Pasting this text into the terminal may be dangerous as it looks like some "
+"commands may be executed."
+msgstr ""
+"הדבקת טקסט זה במסוף עלולה להיות מסוכנת, מכיוון שככל הנראה היא תוביל להרצה של "
+"פקודות מסוימות."
+
+#: src/apprt/gtk/CloseDialog.zig:47
+msgid "Close"
+msgstr "סגירה"
+
+#: src/apprt/gtk/CloseDialog.zig:87
+msgid "Quit Ghostty?"
+msgstr "לצאת מGhostty?"
+
+#: src/apprt/gtk/CloseDialog.zig:88
+msgid "Close Window?"
+msgstr "לסגור את החלון?"
+
+#: src/apprt/gtk/CloseDialog.zig:89
+msgid "Close Tab?"
+msgstr "לסגור את הכרטיסייה?"
+
+#: src/apprt/gtk/CloseDialog.zig:90
+msgid "Close Split?"
+msgstr "לסגור את הפיצול?"
+
+#: src/apprt/gtk/CloseDialog.zig:96
+msgid "All terminal sessions will be terminated."
+msgstr "כל הפעלות המסוף יסתיימו."
+
+#: src/apprt/gtk/CloseDialog.zig:97
+msgid "All terminal sessions in this window will be terminated."
+msgstr "כל הפעלות המסוף בחלון זה יסתיימו."
+
+#: src/apprt/gtk/CloseDialog.zig:98
+msgid "All terminal sessions in this tab will be terminated."
+msgstr "כל הפעלות המסוף בכרטיסייה זו יסתיימו."
+
+#: src/apprt/gtk/CloseDialog.zig:99
+msgid "The currently running process in this split will be terminated."
+msgstr "התהליך שרץ כרגע בפיצול זה יסתיים."
+
+#: src/apprt/gtk/Surface.zig:1257
+msgid "Copied to clipboard"
+msgstr "הועתק ללוח ההעתקה"
+
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "תפריט ראשי"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "הצג/י כרטיסיות פתוחות"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr "פיצול חדש"
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr "⚠️ את/ה מריץ/ה גרסת ניפוי שגיאות של Ghostty! הביצועים יהיו ירודים."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "ההגדרות הוטענו מחדש"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "המפתחים של Ghostty"
+
+#: src/apprt/gtk/inspector.zig:144
+msgid "Ghostty: Terminal Inspector"
+msgstr "Ghostty: בודק המסוף"
diff --git a/po/id_ID.UTF-8.po b/po/id_ID.UTF-8.po
index f82ec6197..51b4bce60 100644
--- a/po/id_ID.UTF-8.po
+++ b/po/id_ID.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-20 15:19+0700\n"
"Last-Translator: Satrio Bayu Aji \n"
"Language-Team: Indonesian \n"
@@ -25,7 +25,8 @@ msgid "Leave blank to restore the default title."
msgstr "Biarkan kosong untuk mengembalikan judul bawaan."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Batal"
@@ -34,10 +35,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Kesalahan konfigurasi"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -46,12 +49,14 @@ msgstr ""
"bawah ini, dan muat ulang konfigurasi anda atau abaikan kesalahan ini."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Abaikan"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Muat ulang konfigurasi"
@@ -79,6 +84,10 @@ msgstr "Belah kiri"
msgid "Split Right"
msgstr "Belah kanan"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -86,7 +95,7 @@ msgstr "Salin"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Tempel"
@@ -116,7 +125,7 @@ msgstr "Tab"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Tab baru"
@@ -144,29 +153,36 @@ msgid "Config"
msgstr "Konfigurasi"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Buka konfigurasi"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Inspektur terminal"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Tentang Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Keluar"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Mengesahkan akses papan klip"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -176,15 +192,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Menyangkal"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Izinkan"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -192,11 +223,11 @@ msgstr ""
"Aplikasi sedang mencoba menulis ke papan klip. Isi papan klip saat ini "
"ditampilkan di bawah ini."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Peringatan: Tempelan yang berpotensi tidak aman"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -204,32 +235,6 @@ msgstr ""
"Menempelkan teks ini ke terminal mungkin berbahaya karena sepertinya "
"beberapa perintah mungkin dijalankan."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Menu utama"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Lihat tab terbuka"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Anda sedang menjalankan versi debug dari Ghostty! Performa akan menurun."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "Memuat ulang konfigurasi"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Pengembang Ghostty"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Tutup"
@@ -266,10 +271,36 @@ msgstr "Semua sesi terminal di tab ini akan diakhiri."
msgid "The currently running process in this split will be terminated."
msgstr "Proses yang sedang berjalan dalam belahan ini akan diakhiri."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Disalin ke papan klip"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Menu utama"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Lihat tab terbuka"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Anda sedang menjalankan versi debug dari Ghostty! Performa akan menurun."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Memuat ulang konfigurasi"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Pengembang Ghostty"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspektur terminal"
diff --git a/po/ja_JP.UTF-8.po b/po/ja_JP.UTF-8.po
index 73ddd9f5a..c965ea29f 100644
--- a/po/ja_JP.UTF-8.po
+++ b/po/ja_JP.UTF-8.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-21 00:08+0900\n"
"Last-Translator: Lon Sagisawa \n"
"Language-Team: Japanese\n"
@@ -27,7 +27,8 @@ msgid "Leave blank to restore the default title."
msgstr "空白にした場合、デフォルトのタイトルを使用します。"
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "キャンセル"
@@ -36,10 +37,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "設定ファイルにエラーがあります"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -48,12 +51,14 @@ msgstr ""
"みをするか、無視してください。"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "無視"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "設定ファイルの再読み込み"
@@ -81,6 +86,10 @@ msgstr "左に分割"
msgid "Split Right"
msgstr "右に分割"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -88,7 +97,7 @@ msgstr "コピー"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "貼り付け"
@@ -118,7 +127,7 @@ msgstr "タブ"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "新しいタブ"
@@ -146,29 +155,36 @@ msgid "Config"
msgstr "設定"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "設定ファイルを開く"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "端末インスペクター"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Ghostty について"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "終了"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "クリップボードへのアクセスを承認"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -178,15 +194,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "拒否"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "許可"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -194,11 +225,11 @@ msgstr ""
"アプリケーションがクリップボードに書き込もうとしています。現在のクリップボー"
"ドの内容は以下の通りです。"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "警告: 危険な可能性のある貼り付け"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -206,32 +237,6 @@ msgstr ""
"このテキストには実行可能なコマンドが含まれており、ターミナルに貼り付けるのは"
"危険な可能性があります。"
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "メインメニュー"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "開いているすべてのタブを表示"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Ghostty のデバッグビルドを実行しています! パフォーマンスが低下しています。"
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "設定を再読み込みしました"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Ghostty 開発者"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "閉じる"
@@ -268,10 +273,36 @@ msgstr "タブ内のすべてのターミナルセッションが終了します
msgid "The currently running process in this split will be terminated."
msgstr "分割ウィンドウ内のすべてのプロセスが終了します。"
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "クリップボードにコピーしました"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "メインメニュー"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "開いているすべてのタブを表示"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Ghostty のデバッグビルドを実行しています! パフォーマンスが低下しています。"
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "設定を再読み込みしました"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Ghostty 開発者"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: 端末インスペクター"
diff --git a/po/ko_KR.UTF-8.po b/po/ko_KR.UTF-8.po
index 42cb2682f..9aa4aad5e 100644
--- a/po/ko_KR.UTF-8.po
+++ b/po/ko_KR.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-03-19 08:54-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-31 03:08+0200\n"
"Last-Translator: Ruben Engelbrecht \n"
"Language-Team: Korean \n"
@@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "제목란을 비워 두면 기본값으로 복원됩니다."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "취소"
@@ -35,25 +36,59 @@ msgid "OK"
msgstr "확인"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "설정 오류"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
-msgstr "설정에 하나 이상의 문제가 발견되었습니다. 아래 오류(를)들을 확인한 후 설정을 다시 불러오거나 무시하세요."
+msgstr ""
+"설정에 하나 이상의 문제가 발견되었습니다. 아래 오류(를)들을 확인한 후 설정을 "
+"다시 불러오거나 무시하세요."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "무시"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "설정 값 다시 불러오기"
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:6
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:38
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:50
+msgid "Split Up"
+msgstr "위로 창 나누기"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:11
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:43
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:55
+msgid "Split Down"
+msgstr "아래로 창 나누기"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:16
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:48
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:60
+msgid "Split Left"
+msgstr "왼쪽으로 창 나누기"
+
+#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:21
+#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:53
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:65
+msgid "Split Right"
+msgstr "오른쪽으로 창 나누기"
+
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -61,7 +96,7 @@ msgstr "복사"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "붙여넣기"
@@ -85,33 +120,13 @@ msgstr "나누기"
msgid "Change Title…"
msgstr "제목 변경…"
-#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:38
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:50
-msgid "Split Up"
-msgstr "위로 창 나누기"
-
-#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:43
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:55
-msgid "Split Down"
-msgstr "아래로 창 나누기"
-
-#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:48
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:60
-msgid "Split Left"
-msgstr "왼쪽으로 창 나누기"
-
-#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:53
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:65
-msgid "Split Right"
-msgstr "오른쪽으로 창 나누기"
-
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:59
msgid "Tab"
msgstr "탭"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:246
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "새 탭"
@@ -139,67 +154,87 @@ msgid "Config"
msgstr "설정"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "설정 열기"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "터미널 인스펙터"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:960
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Ghostty 정보"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "종료"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "클립보드 액세스 권한 부여"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
-msgstr "응용 프로그램이 클립보드에서 읽기를 시도하고 있습니다. 현재 클립보드 내용은 아래와 같습니다."
+msgstr ""
+"응용 프로그램이 클립보드에서 읽기를 시도하고 있습니다. 현재 클립보드 내용은 "
+"아래와 같습니다."
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "거부"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "허용"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
-msgstr "응용 프로그램이 클립보드에 쓰기를 시도하고 있습니다. 현재 클립보드 내용은 아래와 같습니다."
+msgstr ""
+"응용 프로그램이 클립보드에 쓰기를 시도하고 있습니다. 현재 클립보드 내용은 아"
+"래와 같습니다."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "경고: 잠재적으로 안전하지 않은 붙여넣기"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
-msgstr "이 텍스트를 터미널에 붙여넣는 것은 위험할 수 있습니다. 일부 명령이 실행될 수 있는 것으로 보입니다."
-
-#: src/apprt/gtk/inspector.zig:144
-msgid "Ghostty: Terminal Inspector"
-msgstr "Ghostty: 터미널 인스펙터"
-
-#: src/apprt/gtk/Surface.zig:1243
-msgid "Copied to clipboard"
-msgstr "클립보드에 복사됨"
+msgstr ""
+"이 텍스트를 터미널에 붙여넣는 것은 위험할 수 있습니다. 일부 명령이 실행될 수 "
+"있는 것으로 보입니다."
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
@@ -237,23 +272,36 @@ msgstr "이 탭의 모든 터미널 세션이 종료됩니다."
msgid "The currently running process in this split will be terminated."
msgstr "이 분할에서 현재 실행 중인 프로세스가 종료됩니다."
-#: src/apprt/gtk/Window.zig:200
+#: src/apprt/gtk/Surface.zig:1257
+msgid "Copied to clipboard"
+msgstr "클립보드에 복사됨"
+
+#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "메인 메뉴"
-#: src/apprt/gtk/Window.zig:221
+#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "열린 탭 보기"
-#: src/apprt/gtk/Window.zig:295
+#: src/apprt/gtk/Window.zig:266
+#, fuzzy
+msgid "New Split"
+msgstr "나누기"
+
+#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr "⚠️ Ghostty 디버그 빌드로 실행 중입니다! 성능이 저하됩니다."
-#: src/apprt/gtk/Window.zig:725
+#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "설정값을 다시 불러왔습니다"
-#: src/apprt/gtk/Window.zig:941
+#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Ghostty 개발자들"
+
+#: src/apprt/gtk/inspector.zig:144
+msgid "Ghostty: Terminal Inspector"
+msgstr "Ghostty: 터미널 인스펙터"
diff --git a/po/mk_MK.UTF-8.po b/po/mk_MK.UTF-8.po
index 20a43572e..75bb81e00 100644
--- a/po/mk_MK.UTF-8.po
+++ b/po/mk_MK.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-23 14:17+0100\n"
"Last-Translator: Andrej Daskalov \n"
"Language-Team: Macedonian\n"
@@ -25,7 +25,8 @@ msgid "Leave blank to restore the default title."
msgstr "Оставете празно за враќање на стандарсниот наслов."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Откажи"
@@ -34,10 +35,12 @@ msgid "OK"
msgstr "Во ред"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Грешки во конфигурацијата"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -47,12 +50,14 @@ msgstr ""
"овие грешки."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Игнорирај"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Одново вчитај конфигурација"
@@ -80,6 +85,10 @@ msgstr "Подели налево"
msgid "Split Right"
msgstr "Подели надесно"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -87,7 +96,7 @@ msgstr "Копирај"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Вметни"
@@ -117,7 +126,7 @@ msgstr "Јазиче"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Ново јазиче"
@@ -145,29 +154,36 @@ msgid "Config"
msgstr "Конфигурација"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Отвори конфигурација"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Инспектор на терминал"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "За Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Излез"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Авторизирај пристап до привремена меморија"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -177,15 +193,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Одбиј"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Дозволи"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -193,11 +224,11 @@ msgstr ""
"Апликација се обидува да запише во привремената меморија. Содржината е "
"прикажана подолу."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Предупредување: Потенцијално небезбедно вметнување"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -205,32 +236,6 @@ msgstr ""
"Вметнувањето на овој текст во терминалот може да биде опасно, бидејќи "
"изгледа како да ќе се извршат одредени команди."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Главно мени"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Прегледај отворени јазичиња"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Извршувате дебаг верзија на Ghostty! Перформансите ќе бидат намалени."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "Конфигурацијата е одново вчитана"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Развивачи на Ghostty"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Затвори"
@@ -267,10 +272,36 @@ msgstr "Сите сесии во ова јазиче ќе бидат преки
msgid "The currently running process in this split will be terminated."
msgstr "Процесот кој моментално се извршува во оваа поделба ќе биде прекинат."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Копирано во привремена меморија"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Главно мени"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Прегледај отворени јазичиња"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Извршувате дебаг верзија на Ghostty! Перформансите ќе бидат намалени."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Конфигурацијата е одново вчитана"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Развивачи на Ghostty"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Инспектор на терминал"
diff --git a/po/nb_NO.UTF-8.po b/po/nb_NO.UTF-8.po
index 045d47a80..28c1bc559 100644
--- a/po/nb_NO.UTF-8.po
+++ b/po/nb_NO.UTF-8.po
@@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-04-14 16:25+0200\n"
"Last-Translator: cryptocode \n"
"Language-Team: Norwegian Bokmal \n"
@@ -29,7 +29,8 @@ msgid "Leave blank to restore the default title."
msgstr "Blank verdi gjenoppretter standardtittelen."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Avbryt"
@@ -38,10 +39,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Konfigurasjonsfeil"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -50,12 +53,14 @@ msgstr ""
"under, og enten last konfigurasjonen din på nytt eller ignorer disse feilene."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignorer"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Last konfigurasjon på nytt"
@@ -83,6 +88,10 @@ msgstr "Del til venstre"
msgid "Split Right"
msgstr "Del til høyre"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -90,7 +99,7 @@ msgstr "Kopier"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Lim inn"
@@ -120,7 +129,7 @@ msgstr "Fane"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Ny fane"
@@ -148,29 +157,36 @@ msgid "Config"
msgstr "Konfigurasjon"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Åpne konfigurasjon"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Terminalinspektør"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Om Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Avslutt"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Gi tilgang til utklippstavlen"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -180,15 +196,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Avslå"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Tillat"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -196,11 +227,11 @@ msgstr ""
"En applikasjon forsøker å skrive til utklippstavlen. Gjeldende "
"utklippstavleinnhold er vist nedenfor."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Adarsel: Lim inn kan være utrygt"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -208,31 +239,6 @@ msgstr ""
"Det ser ut som at kommandoer vil bli kjørt hvis du limer inn dette, vurder "
"om du mener det er trygt."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Hovedmeny"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Se åpne faner"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr "Del opp vindu"
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr "⚠️ Du kjører et debug-bygg av Ghostty. Debug-bygg har redusert ytelse."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "Konfigurasjonen ble lastet på nytt"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Ghostty-utviklere"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Lukk"
@@ -269,10 +275,35 @@ msgstr "Alle terminaløkter i denne fanen vil bli avsluttet."
msgid "The currently running process in this split will be terminated."
msgstr "Den kjørende prosessen for denne splitten vil bli avsluttet."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Kopiert til utklippstavlen"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Hovedmeny"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Se åpne faner"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr "Del opp vindu"
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr "⚠️ Du kjører et debug-bygg av Ghostty. Debug-bygg har redusert ytelse."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Konfigurasjonen ble lastet på nytt"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Ghostty-utviklere"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Terminalinspektør"
diff --git a/po/nl_NL.UTF-8.po b/po/nl_NL.UTF-8.po
index 355bc4a57..d64592f6d 100644
--- a/po/nl_NL.UTF-8.po
+++ b/po/nl_NL.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-24 15:00+0100\n"
"Last-Translator: Nico Geesink \n"
"Language-Team: Dutch \n"
@@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Laat leeg om de standaard titel te herstellen."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Annuleren"
@@ -35,10 +36,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Configuratiefouten"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -47,12 +50,14 @@ msgstr ""
"fouten en herlaad je configuratie of negeer deze fouten."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Negeer"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Herlaad configuratie"
@@ -80,6 +85,10 @@ msgstr "Splits naar links"
msgid "Split Right"
msgstr "Splits naar rechts"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -87,7 +96,7 @@ msgstr "Kopiëren"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Plakken"
@@ -117,7 +126,7 @@ msgstr "Tabblad"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nieuw tabblad"
@@ -145,29 +154,36 @@ msgid "Config"
msgstr "Configuratie"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Open configuratie"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Terminal inspecteur"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Over Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Afsluiten"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Verleen toegang tot klembord"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -177,15 +193,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Weigeren"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Toestaan"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -193,11 +224,11 @@ msgstr ""
"Een applicatie probeert de inhoud van het klembord te wijzigen. De huidige "
"inhoud van het klembord wordt hieronder weergegeven."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Waarschuwing: mogelijk onveilige plakactie"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -205,33 +236,6 @@ msgstr ""
"Het plakken van deze tekst in de terminal is mogelijk gevaarlijk, omdat het "
"lijkt op een commando dat uitgevoerd kan worden."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Hoofdmenu"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Open tabbladen bekijken"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Je draait een debug versie van Ghostty! Prestaties zullen minder zijn dan "
-"normaal."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "De configuratie is herladen"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Ghostty ontwikkelaars"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Afsluiten"
@@ -269,10 +273,37 @@ msgid "The currently running process in this split will be terminated."
msgstr ""
"Alle processen die nu draaien in deze splitsing zullen worden beëindigd."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Gekopieerd naar klembord"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Hoofdmenu"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Open tabbladen bekijken"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Je draait een debug versie van Ghostty! Prestaties zullen minder zijn dan "
+"normaal."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "De configuratie is herladen"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Ghostty ontwikkelaars"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: terminal inspecteur"
diff --git a/po/pl_PL.UTF-8.po b/po/pl_PL.UTF-8.po
index a68d56818..4f281b415 100644
--- a/po/pl_PL.UTF-8.po
+++ b/po/pl_PL.UTF-8.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-17 12:15+0100\n"
"Last-Translator: Bartosz Sokorski \n"
"Language-Team: Polish \n"
@@ -28,7 +28,8 @@ msgid "Leave blank to restore the default title."
msgstr "Pozostaw puste by przywrócić domyślny tytuł."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Anuluj"
@@ -37,10 +38,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Błędy konfiguracji"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -49,12 +52,14 @@ msgstr ""
"poniżej i przeładuj konfigurację lub zignoruj je."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Zignoruj"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Przeładuj konfigurację"
@@ -82,6 +87,10 @@ msgstr "Podziel w lewo"
msgid "Split Right"
msgstr "Podziel w prawo"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -89,7 +98,7 @@ msgstr "Kopiuj"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Wklej"
@@ -119,7 +128,7 @@ msgstr "Karta"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nowa karta"
@@ -147,29 +156,36 @@ msgid "Config"
msgstr "Konfiguracja"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Otwórz konfigurację"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Inspektor terminala"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "O Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Zamknij"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Udziel dostępu do schowka"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -179,15 +195,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Odmów"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Zezwól"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -195,11 +226,11 @@ msgstr ""
"Aplikacja próbuje zapisać do schowka. Obecna zawartość schowka pokazana "
"poniżej."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Uwaga: potencjalnie niebezpieczne wklejenie ze schowka"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -207,31 +238,6 @@ msgstr ""
"Wklejenie tego tekstu do terminala może być niebezpieczne, ponieważ może "
"spowodować wykonanie komend."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Menu główne"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Zobacz otwarte karty"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr "⚠️ Używasz wersji Ghostty do debugowania! Wydajność będzie obniżona."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "Przeładowano konfigurację"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Twórcy Ghostty"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Zamknij"
@@ -268,10 +274,35 @@ msgstr "Wszystkie sesje terminala w obecnej karcie zostaną zakończone."
msgid "The currently running process in this split will be terminated."
msgstr "Wszyskie trwające procesy w obecnym podziale zostaną zakończone."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Skopiowano do schowka"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Menu główne"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Zobacz otwarte karty"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr "⚠️ Używasz wersji Ghostty do debugowania! Wydajność będzie obniżona."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Przeładowano konfigurację"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Twórcy Ghostty"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Inspektor terminala Ghostty"
diff --git a/po/pt_BR.UTF-8.po b/po/pt_BR.UTF-8.po
index ba13f4460..2979248f2 100644
--- a/po/pt_BR.UTF-8.po
+++ b/po/pt_BR.UTF-8.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-06-20 10:19-0300\n"
"Last-Translator: Mário Victor Ribeiro Silva \n"
"Language-Team: Brazilian Portuguese \n"
"Language-Team: Russian \n"
@@ -28,7 +28,8 @@ msgid "Leave blank to restore the default title."
msgstr "Оставьте пустым, чтобы восстановить исходный заголовок."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Отмена"
@@ -37,10 +38,12 @@ msgid "OK"
msgstr "ОК"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Ошибки конфигурации"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -49,12 +52,14 @@ msgstr ""
"конфигурацию, либо проигнорируйте ошибки."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Игнорировать"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Обновить конфигурацию"
@@ -82,6 +87,10 @@ msgstr "Сплит влево"
msgid "Split Right"
msgstr "Сплит вправо"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -89,7 +98,7 @@ msgstr "Копировать"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Вставить"
@@ -119,7 +128,7 @@ msgstr "Вкладка"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Новая вкладка"
@@ -147,29 +156,36 @@ msgid "Config"
msgstr "Конфигурация"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Открыть конфигурационный файл"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Инспектор терминала"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "О Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Выход"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Разрешить доступ к буферу обмена"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -179,26 +195,41 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Отклонить"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Разрешить"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
msgstr ""
"Приложение пытается записать данные в буфер обмена. Эти данные показаны ниже."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Внимание! Вставляемые данные могут нанести вред вашей системе"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -206,33 +237,6 @@ msgstr ""
"Вставка этого текста в терминал может быть опасной. Это выглядит как "
"команды, которые могут быть исполнены."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Главное меню"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Просмотреть открытые вкладки"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Вы запустили отладочную сборку Ghostty! Это может влиять на "
-"производительность."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "Конфигурация была обновлена"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Разработчики Ghostty"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Закрыть"
@@ -269,10 +273,37 @@ msgstr "Все сессии терминала в этой вкладке буд
msgid "The currently running process in this split will be terminated."
msgstr "Процесс, работающий в этой сплит-области, будет остановлен."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Скопировано в буфер обмена"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Главное меню"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Просмотреть открытые вкладки"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Вы запустили отладочную сборку Ghostty! Это может влиять на "
+"производительность."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Конфигурация была обновлена"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Разработчики Ghostty"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: инспектор терминала"
diff --git a/po/tr_TR.UTF-8.po b/po/tr_TR.UTF-8.po
index 5d761f6a4..7d8d055f8 100644
--- a/po/tr_TR.UTF-8.po
+++ b/po/tr_TR.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-24 22:01+0300\n"
"Last-Translator: Emir SARI \n"
"Language-Team: Turkish\n"
@@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Öntanımlı başlığı geri yüklemek için boş bırakın."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "İptal"
@@ -35,10 +36,12 @@ msgid "OK"
msgstr "Tamam"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Yapılandırma Hataları"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -48,12 +51,14 @@ msgstr ""
"hataları yok sayın."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Yok Say"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Yapılandırmayı Yeniden Yükle"
@@ -81,6 +86,10 @@ msgstr "Sola Doğru Böl"
msgid "Split Right"
msgstr "Sağa Doğru Böl"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -88,7 +97,7 @@ msgstr "Kopyala"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Yapıştır"
@@ -118,7 +127,7 @@ msgstr "Sekme"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Yeni Sekme"
@@ -146,29 +155,36 @@ msgid "Config"
msgstr "Yapılandırma"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Yapılandırmayı Aç"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Uçbirim Denetçisi"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Ghostty Hakkında"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Çık"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Pano Erişimine İzin Ver"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -178,15 +194,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Reddet"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "İzin Ver"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -194,11 +225,11 @@ msgstr ""
"Bir uygulama panoya yazmaya çalışıyor. Geçerli pano içeriği aşağıda "
"gösterilmektedir."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Uyarı: Tehlikeli Olabilecek Yapıştırma"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -206,33 +237,6 @@ msgstr ""
"Bu metni uçbirime yapıştırmak tehlikeli olabilir; çünkü bir komut "
"yürütülebilecekmiş gibi duruyor."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Ana Menü"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Açık Sekmeleri Görüntüle"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr "Yeni Bölme"
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Ghostty’nin hata ayıklama amaçlı yapılmış bir sürümünü kullanıyorsunuz! "
-"Başarım normale göre daha düşük olacaktır."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "Yapılandırma yeniden yüklendi"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Ghostty Geliştiricileri"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Kapat"
@@ -269,10 +273,37 @@ msgstr "Bu sekmedeki tüm uçbirim oturumları sonlandırılacaktır."
msgid "The currently running process in this split will be terminated."
msgstr "Bu bölmedeki şu anda çalışan süreç sonlandırılacaktır."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Panoya kopyalandı"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Ana Menü"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Açık Sekmeleri Görüntüle"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr "Yeni Bölme"
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Ghostty’nin hata ayıklama amaçlı yapılmış bir sürümünü kullanıyorsunuz! "
+"Başarım normale göre daha düşük olacaktır."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Yapılandırma yeniden yüklendi"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Ghostty Geliştiricileri"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Uçbirim Denetçisi"
diff --git a/po/uk_UA.UTF-8.po b/po/uk_UA.UTF-8.po
index bde975fc4..2d01b3932 100644
--- a/po/uk_UA.UTF-8.po
+++ b/po/uk_UA.UTF-8.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-04-22 08:57-0700\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-16 20:16+0200\n"
"Last-Translator: Danylo Zalizchuk \n"
"Language-Team: Ukrainian \n"
@@ -27,7 +27,8 @@ msgid "Leave blank to restore the default title."
msgstr "Залиште порожнім, щоб відновити назву за замовчуванням."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
+#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Відмінити"
@@ -36,10 +37,12 @@ msgid "OK"
msgstr "ОК"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Помилки конфігурації"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
@@ -49,12 +52,14 @@ msgstr ""
"ці помилки."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ігнорувати"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
+#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Перезавантажити конфігурацію"
@@ -82,6 +87,10 @@ msgstr "Розділити панель ліворуч"
msgid "Split Right"
msgstr "Розділити панель праворуч"
+#: src/apprt/gtk/ui/1.5/command-palette.blp:16
+msgid "Execute a command…"
+msgstr ""
+
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
@@ -89,7 +98,7 @@ msgstr "Скопіювати"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Вставити"
@@ -119,7 +128,7 @@ msgstr "Вкладка"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:248
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Нова вкладка"
@@ -147,29 +156,36 @@ msgid "Config"
msgstr "Конфігурація"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Відкрити конфігурацію"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
+msgid "Command Palette"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Інспектор терміналу"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
-#: src/apprt/gtk/Window.zig:1003
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Про Ghostty"
-#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
+#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Завершити"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Дозволити доступ до буфера обміну"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@@ -179,15 +195,30 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Відхилити"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Дозволити"
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
+msgid "Remember choice for this split"
+msgstr ""
+
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
+#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
+msgid "Reload configuration to show this prompt again"
+msgstr ""
+
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
+#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@@ -195,11 +226,11 @@ msgstr ""
"Програма намагається записати дані до буфера обміну. Нижче показано поточний "
"вміст буфера обміну."
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Увага: потенційно небезпечна вставка"
-#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
+#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@@ -207,32 +238,6 @@ msgstr ""
"Вставка цього тексту в термінал може бути небезпечною, оскільки виглядає "
"так, ніби деякі команди можуть бути виконані."
-#: src/apprt/gtk/Window.zig:201
-msgid "Main Menu"
-msgstr "Головне меню"
-
-#: src/apprt/gtk/Window.zig:222
-msgid "View Open Tabs"
-msgstr "Переглянути відкриті вкладки"
-
-#: src/apprt/gtk/Window.zig:249
-msgid "New Split"
-msgstr ""
-
-#: src/apprt/gtk/Window.zig:312
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr ""
-"⚠️ Ви використовуєте відладочну збірку Ghostty! Продуктивність буде погіршено."
-
-#: src/apprt/gtk/Window.zig:744
-msgid "Reloaded the configuration"
-msgstr "Конфігурацію перезавантажено"
-
-#: src/apprt/gtk/Window.zig:984
-msgid "Ghostty Developers"
-msgstr "Розробники Ghostty"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Закрити"
@@ -270,10 +275,36 @@ msgid "The currently running process in this split will be terminated."
msgstr ""
"Поточний процес, що виконується в цій розділеній панелі, буде завершено."
-#: src/apprt/gtk/Surface.zig:1243
+#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Скопійовано в буфер обміну"
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "Головне меню"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "Переглянути відкриті вкладки"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr ""
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr ""
+"⚠️ Ви використовуєте відладочну збірку Ghostty! Продуктивність буде погіршено."
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "Конфігурацію перезавантажено"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Розробники Ghostty"
+
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Інспектор терміналу"
diff --git a/po/zh_CN.UTF-8.po b/po/zh_CN.UTF-8.po
index 17a6dc921..2b5f9f3a1 100644
--- a/po/zh_CN.UTF-8.po
+++ b/po/zh_CN.UTF-8.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
-"POT-Creation-Date: 2025-06-28 17:01+0200\n"
+"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-02-27 09:16+0100\n"
"Last-Translator: Leah \n"
"Language-Team: Chinese (simplified) \n"
@@ -125,7 +125,7 @@ msgstr "标签页"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
-#: src/apprt/gtk/Window.zig:263
+#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "新建标签页"
@@ -166,7 +166,7 @@ msgid "Terminal Inspector"
msgstr "终端调试器"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
-#: src/apprt/gtk/Window.zig:1036
+#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "关于 Ghostty"
@@ -229,35 +229,6 @@ msgid ""
"commands may be executed."
msgstr "将以下内容粘贴至终端内将可能执行有害命令。"
-#: src/apprt/gtk/Window.zig:216
-msgid "Main Menu"
-msgstr "主菜单"
-
-#: src/apprt/gtk/Window.zig:238
-msgid "View Open Tabs"
-msgstr "浏览标签页"
-
-#: src/apprt/gtk/Window.zig:264
-msgid "New Split"
-msgstr "新建分屏"
-
-#: src/apprt/gtk/Window.zig:327
-msgid ""
-"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
-msgstr "⚠️ Ghostty 正在以调试模式运行!性能将大打折扣。"
-
-#: src/apprt/gtk/Window.zig:773
-msgid "Reloaded the configuration"
-msgstr "已重新加载配置"
-
-#: src/apprt/gtk/Window.zig:1017
-msgid "Ghostty Developers"
-msgstr "Ghostty 开发团队"
-
-#: src/apprt/gtk/inspector.zig:144
-msgid "Ghostty: Terminal Inspector"
-msgstr "Ghostty 终端调试器"
-
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "关闭"
@@ -297,3 +268,32 @@ msgstr "分屏内正在运行中的进程将被终止。"
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "已复制至剪贴板"
+
+#: src/apprt/gtk/Window.zig:216
+msgid "Main Menu"
+msgstr "主菜单"
+
+#: src/apprt/gtk/Window.zig:239
+msgid "View Open Tabs"
+msgstr "浏览标签页"
+
+#: src/apprt/gtk/Window.zig:266
+msgid "New Split"
+msgstr "新建分屏"
+
+#: src/apprt/gtk/Window.zig:329
+msgid ""
+"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
+msgstr "⚠️ Ghostty 正在以调试模式运行!性能将大打折扣。"
+
+#: src/apprt/gtk/Window.zig:775
+msgid "Reloaded the configuration"
+msgstr "已重新加载配置"
+
+#: src/apprt/gtk/Window.zig:1019
+msgid "Ghostty Developers"
+msgstr "Ghostty 开发团队"
+
+#: src/apprt/gtk/inspector.zig:144
+msgid "Ghostty: Terminal Inspector"
+msgstr "Ghostty 终端调试器"
diff --git a/src/Command.zig b/src/Command.zig
index 7ed026efe..1bddf8b82 100644
--- a/src/Command.zig
+++ b/src/Command.zig
@@ -188,10 +188,31 @@ fn startPosix(self: *Command, arena: Allocator) !void {
// Finally, replace our process.
// Note: we must use the "p"-variant of exec here because we
// do not guarantee our command is looked up already in the path.
- _ = posix.execvpeZ(self.path, argsZ, envp) catch null;
+ const err = posix.execvpeZ(self.path, argsZ, envp);
- // If we are executing this code, the exec failed. In that scenario,
- // we return a very specific error that can be detected to determine
+ // If we are executing this code, the exec failed. We're in the
+ // child process so there isn't much we can do. We try to output
+ // something reasonable. Its important to note we MUST NOT return
+ // any other error condition from here on out.
+ const stderr = std.io.getStdErr().writer();
+ switch (err) {
+ error.FileNotFound => stderr.print(
+ \\Requested executable not found. Please verify the command is on
+ \\the PATH and try again.
+ \\
+ ,
+ .{},
+ ) catch {},
+
+ else => stderr.print(
+ \\exec syscall failed with unexpected error: {}
+ \\
+ ,
+ .{err},
+ ) catch {},
+ }
+
+ // We return a very specific error that can be detected to determine
// we're in the child.
return error.ExecFailedInChild;
}
diff --git a/src/Surface.zig b/src/Surface.zig
index 4a1c5d6c2..22f80d166 100644
--- a/src/Surface.zig
+++ b/src/Surface.zig
@@ -270,6 +270,7 @@ const DerivedConfig = struct {
title: ?[:0]const u8,
title_report: bool,
links: []Link,
+ link_previews: configpkg.LinkPreviews,
const Link = struct {
regex: oni.Regex,
@@ -336,6 +337,7 @@ const DerivedConfig = struct {
.title = config.title,
.title_report = config.@"title-report",
.links = links,
+ .link_previews = config.@"link-previews",
// Assignments happen sequentially so we have to do this last
// so that the memory is captured from allocs above.
@@ -1034,6 +1036,12 @@ fn childExited(self: *Surface, info: apprt.surface.Message.ChildExited) void {
t.printString("Process exited. Press any key to close the terminal.") catch
break :terminal;
t.modes.set(.cursor_visible, false);
+
+ // We also want to ensure that normal keyboard encoding is on
+ // so that we can close the terminal. We close the terminal on
+ // any key press that encodes a character.
+ t.modes.set(.disable_keyboard, false);
+ t.screen.kitty_keyboard.set(.set, .{});
}
// Waiting after command we stop here. The terminal is updated, our
@@ -1236,7 +1244,7 @@ fn mouseRefreshLinks(
// Get our link at the current position. This returns null if there
// isn't a link OR if we shouldn't be showing links for some reason
// (see further comments for cases).
- const link_: ?apprt.action.MouseOverLink = link: {
+ const link_: ?apprt.action.MouseOverLink, const preview: bool = link: {
// If we clicked and our mouse moved cells then we never
// highlight links until the mouse is unclicked. This follows
// standard macOS and Linux behavior where a click and drag cancels
@@ -1251,18 +1259,21 @@ fn mouseRefreshLinks(
if (!click_pt.coord().eql(pos_vp)) {
log.debug("mouse moved while left click held, ignoring link hover", .{});
- break :link null;
+ break :link .{ null, false };
}
}
- const link = (try self.linkAtPos(pos)) orelse break :link null;
+ const link = (try self.linkAtPos(pos)) orelse break :link .{ null, false };
switch (link[0]) {
.open => {
const str = try self.io.terminal.screen.selectionString(alloc, .{
.sel = link[1],
.trim = false,
});
- break :link .{ .url = str };
+ break :link .{
+ .{ .url = str },
+ self.config.link_previews == .true,
+ };
},
._open_osc8 => {
@@ -1270,9 +1281,14 @@ fn mouseRefreshLinks(
const pin = link[1].start();
const uri = self.osc8URI(pin) orelse {
log.warn("failed to get URI for OSC8 hyperlink", .{});
- break :link null;
+ break :link .{ null, false };
+ };
+ break :link .{
+ .{
+ .url = uri,
+ },
+ self.config.link_previews != .false,
};
- break :link .{ .url = uri };
},
}
};
@@ -1288,11 +1304,15 @@ fn mouseRefreshLinks(
.mouse_shape,
.pointer,
);
- _ = try self.rt_app.performAction(
- .{ .surface = self },
- .mouse_over_link,
- link,
- );
+
+ if (preview) {
+ _ = try self.rt_app.performAction(
+ .{ .surface = self },
+ .mouse_over_link,
+ link,
+ );
+ }
+
try self.queueRender();
return;
}
@@ -2129,14 +2149,6 @@ pub fn keyCallback(
if (self.io.terminal.modes.get(.disable_keyboard)) return .consumed;
}
- // If our process is exited and we press a key then we close the
- // surface. We may want to eventually move this to the apprt rather
- // than in core.
- if (self.child_exited and event.action == .press) {
- self.close();
- return .closed;
- }
-
// If this input event has text, then we hide the mouse if configured.
// We only do this on pressed events to avoid hiding the mouse when we
// change focus due to a keybinding (i.e. switching tabs).
@@ -2231,6 +2243,14 @@ pub fn keyCallback(
event,
if (insp_ev) |*ev| ev else null,
)) |write_req| {
+ // If our process is exited and we press a key that results in
+ // an encoded value, we close the surface. We want to eventually
+ // move this behavior to the apprt probably.
+ if (self.child_exited) {
+ self.close();
+ return .closed;
+ }
+
errdefer write_req.deinit();
self.io.queueMessage(switch (write_req) {
.small => |v| .{ .write_small = v },
@@ -3714,7 +3734,7 @@ fn processLinks(self: *Surface, pos: apprt.CursorPos) !bool {
.trim = false,
});
defer self.alloc.free(str);
- try internal_os.open(self.alloc, .unknown, str);
+ try self.openUrl(.{ .kind = .unknown, .url = str });
},
._open_osc8 => {
@@ -3722,13 +3742,35 @@ fn processLinks(self: *Surface, pos: apprt.CursorPos) !bool {
log.warn("failed to get URI for OSC8 hyperlink", .{});
return false;
};
- try internal_os.open(self.alloc, .unknown, uri);
+ try self.openUrl(.{ .kind = .unknown, .url = uri });
},
}
return true;
}
+fn openUrl(
+ self: *Surface,
+ action: apprt.action.OpenUrl,
+) !void {
+ // If the apprt handles it then we're done.
+ if (try self.rt_app.performAction(
+ .{ .surface = self },
+ .open_url,
+ action,
+ )) return;
+
+ // apprt didn't handle it, fallback to our simple cross-platform
+ // URL opener. We log a warning because we want well-behaved
+ // apprts to handle this themselves.
+ log.warn("apprt did not handle open URL action, falling back to default opener", .{});
+ try internal_os.open(
+ self.alloc,
+ action.kind,
+ action.url,
+ );
+}
+
/// Return the URI for an OSC8 hyperlink at the given position or null
/// if there is no hyperlink.
fn osc8URI(self: *Surface, pin: terminal.Pin) ?[]const u8 {
@@ -4460,6 +4502,18 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
return false;
},
+ .copy_title_to_clipboard => {
+ const title = self.rt_surface.getTitle() orelse return false;
+ if (title.len == 0) return false;
+
+ self.rt_surface.setClipboardString(title, .standard, false) catch |err| {
+ log.err("error copying title to clipboard err={}", .{err});
+ return true;
+ };
+
+ return true;
+ },
+
.paste_from_clipboard => try self.startClipboardRequest(
.standard,
.{ .paste = {} },
@@ -4501,6 +4555,14 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
try self.setFontSize(size);
},
+ .set_font_size => |points| {
+ log.debug("set font size={d}", .{points});
+
+ var size = self.font_size;
+ size.points = std.math.clamp(points, 1.0, 255.0);
+ try self.setFontSize(size);
+ },
+
.prompt_surface_title => return try self.rt_app.performAction(
.{ .surface = self },
.prompt_title,
@@ -4940,7 +5002,7 @@ fn writeScreenFile(
defer self.alloc.free(pathZ);
try self.rt_surface.setClipboardString(pathZ, .standard, false);
},
- .open => try internal_os.open(self.alloc, .text, path),
+ .open => try self.openUrl(.{ .kind = .text, .url = path }),
.paste => self.io.queueMessage(try termio.Message.writeReq(
self.alloc,
path,
diff --git a/src/apprt.zig b/src/apprt.zig
index dd726b3f2..cb542875e 100644
--- a/src/apprt.zig
+++ b/src/apprt.zig
@@ -3,7 +3,7 @@
//! getting user input (mouse/keyboard), etc.
//!
//! This enables compile-time interfaces to be built to swap out the underlying
-//! application runtime. For example: glfw, pure macOS Cocoa, GTK+, browser, etc.
+//! application runtime. For example: pure macOS Cocoa, GTK+, browser, etc.
//!
//! The goal is to have different implementations share as much of the core
//! logic as possible, and to only reach out to platform-specific implementation
@@ -15,7 +15,6 @@ const build_config = @import("build_config.zig");
const structs = @import("apprt/structs.zig");
pub const action = @import("apprt/action.zig");
-pub const glfw = @import("apprt/glfw.zig");
pub const gtk = @import("apprt/gtk.zig");
pub const none = @import("apprt/none.zig");
pub const browser = @import("apprt/browser.zig");
@@ -42,7 +41,6 @@ pub const SurfaceSize = structs.SurfaceSize;
pub const runtime = switch (build_config.artifact) {
.exe => switch (build_config.app_runtime) {
.none => none,
- .glfw => glfw,
.gtk => gtk,
},
.lib => embedded,
@@ -53,18 +51,12 @@ pub const App = runtime.App;
pub const Surface = runtime.Surface;
/// Runtime is the runtime to use for Ghostty. All runtimes do not provide
-/// equivalent feature sets. For example, GTK offers tabbing and more features
-/// that glfw does not provide. However, glfw may require many less
-/// dependencies.
+/// equivalent feature sets.
pub const Runtime = enum {
/// Will not produce an executable at all when `zig build` is called.
/// This is only useful if you're only interested in the lib only (macOS).
none,
- /// Glfw-backed. Very simple. Glfw is statically linked. Tabbing and
- /// other rich windowing features are not supported.
- glfw,
-
/// GTK-backed. Rich windowed application. GTK is dynamically linked.
gtk,
@@ -72,12 +64,8 @@ pub const Runtime = enum {
// The Linux default is GTK because it is full featured.
if (target.os.tag == .linux) return .gtk;
- // Windows we currently only support glfw
- if (target.os.tag == .windows) return .glfw;
-
- // Otherwise, we do NONE so we don't create an exe. The GLFW
- // build is opt-in because it is missing so many features compared
- // to the other builds that are impossible due to the GLFW interface.
+ // Otherwise, we do NONE so we don't create an exe and we
+ // create libghostty.
return .none;
}
};
diff --git a/src/apprt/action.zig b/src/apprt/action.zig
index b4c5164c2..1c3c7c72c 100644
--- a/src/apprt/action.zig
+++ b/src/apprt/action.zig
@@ -267,6 +267,11 @@ pub const Action = union(Key) {
check_for_updates,
+ /// Open a URL using the native OS mechanisms. On macOS this might be `open`
+ /// or on Linux this might be `xdg-open`. The exact mechanism is up to the
+ /// apprt.
+ open_url: OpenUrl,
+
/// Sync with: ghostty_action_tag_e
pub const Key = enum(c_int) {
quit,
@@ -317,6 +322,7 @@ pub const Action = union(Key) {
undo,
redo,
check_for_updates,
+ open_url,
};
/// Sync with: ghostty_action_u
@@ -357,7 +363,11 @@ pub const Action = union(Key) {
// For ABI compatibility, we expect that this is our union size.
// At the time of writing, we don't promise ABI compatibility
// so we can change this but I want to be aware of it.
- assert(@sizeOf(CValue) == 16);
+ assert(@sizeOf(CValue) == switch (@sizeOf(usize)) {
+ 4 => 16,
+ 8 => 24,
+ else => unreachable,
+ });
}
/// Returns the value type for the given key.
@@ -614,3 +624,44 @@ pub const ConfigChange = struct {
};
}
};
+
+/// Open a URL
+pub const OpenUrl = struct {
+ /// The type of data that the URL refers to.
+ kind: Kind,
+
+ /// The URL.
+ url: []const u8,
+
+ /// The type of the data at the URL to open. This is used as a hint to
+ /// potentially open the URL in a different way.
+ ///
+ /// Sync with: ghostty_action_open_url_kind_e
+ pub const Kind = enum(c_int) {
+ /// The type is unknown. This is the default and apprts should
+ /// open the URL in the most generic way possible. For example,
+ /// on macOS this would be the equivalent of `open` or on Linux
+ /// this would be `xdg-open`.
+ unknown,
+
+ /// The URL is known to be a text file. In this case, the apprt
+ /// should try to open the URL in a text editor or viewer or
+ /// some equivalent, if possible.
+ text,
+ };
+
+ // Sync with: ghostty_action_open_url_s
+ pub const C = extern struct {
+ kind: Kind,
+ url: [*]const u8,
+ len: usize,
+ };
+
+ pub fn cval(self: OpenUrl) C {
+ return .{
+ .kind = self.kind,
+ .url = self.url.ptr,
+ .len = self.url.len,
+ };
+ }
+};
diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig
index dec1e4135..30a2d9ff6 100644
--- a/src/apprt/embedded.zig
+++ b/src/apprt/embedded.zig
@@ -236,7 +236,7 @@ pub const App = struct {
var surface = try self.core_app.alloc.create(Surface);
errdefer self.core_app.alloc.destroy(surface);
- // Create the surface -- because windows are surfaces for glfw.
+ // Create the surface
try surface.init(self, opts);
errdefer surface.deinit();
@@ -884,7 +884,7 @@ pub const Surface = struct {
}
// Remove this so that running `ghostty` within Ghostty works.
- env.remove("GHOSTTY_MAC_APP");
+ env.remove("GHOSTTY_MAC_LAUNCH_SOURCE");
// If we were launched from the desktop then we want to
// remove the LANGUAGE env var so that we don't inherit
diff --git a/src/apprt/glfw.zig b/src/apprt/glfw.zig
deleted file mode 100644
index b82771d75..000000000
--- a/src/apprt/glfw.zig
+++ /dev/null
@@ -1,1266 +0,0 @@
-//! Application runtime implementation that uses GLFW (https://www.glfw.org/).
-//!
-//! This works on macOS and Linux with OpenGL and Metal.
-//! (The above sentence may be out of date).
-
-const std = @import("std");
-const builtin = @import("builtin");
-const build_config = @import("../build_config.zig");
-const assert = std.debug.assert;
-const Allocator = std.mem.Allocator;
-const glfw = @import("glfw");
-const macos = @import("macos");
-const objc = @import("objc");
-const cli = @import("../cli.zig");
-const input = @import("../input.zig");
-const internal_os = @import("../os/main.zig");
-const renderer = @import("../renderer.zig");
-const terminal = @import("../terminal/main.zig");
-const Renderer = renderer.Renderer;
-const apprt = @import("../apprt.zig");
-const CoreApp = @import("../App.zig");
-const CoreSurface = @import("../Surface.zig");
-const configpkg = @import("../config.zig");
-const Config = @import("../config.zig").Config;
-
-// Get native API access on certain platforms so we can do more customization.
-const glfwNative = glfw.Native(.{
- .cocoa = builtin.target.os.tag.isDarwin(),
- .x11 = builtin.os.tag == .linux,
-});
-
-/// True if darwin-specific logic is enabled
-const darwin_enabled = builtin.target.os.tag.isDarwin() and
- build_config.artifact == .exe;
-
-const log = std.log.scoped(.glfw);
-
-pub const resourcesDir = internal_os.resourcesDir;
-
-pub const App = struct {
- app: *CoreApp,
- config: Config,
-
- /// Flips to true to quit on the next event loop tick. This
- /// never goes false and forces the event loop to exit.
- quit: bool = false,
-
- /// Mac-specific state.
- darwin: if (darwin_enabled) Darwin else void,
-
- pub const Options = struct {};
-
- pub fn init(self: *App, core_app: *CoreApp, _: Options) !void {
- if (comptime builtin.target.os.tag.isDarwin()) {
- log.warn("WARNING WARNING WARNING: GLFW ON MAC HAS BUGS.", .{});
- log.warn("You should use the AppKit-based app instead. The official download", .{});
- log.warn("is properly built and available from GitHub. If you're building from", .{});
- log.warn("source, see the README for details on how to build the AppKit app.", .{});
- }
-
- if (!glfw.init(.{})) {
- if (glfw.getError()) |err| {
- log.err("error initializing GLFW err={} msg={s}", .{
- err.error_code,
- err.description,
- });
- return err.error_code;
- }
-
- return error.GlfwInitFailedUnknownReason;
- }
- glfw.setErrorCallback(glfwErrorCallback);
-
- // Mac-specific state. For example, on Mac we enable window tabbing.
- var darwin = if (darwin_enabled) try Darwin.init() else {};
- errdefer if (darwin_enabled) darwin.deinit();
-
- // Load our configuration
- var config = try Config.load(core_app.alloc);
- errdefer config.deinit();
-
- // If we had configuration errors, then log them.
- if (!config._diagnostics.empty()) {
- var buf = std.ArrayList(u8).init(core_app.alloc);
- defer buf.deinit();
- for (config._diagnostics.items()) |diag| {
- try diag.write(buf.writer());
- log.warn("configuration error: {s}", .{buf.items});
- buf.clearRetainingCapacity();
- }
-
- // If we have any CLI errors, exit.
- if (config._diagnostics.containsLocation(.cli)) {
- log.warn("CLI errors detected, exiting", .{});
- _ = core_app.mailbox.push(.{
- .quit = {},
- }, .{ .forever = {} });
- }
- }
-
- // Queue a single new window that starts on launch
- // Note: above we may send a quit so this may never happen
- _ = core_app.mailbox.push(.{
- .new_window = .{},
- }, .{ .forever = {} });
-
- // We want the event loop to wake up instantly so we can process our tick.
- glfw.postEmptyEvent();
-
- self.* = .{
- .app = core_app,
- .config = config,
- .darwin = darwin,
- };
- }
-
- pub fn terminate(self: *App) void {
- self.config.deinit();
- glfw.terminate();
- }
-
- /// Run the event loop. This doesn't return until the app exits.
- pub fn run(self: *App) !void {
- while (true) {
- // Wait for any events from the app event loop. wakeup will post
- // an empty event so that this will return.
- //
- // Warning: a known issue on macOS is that this will block while
- // a resize event is actively happening, which will prevent the
- // app tick from happening. I don't know know a way around this
- // but its not a big deal since we don't use glfw for the official
- // mac app, but noting it in case anyone builds for macos using
- // glfw.
- glfw.waitEvents();
-
- // Tick the terminal app
- try self.app.tick(self);
-
- // If the tick caused us to quit, then we're done.
- if (self.quit or self.app.surfaces.items.len == 0) {
- for (self.app.surfaces.items) |surface| {
- surface.close(false);
- }
-
- return;
- }
- }
- }
-
- /// Wakeup the event loop. This should be able to be called from any thread.
- pub fn wakeup(self: *const App) void {
- _ = self;
- glfw.postEmptyEvent();
- }
-
- /// Perform a given action. Returns `true` if the action was able to be
- /// performed, `false` otherwise.
- pub fn performAction(
- self: *App,
- target: apprt.Target,
- comptime action: apprt.Action.Key,
- value: apprt.Action.Value(action),
- ) !bool {
- switch (action) {
- .quit => self.quit = true,
-
- .new_window => _ = try self.newSurface(switch (target) {
- .app => null,
- .surface => |v| v,
- }),
-
- .new_tab => try self.newTab(switch (target) {
- .app => null,
- .surface => |v| v,
- }),
-
- .size_limit => switch (target) {
- .app => {},
- .surface => |surface| try surface.rt_surface.setSizeLimits(.{
- .width = value.min_width,
- .height = value.min_height,
- }, if (value.max_width > 0) .{
- .width = value.max_width,
- .height = value.max_height,
- } else null),
- },
-
- .initial_size => switch (target) {
- .app => {},
- .surface => |surface| try surface.rt_surface.setInitialWindowSize(
- value.width,
- value.height,
- ),
- },
-
- .toggle_fullscreen => self.toggleFullscreen(target),
-
- .open_config => try configpkg.edit.open(self.app.alloc),
-
- .set_title => switch (target) {
- .app => {},
- .surface => |surface| try surface.rt_surface.setTitle(value.title),
- },
-
- .mouse_shape => switch (target) {
- .app => {},
- .surface => |surface| try surface.rt_surface.setMouseShape(value),
- },
-
- .mouse_visibility => switch (target) {
- .app => {},
- .surface => |surface| surface.rt_surface.setMouseVisibility(switch (value) {
- .visible => true,
- .hidden => false,
- }),
- },
-
- .reload_config => try self.reloadConfig(target, value),
-
- // Unimplemented
- .new_split,
- .goto_split,
- .resize_split,
- .equalize_splits,
- .toggle_split_zoom,
- .present_terminal,
- .close_all_windows,
- .close_window,
- .close_tab,
- .toggle_tab_overview,
- .toggle_window_decorations,
- .toggle_quick_terminal,
- .toggle_command_palette,
- .toggle_visibility,
- .goto_tab,
- .move_tab,
- .inspector,
- .render_inspector,
- .quit_timer,
- .float_window,
- .secure_input,
- .key_sequence,
- .desktop_notification,
- .mouse_over_link,
- .cell_size,
- .renderer_health,
- .color_change,
- .pwd,
- .config_change,
- .toggle_maximize,
- .prompt_title,
- .reset_window_size,
- .ring_bell,
- .check_for_updates,
- .undo,
- .redo,
- .show_gtk_inspector,
- => {
- log.info("unimplemented action={}", .{action});
- return false;
- },
- }
-
- return true;
- }
-
- /// Reload the configuration. This should return the new configuration.
- /// The old value can be freed immediately at this point assuming a
- /// successful return.
- ///
- /// The returned pointer value is only valid for a stable self pointer.
- fn reloadConfig(
- self: *App,
- target: apprt.action.Target,
- opts: apprt.action.ReloadConfig,
- ) !void {
- if (opts.soft) {
- switch (target) {
- .app => try self.app.updateConfig(self, &self.config),
- .surface => |core_surface| try core_surface.updateConfig(
- &self.config,
- ),
- }
- return;
- }
-
- // Load our configuration
- var config = try Config.load(self.app.alloc);
- errdefer config.deinit();
-
- // Call into our app to update
- switch (target) {
- .app => try self.app.updateConfig(self, &config),
- .surface => |core_surface| try core_surface.updateConfig(&config),
- }
-
- // Update the existing config, be sure to clean up the old one.
- self.config.deinit();
- self.config = config;
- }
-
- /// Toggle the window to fullscreen mode.
- fn toggleFullscreen(self: *App, target: apprt.Target) void {
- _ = self;
- const surface: *Surface = switch (target) {
- .app => return,
- .surface => |v| v.rt_surface,
- };
- const win = surface.window;
-
- if (surface.isFullscreen()) {
- win.setMonitor(
- null,
- @intCast(surface.monitor_dims.position_x),
- @intCast(surface.monitor_dims.position_y),
- surface.monitor_dims.width,
- surface.monitor_dims.height,
- 0,
- );
- return;
- }
-
- const monitor = win.getMonitor() orelse monitor: {
- log.warn("window had null monitor, getting primary monitor", .{});
- break :monitor glfw.Monitor.getPrimary() orelse {
- log.warn("window could not get any monitor. will not perform action", .{});
- return;
- };
- };
-
- const video_mode = monitor.getVideoMode() orelse {
- log.warn("failed to get video mode. will not perform action", .{});
- return;
- };
-
- const position = win.getPos();
- const size = surface.getSize() catch {
- log.warn("failed to get window size. will not perform fullscreen action", .{});
- return;
- };
-
- surface.monitor_dims = .{
- .width = size.width,
- .height = size.height,
- .position_x = position.x,
- .position_y = position.y,
- };
-
- win.setMonitor(monitor, 0, 0, video_mode.getWidth(), video_mode.getHeight(), 0);
- }
-
- /// Create a new tab in the parent surface.
- fn newTab(self: *App, parent_: ?*CoreSurface) !void {
- if (comptime !darwin_enabled) {
- log.warn("tabbing is not supported on this platform", .{});
- return;
- }
-
- const parent = parent_ orelse {
- _ = try self.newSurface(null);
- return;
- };
-
- // Create the new window
- const window = try self.newSurface(parent);
-
- // Add the new window the parent window
- const parent_win = glfwNative.getCocoaWindow(parent.rt_surface.window).?;
- const other_win = glfwNative.getCocoaWindow(window.window).?;
- const NSWindowOrderingMode = enum(isize) { below = -1, out = 0, above = 1 };
- const nswindow = objc.Object.fromId(parent_win);
- nswindow.msgSend(void, objc.sel("addTabbedWindow:ordered:"), .{
- objc.Object.fromId(other_win),
- NSWindowOrderingMode.above,
- });
-
- // Adding a new tab can cause the tab bar to appear which changes
- // our viewport size. We need to call the size callback in order to
- // update values. For example, we need this to set the proper mouse selection
- // point in the grid.
- const size = parent.rt_surface.getSize() catch |err| {
- log.err("error querying window size for size callback on new tab err={}", .{err});
- return;
- };
- parent.sizeCallback(size) catch |err| {
- log.err("error in size callback from new tab err={}", .{err});
- return;
- };
- }
-
- fn newSurface(self: *App, parent_: ?*CoreSurface) !*Surface {
- // Grab a surface allocation because we're going to need it.
- var surface = try self.app.alloc.create(Surface);
- errdefer self.app.alloc.destroy(surface);
-
- // Create the surface -- because windows are surfaces for glfw.
- try surface.init(self);
- errdefer surface.deinit();
-
- // If we have a parent, inherit some properties
- if (self.config.@"window-inherit-font-size") {
- if (parent_) |parent| {
- try surface.core_surface.setFontSize(parent.font_size);
- }
- }
-
- return surface;
- }
-
- /// Close the given surface.
- pub fn closeSurface(self: *App, surface: *Surface) void {
- surface.deinit();
- self.app.alloc.destroy(surface);
- }
-
- pub fn redrawSurface(self: *App, surface: *Surface) void {
- _ = self;
- _ = surface;
-
- @panic("This should never be called for GLFW.");
- }
-
- pub fn redrawInspector(self: *App, surface: *Surface) void {
- _ = self;
- _ = surface;
-
- // GLFW doesn't support the inspector
- }
-
- fn glfwErrorCallback(code: glfw.ErrorCode, desc: [:0]const u8) void {
- std.log.warn("glfw error={} message={s}", .{ code, desc });
-
- // Workaround for: https://github.com/ocornut/imgui/issues/5908
- // If we get an invalid value with "scancode" in the message we assume
- // it is from the glfw key callback that imgui sets and we clear the
- // error so that our future code doesn't crash.
- if (code == glfw.ErrorCode.InvalidValue and
- std.mem.indexOf(u8, desc, "scancode") != null)
- {
- _ = glfw.getError();
- }
- }
-
- pub fn keyboardLayout(self: *const App) input.KeyboardLayout {
- _ = self;
-
- // Not supported by glfw
- return .unknown;
- }
-
- /// Mac-specific settings. This is only enabled when the target is
- /// Mac and the artifact is a standalone exe. We don't target libs because
- /// the embedded API doesn't do windowing.
- const Darwin = struct {
- tabbing_id: *macos.foundation.String,
-
- pub fn init() !Darwin {
- const NSWindow = objc.getClass("NSWindow").?;
- NSWindow.msgSend(void, objc.sel("setAllowsAutomaticWindowTabbing:"), .{true});
-
- // Our tabbing ID allows all of our windows to group together
- const tabbing_id = try macos.foundation.String.createWithBytes(
- "com.mitchellh.ghostty.window",
- .utf8,
- false,
- );
- errdefer tabbing_id.release();
-
- // Setup our Mac settings
- return .{ .tabbing_id = tabbing_id };
- }
-
- pub fn deinit(self: *Darwin) void {
- self.tabbing_id.release();
- self.* = undefined;
- }
- };
-};
-
-/// These are used to keep track of the original monitor values so that we can
-/// safely toggle on and off of fullscreen.
-const MonitorDimensions = struct {
- width: u32,
- height: u32,
- position_x: i64,
- position_y: i64,
-};
-
-/// Surface represents the drawable surface for glfw. In glfw, a surface
-/// is always a window because that is the only abstraction that glfw exposes.
-///
-/// This means that there is no way for the glfw runtime to support tabs,
-/// splits, etc. without considerable effort. In fact, on Darwin, we do
-/// support tabs because the minimal tabbing interface is a window abstraction,
-/// but this is a bit of a hack. The native Swift runtime should be used instead
-/// which uses real native tabbing.
-///
-/// Other runtimes a surface usually represents the equivalent of a "view"
-/// or "widget" level granularity.
-pub const Surface = struct {
- /// The glfw window handle
- window: glfw.Window,
-
- /// The glfw mouse cursor handle.
- cursor: ?glfw.Cursor,
-
- /// The app we're part of
- app: *App,
-
- /// A core surface
- core_surface: CoreSurface,
-
- /// This is the key event that was processed in keyCallback. This is only
- /// non-null if the event was NOT consumed in keyCallback. This lets us
- /// know in charCallback whether we should populate it and call it again.
- /// (GLFW guarantees that charCallback is called after keyCallback).
- key_event: ?input.KeyEvent = null,
-
- /// The monitor dimensions so we can toggle fullscreen on and off.
- monitor_dims: MonitorDimensions,
-
- /// Save the title text so that we can return it later when requested.
- /// This is allocated from the heap so it must be freed when we deinit the
- /// surface.
- title_text: ?[:0]const u8 = null,
-
- pub const Options = struct {};
-
- /// Initialize the surface into the given self pointer. This gives a
- /// stable pointer to the destination that can be used for callbacks.
- pub fn init(self: *Surface, app: *App) !void {
- // Create our window
- const win = glfw.Window.create(
- 640,
- 480,
- "ghostty",
- if (app.config.fullscreen) glfw.Monitor.getPrimary() else null,
- null,
- Renderer.glfwWindowHints(&app.config),
- ) orelse return glfw.mustGetErrorCode();
- errdefer win.destroy();
-
- // Setup our
- setInitialWindowPosition(
- win,
- app.config.@"window-position-x",
- app.config.@"window-position-y",
- );
-
- // Get our physical DPI - debug only because we don't have a use for
- // this but the logging of it may be useful
- if (builtin.mode == .Debug) {
- const monitor = win.getMonitor() orelse monitor: {
- log.warn("window had null monitor, getting primary monitor", .{});
- break :monitor glfw.Monitor.getPrimary().?;
- };
- const video_mode = monitor.getVideoMode() orelse return glfw.mustGetErrorCode();
- const physical_size = monitor.getPhysicalSize();
- const physical_x_dpi = @as(f32, @floatFromInt(video_mode.getWidth())) / (@as(f32, @floatFromInt(physical_size.width_mm)) / 25.4);
- const physical_y_dpi = @as(f32, @floatFromInt(video_mode.getHeight())) / (@as(f32, @floatFromInt(physical_size.height_mm)) / 25.4);
- log.debug("physical dpi x={} y={}", .{
- physical_x_dpi,
- physical_y_dpi,
- });
- }
-
- // On Mac, enable window tabbing
- if (comptime darwin_enabled) {
- const NSWindowTabbingMode = enum(usize) { automatic = 0, preferred = 1, disallowed = 2 };
- const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(win).?);
-
- // Tabbing mode enables tabbing at all
- nswindow.setProperty("tabbingMode", NSWindowTabbingMode.automatic);
-
- // All windows within a tab bar must have a matching tabbing ID.
- // The app sets this up for us.
- nswindow.setProperty("tabbingIdentifier", app.darwin.tabbing_id);
- }
-
- // Set our callbacks
- win.setUserPointer(&self.core_surface);
- win.setSizeCallback(sizeCallback);
- win.setCharCallback(charCallback);
- win.setKeyCallback(keyCallback);
- win.setFocusCallback(focusCallback);
- win.setRefreshCallback(refreshCallback);
- win.setScrollCallback(scrollCallback);
- win.setCursorPosCallback(cursorPosCallback);
- win.setMouseButtonCallback(mouseButtonCallback);
- win.setDropCallback(dropCallback);
-
- const dimensions: MonitorDimensions = dimensions: {
- const pos = win.getPos();
- const size = win.getFramebufferSize();
- break :dimensions .{
- .width = size.width,
- .height = size.height,
- .position_x = pos.x,
- .position_y = pos.y,
- };
- };
-
- // Build our result
- self.* = .{
- .app = app,
- .window = win,
- .cursor = null,
- .core_surface = undefined,
- .monitor_dims = dimensions,
- };
- errdefer self.* = undefined;
-
- // Initialize our cursor
- try self.setMouseShape(.text);
-
- // Add ourselves to the list of surfaces on the app.
- try app.app.addSurface(self);
- errdefer app.app.deleteSurface(self);
-
- // Get our new surface config
- var config = try apprt.surface.newConfig(app.app, &app.config);
- defer config.deinit();
-
- // Initialize our surface now that we have the stable pointer.
- try self.core_surface.init(
- app.app.alloc,
- &config,
- app.app,
- app,
- self,
- );
- errdefer self.core_surface.deinit();
- }
-
- pub fn deinit(self: *Surface) void {
- if (self.title_text) |t| self.core_surface.alloc.free(t);
-
- // Remove ourselves from the list of known surfaces in the app.
- self.app.app.deleteSurface(self);
-
- // Clean up our core surface so that all the rendering and IO stop.
- self.core_surface.deinit();
-
- if (comptime darwin_enabled) {
- const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(self.window).?);
- const tabgroup = nswindow.getProperty(objc.Object, "tabGroup");
- const windows = tabgroup.getProperty(objc.Object, "windows");
- switch (windows.getProperty(usize, "count")) {
- // If we're going down to one window our tab bar is going to be
- // destroyed so unset it so that the later logic doesn't try to
- // use it.
- 1 => {},
-
- // If our tab bar is visible and we are going down to 1 window,
- // hide the tab bar. The check is "2" because our current window
- // is still present.
- 2 => if (tabgroup.getProperty(bool, "tabBarVisible")) {
- nswindow.msgSend(void, objc.sel("toggleTabBar:"), .{nswindow.value});
- },
-
- else => {},
- }
- }
-
- // We can now safely destroy our windows. We have to do this BEFORE
- // setting up the new focused window below.
- self.window.destroy();
- if (self.cursor) |c| {
- c.destroy();
- self.cursor = null;
- }
- }
-
- /// Checks if the glfw window is in fullscreen.
- pub fn isFullscreen(self: *Surface) bool {
- return self.window.getMonitor() != null;
- }
-
- /// Close this surface.
- pub fn close(self: *Surface, processActive: bool) void {
- _ = processActive;
- self.setShouldClose();
- self.deinit();
- self.app.app.alloc.destroy(self);
- }
-
- /// Set the initial window size. This is called exactly once at
- /// surface initialization time. This may be called before "self"
- /// is fully initialized.
- fn setInitialWindowSize(self: *const Surface, width: u32, height: u32) !void {
- const monitor = self.window.getMonitor() orelse glfw.Monitor.getPrimary() orelse {
- log.warn("window is not on a monitor, not setting initial size", .{});
- return;
- };
-
- const workarea = monitor.getWorkarea();
- self.window.setSize(.{
- .width = @min(width, workarea.width),
- .height = @min(height, workarea.height),
- });
- }
-
- /// Set the initial window position. This is called exactly once at
- /// surface initialization time. This may be called before "self"
- /// is fully initialized.
- fn setInitialWindowPosition(win: glfw.Window, x: ?i16, y: ?i16) void {
- const start_position_x = x orelse return;
- const start_position_y = y orelse return;
-
- log.debug("setting initial window position ({},{})", .{ start_position_x, start_position_y });
- win.setPos(.{ .x = start_position_x, .y = start_position_y });
- }
-
- /// Set the size limits of the window.
- /// Note: this interface is not good, we should redo it if we plan
- /// to use this more. i.e. you can't set max width but no max height,
- /// or no mins.
- fn setSizeLimits(self: *Surface, min: apprt.SurfaceSize, max_: ?apprt.SurfaceSize) !void {
- self.window.setSizeLimits(.{
- .width = min.width,
- .height = min.height,
- }, if (max_) |max| .{
- .width = max.width,
- .height = max.height,
- } else .{
- .width = null,
- .height = null,
- });
- }
-
- /// Returns the content scale for the created window.
- pub fn getContentScale(self: *const Surface) !apprt.ContentScale {
- const scale = self.window.getContentScale();
- return apprt.ContentScale{ .x = scale.x_scale, .y = scale.y_scale };
- }
-
- /// Returns the size of the window in pixels. The pixel size may
- /// not match screen coordinate size but we should be able to convert
- /// back and forth using getContentScale.
- pub fn getSize(self: *const Surface) !apprt.SurfaceSize {
- const size = self.window.getFramebufferSize();
- return apprt.SurfaceSize{ .width = size.width, .height = size.height };
- }
-
- /// Returns the cursor position in scaled pixels relative to the
- /// upper-left of the window.
- pub fn getCursorPos(self: *const Surface) !apprt.CursorPos {
- const unscaled_pos = self.window.getCursorPos();
- const pos = try self.cursorPosToPixels(unscaled_pos);
- return apprt.CursorPos{
- .x = @floatCast(pos.xpos),
- .y = @floatCast(pos.ypos),
- };
- }
-
- /// Set the flag that notes this window should be closed for the next
- /// iteration of the event loop.
- pub fn setShouldClose(self: *Surface) void {
- self.window.setShouldClose(true);
- }
-
- /// Returns true if the window is flagged to close.
- pub fn shouldClose(self: *const Surface) bool {
- return self.window.shouldClose();
- }
-
- /// Set the title of the window.
- fn setTitle(self: *Surface, slice: [:0]const u8) !void {
- if (self.title_text) |t| self.core_surface.alloc.free(t);
- self.title_text = try self.core_surface.alloc.dupeZ(u8, slice);
- self.window.setTitle(self.title_text.?.ptr);
- }
-
- /// Return the title of the window.
- pub fn getTitle(self: *Surface) ?[:0]const u8 {
- return self.title_text;
- }
-
- /// Set the shape of the cursor.
- fn setMouseShape(self: *Surface, shape: terminal.MouseShape) !void {
- if ((comptime builtin.target.os.tag.isDarwin()) and
- !internal_os.macos.isAtLeastVersion(13, 0, 0))
- {
- // We only set our cursor if we're NOT on Mac, or if we are then the
- // macOS version is >= 13 (Ventura). On prior versions, glfw crashes
- // since we use a tab group.
- return;
- }
-
- const new = glfw.Cursor.createStandard(switch (shape) {
- .default => .arrow,
- .text => .ibeam,
- .crosshair => .crosshair,
- .pointer => .pointing_hand,
- .ew_resize => .resize_ew,
- .ns_resize => .resize_ns,
- .nwse_resize => .resize_nwse,
- .nesw_resize => .resize_nesw,
- .all_scroll => .resize_all,
- .not_allowed => .not_allowed,
- else => return, // unsupported, ignore
- }) orelse {
- const err = glfw.mustGetErrorCode();
- log.warn("error creating cursor: {}", .{err});
- return;
- };
- errdefer new.destroy();
-
- // Set our cursor before we destroy the old one
- self.window.setCursor(new);
-
- if (self.cursor) |c| c.destroy();
- self.cursor = new;
- }
-
- /// Set the visibility of the mouse cursor.
- fn setMouseVisibility(self: *Surface, visible: bool) void {
- self.window.setInputModeCursor(if (visible) .normal else .hidden);
- }
-
- pub fn supportsClipboard(
- self: *const Surface,
- clipboard_type: apprt.Clipboard,
- ) bool {
- _ = self;
- return switch (clipboard_type) {
- .standard => true,
- .selection, .primary => comptime builtin.os.tag == .linux,
- };
- }
-
- /// Start an async clipboard request.
- pub fn clipboardRequest(
- self: *Surface,
- clipboard_type: apprt.Clipboard,
- state: apprt.ClipboardRequest,
- ) !void {
- // GLFW can read clipboards immediately so just do that.
- const str: [:0]const u8 = switch (clipboard_type) {
- .standard => glfw.getClipboardString() orelse return glfw.mustGetErrorCode(),
- .selection, .primary => selection: {
- // Not supported except on Linux
- if (comptime builtin.os.tag != .linux) break :selection "";
-
- const raw = glfwNative.getX11SelectionString() orelse
- return glfw.mustGetErrorCode();
- break :selection std.mem.span(raw);
- },
- };
-
- // Complete our request. We always allow unsafe because we don't
- // want to deal with user confirmation in this runtime.
- try self.core_surface.completeClipboardRequest(state, str, true);
- }
-
- /// Set the clipboard.
- pub fn setClipboardString(
- self: *const Surface,
- val: [:0]const u8,
- clipboard_type: apprt.Clipboard,
- confirm: bool,
- ) !void {
- _ = confirm;
- _ = self;
- switch (clipboard_type) {
- .standard => glfw.setClipboardString(val),
- .selection, .primary => {
- // Not supported except on Linux
- if (comptime builtin.os.tag != .linux) return;
- glfwNative.setX11SelectionString(val.ptr);
- },
- }
- }
-
- /// The cursor position from glfw directly is in screen coordinates but
- /// all our interface works in pixels.
- fn cursorPosToPixels(self: *const Surface, pos: glfw.Window.CursorPos) !glfw.Window.CursorPos {
- // The cursor position is in screen coordinates but we
- // want it in pixels. we need to get both the size of the
- // window in both to get the ratio to make the conversion.
- const size = self.window.getSize();
- const fb_size = self.window.getFramebufferSize();
-
- // If our framebuffer and screen are the same, then there is no scaling
- // happening and we can short-circuit by returning the pos as-is.
- if (fb_size.width == size.width and fb_size.height == size.height)
- return pos;
-
- const x_scale = @as(f64, @floatFromInt(fb_size.width)) / @as(f64, @floatFromInt(size.width));
- const y_scale = @as(f64, @floatFromInt(fb_size.height)) / @as(f64, @floatFromInt(size.height));
- return .{
- .xpos = pos.xpos * x_scale,
- .ypos = pos.ypos * y_scale,
- };
- }
-
- pub fn defaultTermioEnv(self: *Surface) !std.process.EnvMap {
- return try internal_os.getEnvMap(self.app.app.alloc);
- }
-
- fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
- _ = width;
- _ = height;
-
- // Get the size. We are given a width/height but this is in screen
- // coordinates and we want raw pixels. The core window uses the content
- // scale to scale appropriately.
- const core_win = window.getUserPointer(CoreSurface) orelse return;
- const size = core_win.rt_surface.getSize() catch |err| {
- log.err("error querying window size for size callback err={}", .{err});
- return;
- };
-
- // Call the primary callback.
- core_win.sizeCallback(size) catch |err| {
- log.err("error in size callback err={}", .{err});
- return;
- };
- }
-
- fn charCallback(window: glfw.Window, codepoint: u21) void {
- const core_win = window.getUserPointer(CoreSurface) orelse return;
-
- // We need a key event in order to process the charcallback. If it
- // isn't set then the key event was consumed.
- var key_event = core_win.rt_surface.key_event orelse return;
- core_win.rt_surface.key_event = null;
-
- // Populate the utf8 value for the event
- var buf: [4]u8 = undefined;
- const len = std.unicode.utf8Encode(codepoint, &buf) catch |err| {
- log.err("error encoding codepoint={} err={}", .{ codepoint, err });
- return;
- };
- key_event.utf8 = buf[0..len];
-
- // On macOS we need to also disable some modifiers because
- // alt+key consumes the alt.
- if (comptime builtin.target.os.tag.isDarwin()) {
- // For GLFW, we say we always consume alt because
- // GLFW doesn't have a way to disable the alt key.
- key_event.consumed_mods.alt = true;
- }
-
- _ = core_win.keyCallback(key_event) catch |err| {
- log.err("error in key callback err={}", .{err});
- return;
- };
- }
-
- fn keyCallback(
- window: glfw.Window,
- glfw_key: glfw.Key,
- scancode: i32,
- glfw_action: glfw.Action,
- glfw_mods: glfw.Mods,
- ) void {
- _ = scancode;
-
- const core_win = window.getUserPointer(CoreSurface) orelse return;
-
- // Convert our glfw types into our input types
- const mods: input.Mods = .{
- .shift = glfw_mods.shift,
- .ctrl = glfw_mods.control,
- .alt = glfw_mods.alt,
- .super = glfw_mods.super,
- };
- const action: input.Action = switch (glfw_action) {
- .release => .release,
- .press => .press,
- .repeat => .repeat,
- };
- const key: input.Key = switch (glfw_key) {
- .a => .key_a,
- .b => .key_b,
- .c => .key_c,
- .d => .key_d,
- .e => .key_e,
- .f => .key_f,
- .g => .key_g,
- .h => .key_h,
- .i => .key_i,
- .j => .key_j,
- .k => .key_k,
- .l => .key_l,
- .m => .key_m,
- .n => .key_n,
- .o => .key_o,
- .p => .key_p,
- .q => .key_q,
- .r => .key_r,
- .s => .key_s,
- .t => .key_t,
- .u => .key_u,
- .v => .key_v,
- .w => .key_w,
- .x => .key_x,
- .y => .key_y,
- .z => .key_z,
- .zero => .digit_0,
- .one => .digit_1,
- .two => .digit_2,
- .three => .digit_3,
- .four => .digit_4,
- .five => .digit_5,
- .six => .digit_6,
- .seven => .digit_7,
- .eight => .digit_8,
- .nine => .digit_9,
- .up => .arrow_up,
- .down => .arrow_down,
- .right => .arrow_right,
- .left => .arrow_left,
- .home => .home,
- .end => .end,
- .page_up => .page_up,
- .page_down => .page_down,
- .escape => .escape,
- .F1 => .f1,
- .F2 => .f2,
- .F3 => .f3,
- .F4 => .f4,
- .F5 => .f5,
- .F6 => .f6,
- .F7 => .f7,
- .F8 => .f8,
- .F9 => .f9,
- .F10 => .f10,
- .F11 => .f11,
- .F12 => .f12,
- .F13 => .f13,
- .F14 => .f14,
- .F15 => .f15,
- .F16 => .f16,
- .F17 => .f17,
- .F18 => .f18,
- .F19 => .f19,
- .F20 => .f20,
- .F21 => .f21,
- .F22 => .f22,
- .F23 => .f23,
- .F24 => .f24,
- .F25 => .f25,
- .kp_0 => .numpad_0,
- .kp_1 => .numpad_1,
- .kp_2 => .numpad_2,
- .kp_3 => .numpad_3,
- .kp_4 => .numpad_4,
- .kp_5 => .numpad_5,
- .kp_6 => .numpad_6,
- .kp_7 => .numpad_7,
- .kp_8 => .numpad_8,
- .kp_9 => .numpad_9,
- .kp_decimal => .numpad_decimal,
- .kp_divide => .numpad_divide,
- .kp_multiply => .numpad_multiply,
- .kp_subtract => .numpad_subtract,
- .kp_add => .numpad_add,
- .kp_enter => .numpad_enter,
- .kp_equal => .numpad_equal,
- .grave_accent => .backquote,
- .minus => .minus,
- .equal => .equal,
- .space => .space,
- .semicolon => .semicolon,
- .apostrophe => .quote,
- .comma => .comma,
- .period => .period,
- .slash => .slash,
- .left_bracket => .bracket_left,
- .right_bracket => .bracket_right,
- .backslash => .backslash,
- .enter => .enter,
- .tab => .tab,
- .backspace => .backspace,
- .insert => .insert,
- .delete => .delete,
- .caps_lock => .caps_lock,
- .scroll_lock => .scroll_lock,
- .num_lock => .num_lock,
- .print_screen => .print_screen,
- .pause => .pause,
- .left_shift => .shift_left,
- .left_control => .control_left,
- .left_alt => .alt_left,
- .left_super => .meta_left,
- .right_shift => .shift_right,
- .right_control => .control_right,
- .right_alt => .alt_right,
- .right_super => .meta_right,
- .menu => .context_menu,
-
- .world_1,
- .world_2,
- .unknown,
- => .unidentified,
- };
-
- // This is a hack for GLFW. We require our apprts to send both
- // the UTF8 encoding AND the keypress at the same time. Its critical
- // for things like ctrl sequences to work. However, GLFW doesn't
- // provide this information all at once. So we just infer based on
- // the key press. This isn't portable but GLFW is only for testing.
- const utf8 = switch (key) {
- inline else => |k| utf8: {
- if (mods.shift) break :utf8 "";
- const cp = k.codepoint() orelse break :utf8 "";
- const byte = std.math.cast(u8, cp) orelse break :utf8 "";
- break :utf8 &.{byte};
- },
- };
-
- const key_event: input.KeyEvent = .{
- .action = action,
- .key = key,
- .mods = mods,
- .consumed_mods = .{},
- .composing = false,
- .utf8 = utf8,
- .unshifted_codepoint = if (utf8.len > 0) @intCast(utf8[0]) else 0,
- };
-
- const effect = core_win.keyCallback(key_event) catch |err| {
- log.err("error in key callback err={}", .{err});
- return;
- };
-
- // Surface closed.
- if (effect == .closed) return;
-
- // If it wasn't consumed, we set it on our self so that charcallback
- // can make another attempt. Otherwise, we set null so the charcallback
- // is ignored.
- core_win.rt_surface.key_event = null;
- if (effect == .ignored and
- (action == .press or action == .repeat))
- {
- core_win.rt_surface.key_event = key_event;
- }
- }
-
- fn focusCallback(window: glfw.Window, focused: bool) void {
- const core_win = window.getUserPointer(CoreSurface) orelse return;
- core_win.focusCallback(focused) catch |err| {
- log.err("error in focus callback err={}", .{err});
- return;
- };
- }
-
- fn refreshCallback(window: glfw.Window) void {
- const core_win = window.getUserPointer(CoreSurface) orelse return;
- core_win.refreshCallback() catch |err| {
- log.err("error in refresh callback err={}", .{err});
- return;
- };
- }
-
- fn scrollCallback(window: glfw.Window, xoff: f64, yoff: f64) void {
- // Glfw doesn't support any of the scroll mods.
- const scroll_mods: input.ScrollMods = .{};
-
- const core_win = window.getUserPointer(CoreSurface) orelse return;
- core_win.scrollCallback(xoff, yoff, scroll_mods) catch |err| {
- log.err("error in scroll callback err={}", .{err});
- return;
- };
- }
-
- fn cursorPosCallback(
- window: glfw.Window,
- unscaled_xpos: f64,
- unscaled_ypos: f64,
- ) void {
- const core_win = window.getUserPointer(CoreSurface) orelse return;
-
- // Convert our unscaled x/y to scaled.
- const pos = core_win.rt_surface.cursorPosToPixels(.{
- .xpos = unscaled_xpos,
- .ypos = unscaled_ypos,
- }) catch |err| {
- log.err(
- "error converting cursor pos to scaled pixels in cursor pos callback err={}",
- .{err},
- );
- return;
- };
-
- core_win.cursorPosCallback(.{
- .x = @floatCast(pos.xpos),
- .y = @floatCast(pos.ypos),
- }, null) catch |err| {
- log.err("error in cursor pos callback err={}", .{err});
- return;
- };
- }
-
- fn mouseButtonCallback(
- window: glfw.Window,
- glfw_button: glfw.MouseButton,
- glfw_action: glfw.Action,
- glfw_mods: glfw.Mods,
- ) void {
- const core_win = window.getUserPointer(CoreSurface) orelse return;
-
- // Convert glfw button to input button
- const mods: input.Mods = .{
- .shift = glfw_mods.shift,
- .ctrl = glfw_mods.control,
- .alt = glfw_mods.alt,
- .super = glfw_mods.super,
- };
- const button: input.MouseButton = switch (glfw_button) {
- .left => .left,
- .right => .right,
- .middle => .middle,
- .four => .four,
- .five => .five,
- .six => .six,
- .seven => .seven,
- .eight => .eight,
- };
- const action: input.MouseButtonState = switch (glfw_action) {
- .press => .press,
- .release => .release,
- else => unreachable,
- };
-
- _ = core_win.mouseButtonCallback(action, button, mods) catch |err| {
- log.err("error in scroll callback err={}", .{err});
- return;
- };
- }
-
- fn dropCallback(window: glfw.Window, paths: [][*:0]const u8) void {
- const surface = window.getUserPointer(CoreSurface) orelse return;
-
- var list = std.ArrayList(u8).init(surface.alloc);
- defer list.deinit();
-
- for (paths) |path| {
- const path_slice = std.mem.span(path);
-
- // preallocate worst case of escaping every char + space
- list.ensureTotalCapacity(path_slice.len * 2 + 1) catch |err| {
- log.err("error in drop callback err={}", .{err});
- return;
- };
-
- const writer = list.writer();
- for (path_slice) |c| {
- if (std.mem.indexOfScalar(u8, "\\ ()[]{}<>\"'`!#$&;|*?\t", c)) |_| {
- writer.print("\\{c}", .{c}) catch unreachable; // memory preallocated
- } else writer.writeByte(c) catch unreachable; // same here
- }
- writer.writeByte(' ') catch unreachable; // separate paths
-
- surface.textCallback(list.items) catch |err| {
- log.err("error in drop callback err={}", .{err});
- return;
- };
-
- list.clearRetainingCapacity(); // avoid unnecessary reallocations
- }
- }
-};
diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig
index c61254fbd..907f3a36d 100644
--- a/src/apprt/gtk/App.zig
+++ b/src/apprt/gtk/App.zig
@@ -496,7 +496,7 @@ pub fn performAction(
.resize_split => self.resizeSplit(target, value),
.equalize_splits => self.equalizeSplits(target),
.goto_split => return self.gotoSplit(target, value),
- .open_config => try configpkg.edit.open(self.core_app.alloc),
+ .open_config => return self.openConfig(),
.config_change => self.configChange(target, value.config),
.reload_config => try self.reloadConfig(target, value),
.inspector => self.controlInspector(target, value),
@@ -519,6 +519,7 @@ pub fn performAction(
.secure_input => self.setSecureInput(target, value),
.ring_bell => try self.ringBell(target),
.toggle_command_palette => try self.toggleCommandPalette(target),
+ .open_url => self.openUrl(value),
// Unimplemented
.close_all_windows,
@@ -1757,3 +1758,34 @@ fn initActions(self: *App) void {
action_map.addAction(action.as(gio.Action));
}
}
+
+fn openConfig(self: *App) !bool {
+ // Get the config file path
+ const alloc = self.core_app.alloc;
+ const path = configpkg.edit.openPath(alloc) catch |err| {
+ log.warn("error getting config file path: {}", .{err});
+ return false;
+ };
+ defer alloc.free(path);
+
+ // Open it using openURL. "path" isn't actually a URL but
+ // at the time of writing that works just fine for GTK.
+ self.openUrl(.{ .kind = .text, .url = path });
+ return true;
+}
+
+fn openUrl(
+ app: *App,
+ value: apprt.action.OpenUrl,
+) void {
+ // TODO: use https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.OpenURI.html
+
+ // Fallback to the minimal cross-platform way of opening a URL.
+ // This is always a safe fallback and enables for example Windows
+ // to open URLs (GTK on Windows via WSL is a thing).
+ internal_os.open(
+ app.core_app.alloc,
+ value.kind,
+ value.url,
+ ) catch |err| log.warn("unable to open url: {}", .{err});
+}
diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig
index 555edb1e4..e6b502c80 100644
--- a/src/apprt/gtk/Window.zig
+++ b/src/apprt/gtk/Window.zig
@@ -214,6 +214,7 @@ pub fn init(self: *Window, app: *App) !void {
{
const btn = gtk.MenuButton.new();
btn.as(gtk.Widget).setTooltipText(i18n._("Main Menu"));
+ btn.as(gtk.Widget).setCanFocus(0);
btn.setIconName("open-menu-symbolic");
btn.setPopover(self.titlebar_menu.asWidget());
_ = gobject.Object.signals.notify.connect(
@@ -253,6 +254,7 @@ pub fn init(self: *Window, app: *App) !void {
},
};
+ btn.setCanFocus(0);
btn.setFocusOnClick(0);
self.headerbar.packEnd(btn);
}
diff --git a/src/build/Config.zig b/src/build/Config.zig
index 5f8780af9..a9a79fb53 100644
--- a/src/build/Config.zig
+++ b/src/build/Config.zig
@@ -9,6 +9,7 @@ const apprt = @import("../apprt.zig");
const font = @import("../font/main.zig");
const rendererpkg = @import("../renderer.zig");
const Command = @import("../Command.zig");
+const XCFramework = @import("GhosttyXCFramework.zig");
const WasmTarget = @import("../os/wasm/target.zig").Target;
const gtk = @import("gtk.zig");
@@ -24,6 +25,7 @@ const app_version: std.SemanticVersion = .{ .major = 1, .minor = 1, .patch = 4 }
/// Standard build configuration options.
optimize: std.builtin.OptimizeMode,
target: std.Build.ResolvedTarget,
+xcframework_target: XCFramework.Target = .universal,
wasm_target: WasmTarget,
/// Comptime interfaces
@@ -48,14 +50,15 @@ patch_rpath: ?[]const u8 = null,
/// Artifacts
flatpak: bool = false,
-emit_test_exe: bool = false,
emit_bench: bool = false,
-emit_helpgen: bool = false,
emit_docs: bool = false,
-emit_webdata: bool = false,
-emit_xcframework: bool = false,
+emit_helpgen: bool = false,
+emit_macos_app: bool = false,
emit_terminfo: bool = false,
emit_termcap: bool = false,
+emit_test_exe: bool = false,
+emit_xcframework: bool = false,
+emit_webdata: bool = false,
/// Environmental properties
env: std.process.EnvMap,
@@ -109,6 +112,14 @@ pub fn init(b: *std.Build) !Config {
.env = env,
};
+ //---------------------------------------------------------------
+ // Target-specific properties
+ config.xcframework_target = b.option(
+ XCFramework.Target,
+ "xcframework-target",
+ "The target for the xcframework.",
+ ) orelse .universal;
+
//---------------------------------------------------------------
// Comptime Interfaces
config.font_backend = b.option(
@@ -340,6 +351,12 @@ pub fn init(b: *std.Build) !Config {
!config.emit_test_exe and
!config.emit_helpgen);
+ config.emit_macos_app = b.option(
+ bool,
+ "emit-macos-app",
+ "Build and install the macOS app bundle.",
+ ) orelse config.emit_xcframework;
+
//---------------------------------------------------------------
// System Packages
@@ -378,11 +395,6 @@ pub fn init(b: *std.Build) !Config {
"glslang",
"spirv-cross",
"simdutf",
-
- // This is default false because it is used for testing
- // primarily and not official packaging. The packaging
- // guide advises against building the GLFW backend.
- "glfw3",
}) |dep| {
_ = b.systemIntegrationOption(dep, .{ .default = false });
}
diff --git a/src/build/GhosttyDocs.zig b/src/build/GhosttyDocs.zig
index 4b5dbfd92..b95b56f74 100644
--- a/src/build/GhosttyDocs.zig
+++ b/src/build/GhosttyDocs.zig
@@ -93,5 +93,32 @@ pub fn init(
pub fn install(self: *const GhosttyDocs) void {
const b = self.steps[0].owner;
- for (self.steps) |step| b.getInstallStep().dependOn(step);
+ self.addStepDependencies(b.getInstallStep());
+}
+
+pub fn addStepDependencies(
+ self: *const GhosttyDocs,
+ other_step: *std.Build.Step,
+) void {
+ for (self.steps) |step| other_step.dependOn(step);
+}
+
+/// Installs some dummy files to satisfy the folder structure of docs
+/// without actually generating any documentation. This is useful
+/// when the `emit-docs` option is not set to true, but we still
+/// need the rough directory structure to exist, such as for the macOS
+/// app.
+pub fn installDummy(self: *const GhosttyDocs, step: *std.Build.Step) void {
+ _ = self;
+
+ const b = step.owner;
+ var wf = b.addWriteFiles();
+ const path = "share/man/.placeholder";
+ step.dependOn(&b.addInstallFile(
+ wf.add(
+ path,
+ "emit-docs not true so no man pages",
+ ),
+ path,
+ ).step);
}
diff --git a/src/build/GhosttyI18n.zig b/src/build/GhosttyI18n.zig
index e0f6b5611..9dcc67a31 100644
--- a/src/build/GhosttyI18n.zig
+++ b/src/build/GhosttyI18n.zig
@@ -50,7 +50,14 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n {
}
pub fn install(self: *const GhosttyI18n) void {
- for (self.steps) |step| self.owner.getInstallStep().dependOn(step);
+ self.addStepDependencies(self.owner.getInstallStep());
+}
+
+pub fn addStepDependencies(
+ self: *const GhosttyI18n,
+ other_step: *std.Build.Step,
+) void {
+ for (self.steps) |step| other_step.dependOn(step);
}
fn createUpdateStep(b: *std.Build) !*std.Build.Step {
@@ -72,24 +79,38 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
xgettext.has_side_effects = true;
inline for (gresource.blueprint_files) |blp| {
- // We avoid using addFileArg here since the full, absolute file path
- // would be added to the file as its location, which differs for
- // everyone's checkout of the repository.
- // This comes at a cost of losing per-file caching, of course.
- xgettext.addArg(std.fmt.comptimePrint(
+ const path = std.fmt.comptimePrint(
"src/apprt/gtk/ui/{[major]}.{[minor]}/{[name]s}.blp",
blp,
- ));
+ );
+ // The arguments to xgettext must be the relative path in the build root
+ // or the resulting files will contain the absolute path. This will cause
+ // a lot of churn because not everyone has the Ghostty code checked out in
+ // exactly the same location.
+ xgettext.addArg(path);
+ // Mark the file as an input so that the Zig build system caching will work.
+ xgettext.addFileInput(b.path(path));
}
{
- var gtk_files = try b.build_root.handle.openDir(
+ // Iterate over all of the files underneath `src/apprt/gtk`. We store
+ // them in an array so that they can be sorted into a determininistic
+ // order. That will minimize code churn as directory walking is not
+ // guaranteed to happen in any particular order.
+
+ var gtk_files: std.ArrayListUnmanaged([]const u8) = .empty;
+ defer {
+ for (gtk_files.items) |item| b.allocator.free(item);
+ gtk_files.deinit(b.allocator);
+ }
+
+ var gtk_dir = try b.build_root.handle.openDir(
"src/apprt/gtk",
.{ .iterate = true },
);
- defer gtk_files.close();
+ defer gtk_dir.close();
- var walk = try gtk_files.walk(b.allocator);
+ var walk = try gtk_dir.walk(b.allocator);
defer walk.deinit();
while (try walk.next()) |src| {
switch (src.kind) {
@@ -102,7 +123,29 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
else => continue,
}
- xgettext.addArg((b.pathJoin(&.{ "src/apprt/gtk", src.path })));
+ try gtk_files.append(b.allocator, try b.allocator.dupe(u8, src.path));
+ }
+
+ std.mem.sort(
+ []const u8,
+ gtk_files.items,
+ {},
+ struct {
+ fn lt(_: void, lhs: []const u8, rhs: []const u8) bool {
+ return std.mem.order(u8, lhs, rhs) == .lt;
+ }
+ }.lt,
+ );
+
+ for (gtk_files.items) |item| {
+ const path = b.pathJoin(&.{ "src/apprt/gtk", item });
+ // The arguments to xgettext must be the relative path in the build root
+ // or the resulting files will contain the absolute path. This will
+ // cause a lot of churn because not everyone has the Ghostty code
+ // checked out in exactly the same location.
+ xgettext.addArg(path);
+ // Mark the file as an input so that the Zig build system caching will work.
+ xgettext.addFileInput(b.path(path));
}
}
@@ -113,7 +156,7 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
);
inline for (internal_os.i18n.locales) |locale| {
- const msgmerge = b.addSystemCommand(&.{ "msgmerge", "-q" });
+ const msgmerge = b.addSystemCommand(&.{ "msgmerge", "--quiet", "--no-fuzzy-matching" });
msgmerge.addFileArg(b.path("po/" ++ locale ++ ".po"));
msgmerge.addFileArg(xgettext.captureStdOut());
usf.addCopyFileToSource(msgmerge.captureStdOut(), "po/" ++ locale ++ ".po");
diff --git a/src/build/GhosttyResources.zig b/src/build/GhosttyResources.zig
index 34b5e35f8..ef04b21fd 100644
--- a/src/build/GhosttyResources.zig
+++ b/src/build/GhosttyResources.zig
@@ -397,5 +397,12 @@ fn addLinuxAppResources(
pub fn install(self: *const GhosttyResources) void {
const b = self.steps[0].owner;
- for (self.steps) |step| b.getInstallStep().dependOn(step);
+ self.addStepDependencies(b.getInstallStep());
+}
+
+pub fn addStepDependencies(
+ self: *const GhosttyResources,
+ other_step: *std.Build.Step,
+) void {
+ for (self.steps) |step| other_step.dependOn(step);
}
diff --git a/src/build/GhosttyXCFramework.zig b/src/build/GhosttyXCFramework.zig
index 0dc4f5762..7debd6906 100644
--- a/src/build/GhosttyXCFramework.zig
+++ b/src/build/GhosttyXCFramework.zig
@@ -7,11 +7,23 @@ const GhosttyLib = @import("GhosttyLib.zig");
const XCFrameworkStep = @import("XCFrameworkStep.zig");
xcframework: *XCFrameworkStep,
-macos: GhosttyLib,
+target: Target,
-pub fn init(b: *std.Build, deps: *const SharedDeps) !GhosttyXCFramework {
- // Create our universal macOS static library.
- const macos = try GhosttyLib.initMacOSUniversal(b, deps);
+pub const Target = enum { native, universal };
+
+pub fn init(
+ b: *std.Build,
+ deps: *const SharedDeps,
+ target: Target,
+) !GhosttyXCFramework {
+ // Universal macOS build
+ const macos_universal = try GhosttyLib.initMacOSUniversal(b, deps);
+
+ // Native macOS build
+ const macos_native = try GhosttyLib.initStatic(b, &try deps.retarget(
+ b,
+ Config.genericMacOSTarget(b, null),
+ ));
// iOS
const ios = try GhosttyLib.initStatic(b, &try deps.retarget(
@@ -47,29 +59,43 @@ pub fn init(b: *std.Build, deps: *const SharedDeps) !GhosttyXCFramework {
const xcframework = XCFrameworkStep.create(b, .{
.name = "GhosttyKit",
.out_path = "macos/GhosttyKit.xcframework",
- .libraries = &.{
- .{
- .library = macos.output,
- .headers = b.path("include"),
+ .libraries = switch (target) {
+ .universal => &.{
+ .{
+ .library = macos_universal.output,
+ .headers = b.path("include"),
+ },
+ .{
+ .library = ios.output,
+ .headers = b.path("include"),
+ },
+ .{
+ .library = ios_sim.output,
+ .headers = b.path("include"),
+ },
},
- .{
- .library = ios.output,
+
+ .native => &.{.{
+ .library = macos_native.output,
.headers = b.path("include"),
- },
- .{
- .library = ios_sim.output,
- .headers = b.path("include"),
- },
+ }},
},
});
return .{
.xcframework = xcframework,
- .macos = macos,
+ .target = target,
};
}
pub fn install(self: *const GhosttyXCFramework) void {
const b = self.xcframework.step.owner;
- b.getInstallStep().dependOn(self.xcframework.step);
+ self.addStepDependencies(b.getInstallStep());
+}
+
+pub fn addStepDependencies(
+ self: *const GhosttyXCFramework,
+ other_step: *std.Build.Step,
+) void {
+ other_step.dependOn(self.xcframework.step);
}
diff --git a/src/build/GhosttyXcodebuild.zig b/src/build/GhosttyXcodebuild.zig
new file mode 100644
index 000000000..7fa2d2f95
--- /dev/null
+++ b/src/build/GhosttyXcodebuild.zig
@@ -0,0 +1,157 @@
+const Ghostty = @This();
+
+const std = @import("std");
+const builtin = @import("builtin");
+const RunStep = std.Build.Step.Run;
+const Config = @import("Config.zig");
+const Docs = @import("GhosttyDocs.zig");
+const I18n = @import("GhosttyI18n.zig");
+const Resources = @import("GhosttyResources.zig");
+const XCFramework = @import("GhosttyXCFramework.zig");
+
+build: *std.Build.Step.Run,
+open: *std.Build.Step.Run,
+copy: *std.Build.Step.Run,
+
+pub const Deps = struct {
+ xcframework: *const XCFramework,
+ docs: *const Docs,
+ i18n: *const I18n,
+ resources: *const Resources,
+};
+
+pub fn init(
+ b: *std.Build,
+ config: *const Config,
+ deps: Deps,
+) !Ghostty {
+ const xc_config = switch (config.optimize) {
+ .Debug => "Debug",
+ .ReleaseSafe,
+ .ReleaseSmall,
+ .ReleaseFast,
+ => "Release",
+ };
+
+ const app_path = b.fmt("macos/build/{s}/Ghostty.app", .{xc_config});
+
+ // Our step to build the Ghostty macOS app.
+ const build = build: {
+ // External environment variables can mess up xcodebuild, so
+ // we create a new empty environment.
+ const env_map = try b.allocator.create(std.process.EnvMap);
+ env_map.* = .init(b.allocator);
+
+ const build = RunStep.create(b, "xcodebuild");
+ build.has_side_effects = true;
+ build.cwd = b.path("macos");
+ build.env_map = env_map;
+ build.addArgs(&.{
+ "xcodebuild",
+ "-target",
+ "Ghostty",
+ "-configuration",
+ xc_config,
+ });
+
+ switch (deps.xcframework.target) {
+ // Universal is our default target, so we don't have to
+ // add anything.
+ .universal => {},
+
+ // Native we need to override the architecture in the Xcode
+ // project with the -arch flag.
+ .native => build.addArgs(&.{
+ "-arch",
+ switch (builtin.cpu.arch) {
+ .aarch64 => "arm64",
+ .x86_64 => "x86_64",
+ else => @panic("unsupported macOS arch"),
+ },
+ }),
+ }
+
+ // We need the xcframework
+ deps.xcframework.addStepDependencies(&build.step);
+
+ // We also need all these resources because the xcode project
+ // references them via symlinks.
+ deps.resources.addStepDependencies(&build.step);
+ deps.i18n.addStepDependencies(&build.step);
+ deps.docs.installDummy(&build.step);
+
+ // Expect success
+ build.expectExitCode(0);
+
+ break :build build;
+ };
+
+ // Our step to open the resulting Ghostty app.
+ const open = open: {
+ const disable_save_state = RunStep.create(b, "disable save state");
+ disable_save_state.has_side_effects = true;
+ disable_save_state.addArgs(&.{
+ "/usr/libexec/PlistBuddy",
+ "-c",
+ // We'll have to change this to `Set` if we ever put this
+ // into our Info.plist.
+ "Add :NSQuitAlwaysKeepsWindows bool false",
+ b.fmt("{s}/Contents/Info.plist", .{app_path}),
+ });
+ disable_save_state.expectExitCode(0);
+ disable_save_state.step.dependOn(&build.step);
+
+ const open = RunStep.create(b, "run Ghostty app");
+ open.has_side_effects = true;
+ open.cwd = b.path("");
+ open.addArgs(&.{b.fmt(
+ "{s}/Contents/MacOS/ghostty",
+ .{app_path},
+ )});
+
+ // Open depends on the app
+ open.step.dependOn(&build.step);
+ open.step.dependOn(&disable_save_state.step);
+
+ // This overrides our default behavior and forces logs to show
+ // up on stderr (in addition to the centralized macOS log).
+ open.setEnvironmentVariable("GHOSTTY_LOG", "1");
+
+ // Configure how we're launching
+ open.setEnvironmentVariable("GHOSTTY_MAC_LAUNCH_SOURCE", "zig_run");
+
+ if (b.args) |args| {
+ open.addArgs(args);
+ }
+
+ break :open open;
+ };
+
+ // Our step to copy the app bundle to the install path.
+ // We have to use `cp -R` because there are symlinks in the
+ // bundle.
+ const copy = copy: {
+ const step = RunStep.create(b, "copy app bundle");
+ step.addArgs(&.{ "cp", "-R" });
+ step.addFileArg(b.path(app_path));
+ step.addArg(b.fmt("{s}", .{b.install_path}));
+ step.step.dependOn(&build.step);
+ break :copy step;
+ };
+
+ return .{
+ .build = build,
+ .open = open,
+ .copy = copy,
+ };
+}
+
+pub fn install(self: *const Ghostty) void {
+ const b = self.copy.step.owner;
+ b.getInstallStep().dependOn(&self.copy.step);
+}
+
+pub fn installXcframework(self: *const Ghostty) void {
+ const b = self.build.step.owner;
+ b.getInstallStep().dependOn(&self.build.step);
+}
diff --git a/src/build/SharedDeps.zig b/src/build/SharedDeps.zig
index f173e4856..b6e9900e2 100644
--- a/src/build/SharedDeps.zig
+++ b/src/build/SharedDeps.zig
@@ -500,6 +500,43 @@ pub fn add(
try static_libs.append(utfcpp_dep.artifact("utfcpp").getEmittedBin());
}
+ // Fonts
+ {
+ // JetBrains Mono
+ const jb_mono = b.dependency("jetbrains_mono", .{});
+ step.root_module.addAnonymousImport(
+ "jetbrains_mono_regular",
+ .{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Regular.ttf") },
+ );
+ step.root_module.addAnonymousImport(
+ "jetbrains_mono_bold",
+ .{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Bold.ttf") },
+ );
+ step.root_module.addAnonymousImport(
+ "jetbrains_mono_italic",
+ .{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Italic.ttf") },
+ );
+ step.root_module.addAnonymousImport(
+ "jetbrains_mono_bold_italic",
+ .{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-BoldItalic.ttf") },
+ );
+ step.root_module.addAnonymousImport(
+ "jetbrains_mono_variable",
+ .{ .root_source_file = jb_mono.path("fonts/variable/JetBrainsMono[wght].ttf") },
+ );
+ step.root_module.addAnonymousImport(
+ "jetbrains_mono_variable_italic",
+ .{ .root_source_file = jb_mono.path("fonts/variable/JetBrainsMono-Italic[wght].ttf") },
+ );
+
+ // Symbols-only nerd font
+ const nf_symbols = b.dependency("nerd_fonts_symbols_only", .{});
+ step.root_module.addAnonymousImport(
+ "nerd_fonts_symbols_only",
+ .{ .root_source_file = nf_symbols.path("SymbolsNerdFontMono-Regular.ttf") },
+ );
+ }
+
// If we're building an exe then we have additional dependencies.
if (step.kind != .lib) {
// We always statically compile glad
@@ -515,17 +552,6 @@ pub fn add(
switch (self.config.app_runtime) {
.none => {},
-
- .glfw => if (b.lazyDependency("glfw", .{
- .target = target,
- .optimize = optimize,
- })) |glfw_dep| {
- step.root_module.addImport(
- "glfw",
- glfw_dep.module("glfw"),
- );
- },
-
.gtk => try self.addGTK(step),
}
}
@@ -734,6 +760,9 @@ pub fn gtkDistResources(
});
const resources_c = generate_c.addOutputFileArg("ghostty_resources.c");
generate_c.addFileArg(gresource_xml);
+ for (gresource.dependencies) |file| {
+ generate_c.addFileInput(b.path(file));
+ }
const generate_h = b.addSystemCommand(&.{
"glib-compile-resources",
@@ -744,6 +773,9 @@ pub fn gtkDistResources(
});
const resources_h = generate_h.addOutputFileArg("ghostty_resources.h");
generate_h.addFileArg(gresource_xml);
+ for (gresource.dependencies) |file| {
+ generate_h.addFileInput(b.path(file));
+ }
return .{
.resources_c = .{
diff --git a/src/build/XCFrameworkStep.zig b/src/build/XCFrameworkStep.zig
index 823e5aac4..8a0d5dc67 100644
--- a/src/build/XCFrameworkStep.zig
+++ b/src/build/XCFrameworkStep.zig
@@ -55,6 +55,9 @@ pub fn create(b: *std.Build, opts: Options) *XCFrameworkStep {
}
run.addArg("-output");
run.addArg(opts.out_path);
+ run.expectExitCode(0);
+ _ = run.captureStdOut();
+ _ = run.captureStdErr();
break :run run;
};
run_create.step.dependOn(&run_delete.step);
diff --git a/src/build/main.zig b/src/build/main.zig
index 3154d395f..f25ce1c23 100644
--- a/src/build/main.zig
+++ b/src/build/main.zig
@@ -15,6 +15,7 @@ pub const GhosttyFrameData = @import("GhosttyFrameData.zig");
pub const GhosttyLib = @import("GhosttyLib.zig");
pub const GhosttyResources = @import("GhosttyResources.zig");
pub const GhosttyI18n = @import("GhosttyI18n.zig");
+pub const GhosttyXcodebuild = @import("GhosttyXcodebuild.zig");
pub const GhosttyXCFramework = @import("GhosttyXCFramework.zig");
pub const GhosttyWebdata = @import("GhosttyWebdata.zig");
pub const HelpStrings = @import("HelpStrings.zig");
diff --git a/src/cli/version.zig b/src/cli/version.zig
index a27d1050d..22608fa88 100644
--- a/src/cli/version.zig
+++ b/src/cli/version.zig
@@ -15,8 +15,6 @@ pub const Options = struct {};
/// The `version` command is used to display information about Ghostty. Recognized as
/// either `+version` or `--version`.
pub fn run(alloc: Allocator) !u8 {
- _ = alloc;
-
const stdout = std.io.getStdOut().writer();
const tty = std.io.getStdOut().isTty();
@@ -34,32 +32,37 @@ pub fn run(alloc: Allocator) !u8 {
try stdout.print(" - channel: {s}\n", .{@tagName(build_config.release_channel)});
try stdout.print("Build Config\n", .{});
- try stdout.print(" - Zig version: {s}\n", .{builtin.zig_version_string});
- try stdout.print(" - build mode : {}\n", .{builtin.mode});
- try stdout.print(" - app runtime: {}\n", .{build_config.app_runtime});
- try stdout.print(" - font engine: {}\n", .{build_config.font_backend});
- try stdout.print(" - renderer : {}\n", .{renderer.Renderer});
- try stdout.print(" - libxev : {s}\n", .{@tagName(xev.backend)});
+ try stdout.print(" - Zig version : {s}\n", .{builtin.zig_version_string});
+ try stdout.print(" - build mode : {}\n", .{builtin.mode});
+ try stdout.print(" - app runtime : {}\n", .{build_config.app_runtime});
+ try stdout.print(" - font engine : {}\n", .{build_config.font_backend});
+ try stdout.print(" - renderer : {}\n", .{renderer.Renderer});
+ try stdout.print(" - libxev : {s}\n", .{@tagName(xev.backend)});
if (comptime build_config.app_runtime == .gtk) {
- try stdout.print(" - desktop env: {s}\n", .{@tagName(internal_os.desktopEnvironment())});
- try stdout.print(" - GTK version:\n", .{});
- try stdout.print(" build : {}\n", .{gtk_version.comptime_version});
- try stdout.print(" runtime : {}\n", .{gtk_version.getRuntimeVersion()});
- try stdout.print(" - libadwaita : enabled\n", .{});
- try stdout.print(" build : {}\n", .{adw_version.comptime_version});
- try stdout.print(" runtime : {}\n", .{adw_version.getRuntimeVersion()});
+ if (comptime builtin.os.tag == .linux) {
+ const kernel_info = internal_os.getKernelInfo(alloc);
+ defer if (kernel_info) |k| alloc.free(k);
+ try stdout.print(" - kernel version: {s}\n", .{kernel_info orelse "Kernel information unavailable"});
+ }
+ try stdout.print(" - desktop env : {s}\n", .{@tagName(internal_os.desktopEnvironment())});
+ try stdout.print(" - GTK version :\n", .{});
+ try stdout.print(" build : {}\n", .{gtk_version.comptime_version});
+ try stdout.print(" runtime : {}\n", .{gtk_version.getRuntimeVersion()});
+ try stdout.print(" - libadwaita : enabled\n", .{});
+ try stdout.print(" build : {}\n", .{adw_version.comptime_version});
+ try stdout.print(" runtime : {}\n", .{adw_version.getRuntimeVersion()});
if (comptime build_options.x11) {
- try stdout.print(" - libX11 : enabled\n", .{});
+ try stdout.print(" - libX11 : enabled\n", .{});
} else {
- try stdout.print(" - libX11 : disabled\n", .{});
+ try stdout.print(" - libX11 : disabled\n", .{});
}
// We say `libwayland` since it is possible to build Ghostty without
// Wayland integration but with Wayland-enabled GTK
if (comptime build_options.wayland) {
- try stdout.print(" - libwayland : enabled\n", .{});
+ try stdout.print(" - libwayland : enabled\n", .{});
} else {
- try stdout.print(" - libwayland : disabled\n", .{});
+ try stdout.print(" - libwayland : disabled\n", .{});
}
}
return 0;
diff --git a/src/config.zig b/src/config.zig
index ac38eb89c..efc9fd973 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -14,6 +14,7 @@ pub const entryFormatter = formatter.entryFormatter;
pub const formatEntry = formatter.formatEntry;
// Field types
+pub const BoldColor = Config.BoldColor;
pub const ClipboardAccess = Config.ClipboardAccess;
pub const Command = Config.Command;
pub const ConfirmCloseSurface = Config.ConfirmCloseSurface;
@@ -37,6 +38,7 @@ pub const ShellIntegrationFeatures = Config.ShellIntegrationFeatures;
pub const WindowPaddingColor = Config.WindowPaddingColor;
pub const BackgroundImagePosition = Config.BackgroundImagePosition;
pub const BackgroundImageFit = Config.BackgroundImageFit;
+pub const LinkPreviews = Config.LinkPreviews;
// Alternate APIs
pub const CAPI = @import("config/CAPI.zig");
diff --git a/src/config/CAPI.zig b/src/config/CAPI.zig
index 0b7108a59..bdc59797a 100644
--- a/src/config/CAPI.zig
+++ b/src/config/CAPI.zig
@@ -1,7 +1,9 @@
const std = @import("std");
+const assert = std.debug.assert;
const cli = @import("../cli.zig");
const inputpkg = @import("../input.zig");
-const global = &@import("../global.zig").state;
+const state = &@import("../global.zig").state;
+const c = @import("../main_c.zig");
const Config = @import("Config.zig");
const c_get = @import("c_get.zig");
@@ -12,14 +14,14 @@ const log = std.log.scoped(.config);
/// Create a new configuration filled with the initial default values.
export fn ghostty_config_new() ?*Config {
- const result = global.alloc.create(Config) catch |err| {
+ const result = state.alloc.create(Config) catch |err| {
log.err("error allocating config err={}", .{err});
return null;
};
- result.* = Config.default(global.alloc) catch |err| {
+ result.* = Config.default(state.alloc) catch |err| {
log.err("error creating config err={}", .{err});
- global.alloc.destroy(result);
+ state.alloc.destroy(result);
return null;
};
@@ -29,20 +31,20 @@ export fn ghostty_config_new() ?*Config {
export fn ghostty_config_free(ptr: ?*Config) void {
if (ptr) |v| {
v.deinit();
- global.alloc.destroy(v);
+ state.alloc.destroy(v);
}
}
/// Deep clone the configuration.
export fn ghostty_config_clone(self: *Config) ?*Config {
- const result = global.alloc.create(Config) catch |err| {
+ const result = state.alloc.create(Config) catch |err| {
log.err("error allocating config err={}", .{err});
return null;
};
- result.* = self.clone(global.alloc) catch |err| {
+ result.* = self.clone(state.alloc) catch |err| {
log.err("error cloning config err={}", .{err});
- global.alloc.destroy(result);
+ state.alloc.destroy(result);
return null;
};
@@ -51,7 +53,7 @@ export fn ghostty_config_clone(self: *Config) ?*Config {
/// Load the configuration from the CLI args.
export fn ghostty_config_load_cli_args(self: *Config) void {
- self.loadCliArgs(global.alloc) catch |err| {
+ self.loadCliArgs(state.alloc) catch |err| {
log.err("error loading config err={}", .{err});
};
}
@@ -60,7 +62,7 @@ export fn ghostty_config_load_cli_args(self: *Config) void {
/// is usually done first. The default file locations are locations
/// such as the home directory.
export fn ghostty_config_load_default_files(self: *Config) void {
- self.loadDefaultFiles(global.alloc) catch |err| {
+ self.loadDefaultFiles(state.alloc) catch |err| {
log.err("error loading config err={}", .{err});
};
}
@@ -69,7 +71,7 @@ export fn ghostty_config_load_default_files(self: *Config) void {
/// file locations in the previously loaded configuration. This will
/// recursively continue to load up to a built-in limit.
export fn ghostty_config_load_recursive_files(self: *Config) void {
- self.loadRecursiveFiles(global.alloc) catch |err| {
+ self.loadRecursiveFiles(state.alloc) catch |err| {
log.err("error loading config err={}", .{err});
};
}
@@ -122,10 +124,13 @@ export fn ghostty_config_get_diagnostic(self: *Config, idx: u32) Diagnostic {
return .{ .message = message.ptr };
}
-export fn ghostty_config_open() void {
- edit.open(global.alloc) catch |err| {
+export fn ghostty_config_open_path() c.String {
+ const path = edit.openPath(state.alloc) catch |err| {
log.err("error opening config in editor err={}", .{err});
+ return .empty;
};
+
+ return .fromSlice(path);
}
/// Sync with ghostty_diagnostic_s
diff --git a/src/config/Config.zig b/src/config/Config.zig
index ef8f48ee9..66da2b5e9 100644
--- a/src/config/Config.zig
+++ b/src/config/Config.zig
@@ -62,6 +62,17 @@ pub const compatibility = std.StaticStringMap(
// Ghostty 1.2 removed the `hidden` value from `gtk-tabs-location` and
// moved it to `window-show-tab-bar`.
.{ "gtk-tabs-location", compatGtkTabsLocation },
+
+ // Ghostty 1.2 lets you set `cell-foreground` and `cell-background`
+ // to match the cell foreground and background colors, respectively.
+ // This can be used with `cursor-color` and `cursor-text` to recreate
+ // this behavior. This applies to selection too.
+ .{ "cursor-invert-fg-bg", compatCursorInvertFgBg },
+ .{ "selection-invert-fg-bg", compatSelectionInvertFgBg },
+
+ // Ghostty 1.2 merged `bold-is-bright` into the new `bold-color`
+ // by setting the value to "bright".
+ .{ "bold-is-bright", compatBoldIsBright },
});
/// The font families to use.
@@ -294,6 +305,7 @@ pub const compatibility = std.StaticStringMap(
///
/// * `cursor` - Break runs under the cursor.
///
+/// Available since: 1.2.0
@"font-shaping-break": FontShapingBreak = .{},
/// What color space to use when performing alpha blending.
@@ -318,6 +330,8 @@ pub const compatibility = std.StaticStringMap(
/// * `linear-corrected` - Same as `linear`, but with a correction step applied
/// for text that makes it look nearly or completely identical to `native`,
/// but without any of the darkening artifacts.
+///
+/// Available since: 1.1.0
@"alpha-blending": AlphaBlending =
if (builtin.os.tag == .macos)
.native
@@ -385,6 +399,20 @@ pub const compatibility = std.StaticStringMap(
/// Thickness in pixels or percentage adjustment of box drawing characters.
/// See the notes about adjustments in `adjust-cell-width`.
@"adjust-box-thickness": ?MetricModifier = null,
+/// Height in pixels or percentage adjustment of maximum height for nerd font icons.
+///
+/// Increasing this value will allow nerd font icons to be larger, but won't
+/// necessarily force them to be. Decreasing this value will make nerd font
+/// icons smaller.
+///
+/// The default value for the icon height is 1.2 times the height of capital
+/// letters in your primary font, so something like -16.6% would make icons
+/// roughly the same height as capital letters.
+///
+/// See the notes about adjustments in `adjust-cell-width`.
+///
+/// Available in: 1.2.0
+@"adjust-icon-height": ?MetricModifier = null,
/// The method to use for calculating the cell width of a grapheme cluster.
/// The default value is `unicode` which uses the Unicode standard to determine
@@ -425,13 +453,16 @@ pub const compatibility = std.StaticStringMap(
///
/// Available flags:
///
-/// * `hinting` - Enable or disable hinting, enabled by default.
-/// * `force-autohint` - Use the freetype auto-hinter rather than the
-/// font's native hinter. Enabled by default.
-/// * `monochrome` - Instructs renderer to use 1-bit monochrome
-/// rendering. This option doesn't impact the hinter.
-/// Enabled by default.
-/// * `autohint` - Use the freetype auto-hinter. Enabled by default.
+/// * `hinting` - Enable or disable hinting. Enabled by default.
+///
+/// * `force-autohint` - Always use the freetype auto-hinter instead of
+/// the font's native hinter. Disabled by default.
+///
+/// * `monochrome` - Instructs renderer to use 1-bit monochrome rendering.
+/// This will disable anti-aliasing, and probably not look very good unless
+/// you're using a pixel font. Disabled by default.
+///
+/// * `autohint` - Enable the freetype auto-hinter. Enabled by default.
///
/// Example: `hinting`, `no-hinting`, `force-autohint`, `no-force-autohint`
@"freetype-load-flags": FreetypeLoadFlags = .{},
@@ -489,7 +520,6 @@ pub const compatibility = std.StaticStringMap(
/// be fixed in a future update:
///
/// - macOS: titlebar tabs style is not updated when switching themes.
-///
theme: ?Theme = null,
/// Background color for the window.
@@ -513,6 +543,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// For sufficiently large images, this could lead to a large increase in
/// memory usage (specifically VRAM usage). A future Ghostty improvement
/// will resolve this by sharing image textures across terminals.
+///
+/// Available since: 1.2.0
@"background-image": ?Path = null,
/// Background image opacity.
@@ -532,6 +564,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// configured `background-opacity` is `0.5` and `background-image-opacity`
/// is set to `1.5`, then the final opacity of the background image will be
/// `0.5 * 1.5 = 0.75`.
+///
+/// Available since: 1.2.0
@"background-image-opacity": f32 = 1.0,
/// Background image position.
@@ -548,6 +582,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// * `bottom-right`
///
/// The default value is `center`.
+///
+/// Available since: 1.2.0
@"background-image-position": BackgroundImagePosition = .center,
/// Background image fit.
@@ -576,6 +612,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// Don't scale the background image.
///
/// The default value is `contain`.
+///
+/// Available since: 1.2.0
@"background-image-fit": BackgroundImageFit = .contain,
/// Whether to repeat the background image or not.
@@ -585,22 +623,19 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// fill the terminal area.
///
/// The default value is `false`.
+///
+/// Available since: 1.2.0
@"background-image-repeat": bool = false,
/// The foreground and background color for selection. If this is not set, then
/// the selection color is just the inverted window background and foreground
/// (note: not to be confused with the cell bg/fg).
/// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
-@"selection-foreground": ?Color = null,
-@"selection-background": ?Color = null,
-
-/// Swap the foreground and background colors of cells for selection. This
-/// option overrides the `selection-foreground` and `selection-background`
-/// options.
-///
-/// If you select across cells with differing foregrounds and backgrounds, the
-/// selection color will vary across the selection.
-@"selection-invert-fg-bg": bool = false,
+/// Since version 1.2.0, this can also be set to `cell-foreground` to match
+/// the cell foreground color, or `cell-background` to match the cell
+/// background color.
+@"selection-foreground": ?TerminalColor = null,
+@"selection-background": ?TerminalColor = null,
/// Whether to clear selected text when typing. This defaults to `true`.
/// This is typical behavior for most terminal emulators as well as
@@ -615,6 +650,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
///
/// If this is `false`, then the selection can still be manually
/// cleared by clicking once or by pressing `escape`.
+///
+/// Available since: 1.2.0
@"selection-clear-on-typing": bool = true,
/// The minimum contrast ratio between the foreground and background colors.
@@ -644,12 +681,19 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
palette: Palette = .{},
/// The color of the cursor. If this is not set, a default will be chosen.
-/// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
-@"cursor-color": ?Color = null,
-
-/// Swap the foreground and background colors of the cell under the cursor. This
-/// option overrides the `cursor-color` and `cursor-text` options.
-@"cursor-invert-fg-bg": bool = false,
+///
+/// Direct colors can be specified as either hex (`#RRGGBB` or `RRGGBB`)
+/// or a named X11 color.
+///
+/// Additionally, special values can be used to set the color to match
+/// other colors at runtime:
+///
+/// * `cell-foreground` - Match the cell foreground color.
+/// (Available since version 1.2.0)
+///
+/// * `cell-background` - Match the cell background color.
+/// (Available since version 1.2.0)
+@"cursor-color": ?TerminalColor = null,
/// The opacity level (opposite of transparency) of the cursor. A value of 1
/// is fully opaque and a value of 0 is fully transparent. A value less than 0
@@ -673,7 +717,6 @@ palette: Palette = .{},
/// * `bar`
/// * `underline`
/// * `block_hollow`
-///
@"cursor-style": terminal.CursorStyle = .block,
/// Sets the default blinking state of the cursor. This is just the default
@@ -693,13 +736,15 @@ palette: Palette = .{},
/// * ` ` (blank)
/// * `true`
/// * `false`
-///
@"cursor-style-blink": ?bool = null,
/// The color of the text under the cursor. If this is not set, a default will
/// be chosen.
/// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
-@"cursor-text": ?Color = null,
+/// Since version 1.2.0, this can also be set to `cell-foreground` to match
+/// the cell foreground color, or `cell-background` to match the cell
+/// background color.
+@"cursor-text": ?TerminalColor = null,
/// Enables the ability to move the cursor at prompts by using `alt+click` on
/// Linux and `option+click` on macOS.
@@ -747,7 +792,6 @@ palette: Palette = .{},
/// * `false`
/// * `always`
/// * `never`
-///
@"mouse-shift-capture": MouseShiftCapture = .false,
/// Multiplier for scrolling distance with the mouse wheel. Any value less
@@ -755,6 +799,8 @@ palette: Palette = .{},
/// value.
///
/// A value of "3" (default) scrolls 3 lines per tick.
+///
+/// Available since: 1.2.0
@"mouse-scroll-multiplier": f64 = 3.0,
/// The opacity level (opposite of transparency) of the background. A value of
@@ -823,6 +869,8 @@ palette: Palette = .{},
/// The color of the split divider. If this is not set, a default will be chosen.
/// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
+///
+/// Available since: 1.1.0
@"split-divider-color": ?Color = null,
/// The command to run, usually a shell. If this is not an absolute path, it'll
@@ -837,14 +885,14 @@ palette: Palette = .{},
/// arguments are provided, the command will be executed using `/bin/sh -c`
/// to offload shell argument expansion.
///
-/// To avoid shell expansion altogether, prefix the command with `direct:`,
-/// e.g. `direct:nvim foo`. This will avoid the roundtrip to `/bin/sh` but will
-/// also not support any shell parsing such as arguments with spaces, filepaths
-/// with `~`, globs, etc.
+/// To avoid shell expansion altogether, prefix the command with `direct:`, e.g.
+/// `direct:nvim foo`. This will avoid the roundtrip to `/bin/sh` but will also
+/// not support any shell parsing such as arguments with spaces, filepaths with
+/// `~`, globs, etc. (Available since: 1.2.0)
///
-/// You can also explicitly prefix the command with `shell:` to always
-/// wrap the command in a shell. This can be used to ensure our heuristics
-/// to choose the right mode are not used in case they are wrong.
+/// You can also explicitly prefix the command with `shell:` to always wrap the
+/// command in a shell. This can be used to ensure our heuristics to choose the
+/// right mode are not used in case they are wrong. (Available since: 1.2.0)
///
/// This command will be used for all new terminal surfaces, i.e. new windows,
/// tabs, etc. If you want to run a command only for the first terminal surface
@@ -890,7 +938,6 @@ command: ?Command = null,
/// shell integration with a `-e`-executed command, you must either
/// name your binary appropriately or source the shell integration script
/// manually.
-///
@"initial-command": ?Command = null,
/// Extra environment variables to pass to commands launched in a terminal
@@ -927,6 +974,8 @@ command: ?Command = null,
/// These environment variables _will not_ be passed to commands run by Ghostty
/// for other purposes, like `open` or `xdg-open` used to open URLs in your
/// browser.
+///
+/// Available since: 1.2.0
env: RepeatableStringMap = .{},
/// Data to send as input to the command on startup.
@@ -968,6 +1017,8 @@ env: RepeatableStringMap = .{},
///
/// Changing this configuration at runtime will only affect new
/// terminals.
+///
+/// Available since: 1.2.0
input: RepeatableReadableIO = .{},
/// If true, keep the terminal open after the command exits. Normally, the
@@ -1030,9 +1081,21 @@ link: RepeatableLink = .{},
/// `link`). If you want to customize URL matching, use `link` and disable this.
@"link-url": bool = true,
+/// Show link previews for a matched URL.
+///
+/// When true, link previews are shown for all matched URLs. When false, link
+/// previews are never shown. When set to "osc8", link previews are only shown
+/// for hyperlinks created with the OSC 8 sequence (in this case, the link text
+/// can differ from the link destination).
+///
+/// Available since: 1.2.0
+@"link-previews": LinkPreviews = .true,
+
/// Whether to start the window in a maximized state. This setting applies
/// to new windows and does not apply to tabs, splits, etc. However, this setting
/// will apply to all new windows, not just the first one.
+///
+/// Available since: 1.1.0
maximize: bool = false,
/// Start new windows in fullscreen. This setting applies to new windows and
@@ -1257,6 +1320,8 @@ class: ?[:0]const u8 = null,
/// applies to actions that are surface-specific. For actions that
/// are already global (e.g. `quit`), this prefix has no effect.
///
+/// Available since: 1.0.0
+///
/// * `global:` - Make the keybind global. By default, keybinds only work
/// within Ghostty and under the right conditions (application focused,
/// sometimes terminal focused, etc.). If you want a keybind to work
@@ -1265,6 +1330,9 @@ class: ?[:0]const u8 = null,
/// work in all environments; see the additional notes below for more
/// information.
///
+/// Available since: 1.0.0 (on macOS)
+/// Available since: 1.2.0 (on GTK)
+///
/// * `unconsumed:` - Do not consume the input. By default, a keybind
/// will consume the input, meaning that the associated encoding (if
/// any) will not be sent to the running program in the terminal. If
@@ -1275,6 +1343,8 @@ class: ?[:0]const u8 = null,
/// Since they are not associated with a specific terminal surface,
/// they're never encoded.
///
+/// Available since: 1.0.0
+///
/// * `performable:` - Only consume the input if the action is able to be
/// performed. For example, the `copy_to_clipboard` action will only
/// consume the input if there is a selection to copy. If there is no
@@ -1290,6 +1360,8 @@ class: ?[:0]const u8 = null,
/// Performable keybinds will still work, they just won't appear as
/// a shortcut label in the menu.
///
+/// Available since: 1.1.0
+///
/// Keybind triggers are not unique per prefix combination. For example,
/// `ctrl+a` and `global:ctrl+a` are not two separate keybinds. The keybind
/// set later will overwrite the keybind set earlier. In this case, the
@@ -1399,7 +1471,6 @@ keybind: Keybinds = .{},
/// do not look good extended.
/// * The nearest row contains a perfect fit powerline character. These
/// don't look good extended.
-///
@"window-padding-color": WindowPaddingColor = .background,
/// Synchronize rendering with the screen refresh rate. If true, this will
@@ -1446,6 +1517,8 @@ keybind: Keybinds = .{},
///
/// * `client` - Prefer client-side decorations.
///
+/// Available since: 1.1.0
+///
/// * `server` - Prefer server-side decorations. This is only relevant
/// on Linux with GTK, either on X11, or Wayland on a compositor that
/// supports the `org_kde_kwin_server_decoration` protocol (e.g. KDE Plasma,
@@ -1454,6 +1527,8 @@ keybind: Keybinds = .{},
/// If `server` is set but the environment doesn't support server-side
/// decorations, client-side decorations will be used instead.
///
+/// Available since: 1.1.0
+///
/// The default value is `auto`.
///
/// For the sake of backwards compatibility and convenience, this setting also
@@ -1476,6 +1551,8 @@ keybind: Keybinds = .{},
///
/// Note: any font available on the system may be used, this font is not
/// required to be a fixed-width font.
+///
+/// Available since: 1.1.0 (on GTK)
@"window-title-font-family": ?[:0]const u8 = null,
/// The text that will be displayed in the subtitle of the window. Valid values:
@@ -1485,6 +1562,8 @@ keybind: Keybinds = .{},
/// surface.
///
/// This feature is only supported on GTK.
+///
+/// Available since: 1.1.0
@"window-subtitle": WindowSubtitle = .false,
/// The theme to use for the windows. Valid values:
@@ -1569,9 +1648,9 @@ keybind: Keybinds = .{},
/// the visible screen area. This means that if the menu bar is visible, the
/// window will be placed below the menu bar.
///
-/// Note: this is only supported on macOS and Linux GLFW builds. The GTK
-/// runtime does not support setting the window position, as windows are
-/// only allowed position themselves in X11 and not Wayland.
+/// Note: this is only supported on macOS. The GTK runtime does not support
+/// setting the window position, as windows are only allowed position
+/// themselves in X11 and not Wayland.
@"window-position-x": ?i16 = null,
@"window-position-y": ?i16 = null,
@@ -1628,6 +1707,8 @@ keybind: Keybinds = .{},
///
/// Always display the tab bar, even when there's only one tab.
///
+/// Available since: 1.2.0
+///
/// - `auto` *(default)*
///
/// Automatically show and hide the tab bar. The tab bar is only
@@ -1712,6 +1793,8 @@ keybind: Keybinds = .{},
///
/// The maximum value is `584y 49w 23h 34m 33s 709ms 551µs 615ns`. Any
/// value larger than this will be clamped to the maximum value.
+///
+/// Available since 1.0.0
@"resize-overlay-duration": Duration = .{ .duration = 750 * std.time.ns_per_ms },
/// If true, when there are multiple split panes, the mouse selects the pane
@@ -1757,6 +1840,8 @@ keybind: Keybinds = .{},
/// Warning: This can expose sensitive information at best and enable
/// arbitrary code execution at worst (with a maliciously crafted title
/// and a minor amount of user interaction).
+///
+/// Available since: 1.0.1
@"title-report": bool = false,
/// The total amount of bytes that can be used for image data (e.g. the Kitty
@@ -1944,6 +2029,8 @@ keybind: Keybinds = .{},
/// This configuration is only supported on macOS. Linux doesn't
/// support undo operations at all so this configuration has no
/// effect.
+///
+/// Available since: 1.2.0
@"undo-timeout": Duration = .{ .duration = 5 * std.time.ns_per_s },
/// The position of the "quick" terminal window. To learn more about the
@@ -2047,6 +2134,8 @@ keybind: Keybinds = .{},
///
/// Only implemented on macOS.
/// On Linux the behavior is always equivalent to `move`.
+///
+/// Available since: 1.1.0
@"quick-terminal-space-behavior": QuickTerminalSpaceBehavior = .move,
/// Determines under which circumstances that the quick terminal should receive
@@ -2075,6 +2164,8 @@ keybind: Keybinds = .{},
///
/// Only has an effect on Linux Wayland.
/// On macOS the behavior is always equivalent to `on-demand`.
+///
+/// Available since: 1.2.0
@"quick-terminal-keyboard-interactivity": QuickTerminalKeyboardInteractivity = .@"on-demand",
/// Whether to enable shell integration auto-injection or not. Shell integration
@@ -2142,6 +2233,8 @@ keybind: Keybinds = .{},
/// ```ini
/// command-palette-entry =
/// ```
+///
+/// Available since: 1.2.0
@"command-palette-entry": RepeatableCommand = .{},
/// Sets the reporting format for OSC sequences that request color information.
@@ -2306,6 +2399,8 @@ keybind: Keybinds = .{},
/// Only implemented on macOS.
///
/// Example: `audio`, `no-audio`, `system`, `no-system`
+///
+/// Available since: 1.2.0
@"bell-features": BellFeatures = .{},
/// If `audio` is an enabled bell feature, this is a path to an audio file. If
@@ -2313,12 +2408,16 @@ keybind: Keybinds = .{},
/// configuration file that it is referenced from, or from the current working
/// directory if this is used as a CLI flag. The path may be prefixed with `~/`
/// to reference the user's home directory. (GTK only)
+///
+/// Available since: 1.2.0
@"bell-audio-path": ?Path = null,
/// If `audio` is an enabled bell feature, this is the volume to play the audio
/// file at (relative to the system volume). This is a floating point number
/// ranging from 0.0 (silence) to 1.0 (as loud as possible). The default is 0.5.
/// (GTK only)
+///
+/// Available since: 1.2.0
@"bell-audio-volume": f64 = 0.5,
/// Control the in-app notifications that Ghostty shows.
@@ -2344,6 +2443,8 @@ keybind: Keybinds = .{},
/// enable all notifications.
///
/// This configuration only applies to GTK.
+///
+/// Available since: 1.1.0
@"app-notifications": AppNotifications = .{},
/// If anything other than false, fullscreen mode on macOS will not use the
@@ -2394,6 +2495,8 @@ keybind: Keybinds = .{},
/// The default value is `visible`.
///
/// Changing this option at runtime only applies to new windows.
+///
+/// Available since: 1.2.0
@"macos-window-buttons": MacWindowButtons = .visible,
/// The style of the macOS titlebar. Available values are: "native",
@@ -2491,8 +2594,6 @@ keybind: Keybinds = .{},
///
/// The values `left` or `right` enable this for the left or right *Option*
/// key, respectively.
-///
-/// This does not work with GLFW builds.
@"macos-option-as-alt": ?OptionAsAlt = null,
/// Whether to enable the macOS window shadow. The default value is true.
@@ -2518,6 +2619,8 @@ keybind: Keybinds = .{},
///
/// Note: When the macOS application is hidden, keyboard layout changes
/// will no longer be automatic. This is a limitation of macOS.
+///
+/// Available since: 1.2.0
@"macos-hidden": MacHidden = .never,
/// If true, Ghostty on macOS will automatically enable the "Secure Input"
@@ -2579,7 +2682,6 @@ keybind: Keybinds = .{},
/// This is because the update dialog is managed through a
/// separate framework and cannot be customized without significant
/// effort.
-///
@"macos-icon": MacAppIcon = .official,
/// The material to use for the frame of the macOS app icon.
@@ -2593,7 +2695,6 @@ keybind: Keybinds = .{},
///
/// Note: This configuration is required when `macos-icon` is set to
/// `custom-style`.
-///
@"macos-icon-frame": MacAppIconFrame = .aluminum,
/// The color of the ghost in the macOS app icon.
@@ -2614,7 +2715,6 @@ keybind: Keybinds = .{},
///
/// Note: This configuration is required when `macos-icon` is set to
/// `custom-style`.
-///
@"macos-icon-screen-color": ?ColorList = null,
/// Whether macOS Shortcuts are allowed to control Ghostty.
@@ -2638,6 +2738,7 @@ keybind: Keybinds = .{},
///
/// * `deny` - Deny Shortcuts from controlling Ghostty.
///
+/// Available since: 1.2.0
@"macos-shortcuts": MacShortcuts = .ask,
/// Put every surface (tab, split, window) into a dedicated Linux cgroup.
@@ -2665,7 +2766,6 @@ keybind: Keybinds = .{},
/// * `always` - Always use cgroups.
/// * `single-instance` - Enable cgroups only for Ghostty instances launched
/// as single-instance applications (see gtk-single-instance).
-///
@"linux-cgroup": LinuxCgroup = if (builtin.os.tag == .linux)
.@"single-instance"
else
@@ -2702,6 +2802,8 @@ else
/// Enable or disable GTK's OpenGL debugging logs. The default is `true` for
/// debug builds, `false` for all others.
+///
+/// Available since: 1.1.0
@"gtk-opengl-debug": bool = builtin.mode == .Debug,
/// If `true`, the Ghostty GTK application will run in single-instance mode:
@@ -2739,6 +2841,8 @@ else
/// If this is `true`, the titlebar will be hidden when the window is maximized,
/// and shown when the titlebar is unmaximized. GTK only.
+///
+/// Available since: 1.1.0
@"gtk-titlebar-hide-when-maximized": bool = false,
/// Determines the appearance of the top and bottom bars tab bar.
@@ -2761,14 +2865,14 @@ else
///
/// GTK CSS documentation can be found at the following links:
///
-/// * - An overview of GTK CSS.
-/// * - A comprehensive list
+/// * https://docs.gtk.org/gtk4/css-overview.html - An overview of GTK CSS.
+/// * https://docs.gtk.org/gtk4/css-properties.html - A comprehensive list
/// of supported CSS properties.
///
/// Launch Ghostty with `env GTK_DEBUG=interactive ghostty` to tweak Ghostty's
/// CSS in real time using the GTK Inspector. Errors in your CSS files would
/// also be reported in the terminal you started Ghostty from. See
-/// for more
+/// https://developer.gnome.org/documentation/tools/inspector.html for more
/// information about the GTK Inspector.
///
/// This configuration can be repeated multiple times to load multiple files.
@@ -2776,14 +2880,32 @@ else
/// not exist. If you want to include a file that begins with a literal ?
/// character, surround the file path in double quotes (").
/// The file size limit for a single stylesheet is 5MiB.
+///
+/// Available since: 1.1.0
@"gtk-custom-css": RepeatablePath = .{},
/// If `true` (default), applications running in the terminal can show desktop
/// notifications using certain escape sequences such as OSC 9 or OSC 777.
@"desktop-notifications": bool = true,
-/// If `true`, the bold text will use the bright color palette.
-@"bold-is-bright": bool = false,
+/// Modifies the color used for bold text in the terminal.
+///
+/// This can be set to a specific color, using the same format as
+/// `background` or `foreground` (e.g. `#RRGGBB` but other formats
+/// are also supported; see the aforementioned documentation). If a
+/// specific color is set, this color will always be used for the default
+/// bold text color. It will set the rest of the bold colors to `bright`.
+///
+/// This can also be set to `bright`, which uses the bright color palette
+/// for bold text. For example, if the text is red, then the bold will
+/// use the bright red color. The terminal palette is set with `palette`
+/// but can also be overridden by the terminal application itself using
+/// escape sequences such as OSC 4. (Since Ghostty 1.2.0, the previous
+/// configuration `bold-is-bright` is deprecated and replaced by this
+/// usage).
+///
+/// Available since Ghostty 1.2.0.
+@"bold-color": ?BoldColor = null,
/// This will be used to set the `TERM` environment variable.
/// HACK: We set this with an `xterm` prefix because vim uses that to enable key
@@ -2812,6 +2934,8 @@ term: []const u8 = "xterm-ghostty",
/// this isn't intended to be modified by users, the documentation is
/// lighter than the other configurations and users are expected to
/// refer to the code for details.
+///
+/// Available since: 1.2.0
@"launched-from": ?LaunchSource = null,
/// Configures the low-level API to use for async IO, eventing, etc.
@@ -2840,6 +2964,8 @@ term: []const u8 = "xterm-ghostty",
///
/// This is only supported on Linux, since this is the only platform
/// where we have multiple options. On macOS, we always use `kqueue`.
+///
+/// Available since: 1.2.0
@"async-backend": AsyncBackend = .auto,
/// Control the auto-update functionality of Ghostty. This is only supported
@@ -3826,10 +3952,6 @@ pub fn parseManuallyHook(
return true;
}
-/// parseFieldManuallyFallback is a fallback called only when
-/// parsing the field directly failed. It can be used to implement
-/// backward compatibility. Since this is only called when parsing
-/// fails, it doesn't impact happy-path performance.
fn compatGtkTabsLocation(
self: *Config,
alloc: Allocator,
@@ -3847,6 +3969,68 @@ fn compatGtkTabsLocation(
return false;
}
+fn compatCursorInvertFgBg(
+ self: *Config,
+ alloc: Allocator,
+ key: []const u8,
+ value_: ?[]const u8,
+) bool {
+ _ = alloc;
+ assert(std.mem.eql(u8, key, "cursor-invert-fg-bg"));
+
+ // We don't do anything if the value is unset, which is technically
+ // not EXACTLY the same as prior behavior since it would fallback
+ // to doing whatever cursor-color/cursor-text were set to, but
+ // I don't want to store what that is separately so this is close
+ // enough.
+ //
+ // Realistically, these fields were mutually exclusive so anyone
+ // relying on that behavior should just upgrade to the new
+ // cursor-color/cursor-text fields.
+ const set = cli.args.parseBool(value_ orelse "t") catch return false;
+ if (set) {
+ self.@"cursor-color" = .@"cell-foreground";
+ self.@"cursor-text" = .@"cell-background";
+ }
+
+ return true;
+}
+
+fn compatSelectionInvertFgBg(
+ self: *Config,
+ alloc: Allocator,
+ key: []const u8,
+ value_: ?[]const u8,
+) bool {
+ _ = alloc;
+ assert(std.mem.eql(u8, key, "selection-invert-fg-bg"));
+
+ const set = cli.args.parseBool(value_ orelse "t") catch return false;
+ if (set) {
+ self.@"selection-foreground" = .@"cell-background";
+ self.@"selection-background" = .@"cell-foreground";
+ }
+
+ return true;
+}
+
+fn compatBoldIsBright(
+ self: *Config,
+ alloc: Allocator,
+ key: []const u8,
+ value_: ?[]const u8,
+) bool {
+ _ = alloc;
+ assert(std.mem.eql(u8, key, "bold-is-bright"));
+
+ const set = cli.args.parseBool(value_ orelse "t") catch return false;
+ if (set) {
+ self.@"bold-color" = .bright;
+ }
+
+ return true;
+}
+
/// Create a shallow copy of this config. This will share all the memory
/// allocated with the previous config but will have a new arena for
/// any changes or new allocations. The config should have `deinit`
@@ -4271,6 +4455,12 @@ pub const WindowSubtitle = enum {
@"working-directory",
};
+pub const LinkPreviews = enum {
+ false,
+ true,
+ osc8,
+};
+
/// Color represents a color using RGB.
///
/// This is a packed struct so that the C API to read color values just
@@ -4409,6 +4599,117 @@ pub const Color = struct {
}
};
+/// Represents color values that can also reference special color
+/// values such as "cell-foreground" or "cell-background".
+pub const TerminalColor = union(enum) {
+ color: Color,
+ @"cell-foreground",
+ @"cell-background",
+
+ pub fn parseCLI(input_: ?[]const u8) !TerminalColor {
+ const input = input_ orelse return error.ValueRequired;
+ if (std.mem.eql(u8, input, "cell-foreground")) return .@"cell-foreground";
+ if (std.mem.eql(u8, input, "cell-background")) return .@"cell-background";
+ return .{ .color = try Color.parseCLI(input) };
+ }
+
+ /// Used by Formatter
+ pub fn formatEntry(self: TerminalColor, formatter: anytype) !void {
+ switch (self) {
+ .color => try self.color.formatEntry(formatter),
+
+ .@"cell-foreground",
+ .@"cell-background",
+ => try formatter.formatEntry([:0]const u8, @tagName(self)),
+ }
+ }
+
+ test "parseCLI" {
+ const testing = std.testing;
+
+ try testing.expectEqual(
+ TerminalColor{ .color = Color{ .r = 78, .g = 42, .b = 132 } },
+ try TerminalColor.parseCLI("#4e2a84"),
+ );
+ try testing.expectEqual(
+ TerminalColor{ .color = Color{ .r = 0, .g = 0, .b = 0 } },
+ try TerminalColor.parseCLI("black"),
+ );
+ try testing.expectEqual(
+ TerminalColor.@"cell-foreground",
+ try TerminalColor.parseCLI("cell-foreground"),
+ );
+ try testing.expectEqual(
+ TerminalColor.@"cell-background",
+ try TerminalColor.parseCLI("cell-background"),
+ );
+
+ try testing.expectError(error.InvalidValue, TerminalColor.parseCLI("a"));
+ }
+
+ test "formatConfig" {
+ const testing = std.testing;
+ var buf = std.ArrayList(u8).init(testing.allocator);
+ defer buf.deinit();
+
+ var sc: TerminalColor = .@"cell-foreground";
+ try sc.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
+ try testing.expectEqualSlices(u8, "a = cell-foreground\n", buf.items);
+ }
+};
+
+/// Represents color values that can be used for bold. See `bold-color`.
+pub const BoldColor = union(enum) {
+ color: Color,
+ bright,
+
+ pub fn parseCLI(input_: ?[]const u8) !BoldColor {
+ const input = input_ orelse return error.ValueRequired;
+ if (std.mem.eql(u8, input, "bright")) return .bright;
+ return .{ .color = try Color.parseCLI(input) };
+ }
+
+ /// Used by Formatter
+ pub fn formatEntry(self: BoldColor, formatter: anytype) !void {
+ switch (self) {
+ .color => try self.color.formatEntry(formatter),
+ .bright => try formatter.formatEntry(
+ [:0]const u8,
+ @tagName(self),
+ ),
+ }
+ }
+
+ test "parseCLI" {
+ const testing = std.testing;
+
+ try testing.expectEqual(
+ BoldColor{ .color = Color{ .r = 78, .g = 42, .b = 132 } },
+ try BoldColor.parseCLI("#4e2a84"),
+ );
+ try testing.expectEqual(
+ BoldColor{ .color = Color{ .r = 0, .g = 0, .b = 0 } },
+ try BoldColor.parseCLI("black"),
+ );
+ try testing.expectEqual(
+ BoldColor.bright,
+ try BoldColor.parseCLI("bright"),
+ );
+
+ try testing.expectError(error.InvalidValue, BoldColor.parseCLI("a"));
+ }
+
+ test "formatConfig" {
+ const testing = std.testing;
+ var buf = std.ArrayList(u8).init(testing.allocator);
+ defer buf.deinit();
+
+ var sc: BoldColor = .bright;
+ try sc.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
+ try testing.expectEqualSlices(u8, "a = bright\n", buf.items);
+ }
+};
+
pub const ColorList = struct {
const Self = @This();
@@ -5342,7 +5643,14 @@ pub const Keybinds = struct {
.mods = mods,
},
.{ .goto_tab = (i - start) + 1 },
- .{ .performable = true },
+ .{
+ // On macOS we keep this not performable so that the
+ // keyboard shortcuts in tabs work. In the future the
+ // correct fix is to fix the reverse mapping lookup
+ // to allow us to lookup performable keybinds
+ // conditionally.
+ .performable = !builtin.target.os.tag.isDarwin(),
+ },
);
}
try self.set.putFlags(
@@ -5352,7 +5660,10 @@ pub const Keybinds = struct {
.mods = mods,
},
.{ .last_tab = {} },
- .{ .performable = true },
+ .{
+ // See comment above with the numeric goto_tab
+ .performable = !builtin.target.os.tag.isDarwin(),
+ },
);
}
@@ -6407,8 +6718,9 @@ pub const RepeatableCommand = struct {
try list.parseCLI(alloc, "title:Foo,action:ignore");
try list.parseCLI(alloc, "title:Bar,description:bobr,action:text:ale bydle");
try list.parseCLI(alloc, "title:Quux,description:boo,action:increase_font_size:2.5");
+ try list.parseCLI(alloc, "title:Baz,description:Raspberry Pie,action:set_font_size:3.14");
- try testing.expectEqual(@as(usize, 3), list.value.items.len);
+ try testing.expectEqual(@as(usize, 4), list.value.items.len);
try testing.expectEqual(inputpkg.Binding.Action.ignore, list.value.items[0].action);
try testing.expectEqualStrings("Foo", list.value.items[0].title);
@@ -6425,6 +6737,13 @@ pub const RepeatableCommand = struct {
try testing.expectEqualStrings("Quux", list.value.items[2].title);
try testing.expectEqualStrings("boo", list.value.items[2].description);
+ try testing.expectEqual(
+ inputpkg.Binding.Action{ .set_font_size = 3.14 },
+ list.value.items[3].action,
+ );
+ try testing.expectEqualStrings("Baz", list.value.items[3].title);
+ try testing.expectEqualStrings("Raspberry Pie", list.value.items[3].description);
+
try list.parseCLI(alloc, "");
try testing.expectEqual(@as(usize, 0), list.value.items.len);
}
@@ -6960,8 +7279,8 @@ pub const FreetypeLoadFlags = packed struct {
// for Freetype itself. Ghostty hasn't made any opinionated changes
// to these defaults.
hinting: bool = true,
- @"force-autohint": bool = true,
- monochrome: bool = true,
+ @"force-autohint": bool = false,
+ monochrome: bool = false,
autohint: bool = true,
};
@@ -8042,3 +8361,71 @@ test "theme specifying light/dark sets theme usage in conditional state" {
try testing.expect(cfg._conditional_set.contains(.theme));
}
}
+
+test "compatibility: removed cursor-invert-fg-bg" {
+ const testing = std.testing;
+ const alloc = testing.allocator;
+
+ {
+ var cfg = try Config.default(alloc);
+ defer cfg.deinit();
+ var it: TestIterator = .{ .data = &.{
+ "--cursor-invert-fg-bg",
+ } };
+ try cfg.loadIter(alloc, &it);
+ try cfg.finalize();
+
+ try testing.expectEqual(
+ TerminalColor.@"cell-foreground",
+ cfg.@"cursor-color",
+ );
+ try testing.expectEqual(
+ TerminalColor.@"cell-background",
+ cfg.@"cursor-text",
+ );
+ }
+}
+
+test "compatibility: removed selection-invert-fg-bg" {
+ const testing = std.testing;
+ const alloc = testing.allocator;
+
+ {
+ var cfg = try Config.default(alloc);
+ defer cfg.deinit();
+ var it: TestIterator = .{ .data = &.{
+ "--selection-invert-fg-bg",
+ } };
+ try cfg.loadIter(alloc, &it);
+ try cfg.finalize();
+
+ try testing.expectEqual(
+ TerminalColor.@"cell-background",
+ cfg.@"selection-foreground",
+ );
+ try testing.expectEqual(
+ TerminalColor.@"cell-foreground",
+ cfg.@"selection-background",
+ );
+ }
+}
+
+test "compatibility: removed bold-is-bright" {
+ const testing = std.testing;
+ const alloc = testing.allocator;
+
+ {
+ var cfg = try Config.default(alloc);
+ defer cfg.deinit();
+ var it: TestIterator = .{ .data = &.{
+ "--bold-is-bright",
+ } };
+ try cfg.loadIter(alloc, &it);
+ try cfg.finalize();
+
+ try testing.expectEqual(
+ BoldColor.bright,
+ cfg.@"bold-color",
+ );
+ }
+}
diff --git a/src/config/edit.zig b/src/config/edit.zig
index ae4394942..38dc98169 100644
--- a/src/config/edit.zig
+++ b/src/config/edit.zig
@@ -5,18 +5,19 @@ const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const internal_os = @import("../os/main.zig");
-/// Open the configuration in the OS default editor according to the default
-/// paths the main config file could be in.
+/// The path to the configuration that should be opened for editing.
///
-/// On Linux, this will open the file at the XDG config path. This is the
+/// On Linux, this will use the file at the XDG config path. This is the
/// only valid path for Linux so we don't need to check for other paths.
///
/// On macOS, both XDG and AppSupport paths are valid. Because Ghostty
-/// prioritizes AppSupport over XDG, we will open AppSupport if it exists,
+/// prioritizes AppSupport over XDG, we will use AppSupport if it exists,
/// followed by XDG if it exists, and finally AppSupport if neither exist.
/// For the existence check, we also prefer non-empty files over empty
/// files.
-pub fn open(alloc_gpa: Allocator) !void {
+///
+/// The returned value is allocated using the provided allocator.
+pub fn openPath(alloc_gpa: Allocator) ![:0]const u8 {
// Use an arena to make memory management easier in here.
var arena = ArenaAllocator.init(alloc_gpa);
defer arena.deinit();
@@ -41,7 +42,7 @@ pub fn open(alloc_gpa: Allocator) !void {
}
};
- try internal_os.open(alloc_gpa, .text, config_path);
+ return try alloc_gpa.dupeZ(u8, config_path);
}
/// Returns the config path to use for open for the current OS.
diff --git a/src/font/Collection.zig b/src/font/Collection.zig
index 8533331bc..eb4349fb0 100644
--- a/src/font/Collection.zig
+++ b/src/font/Collection.zig
@@ -69,10 +69,14 @@ pub fn deinit(self: *Collection, alloc: Allocator) void {
if (self.load_options) |*v| v.deinit(alloc);
}
-pub const AddError = Allocator.Error || error{
- CollectionFull,
- DeferredLoadingUnavailable,
-};
+pub const AddError =
+ Allocator.Error ||
+ AdjustSizeError ||
+ error{
+ CollectionFull,
+ DeferredLoadingUnavailable,
+ SetSizeFailed,
+ };
/// Add a face to the collection for the given style. This face will be added
/// next in priority if others exist already, i.e. it'll be the _last_ to be
@@ -81,10 +85,9 @@ pub const AddError = Allocator.Error || error{
/// If no error is encountered then the collection takes ownership of the face,
/// in which case face will be deallocated when the collection is deallocated.
///
-/// If a loaded face is added to the collection, it should be the same
-/// size as all the other faces in the collection. This function will not
-/// verify or modify the size until the size of the entire collection is
-/// changed.
+/// If a loaded face is added to the collection, its size will be changed to
+/// match the size specified in load_options, adjusted for harmonization with
+/// the primary face.
pub fn add(
self: *Collection,
alloc: Allocator,
@@ -103,9 +106,107 @@ pub fn add(
return error.DeferredLoadingUnavailable;
try list.append(alloc, face);
+
+ var owned: *Entry = list.at(idx);
+
+ // If the face is already loaded, apply font size adjustment
+ // now, otherwise we'll apply it whenever we do load it.
+ if (owned.getLoaded()) |loaded| {
+ if (try self.adjustedSize(loaded)) |opts| {
+ loaded.setSize(opts.faceOptions()) catch return error.SetSizeFailed;
+ }
+ }
+
return .{ .style = style, .idx = @intCast(idx) };
}
+pub const AdjustSizeError = font.Face.GetMetricsError;
+
+// Calculate a size for the provided face that will match it with the primary
+// font, metrically, to improve consistency with fallback fonts. Right now we
+// match the font based on the ex height, or the ideograph width if the font
+// has ideographs in it.
+//
+// This returns null if load options is null or if self.load_options is null.
+//
+// This is very much like the `font-size-adjust` CSS property in how it works.
+// ref: https://developer.mozilla.org/en-US/docs/Web/CSS/font-size-adjust
+//
+// TODO: In the future, provide config options that allow the user to select
+// which metric should be matched for fallback fonts, instead of hard
+// coding it as ex height.
+pub fn adjustedSize(
+ self: *Collection,
+ face: *Face,
+) AdjustSizeError!?LoadOptions {
+ const load_options = self.load_options orelse return null;
+
+ // We silently do nothing if we can't get the primary
+ // face, because this might be the primary face itself.
+ const primary_face = self.getFace(.{ .idx = 0 }) catch return null;
+
+ // We do nothing if the primary face and this face are the same.
+ if (@intFromPtr(primary_face) == @intFromPtr(face)) return null;
+
+ const primary_metrics = try primary_face.getMetrics();
+ const face_metrics = try face.getMetrics();
+
+ // We use the ex height to match our font sizes, so that the height of
+ // lower-case letters matches between all fonts in the fallback chain.
+ //
+ // We estimate ex height as 0.75 * cap height if it's not specifically
+ // provided, and we estimate cap height as 0.75 * ascent in the same case.
+ //
+ // If the fallback font has an ic_width we prefer that, for normalization
+ // of CJK font sizes when mixed with latin fonts.
+ //
+ // We estimate the ic_width as twice the cell width if it isn't provided.
+ var primary_cap = primary_metrics.cap_height orelse 0.0;
+ if (primary_cap <= 0) primary_cap = primary_metrics.ascent * 0.75;
+
+ var primary_ex = primary_metrics.ex_height orelse 0.0;
+ if (primary_ex <= 0) primary_ex = primary_cap * 0.75;
+
+ var primary_ic = primary_metrics.ic_width orelse 0.0;
+ if (primary_ic <= 0) primary_ic = primary_metrics.cell_width * 2;
+
+ var face_cap = face_metrics.cap_height orelse 0.0;
+ if (face_cap <= 0) face_cap = face_metrics.ascent * 0.75;
+
+ var face_ex = face_metrics.ex_height orelse 0.0;
+ if (face_ex <= 0) face_ex = face_cap * 0.75;
+
+ var face_ic = face_metrics.ic_width orelse 0.0;
+ if (face_ic <= 0) face_ic = face_metrics.cell_width * 2;
+
+ // If the line height of the scaled font would be larger than
+ // the line height of the primary font, we don't want that, so
+ // we take the minimum between matching the ic/ex and the line
+ // height.
+ //
+ // NOTE: We actually allow the line height to be up to 1.2
+ // times the primary line height because empirically
+ // this is usually fine and is better for CJK.
+ //
+ // TODO: We should probably provide a config option that lets
+ // the user pick what metric to use for size adjustment.
+ const scale = @min(
+ 1.2 * primary_metrics.lineHeight() / face_metrics.lineHeight(),
+ if (face_metrics.ic_width != null)
+ primary_ic / face_ic
+ else
+ primary_ex / face_ex,
+ );
+
+ // Make a copy of our load options, set the size to the size of
+ // the provided face, and then multiply that by our scaling factor.
+ var opts = load_options;
+ opts.size = face.size;
+ opts.size.points *= @as(f32, @floatCast(scale));
+
+ return opts;
+}
+
/// Return the Face represented by a given Index. The returned pointer
/// is only valid as long as this collection is not modified.
///
@@ -129,21 +230,38 @@ pub fn getFace(self: *Collection, index: Index) !*Face {
break :item item;
};
- return try self.getFaceFromEntry(item);
+ const face = try self.getFaceFromEntry(
+ item,
+ // We only want to adjust the size if this isn't the primary face.
+ index.style != .regular or index.idx > 0,
+ );
+
+ return face;
}
/// Get the face from an entry.
///
/// This entry must not be an alias.
-fn getFaceFromEntry(self: *Collection, entry: *Entry) !*Face {
+fn getFaceFromEntry(
+ self: *Collection,
+ entry: *Entry,
+ /// Whether to adjust the font size to match the primary face after loading.
+ adjust: bool,
+) !*Face {
assert(entry.* != .alias);
return switch (entry.*) {
inline .deferred, .fallback_deferred => |*d, tag| deferred: {
const opts = self.load_options orelse
return error.DeferredLoadingUnavailable;
- const face = try d.load(opts.library, opts.faceOptions());
+ var face = try d.load(opts.library, opts.faceOptions());
d.deinit();
+
+ // If we need to adjust the size, do so.
+ if (adjust) if (try self.adjustedSize(&face)) |new_opts| {
+ try face.setSize(new_opts.faceOptions());
+ };
+
entry.* = switch (tag) {
.deferred => .{ .loaded = face },
.fallback_deferred => .{ .fallback_loaded = face },
@@ -247,7 +365,7 @@ pub fn completeStyles(
while (it.next()) |entry| {
// Load our face. If we fail to load it, we just skip it and
// continue on to try the next one.
- const face = self.getFaceFromEntry(entry) catch |err| {
+ const face = self.getFaceFromEntry(entry, false) catch |err| {
log.warn("error loading regular entry={d} err={}", .{
it.index - 1,
err,
@@ -371,7 +489,7 @@ fn syntheticBold(self: *Collection, entry: *Entry) !Face {
const opts = self.load_options orelse return error.DeferredLoadingUnavailable;
// Try to bold it.
- const regular = try self.getFaceFromEntry(entry);
+ const regular = try self.getFaceFromEntry(entry, false);
const face = try regular.syntheticBold(opts.faceOptions());
var buf: [256]u8 = undefined;
@@ -391,7 +509,7 @@ fn syntheticItalic(self: *Collection, entry: *Entry) !Face {
const opts = self.load_options orelse return error.DeferredLoadingUnavailable;
// Try to italicize it.
- const regular = try self.getFaceFromEntry(entry);
+ const regular = try self.getFaceFromEntry(entry, false);
const face = try regular.syntheticItalic(opts.faceOptions());
var buf: [256]u8 = undefined;
@@ -420,9 +538,12 @@ pub fn setSize(self: *Collection, size: DesiredSize) !void {
while (it.next()) |array| {
var entry_it = array.value.iterator(0);
while (entry_it.next()) |entry| switch (entry.*) {
- .loaded, .fallback_loaded => |*f| try f.setSize(
- opts.faceOptions(),
- ),
+ .loaded,
+ .fallback_loaded,
+ => |*f| {
+ const new_opts = try self.adjustedSize(f) orelse opts.*;
+ try f.setSize(new_opts.faceOptions());
+ },
// Deferred aren't loaded so we don't need to set their size.
// The size for when they're loaded is set since `opts` changed.
@@ -549,6 +670,16 @@ pub const Entry = union(enum) {
}
}
+ /// If this face is loaded, or is an alias to a loaded face,
+ /// then this returns the `Face`, otherwise returns null.
+ pub fn getLoaded(self: *Entry) ?*Face {
+ return switch (self.*) {
+ .deferred, .fallback_deferred => null,
+ .loaded, .fallback_loaded => |*face| face,
+ .alias => |v| v.getLoaded(),
+ };
+ }
+
/// True if the entry is deferred.
fn isDeferred(self: Entry) bool {
return switch (self) {
@@ -906,12 +1037,13 @@ test "metrics" {
var c = init();
defer c.deinit(alloc);
- c.load_options = .{ .library = lib };
+ const size: DesiredSize = .{ .points = 12, .xdpi = 96, .ydpi = 96 };
+ c.load_options = .{ .library = lib, .size = size };
_ = try c.add(alloc, .regular, .{ .loaded = try .init(
lib,
testFont,
- .{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } },
+ .{ .size = size },
) });
try c.updateMetrics();
@@ -940,6 +1072,7 @@ test "metrics" {
.overline_thickness = 1,
.box_thickness = 1,
.cursor_height = 17,
+ .icon_height = 11,
}, c.metrics);
// Resize should change metrics
@@ -956,5 +1089,65 @@ test "metrics" {
.overline_thickness = 2,
.box_thickness = 2,
.cursor_height = 34,
+ .icon_height = 23,
}, c.metrics);
}
+
+// TODO: Also test CJK fallback sizing, we don't currently have a CJK test font.
+test "adjusted sizes" {
+ const testing = std.testing;
+ const alloc = testing.allocator;
+ const testFont = font.embedded.inconsolata;
+ const fallback = font.embedded.monaspace_neon;
+
+ var lib = try Library.init(alloc);
+ defer lib.deinit();
+
+ var c = init();
+ defer c.deinit(alloc);
+ const size: DesiredSize = .{ .points = 12, .xdpi = 96, .ydpi = 96 };
+ c.load_options = .{ .library = lib, .size = size };
+
+ // Add our primary face.
+ _ = try c.add(alloc, .regular, .{ .loaded = try .init(
+ lib,
+ testFont,
+ .{ .size = size },
+ ) });
+
+ try c.updateMetrics();
+
+ // Add the fallback face.
+ const fallback_idx = try c.add(alloc, .regular, .{ .loaded = try .init(
+ lib,
+ fallback,
+ .{ .size = size },
+ ) });
+
+ // The ex heights should match.
+ {
+ const primary_metrics = try (try c.getFace(.{ .idx = 0 })).getMetrics();
+ const fallback_metrics = try (try c.getFace(fallback_idx)).getMetrics();
+
+ try std.testing.expectApproxEqAbs(
+ primary_metrics.ex_height.?,
+ fallback_metrics.ex_height.?,
+ // We accept anything within half a pixel.
+ 0.5,
+ );
+ }
+
+ // Resize should keep that relationship.
+ try c.setSize(.{ .points = 37, .xdpi = 96, .ydpi = 96 });
+ {
+ const primary_metrics = try (try c.getFace(.{ .idx = 0 })).getMetrics();
+ const fallback_metrics = try (try c.getFace(fallback_idx)).getMetrics();
+
+ try std.testing.expectApproxEqAbs(
+ primary_metrics.ex_height.?,
+ fallback_metrics.ex_height.?,
+ // We accept anything within half a pixel.
+ 0.5,
+ );
+ }
+}
diff --git a/src/font/Glyph.zig b/src/font/Glyph.zig
index fa29e44fa..f99370271 100644
--- a/src/font/Glyph.zig
+++ b/src/font/Glyph.zig
@@ -17,9 +17,3 @@ offset_y: i32,
/// be normalized to be between 0 and 1 prior to use in shaders.
atlas_x: u32,
atlas_y: u32,
-
-/// horizontal position to increase drawing position for strings
-advance_x: f32,
-
-/// Whether we drew this glyph ourselves with the sprite font.
-sprite: bool = false,
diff --git a/src/font/Metrics.zig b/src/font/Metrics.zig
index bf527a021..89f6a507f 100644
--- a/src/font/Metrics.zig
+++ b/src/font/Metrics.zig
@@ -35,9 +35,8 @@ cursor_thickness: u32 = 1,
/// The height in pixels of the cursor sprite.
cursor_height: u32,
-/// Original cell width in pixels. This is used to keep
-/// glyphs centered if the cell width is adjusted wider.
-original_cell_width: ?u32 = null,
+/// The constraint height for nerd fonts icons.
+icon_height: u32,
/// Minimum acceptable values for some fields to prevent modifiers
/// from being able to, for example, cause 0-thickness underlines.
@@ -50,6 +49,7 @@ const Minimums = struct {
const box_thickness = 1;
const cursor_thickness = 1;
const cursor_height = 1;
+ const icon_height = 1;
};
/// Metrics extracted from a font face, based on
@@ -107,6 +107,19 @@ pub const FaceMetrics = struct {
/// a provided ex height metric or measured from the height of the
/// lowercase x glyph.
ex_height: ?f64 = null,
+
+ /// The width of the character "水" (CJK water ideograph, U+6C34),
+ /// if present. This is used for font size adjustment, to normalize
+ /// the width of CJK fonts mixed with latin fonts.
+ ///
+ /// NOTE: IC = Ideograph Character
+ ic_width: ?f64 = null,
+
+ /// Convenience function for getting the line height
+ /// (ascent - descent + line_gap).
+ pub inline fn lineHeight(self: FaceMetrics) f64 {
+ return self.ascent - self.descent + self.line_gap;
+ }
};
/// Calculate our metrics based on values extracted from a font.
@@ -120,7 +133,7 @@ pub fn calc(face: FaceMetrics) Metrics {
// that the cell is large enough for the provided size, since we cast
// it to an integer later.
const cell_width = @ceil(face.cell_width);
- const cell_height = @ceil(face.ascent - face.descent + face.line_gap);
+ const cell_height = @ceil(face.lineHeight());
// We split our line gap in two parts, and put half of it on the top
// of the cell and the other half on the bottom, so that our text never
@@ -164,6 +177,17 @@ pub fn calc(face: FaceMetrics) Metrics {
(face.strikethrough_position orelse
ex_height * 0.5 + strikethrough_thickness * 0.5));
+ // The calculation for icon height in the nerd fonts patcher
+ // is two thirds cap height to one third line height, but we
+ // use an opinionated default of 1.2 * cap height instead.
+ //
+ // Doing this prevents fonts with very large line heights
+ // from having excessively oversized icons, and allows fonts
+ // with very small line heights to still have roomy icons.
+ //
+ // We do cap it at `cell_height` though for obvious reasons.
+ const icon_height = @min(cell_height, cap_height * 1.2);
+
var result: Metrics = .{
.cell_width = @intFromFloat(cell_width),
.cell_height = @intFromFloat(cell_height),
@@ -176,6 +200,7 @@ pub fn calc(face: FaceMetrics) Metrics {
.overline_thickness = @intFromFloat(underline_thickness),
.box_thickness = @intFromFloat(underline_thickness),
.cursor_height = @intFromFloat(cell_height),
+ .icon_height = @intFromFloat(icon_height),
};
// Ensure all metrics are within their allowable range.
@@ -201,11 +226,6 @@ pub fn apply(self: *Metrics, mods: ModifierSet) void {
const new = @max(entry.value_ptr.apply(original), 1);
if (new == original) continue;
- // Preserve the original cell width if not set.
- if (self.original_cell_width == null) {
- self.original_cell_width = self.cell_width;
- }
-
// Set the new value
@field(self, @tagName(tag)) = new;
@@ -419,6 +439,7 @@ fn init() Metrics {
.overline_thickness = 0,
.box_thickness = 0,
.cursor_height = 0,
+ .icon_height = 0,
};
}
diff --git a/src/font/SharedGrid.zig b/src/font/SharedGrid.zig
index dcfa0a551..3ccac7fa1 100644
--- a/src/font/SharedGrid.zig
+++ b/src/font/SharedGrid.zig
@@ -265,13 +265,35 @@ pub fn renderGlyph(
.emoji => &self.atlas_color,
};
+ var render_opts = opts;
+
+ // Always use these constraints for emoji.
+ if (p == .emoji) {
+ render_opts.constraint = .{
+ // Make the emoji as wide as possible, scaling proportionally,
+ // but then scale it down as necessary if its new size exceeds
+ // the cell height.
+ .size_horizontal = .cover,
+ .size_vertical = .fit,
+
+ // Center the emoji in its cells.
+ .align_horizontal = .center,
+ .align_vertical = .center,
+
+ // Add a small bit of padding so the emoji
+ // doesn't quite touch the edges of the cells.
+ .pad_left = 0.025,
+ .pad_right = 0.025,
+ };
+ }
+
// Render into the atlas
const glyph = self.resolver.renderGlyph(
alloc,
atlas,
index,
glyph_index,
- opts,
+ render_opts,
) catch |err| switch (err) {
// If the atlas is full, we resize it
error.AtlasFull => blk: {
@@ -281,7 +303,7 @@ pub fn renderGlyph(
atlas,
index,
glyph_index,
- opts,
+ render_opts,
);
},
@@ -325,7 +347,8 @@ const GlyphKey = struct {
cell_width: u2,
thicken: bool,
thicken_strength: u8,
- _padding: u5 = 0,
+ constraint_width: u2,
+ _padding: u3 = 0,
},
inline fn from(key: GlyphKey) Packed {
@@ -336,6 +359,7 @@ const GlyphKey = struct {
.cell_width = key.opts.cell_width orelse 0,
.thicken = key.opts.thicken,
.thicken_strength = key.opts.thicken_strength,
+ .constraint_width = key.opts.constraint_width,
},
};
}
diff --git a/src/font/SharedGridSet.zig b/src/font/SharedGridSet.zig
index e3e61907b..14a8babad 100644
--- a/src/font/SharedGridSet.zig
+++ b/src/font/SharedGridSet.zig
@@ -260,34 +260,51 @@ fn collection(
.regular,
.{ .fallback_loaded = try .init(
self.font_lib,
- font.embedded.regular,
+ font.embedded.variable,
load_options.faceOptions(),
) },
);
- _ = try c.add(
+ try (try c.getFace(try c.add(
self.alloc,
.bold,
.{ .fallback_loaded = try .init(
self.font_lib,
- font.embedded.bold,
+ font.embedded.variable,
load_options.faceOptions(),
) },
+ ))).setVariations(
+ &.{.{ .id = .init("wght"), .value = 700 }},
+ load_options.faceOptions(),
);
_ = try c.add(
self.alloc,
.italic,
.{ .fallback_loaded = try .init(
self.font_lib,
- font.embedded.italic,
+ font.embedded.variable_italic,
load_options.faceOptions(),
) },
);
- _ = try c.add(
+ try (try c.getFace(try c.add(
self.alloc,
.bold_italic,
.{ .fallback_loaded = try .init(
self.font_lib,
- font.embedded.bold_italic,
+ font.embedded.variable_italic,
+ load_options.faceOptions(),
+ ) },
+ ))).setVariations(
+ &.{.{ .id = .init("wght"), .value = 700 }},
+ load_options.faceOptions(),
+ );
+
+ // Nerd-font symbols fallback.
+ _ = try c.add(
+ self.alloc,
+ .regular,
+ .{ .fallback_loaded = try Face.init(
+ self.font_lib,
+ font.embedded.symbols_nerd_font,
load_options.faceOptions(),
) },
);
@@ -432,6 +449,7 @@ pub const DerivedConfig = struct {
@"adjust-cursor-thickness": ?Metrics.Modifier,
@"adjust-cursor-height": ?Metrics.Modifier,
@"adjust-box-thickness": ?Metrics.Modifier,
+ @"adjust-icon-height": ?Metrics.Modifier,
@"freetype-load-flags": font.face.FreetypeLoadFlags,
/// Initialize a DerivedConfig. The config should be either a
@@ -471,6 +489,7 @@ pub const DerivedConfig = struct {
.@"adjust-cursor-thickness" = config.@"adjust-cursor-thickness",
.@"adjust-cursor-height" = config.@"adjust-cursor-height",
.@"adjust-box-thickness" = config.@"adjust-box-thickness",
+ .@"adjust-icon-height" = config.@"adjust-icon-height",
.@"freetype-load-flags" = if (font.face.FreetypeLoadFlags != void) config.@"freetype-load-flags" else {},
// This must be last so the arena contains all our allocations
@@ -617,6 +636,7 @@ pub const Key = struct {
if (config.@"adjust-cursor-thickness") |m| try set.put(alloc, .cursor_thickness, m);
if (config.@"adjust-cursor-height") |m| try set.put(alloc, .cursor_height, m);
if (config.@"adjust-box-thickness") |m| try set.put(alloc, .box_thickness, m);
+ if (config.@"adjust-icon-height") |m| try set.put(alloc, .icon_height, m);
break :set set;
};
diff --git a/src/font/discovery.zig b/src/font/discovery.zig
index 9284f9486..6f51379b4 100644
--- a/src/font/discovery.zig
+++ b/src/font/discovery.zig
@@ -831,6 +831,9 @@ pub const CoreText = struct {
i: usize,
pub fn deinit(self: *DiscoverIterator) void {
+ for (self.list) |desc| {
+ desc.release();
+ }
self.alloc.free(self.list);
self.* = undefined;
}
diff --git a/src/font/embedded.zig b/src/font/embedded.zig
index 31b07ff31..1e496075d 100644
--- a/src/font/embedded.zig
+++ b/src/font/embedded.zig
@@ -6,19 +6,29 @@
//! redistribution and include their license as necessary.
/// Default fonts that we prefer for Ghostty.
-pub const regular = @embedFile("res/JetBrainsMonoNerdFont-Regular.ttf");
-pub const bold = @embedFile("res/JetBrainsMonoNerdFont-Bold.ttf");
-pub const italic = @embedFile("res/JetBrainsMonoNerdFont-Italic.ttf");
-pub const bold_italic = @embedFile("res/JetBrainsMonoNerdFont-BoldItalic.ttf");
+pub const variable = @embedFile("jetbrains_mono_variable");
+pub const variable_italic = @embedFile("jetbrains_mono_variable_italic");
+
+/// Symbols-only nerd font.
+pub const symbols_nerd_font = @embedFile("nerd_fonts_symbols_only");
+
+/// Static jetbrains mono faces, currently unused.
+pub const regular = @embedFile("jetbrains_mono_regular");
+pub const bold = @embedFile("jetbrains_mono_bold");
+pub const italic = @embedFile("jetbrains_mono_italic");
+pub const bold_italic = @embedFile("jetbrains_mono_bold_italic");
+
+/// Emoji fonts
pub const emoji = @embedFile("res/NotoColorEmoji.ttf");
pub const emoji_text = @embedFile("res/NotoEmoji-Regular.ttf");
+// Fonts below are ONLY used for testing.
+
/// Fonts with general properties
pub const arabic = @embedFile("res/KawkabMono-Regular.ttf");
-pub const variable = @embedFile("res/Lilex-VF.ttf");
-/// Font with nerd fonts embedded.
-pub const nerd_font = @embedFile("res/JetBrainsMonoNerdFont-Regular.ttf");
+/// A font for testing which is patched with nerd font symbols.
+pub const test_nerd_font = @embedFile("res/JetBrainsMonoNerdFont-Regular.ttf");
/// Specific font families below:
pub const code_new_roman = @embedFile("res/CodeNewRoman-Regular.otf");
diff --git a/src/font/face.zig b/src/font/face.zig
index 6355578db..fc5118c3d 100644
--- a/src/font/face.zig
+++ b/src/font/face.zig
@@ -94,6 +94,17 @@ pub const RenderOptions = struct {
/// optionally by the rasterizer to better layout the glyph.
cell_width: ?u2 = null,
+ /// Constraint and alignment properties for the glyph. The rasterizer
+ /// should call the `constrain` function on this with the original size
+ /// and bearings of the glyph to get remapped values that the glyph
+ /// should be scaled/moved to.
+ constraint: Constraint = .none,
+
+ /// The number of cells, horizontally that the glyph is free to take up
+ /// when resized and aligned by `constraint`. This is usually 1, but if
+ /// there's whitespace to the right of the cell then it can be 2.
+ constraint_width: u2 = 1,
+
/// Thicken the glyph. This draws the glyph with a thicker stroke width.
/// This is purely an aesthetic setting.
///
@@ -108,6 +119,280 @@ pub const RenderOptions = struct {
///
/// CoreText only.
thicken_strength: u8 = 255,
+
+ /// See the `constraint` field.
+ pub const Constraint = struct {
+ /// Don't constrain the glyph in any way.
+ pub const none: Constraint = .{};
+
+ /// Vertical sizing rule.
+ size_vertical: Size = .none,
+ /// Horizontal sizing rule.
+ size_horizontal: Size = .none,
+
+ /// Vertical alignment rule.
+ align_vertical: Align = .none,
+ /// Horizontal alignment rule.
+ align_horizontal: Align = .none,
+
+ /// Top padding when resizing.
+ pad_top: f64 = 0.0,
+ /// Left padding when resizing.
+ pad_left: f64 = 0.0,
+ /// Right padding when resizing.
+ pad_right: f64 = 0.0,
+ /// Bottom padding when resizing.
+ pad_bottom: f64 = 0.0,
+
+ // This acts as a multiple of the provided width when applying
+ // constraints, so if this is 1.6 for example, then a width of
+ // 10 would be treated as though it were 16.
+ group_width: f64 = 1.0,
+ // This acts as a multiple of the provided height when applying
+ // constraints, so if this is 1.6 for example, then a height of
+ // 10 would be treated as though it were 16.
+ group_height: f64 = 1.0,
+ // This is an x offset for the actual width within the group width.
+ // If this is 0.5 then the glyph will be offset so that its left
+ // edge sits at the halfway point of the group width.
+ group_x: f64 = 0.0,
+ // This is a y offset for the actual height within the group height.
+ // If this is 0.5 then the glyph will be offset so that its bottom
+ // edge sits at the halfway point of the group height.
+ group_y: f64 = 0.0,
+
+ /// Maximum ratio of width to height when resizing.
+ max_xy_ratio: ?f64 = null,
+
+ /// Maximum number of cells horizontally to use.
+ max_constraint_width: u2 = 2,
+
+ /// What to use as the height metric when constraining the glyph.
+ height: Height = .cell,
+
+ pub const Size = enum {
+ /// Don't change the size of this glyph.
+ none,
+ /// Move the glyph and optionally scale it down
+ /// proportionally to fit within the given axis.
+ fit,
+ /// Move and resize the glyph proportionally to
+ /// cover the given axis.
+ cover,
+ /// Same as `cover` but not proportional.
+ stretch,
+ };
+
+ pub const Align = enum {
+ /// Don't move the glyph on this axis.
+ none,
+ /// Move the glyph so that its leading (bottom/left)
+ /// edge aligns with the leading edge of the axis.
+ start,
+ /// Move the glyph so that its trailing (top/right)
+ /// edge aligns with the trailing edge of the axis.
+ end,
+ /// Move the glyph so that it is centered on this axis.
+ center,
+ };
+
+ pub const Height = enum {
+ /// Use the full height of the cell for constraining this glyph.
+ cell,
+ /// Use the "icon height" from the grid metrics as the height.
+ icon,
+ };
+
+ /// The size and position of a glyph.
+ pub const GlyphSize = struct {
+ width: f64,
+ height: f64,
+ x: f64,
+ y: f64,
+ };
+
+ /// Apply this constraint to the provided glyph
+ /// size, given the available width and height.
+ pub fn constrain(
+ self: Constraint,
+ glyph: GlyphSize,
+ metrics: Metrics,
+ /// Number of cells horizontally available for this glyph.
+ constraint_width: u2,
+ ) GlyphSize {
+ var g = glyph;
+
+ var available_width: f64 = @floatFromInt(
+ metrics.cell_width * @min(
+ self.max_constraint_width,
+ constraint_width,
+ ),
+ );
+ const available_height: f64 = @floatFromInt(switch (self.height) {
+ .cell => metrics.cell_height,
+ .icon => metrics.icon_height,
+ });
+
+ // We make the opinionated choice here to reduce the width
+ // of icon-height symbols by the same amount horizontally,
+ // since otherwise wide aspect ratio icons like folders end
+ // up far too wide.
+ //
+ // But we *only* do this if the constraint width is 2, since
+ // otherwise it would make them way too small when sized for
+ // a single cell.
+ const is_icon_width = self.height == .icon and @min(self.max_constraint_width, constraint_width) > 1;
+ const orig_avail_width = available_width;
+ if (is_icon_width) {
+ const cell_height: f64 = @floatFromInt(metrics.cell_height);
+ const ratio = available_height / cell_height;
+ available_width *= ratio;
+ }
+
+ const w = available_width -
+ self.pad_left * available_width -
+ self.pad_right * available_width;
+ const h = available_height -
+ self.pad_top * available_height -
+ self.pad_bottom * available_height;
+
+ // Subtract padding from the bearings so that our
+ // alignment and sizing code works correctly. We
+ // re-add before returning.
+ g.x -= self.pad_left * available_width;
+ g.y -= self.pad_bottom * available_height;
+
+ // Multiply by group width and height for better sizing.
+ g.width *= self.group_width;
+ g.height *= self.group_height;
+
+ switch (self.size_horizontal) {
+ .none => {},
+ .fit => if (g.width > w) {
+ const orig_height = g.height;
+ // Adjust our height and width to proportionally
+ // scale them to fit the glyph to the cell width.
+ g.height *= w / g.width;
+ g.width = w;
+ // Set our x to 0 since anything else would mean
+ // the glyph extends outside of the cell width.
+ g.x = 0;
+ // Compensate our y to keep things vertically
+ // centered as they're scaled down.
+ g.y += (orig_height - g.height) / 2;
+ } else if (g.width + g.x > w) {
+ // If the width of the glyph can fit in the cell but
+ // is currently outside due to the left bearing, then
+ // we reduce the left bearing just enough to fit it
+ // back in the cell.
+ g.x = w - g.width;
+ } else if (g.x < 0) {
+ g.x = 0;
+ },
+ .cover => {
+ const orig_height = g.height;
+
+ g.height *= w / g.width;
+ g.width = w;
+
+ g.x = 0;
+
+ g.y += (orig_height - g.height) / 2;
+ },
+ .stretch => {
+ g.width = w;
+ g.x = 0;
+ },
+ }
+
+ switch (self.size_vertical) {
+ .none => {},
+ .fit => if (g.height > h) {
+ const orig_width = g.width;
+ // Adjust our height and width to proportionally
+ // scale them to fit the glyph to the cell height.
+ g.width *= h / g.height;
+ g.height = h;
+ // Set our y to 0 since anything else would mean
+ // the glyph extends outside of the cell height.
+ g.y = 0;
+ // Compensate our x to keep things horizontally
+ // centered as they're scaled down.
+ g.x += (orig_width - g.width) / 2;
+ } else if (g.height + g.y > h) {
+ // If the height of the glyph can fit in the cell but
+ // is currently outside due to the bottom bearing, then
+ // we reduce the bottom bearing just enough to fit it
+ // back in the cell.
+ g.y = h - g.height;
+ } else if (g.y < 0) {
+ g.y = 0;
+ },
+ .cover => {
+ const orig_width = g.width;
+
+ g.width *= h / g.height;
+ g.height = h;
+
+ g.y = 0;
+
+ g.x += (orig_width - g.width) / 2;
+ },
+ .stretch => {
+ g.height = h;
+ g.y = 0;
+ },
+ }
+
+ // Add group-relative position
+ g.x += self.group_x * g.width;
+ g.y += self.group_y * g.height;
+
+ // Divide group width and height back out before we align.
+ g.width /= self.group_width;
+ g.height /= self.group_height;
+
+ if (self.max_xy_ratio) |ratio| if (g.width > g.height * ratio) {
+ const orig_width = g.width;
+ g.width = g.height * ratio;
+ g.x += (orig_width - g.width) / 2;
+ };
+
+ switch (self.align_horizontal) {
+ .none => {},
+ .start => g.x = 0,
+ .end => g.x = w - g.width,
+ .center => g.x = (w - g.width) / 2,
+ }
+
+ switch (self.align_vertical) {
+ .none => {},
+ .start => g.y = 0,
+ .end => g.y = h - g.height,
+ .center => g.y = (h - g.height) / 2,
+ }
+
+ // Add offset for icon width restriction, to keep it centered.
+ if (is_icon_width) {
+ g.x += (orig_avail_width - available_width) / 2;
+ }
+
+ // Re-add our padding before returning.
+ g.x += self.pad_left * available_width;
+ g.y += self.pad_bottom * available_height;
+
+ // If the available height is less than the cell height, we
+ // add half of the difference to center it in the full height.
+ //
+ // If necessary, in the future, we can adjust this to account
+ // for alignment, but that isn't necessary with any of the nf
+ // icons afaict.
+ const cell_height: f64 = @floatFromInt(metrics.cell_height);
+ g.y += (cell_height - available_height) / 2;
+
+ return g;
+ }
+ };
};
test {
diff --git a/src/font/face/coretext.zig b/src/font/face/coretext.zig
index 06bba661f..e2d60905d 100644
--- a/src/font/face/coretext.zig
+++ b/src/font/face/coretext.zig
@@ -31,6 +31,9 @@ pub const Face = struct {
/// tables).
color: ?ColorState = null,
+ /// The current size this font is set to.
+ size: font.face.DesiredSize,
+
/// True if our build is using Harfbuzz. If we're not, we can avoid
/// some Harfbuzz-specific code paths.
const harfbuzz_shaper = font.options.backend.hasHarfbuzz();
@@ -106,6 +109,7 @@ pub const Face = struct {
.font = ct_font,
.hb_font = hb_font,
.color = color,
+ .size = opts.size,
};
result.quirks_disable_default_font_features = quirks.disableDefaultFontFeatures(&result);
@@ -291,22 +295,29 @@ pub const Face = struct {
// in the bottom left and +Y pointing up.
var rect = self.font.getBoundingRectsForGlyphs(.horizontal, &glyphs, null);
+ // Determine whether this is a color glyph.
+ const is_color = self.isColorGlyph(glyph_index);
+ // And whether it's (probably) a bitmap (sbix).
+ const sbix = is_color and self.color != null and self.color.?.sbix;
+
// If we're rendering a synthetic bold then we will gain 50% of
// the line width on every edge, which means we should increase
// our width and height by the line width and subtract half from
// our origin points.
- if (self.synthetic_bold) |line_width| {
+ //
+ // We don't add extra size if it's a sbix color font though,
+ // since bitmaps aren't affected by synthetic bold.
+ if (!sbix) if (self.synthetic_bold) |line_width| {
rect.size.width += line_width;
rect.size.height += line_width;
rect.origin.x -= line_width / 2;
rect.origin.y -= line_width / 2;
- }
+ };
// We make an assumption that font smoothing ("thicken")
// adds no more than 1 extra pixel to any edge. We don't
// add extra size if it's a sbix color font though, since
// bitmaps aren't affected by smoothing.
- const sbix = self.color != null and self.color.?.sbix;
if (opts.thicken and !sbix) {
rect.size.width += 2.0;
rect.size.height += 2.0;
@@ -314,29 +325,77 @@ pub const Face = struct {
rect.origin.y -= 1.0;
}
- // We compute the minimum and maximum x and y values.
- // We round our min points down and max points up.
- const x0: i32, const x1: i32, const y0: i32, const y1: i32 = .{
- @intFromFloat(@floor(rect.origin.x)),
- @intFromFloat(@ceil(rect.origin.x) + @ceil(rect.size.width)),
- @intFromFloat(@floor(rect.origin.y)),
- @intFromFloat(@ceil(rect.origin.y) + @ceil(rect.size.height)),
- };
+ // If our rect is smaller than a quarter pixel in either axis
+ // then it has no outlines or they're too small to render.
+ //
+ // In this case we just return 0-sized glyph struct.
+ if (rect.size.width < 0.25 or rect.size.height < 0.25)
+ return font.Glyph{
+ .width = 0,
+ .height = 0,
+ .offset_x = 0,
+ .offset_y = 0,
+ .atlas_x = 0,
+ .atlas_y = 0,
+ };
- // This bitmap is blank. I've seen it happen in a font, I don't know why.
- // If it is empty, we just return a valid glyph struct that does nothing.
- if (x1 <= x0 or y1 <= y0) return font.Glyph{
- .width = 0,
- .height = 0,
- .offset_x = 0,
- .offset_y = 0,
- .atlas_x = 0,
- .atlas_y = 0,
- .advance_x = 0,
- };
+ const metrics = opts.grid_metrics;
+ const cell_width: f64 = @floatFromInt(metrics.cell_width);
+ // const cell_height: f64 = @floatFromInt(metrics.cell_height);
- const width: u32 = @intCast(x1 - x0);
- const height: u32 = @intCast(y1 - y0);
+ const glyph_size = opts.constraint.constrain(
+ .{
+ .width = rect.size.width,
+ .height = rect.size.height,
+ .x = rect.origin.x,
+ .y = rect.origin.y + @as(f64, @floatFromInt(metrics.cell_baseline)),
+ },
+ metrics,
+ opts.constraint_width,
+ );
+
+ // We manually quantize the position and size of the glyph to whole
+ // pixel boundaries. Since macOS doesn't do font hinting this helps
+ // a lot for legibility at small sizes on low dpi displays.
+ //
+ // Well, okay, so, it seems like macOS does have a rudimentary auto-
+ // hinter of sorts, except they call it "subpixel quantization"[^1].
+ //
+ // Why not just use that? Because it's unpredictable and would force
+ // us to have an extra pixel of padding in the atlas for most glyphs
+ // that don't need it, since it's hard to know whether a given glyph
+ // will have its bottom or left edge snapped out an extra pixel.
+ //
+ // Also, this empirically just looks a whole lot better than theirs.
+ // Admittedly this is a very specific use case, we're rendering for
+ // a monospace grid and don't really have to worry about sub-pixel
+ // positioning; I'm sure Apple's technique is better for cases with
+ // proportional text.
+ //
+ // An effort was made to more or less match Apple's quantization in
+ // terms of resulting whole-pixel glyph sizes. Oddly it looks like
+ // Apple is still horizontally quantizing to thirds of a pixel, as
+ // if they're doing subpixel rendering for a horizontally striped
+ // LCD, even though they haven't done subpixel rendering for years.
+ // We don't match them on that, it tends to just make it blurrier.
+ //
+ // [^1]: Well I'm 80% sure it's hinting since it seems to account for
+ // features inside of the glyph like crossbars, not just the bounding
+ // box like we do. The documentation is... sparse. Ref:
+ // https://developer.apple.com/documentation/coregraphics/cgcontext/setshouldsubpixelquantizefonts(_:)?language=objc
+ //
+ // TODO: Maybe gate this so it only applies at small font sizes,
+ // or else offer a user config option that can disable it.
+ const x = @round(glyph_size.x);
+ const y = @round(glyph_size.y);
+ // We subtract a third here so that we behave (somewhat) like the weird
+ // one third pixel quantization that Apple does. This is basically just
+ // a fudge factor though.
+ const width = @max(1.0, @ceil(glyph_size.width + glyph_size.x - x - 1.0 / 3.0));
+ const height = @max(1.0, @ceil(glyph_size.height + glyph_size.y - y));
+
+ const px_width: u32 = @intFromFloat(@ceil(width));
+ const px_height: u32 = @intFromFloat(@ceil(height));
// Settings that are specific to if we are rendering text or emoji.
const color: struct {
@@ -344,7 +403,7 @@ pub const Face = struct {
depth: u32,
space: *macos.graphics.ColorSpace,
context_opts: c_uint,
- } = if (!self.isColorGlyph(glyph_index)) .{
+ } = if (!is_color) .{
.color = false,
.depth = 1,
.space = try macos.graphics.ColorSpace.createNamed(.linearGray),
@@ -371,17 +430,17 @@ pub const Face = struct {
// usually stabilizes pretty quickly and is very infrequent so I think
// the allocation overhead is acceptable compared to the cost of
// caching it forever or having to deal with a cache lifetime.
- const buf = try alloc.alloc(u8, width * height * color.depth);
+ const buf = try alloc.alloc(u8, px_width * px_height * color.depth);
defer alloc.free(buf);
@memset(buf, 0);
const context = macos.graphics.BitmapContext.context;
const ctx = try macos.graphics.BitmapContext.create(
buf,
- width,
- height,
+ px_width,
+ px_height,
8,
- width * color.depth,
+ px_width * color.depth,
color.space,
color.context_opts,
);
@@ -390,23 +449,34 @@ pub const Face = struct {
// Perform an initial fill. This ensures that we don't have any
// uninitialized pixels in the bitmap.
if (color.color)
- context.setRGBFillColor(ctx, 1, 1, 1, 0)
+ context.setRGBFillColor(ctx, 0, 0, 0, 0)
else
- context.setGrayFillColor(ctx, 1, 0);
+ context.setGrayFillColor(ctx, 0, 0);
context.fillRect(ctx, .{
.origin = .{ .x = 0, .y = 0 },
.size = .{
- .width = @floatFromInt(width),
- .height = @floatFromInt(height),
+ .width = @floatFromInt(px_width),
+ .height = @floatFromInt(px_height),
},
});
+ // "Font smoothing" is what we call "thickening", it's an attempt
+ // to compensate for optical thinning of fonts, but at this point
+ // it's just something that makes the text look closer to system
+ // applications if users want that.
context.setAllowsFontSmoothing(ctx, true);
- context.setShouldSmoothFonts(ctx, opts.thicken); // The amadeus "enthicken"
- context.setAllowsFontSubpixelQuantization(ctx, true);
- context.setShouldSubpixelQuantizeFonts(ctx, true);
+ context.setShouldSmoothFonts(ctx, opts.thicken);
+
+ // Subpixel positioning allows glyphs to be placed at non-integer
+ // coordinates. We need this for our alignment.
context.setAllowsFontSubpixelPositioning(ctx, true);
context.setShouldSubpixelPositionFonts(ctx, true);
+
+ // See comments about quantization earlier in the function.
+ context.setAllowsFontSubpixelQuantization(ctx, false);
+ context.setShouldSubpixelQuantizeFonts(ctx, false);
+
+ // Anti-aliasing is self explanatory.
context.setAllowsAntialiasing(ctx, true);
context.setShouldAntialias(ctx, true);
@@ -427,76 +497,78 @@ pub const Face = struct {
context.setLineWidth(ctx, line_width);
}
+ // Scale the drawing context so that when we draw
+ // our glyph it's stretched to the constrained size.
+ context.scaleCTM(
+ ctx,
+ width / rect.size.width,
+ height / rect.size.height,
+ );
+
// We want to render the glyphs at (0,0), but the glyphs themselves
// are offset by bearings, so we have to undo those bearings in order
// to get them to 0,0.
- self.font.drawGlyphs(&glyphs, &.{
- .{
- .x = @floatFromInt(-x0),
- .y = @floatFromInt(-y0),
- },
- }, ctx);
+ self.font.drawGlyphs(&glyphs, &.{.{
+ .x = -rect.origin.x,
+ .y = -rect.origin.y,
+ }}, ctx);
- const region = region: {
- // We reserve a region that's 1px wider and taller than we need
- // in order to create a 1px separation between adjacent glyphs
- // to prevent interpolation with adjacent glyphs while sampling
- // from the atlas.
- var region = try atlas.reserve(
- alloc,
- width + 1,
- height + 1,
- );
-
- // We adjust the region width and height back down since we
- // don't need the extra pixel, we just needed to reserve it
- // so that it isn't used for other glyphs in the future.
- region.width -= 1;
- region.height -= 1;
- break :region region;
- };
+ // Write our rasterized glyph to the atlas.
+ const region = try atlas.reserve(alloc, px_width, px_height);
atlas.set(region, buf);
- const metrics = opts.grid_metrics;
-
// This should be the distance from the bottom of
// the cell to the top of the glyph's bounding box.
- //
- // The calculation is distance from bottom of cell to
- // baseline plus distance from baseline to top of glyph.
- const offset_y: i32 = @as(i32, @intCast(metrics.cell_baseline)) + y1;
+ const offset_y: i32 = @as(i32, @intFromFloat(@ceil(y + height)));
// This should be the distance from the left of
// the cell to the left of the glyph's bounding box.
const offset_x: i32 = offset_x: {
- var result: i32 = x0;
-
- // If our cell was resized then we adjust our glyph's
- // position relative to the new center. This keeps glyphs
- // centered in the cell whether it was made wider or narrower.
- if (metrics.original_cell_width) |original_width| {
- const before: i32 = @intCast(original_width);
- const after: i32 = @intCast(metrics.cell_width);
- // Increase the offset by half of the difference
- // between the widths to keep things centered.
- result += @divTrunc(after - before, 2);
+ // If the glyph's advance is narrower than the cell width then we
+ // center the advance of the glyph within the cell width. At first
+ // I implemented this to proportionally scale the center position
+ // of the glyph but that messes up glyphs that are meant to align
+ // vertically with others, so this is a compromise.
+ //
+ // This makes it so that when the `adjust-cell-width` config is
+ // used, or when a fallback font with a different advance width
+ // is used, we don't get weirdly aligned glyphs.
+ //
+ // We don't do this if the constraint has a horizontal alignment,
+ // since in that case the position was already calculated with the
+ // new cell width in mind.
+ if (opts.constraint.align_horizontal == .none) {
+ var advances: [glyphs.len]macos.graphics.Size = undefined;
+ _ = self.font.getAdvancesForGlyphs(.horizontal, &glyphs, &advances);
+ const advance = advances[0].width;
+ const new_advance =
+ cell_width * @as(f64, @floatFromInt(opts.cell_width orelse 1));
+ // If the original advance is greater than the cell width then
+ // it's possible that this is a ligature or other glyph that is
+ // intended to overflow the cell to one side or the other, and
+ // adjusting the bearings could mess that up, so we just leave
+ // it alone if that's the case.
+ //
+ // We also don't want to do anything if the advance is zero or
+ // less, since this is used for stuff like combining characters.
+ if (advance > new_advance or advance <= 0.0) {
+ break :offset_x @intFromFloat(@ceil(x));
+ }
+ break :offset_x @intFromFloat(
+ @round(x + (new_advance - advance) / 2),
+ );
+ } else {
+ break :offset_x @intFromFloat(@ceil(x));
}
-
- break :offset_x result;
};
- // Get our advance
- var advances: [glyphs.len]macos.graphics.Size = undefined;
- _ = self.font.getAdvancesForGlyphs(.horizontal, &glyphs, &advances);
-
return .{
- .width = width,
- .height = height,
+ .width = px_width,
+ .height = px_height,
.offset_x = offset_x,
.offset_y = offset_y,
.atlas_x = region.x,
.atlas_y = region.y,
- .advance_x = @floatCast(advances[0].width),
};
}
@@ -728,6 +800,20 @@ pub const Face = struct {
break :cell_width max;
};
+ // Measure "水" (CJK water ideograph, U+6C34) for our ic width.
+ const ic_width: ?f64 = ic_width: {
+ const glyph = self.glyphIndex('水') orelse break :ic_width null;
+
+ var advances: [1]macos.graphics.Size = undefined;
+ _ = ct_font.getAdvancesForGlyphs(
+ .horizontal,
+ &.{@intCast(glyph)},
+ &advances,
+ );
+
+ break :ic_width advances[0].width;
+ };
+
return .{
.cell_width = cell_width,
.ascent = ascent,
@@ -739,6 +825,7 @@ pub const Face = struct {
.strikethrough_thickness = strikethrough_thickness,
.cap_height = cap_height,
.ex_height = ex_height,
+ .ic_width = ic_width,
};
}
diff --git a/src/font/face/freetype.zig b/src/font/face/freetype.zig
index accb891a4..f42868e5c 100644
--- a/src/font/face/freetype.zig
+++ b/src/font/face/freetype.zig
@@ -15,12 +15,13 @@ const Allocator = std.mem.Allocator;
const font = @import("../main.zig");
const Glyph = font.Glyph;
const Library = font.Library;
-const convert = @import("freetype_convert.zig");
const opentype = @import("../opentype.zig");
const fastmem = @import("../../fastmem.zig");
const quirks = @import("../../quirks.zig");
const config = @import("../../config.zig");
+const F26Dot6 = opentype.sfnt.F26Dot6;
+
const log = std.log.scoped(.font_face);
pub const Face = struct {
@@ -58,13 +59,8 @@ pub const Face = struct {
bold: bool = false,
} = .{},
- /// The matrix applied to a regular font to create a synthetic italic.
- const italic_matrix: freetype.c.FT_Matrix = .{
- .xx = 0x10000,
- .xy = 0x044ED, // approx. tan(15)
- .yx = 0,
- .yy = 0x10000,
- };
+ /// The current size this font is set to.
+ size: font.face.DesiredSize,
/// Initialize a new font face with the given source in-memory.
pub fn initFile(
@@ -114,6 +110,7 @@ pub const Face = struct {
.hb_font = hb_font,
.ft_mutex = ft_mutex,
.load_flags = opts.freetype_load_flags,
+ .size = opts.size,
};
result.quirks_disable_default_font_features = quirks.disableDefaultFontFeatures(&result);
@@ -210,6 +207,7 @@ pub const Face = struct {
/// for clearing any glyph caches, font atlas data, etc.
pub fn setSize(self: *Face, opts: font.face.Options) !void {
try setSize_(self.face, opts.size);
+ self.size = opts.size;
}
fn setSize_(face: freetype.Face, size: font.face.DesiredSize) !void {
@@ -330,26 +328,32 @@ pub const Face = struct {
self.ft_mutex.lock();
defer self.ft_mutex.unlock();
- const metrics = opts.grid_metrics;
+ // We enable hinting by default, and disable it if either of the
+ // constraint alignments are not center or none, since this means
+ // that the glyph needs to be aligned flush to the cell edge, and
+ // hinting can mess that up.
+ const do_hinting = self.load_flags.hinting and
+ switch (opts.constraint.align_horizontal) {
+ .start, .end => false,
+ .center, .none => true,
+ } and
+ switch (opts.constraint.align_vertical) {
+ .start, .end => false,
+ .center, .none => true,
+ };
- // If we have synthetic italic, then we apply a transformation matrix.
- // We have to undo this because synthetic italic works by increasing
- // the ref count of the base face.
- if (self.synthetic.italic) self.face.setTransform(&italic_matrix, null);
- defer if (self.synthetic.italic) self.face.setTransform(null, null);
-
- // If our glyph has color, we want to render the color
+ // Load the glyph.
try self.face.loadGlyph(glyph_index, .{
+ // If our glyph has color, we want to render the color
.color = self.face.hasColor(),
- // If we have synthetic bold, we have to set some additional
- // glyph properties before render so we don't render here.
- .render = !self.synthetic.bold,
+ // We don't render, because we'll invoke the render
+ // manually after applying constraints further down.
+ .render = false,
// use options from config
- .no_hinting = !self.load_flags.hinting,
- .force_autohint = !self.load_flags.@"force-autohint",
- .monochrome = !self.load_flags.monochrome,
+ .no_hinting = !do_hinting,
+ .force_autohint = self.load_flags.@"force-autohint",
.no_autohint = !self.load_flags.autohint,
// NO_SVG set to true because we don't currently support rendering
@@ -359,260 +363,328 @@ pub const Face = struct {
});
const glyph = self.face.handle.*.glyph;
- // For synthetic bold, we embolden the glyph and render it.
+ const glyph_width: f64 = f26dot6ToF64(glyph.*.metrics.width);
+ const glyph_height: f64 = f26dot6ToF64(glyph.*.metrics.height);
+
+ // If our glyph is smaller than a quarter pixel in either axis
+ // then it has no outlines or they're too small to render.
+ //
+ // In this case we just return 0-sized glyph struct.
+ if (glyph_width < 0.25 or glyph_height < 0.25)
+ return font.Glyph{
+ .width = 0,
+ .height = 0,
+ .offset_x = 0,
+ .offset_y = 0,
+ .atlas_x = 0,
+ .atlas_y = 0,
+ };
+
+ // For synthetic bold, we embolden the glyph.
if (self.synthetic.bold) {
// We need to scale the embolden amount based on the font size.
// This is a heuristic I found worked well across a variety of
// founts: 1 pixel per 64 units of height.
- const height: f64 = @floatFromInt(self.face.handle.*.size.*.metrics.height);
+ const font_height: f64 = @floatFromInt(self.face.handle.*.size.*.metrics.height);
const ratio: f64 = 64.0 / 2048.0;
- const amount = @ceil(height * ratio);
+ const amount = @ceil(font_height * ratio);
_ = freetype.c.FT_Outline_Embolden(&glyph.*.outline, @intFromFloat(amount));
- try self.face.renderGlyph(.normal);
}
- // This bitmap is blank. I've seen it happen in a font, I don't know why.
- // If it is empty, we just return a valid glyph struct that does nothing.
- const bitmap_ft = glyph.*.bitmap;
- if (bitmap_ft.rows == 0) return .{
- .width = 0,
- .height = 0,
- .offset_x = 0,
- .offset_y = 0,
- .atlas_x = 0,
- .atlas_y = 0,
- .advance_x = 0,
- };
+ // Next we need to apply any constraints.
+ const metrics = opts.grid_metrics;
- // Ensure we know how to work with the font format. And assure that
- // or color depth is as expected on the texture atlas. If format is null
- // it means there is no native color format for our Atlas and we must try
- // conversion.
- const format: ?font.Atlas.Format = switch (bitmap_ft.pixel_mode) {
- freetype.c.FT_PIXEL_MODE_MONO => null,
- freetype.c.FT_PIXEL_MODE_GRAY => .grayscale,
- freetype.c.FT_PIXEL_MODE_BGRA => .bgra,
+ const cell_width: f64 = @floatFromInt(metrics.cell_width);
+ // const cell_height: f64 = @floatFromInt(metrics.cell_height);
+
+ const glyph_x: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingX);
+ const glyph_y: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingY) - glyph_height;
+
+ const glyph_size = opts.constraint.constrain(
+ .{
+ .width = glyph_width,
+ .height = glyph_height,
+ .x = glyph_x,
+ .y = glyph_y + @as(f64, @floatFromInt(metrics.cell_baseline)),
+ },
+ metrics,
+ opts.constraint_width,
+ );
+
+ const width = glyph_size.width;
+ const height = glyph_size.height;
+ // This may need to be adjusted later on.
+ var x = glyph_size.x;
+ const y = glyph_size.y;
+
+ // Now we can render the glyph.
+ var bitmap: freetype.c.FT_Bitmap = undefined;
+ _ = freetype.c.FT_Bitmap_Init(&bitmap);
+ defer _ = freetype.c.FT_Bitmap_Done(self.lib.lib.handle, &bitmap);
+ switch (glyph.*.format) {
+ freetype.c.FT_GLYPH_FORMAT_OUTLINE => {
+ // Manually adjust the glyph outline with this transform.
+ //
+ // This offers better precision than using the freetype transform
+ // matrix, since that has 16.16 coefficients, and also I was having
+ // weird issues that I can only assume where due to freetype doing
+ // some bad caching or something when I did this using the matrix.
+ const scale_x = width / glyph_width;
+ const scale_y = height / glyph_height;
+ const skew: f64 =
+ if (self.synthetic.italic)
+ // We skew by 12 degrees to synthesize italics.
+ @tan(std.math.degreesToRadians(12))
+ else
+ 0.0;
+
+ var bbox_before: freetype.c.FT_BBox = undefined;
+ _ = freetype.c.FT_Outline_Get_BBox(&glyph.*.outline, &bbox_before);
+
+ const outline = &glyph.*.outline;
+ for (outline.points[0..@intCast(outline.n_points)]) |*p| {
+ // Convert to f64 for processing
+ var px = f26dot6ToF64(p.x);
+ var py = f26dot6ToF64(p.y);
+
+ // Scale
+ px *= scale_x;
+ py *= scale_y;
+
+ // Skew
+ px += py * skew;
+
+ // Convert back and store
+ p.x = @as(i32, @bitCast(F26Dot6.from(px)));
+ p.y = @as(i32, @bitCast(F26Dot6.from(py)));
+ }
+
+ var bbox_after: freetype.c.FT_BBox = undefined;
+ _ = freetype.c.FT_Outline_Get_BBox(&glyph.*.outline, &bbox_after);
+
+ // If our bounding box changed, account for the lsb difference.
+ //
+ // This can happen when we skew glyphs that have a bit sticking
+ // out to the left higher up, like the top of the T or the serif
+ // on the lower case l in many monospace fonts.
+ x += f26dot6ToF64(bbox_after.xMin) - f26dot6ToF64(bbox_before.xMin);
+
+ try self.face.renderGlyph(
+ if (self.load_flags.monochrome)
+ .mono
+ else
+ .normal,
+ );
+
+ // Copy the glyph's bitmap, making sure
+ // that it's 8bpp and densely packed.
+ if (freetype.c.FT_Bitmap_Convert(
+ self.lib.lib.handle,
+ &glyph.*.bitmap,
+ &bitmap,
+ 1,
+ ) != 0) {
+ return error.BitmapHandlingError;
+ }
+ },
+
+ freetype.c.FT_GLYPH_FORMAT_BITMAP => {
+ // If our glyph has a non-color bitmap, we need
+ // to convert it to dense 8bpp so that the scale
+ // operation works correctly.
+ switch (glyph.*.bitmap.pixel_mode) {
+ freetype.c.FT_PIXEL_MODE_BGRA,
+ freetype.c.FT_PIXEL_MODE_GRAY,
+ => {},
+ else => {
+ var converted: freetype.c.FT_Bitmap = undefined;
+ freetype.c.FT_Bitmap_Init(&converted);
+ if (freetype.c.FT_Bitmap_Convert(
+ self.lib.lib.handle,
+ &glyph.*.bitmap,
+ &converted,
+ 1,
+ ) != 0) {
+ return error.BitmapHandlingError;
+ }
+ // Free the existing glyph bitmap and
+ // replace it with the converted one.
+ _ = freetype.c.FT_Bitmap_Done(
+ self.lib.lib.handle,
+ &glyph.*.bitmap,
+ );
+ glyph.*.bitmap = converted;
+ },
+ }
+
+ const glyph_bitmap = glyph.*.bitmap;
+
+ // Round our target width and height
+ // as the size for our scaled bitmap.
+ const w: u32 = @intFromFloat(@round(width));
+ const h: u32 = @intFromFloat(@round(height));
+ const pitch = w * atlas.format.depth();
+
+ // Allocate a buffer for our scaled bitmap.
+ //
+ // We'll copy this to the original bitmap once we're
+ // done so we can free it at the end of this scope.
+ const buf = try alloc.alloc(u8, pitch * h);
+ defer alloc.free(buf);
+
+ // Resize
+ if (stb.stbir_resize_uint8(
+ glyph_bitmap.buffer,
+ @intCast(glyph_bitmap.width),
+ @intCast(glyph_bitmap.rows),
+ glyph_bitmap.pitch,
+ buf.ptr,
+ @intCast(w),
+ @intCast(h),
+ @intCast(pitch),
+ atlas.format.depth(),
+ ) == 0) {
+ // This should never fail because this is a
+ // fairly straightforward in-memory operation...
+ return error.GlyphResizeFailed;
+ }
+
+ const scaled_bitmap: freetype.c.FT_Bitmap = .{
+ .buffer = buf.ptr,
+ .width = @intCast(w),
+ .rows = @intCast(h),
+ .pitch = @intCast(pitch),
+ .pixel_mode = glyph_bitmap.pixel_mode,
+ .num_grays = glyph_bitmap.num_grays,
+ };
+
+ // Replace the bitmap's buffer and size info.
+ if (freetype.c.FT_Bitmap_Copy(
+ self.lib.lib.handle,
+ &scaled_bitmap,
+ &bitmap,
+ ) != 0) {
+ return error.BitmapHandlingError;
+ }
+ },
+
+ else => |f| {
+ // Glyph formats are tags, so we can
+ // output a semi-readable error here.
+ log.err(
+ "Can't render glyph with unsupported glyph format \"{s}\"",
+ .{[4]u8{
+ @truncate(f >> 24),
+ @truncate(f >> 16),
+ @truncate(f >> 8),
+ @truncate(f >> 0),
+ }},
+ );
+ return error.UnsupportedGlyphFormat;
+ },
+ }
+
+ // If this is a color glyph but we're trying to render it to the
+ // grayscale atlas, or vice versa, then we throw and error. Maybe
+ // in the future we could convert, but for now it should be fine.
+ switch (bitmap.pixel_mode) {
+ freetype.c.FT_PIXEL_MODE_GRAY => if (atlas.format != .grayscale) {
+ return error.WrongAtlas;
+ },
+ freetype.c.FT_PIXEL_MODE_BGRA => if (atlas.format != .bgra) {
+ return error.WrongAtlas;
+ },
else => {
- log.warn("glyph={} pixel mode={}", .{ glyph_index, bitmap_ft.pixel_mode });
+ log.warn("glyph={} pixel mode={}", .{ glyph_index, bitmap.pixel_mode });
@panic("unsupported pixel mode");
},
- };
-
- // If our atlas format doesn't match, look for conversions if possible.
- const bitmap_converted = if (format == null or atlas.format != format.?) blk: {
- const func = convert.map[bitmap_ft.pixel_mode].get(atlas.format) orelse {
- log.warn("glyph={} pixel mode={}", .{ glyph_index, bitmap_ft.pixel_mode });
- return error.UnsupportedPixelMode;
- };
-
- log.debug("converting from pixel_mode={} to atlas_format={}", .{
- bitmap_ft.pixel_mode,
- atlas.format,
- });
- break :blk try func(alloc, bitmap_ft);
- } else null;
- defer if (bitmap_converted) |bm| {
- const len = @as(usize, @intCast(bm.pitch)) * @as(usize, @intCast(bm.rows));
- alloc.free(bm.buffer[0..len]);
- };
-
- // Now we need to see if we need to resize this bitmap. This can happen
- // in scenarios where we have fixed size glyphs. For example, emoji
- // can be quite large (i.e. 128x128) when we have a cell width of 24!
- // The issue with large bitmaps is they take a huge amount of space in
- // the atlas and force resizes quite frequently. We pay some CPU cost
- // up front to resize the glyph to avoid significant CPU cost to resize
- // and copy the atlas.
- const bitmap_original = bitmap_converted orelse bitmap_ft;
- const bitmap_resized: ?freetype.c.struct_FT_Bitmap_ = resized: {
- const original_width = bitmap_original.width;
- const original_height = bitmap_original.rows;
- var result = bitmap_original;
- // TODO: We are limiting this to only color glyphs, so mainly emoji.
- // We can rework this after a future improvement (promised by Qwerasd)
- // which implements more flexible resizing rules.
- if (atlas.format != .grayscale and opts.cell_width != null) {
- const cell_width = opts.cell_width orelse unreachable;
- // If we have a cell_width, we constrain
- // the glyph to fit within the cell(s).
- result.width = metrics.cell_width * @as(u32, cell_width);
- result.rows = (result.width * original_height) / original_width;
- } else {
- // If we don't have a cell_width, we scale to fill vertically
- result.rows = metrics.cell_height;
- result.width = (metrics.cell_height * original_width) / original_height;
- }
-
- // If we already fit, we don't need to resize
- if (original_height <= result.rows and original_width <= result.width) {
- break :resized null;
- }
-
- result.pitch = @as(c_int, @intCast(result.width)) * atlas.format.depth();
-
- const buf = try alloc.alloc(
- u8,
- @as(usize, @intCast(result.pitch)) * @as(usize, @intCast(result.rows)),
- );
- result.buffer = buf.ptr;
- errdefer alloc.free(buf);
-
- if (stb.stbir_resize_uint8(
- bitmap_original.buffer,
- @intCast(original_width),
- @intCast(original_height),
- bitmap_original.pitch,
- result.buffer,
- @intCast(result.width),
- @intCast(result.rows),
- result.pitch,
- atlas.format.depth(),
- ) == 0) {
- // This should never fail because this is a fairly straightforward
- // in-memory operation...
- return error.GlyphResizeFailed;
- }
-
- break :resized result;
- };
- defer if (bitmap_resized) |bm| {
- const len = @as(usize, @intCast(bm.pitch)) * @as(usize, @intCast(bm.rows));
- alloc.free(bm.buffer[0..len]);
- };
-
- const bitmap = bitmap_resized orelse (bitmap_converted orelse bitmap_ft);
- const tgt_w = bitmap.width;
- const tgt_h = bitmap.rows;
-
- // Must have non-empty bitmap because we return earlier
- // if zero. We assume the rest of this that it is nont-zero so
- // this is important.
- assert(tgt_w > 0 and tgt_h > 0);
-
- // If we resized our bitmap, we need to recalculate some metrics that
- // we use such as the top/left offsets. These need to be scaled by the
- // same ratio as the resize.
- const glyph_metrics = if (bitmap_resized) |bm| metrics: {
- // Our ratio for the resize
- const ratio = ratio: {
- const new: f64 = @floatFromInt(bm.rows);
- const old: f64 = @floatFromInt(bitmap_original.rows);
- break :ratio new / old;
- };
-
- var copy = glyph.*;
- copy.bitmap_top = @as(c_int, @intFromFloat(@round(@as(f64, @floatFromInt(copy.bitmap_top)) * ratio)));
- copy.bitmap_left = @as(c_int, @intFromFloat(@round(@as(f64, @floatFromInt(copy.bitmap_left)) * ratio)));
- break :metrics copy;
- } else glyph.*;
-
- // Allocate our texture atlas region
- const region = region: {
- // We need to add a 1px padding to the font so that we don't
- // get fuzzy issues when blending textures.
- const padding = 1;
-
- // Get the full padded region
- var region = try atlas.reserve(
- alloc,
- tgt_w + (padding * 2), // * 2 because left+right
- tgt_h + (padding * 2), // * 2 because top+bottom
- );
-
- // Modify the region so that we remove the padding so that
- // we write to the non-zero location. The data in an Altlas
- // is always initialized to zero (Atlas.clear) so we don't
- // need to worry about zero-ing that.
- region.x += padding;
- region.y += padding;
- region.width -= padding * 2;
- region.height -= padding * 2;
- break :region region;
- };
-
- // Copy the image into the region.
- assert(region.width > 0 and region.height > 0);
- {
- const depth = atlas.format.depth();
-
- // We can avoid a buffer copy if our atlas width and bitmap
- // width match and the bitmap pitch is just the width (meaning
- // the data is tightly packed).
- const needs_copy = !(tgt_w == bitmap.width and (bitmap.width * depth) == bitmap.pitch);
-
- // If we need to copy the data, we copy it into a temporary buffer.
- const buffer = if (needs_copy) buffer: {
- const temp = try alloc.alloc(u8, tgt_w * tgt_h * depth);
- var dst_ptr = temp;
- var src_ptr = bitmap.buffer;
- var i: usize = 0;
- while (i < bitmap.rows) : (i += 1) {
- fastmem.copy(u8, dst_ptr, src_ptr[0 .. bitmap.width * depth]);
- dst_ptr = dst_ptr[tgt_w * depth ..];
- src_ptr += @as(usize, @intCast(bitmap.pitch));
- }
- break :buffer temp;
- } else bitmap.buffer[0..(tgt_w * tgt_h * depth)];
- defer if (buffer.ptr != bitmap.buffer) alloc.free(buffer);
-
- // Write the glyph information into the atlas
- assert(region.width == tgt_w);
- assert(region.height == tgt_h);
- atlas.set(region, buffer);
}
- const offset_y: c_int = offset_y: {
- // For non-scalable colorized fonts, we assume they are pictographic
- // and just center the glyph. So far this has only applied to emoji
- // fonts. Emoji fonts don't always report a correct ascender/descender
- // (mainly Apple Emoji) so we just center them. Also, since emoji font
- // aren't scalable, cell_baseline is incorrect anyways.
- //
- // NOTE(mitchellh): I don't know if this is right, this doesn't
- // _feel_ right, but it makes all my limited test cases work.
- if (self.face.hasColor() and !self.face.isScalable()) {
- break :offset_y @intCast(tgt_h + (metrics.cell_height -| tgt_h) / 2);
+ const px_width = bitmap.width;
+ const px_height = bitmap.rows;
+ const len: usize = @intCast(
+ @as(c_uint, @intCast(@abs(bitmap.pitch))) * bitmap.rows,
+ );
+
+ // If our bitmap is grayscale, make sure to multiply all pixel
+ // values by the right factor to bring `num_grays` up to 256.
+ //
+ // This is necessary because FT_Bitmap_Convert doesn't do this,
+ // it just sets num_grays to the correct number and uses the
+ // original smaller pixel values.
+ if (bitmap.pixel_mode == freetype.c.FT_PIXEL_MODE_GRAY and
+ bitmap.num_grays < 256)
+ {
+ const factor: u8 = @intCast(255 / (bitmap.num_grays - 1));
+ for (bitmap.buffer[0..len]) |*p| {
+ p.* *= factor;
}
+ bitmap.num_grays = 256;
+ }
- // The Y offset is the offset of the top of our bitmap PLUS our
- // baseline calculation. The baseline calculation is so that everything
- // is properly centered when we render it out into a monospace grid.
- // Note: we add here because our X/Y is actually reversed, adding goes UP.
- break :offset_y glyph_metrics.bitmap_top + @as(c_int, @intCast(metrics.cell_baseline));
- };
+ // Must have non-empty bitmap because we return earlier if zero.
+ // We assume the rest of this that it is non-zero so this is important.
+ assert(px_width > 0 and px_height > 0);
+ // If this doesn't match then something is wrong.
+ assert(px_width * atlas.format.depth() == bitmap.pitch);
+
+ // Allocate our texture atlas region and copy our bitmap in to it.
+ const region = try atlas.reserve(alloc, px_width, px_height);
+ atlas.set(region, bitmap.buffer[0..len]);
+
+ // This should be the distance from the bottom of
+ // the cell to the top of the glyph's bounding box.
+ const offset_y: i32 =
+ @as(i32, @intFromFloat(@floor(y))) +
+ @as(i32, @intCast(px_height));
+
+ // This should be the distance from the left of
+ // the cell to the left of the glyph's bounding box.
const offset_x: i32 = offset_x: {
- var result: i32 = glyph_metrics.bitmap_left;
-
- // If our cell was resized to be wider then we center our
- // glyph in the cell.
- if (metrics.original_cell_width) |original_width| {
- if (original_width < metrics.cell_width) {
- const diff = (metrics.cell_width - original_width) / 2;
- result += @intCast(diff);
+ // If the glyph's advance is narrower than the cell width then we
+ // center the advance of the glyph within the cell width. At first
+ // I implemented this to proportionally scale the center position
+ // of the glyph but that messes up glyphs that are meant to align
+ // vertically with others, so this is a compromise.
+ //
+ // This makes it so that when the `adjust-cell-width` config is
+ // used, or when a fallback font with a different advance width
+ // is used, we don't get weirdly aligned glyphs.
+ //
+ // We don't do this if the constraint has a horizontal alignment,
+ // since in that case the position was already calculated with the
+ // new cell width in mind.
+ if (opts.constraint.align_horizontal == .none) {
+ const advance = f26dot6ToFloat(glyph.*.advance.x);
+ const new_advance =
+ cell_width * @as(f64, @floatFromInt(opts.cell_width orelse 1));
+ // If the original advance is greater than the cell width then
+ // it's possible that this is a ligature or other glyph that is
+ // intended to overflow the cell to one side or the other, and
+ // adjusting the bearings could mess that up, so we just leave
+ // it alone if that's the case.
+ //
+ // We also don't want to do anything if the advance is zero or
+ // less, since this is used for stuff like combining characters.
+ if (advance > new_advance or advance <= 0.0) {
+ break :offset_x @intFromFloat(@floor(x));
}
+ break :offset_x @intFromFloat(
+ @floor(x + (new_advance - advance) / 2),
+ );
+ } else {
+ break :offset_x @intFromFloat(@floor(x));
}
-
- break :offset_x result;
};
- // log.warn("renderGlyph width={} height={} offset_x={} offset_y={} glyph_metrics={}", .{
- // tgt_w,
- // tgt_h,
- // glyph_metrics.bitmap_left,
- // offset_y,
- // glyph_metrics,
- // });
-
- // Store glyph metadata
return Glyph{
- .width = tgt_w,
- .height = tgt_h,
+ .width = px_width,
+ .height = px_height,
.offset_x = offset_x,
.offset_y = offset_y,
.atlas_x = region.x,
.atlas_y = region.y,
- .advance_x = f26dot6ToFloat(glyph_metrics.advance.x),
};
}
@@ -631,7 +703,7 @@ pub const Face = struct {
}
fn f26dot6ToF64(v: freetype.c.FT_F26Dot6) f64 {
- return @as(opentype.sfnt.F26Dot6, @bitCast(@as(u32, @intCast(v)))).to(f64);
+ return @as(F26Dot6, @bitCast(@as(i32, @intCast(v)))).to(f64);
}
pub const GetMetricsError = error{
@@ -783,7 +855,7 @@ pub const Face = struct {
while (c < 127) : (c += 1) {
if (face.getCharIndex(c)) |glyph_index| {
if (face.loadGlyph(glyph_index, .{
- .render = true,
+ .render = false,
.no_svg = true,
})) {
max = @max(
@@ -821,7 +893,7 @@ pub const Face = struct {
defer self.ft_mutex.unlock();
if (face.getCharIndex('H')) |glyph_index| {
if (face.loadGlyph(glyph_index, .{
- .render = true,
+ .render = false,
.no_svg = true,
})) {
break :cap f26dot6ToF64(face.handle.*.glyph.*.metrics.height);
@@ -834,7 +906,7 @@ pub const Face = struct {
defer self.ft_mutex.unlock();
if (face.getCharIndex('x')) |glyph_index| {
if (face.loadGlyph(glyph_index, .{
- .render = true,
+ .render = false,
.no_svg = true,
})) {
break :ex f26dot6ToF64(face.handle.*.glyph.*.metrics.height);
@@ -845,6 +917,21 @@ pub const Face = struct {
};
};
+ // Measure "水" (CJK water ideograph, U+6C34) for our ic width.
+ const ic_width: ?f64 = ic_width: {
+ self.ft_mutex.lock();
+ defer self.ft_mutex.unlock();
+
+ const glyph = face.getCharIndex('水') orelse break :ic_width null;
+
+ face.loadGlyph(glyph, .{
+ .render = false,
+ .no_svg = true,
+ }) catch break :ic_width null;
+
+ break :ic_width f26dot6ToF64(face.handle.*.glyph.*.advance.x);
+ };
+
return .{
.cell_width = cell_width,
@@ -860,6 +947,7 @@ pub const Face = struct {
.cap_height = cap_height,
.ex_height = ex_height,
+ .ic_width = ic_width,
};
}
@@ -950,13 +1038,15 @@ test "color emoji" {
}
// resize
+ // TODO: Comprehensive tests for constraints,
+ // this is just an adapted legacy test.
{
const glyph = try ft_font.renderGlyph(
alloc,
&atlas,
ft_font.glyphIndex('🥸').?,
.{ .grid_metrics = .{
- .cell_width = 10,
+ .cell_width = 13,
.cell_height = 24,
.cell_baseline = 0,
.underline_position = 0,
@@ -967,6 +1057,12 @@ test "color emoji" {
.overline_thickness = 0,
.box_thickness = 0,
.cursor_height = 0,
+ .icon_height = 0,
+ }, .constraint_width = 2, .constraint = .{
+ .size_horizontal = .cover,
+ .size_vertical = .cover,
+ .align_horizontal = .center,
+ .align_vertical = .center,
} },
);
try testing.expectEqual(@as(u32, 24), glyph.height);
diff --git a/src/font/face/freetype_convert.zig b/src/font/face/freetype_convert.zig
deleted file mode 100644
index 3a7cf8c98..000000000
--- a/src/font/face/freetype_convert.zig
+++ /dev/null
@@ -1,88 +0,0 @@
-//! Various conversions from Freetype formats to Atlas formats. These are
-//! currently implemented naively. There are definitely MUCH faster ways
-//! to do this (likely using SIMD), but I started simple.
-const std = @import("std");
-const freetype = @import("freetype");
-const font = @import("../main.zig");
-const assert = std.debug.assert;
-const Allocator = std.mem.Allocator;
-
-/// The mapping from freetype format to atlas format.
-pub const map = genMap();
-
-/// The map type.
-pub const Map = [freetype.c.FT_PIXEL_MODE_MAX]AtlasArray;
-
-/// Conversion function type. The returning bitmap buffer is guaranteed
-/// to be exactly `width * rows * depth` long for freeing it. The caller must
-/// free the bitmap buffer. The depth is the depth of the atlas format in the
-/// map.
-pub const Func = *const fn (Allocator, Bitmap) Allocator.Error!Bitmap;
-
-/// Alias for the freetype FT_Bitmap type to make it easier to type.
-pub const Bitmap = freetype.c.struct_FT_Bitmap_;
-
-const AtlasArray = std.EnumArray(font.Atlas.Format, ?Func);
-
-fn genMap() Map {
- var result: Map = undefined;
-
- // Initialize to no converter
- var i: usize = 0;
- while (i < freetype.c.FT_PIXEL_MODE_MAX) : (i += 1) {
- result[i] = .initFill(null);
- }
-
- // Map our converters
- result[freetype.c.FT_PIXEL_MODE_MONO].set(.grayscale, monoToGrayscale);
-
- return result;
-}
-
-pub fn monoToGrayscale(alloc: Allocator, bm: Bitmap) Allocator.Error!Bitmap {
- var buf = try alloc.alloc(u8, bm.width * bm.rows);
- errdefer alloc.free(buf);
-
- for (0..bm.rows) |y| {
- const row_offset = y * @as(usize, @intCast(bm.pitch));
- for (0..bm.width) |x| {
- const byte_offset = row_offset + @divTrunc(x, 8);
- const mask = @as(u8, 1) << @intCast(7 - (x % 8));
- const bit: u8 = @intFromBool((bm.buffer[byte_offset] & mask) != 0);
- buf[y * bm.width + x] = bit * 255;
- }
- }
-
- var copy = bm;
- copy.buffer = buf.ptr;
- copy.pixel_mode = freetype.c.FT_PIXEL_MODE_GRAY;
- copy.pitch = @as(c_int, @intCast(bm.width));
- return copy;
-}
-
-test {
- // Force comptime to run
- _ = map;
-}
-
-test "mono to grayscale" {
- const testing = std.testing;
- const alloc = testing.allocator;
-
- var mono_data = [_]u8{0b1010_0101};
- const source: Bitmap = .{
- .rows = 1,
- .width = 8,
- .pitch = 1,
- .buffer = @ptrCast(&mono_data),
- .num_grays = 0,
- .pixel_mode = freetype.c.FT_PIXEL_MODE_MONO,
- .palette_mode = 0,
- .palette = null,
- };
-
- const result = try monoToGrayscale(alloc, source);
- defer alloc.free(result.buffer[0..(result.width * result.rows)]);
- try testing.expect(result.pixel_mode == freetype.c.FT_PIXEL_MODE_GRAY);
- try testing.expectEqual(@as(u8, 255), result.buffer[0]);
-}
diff --git a/src/font/face/web_canvas.zig b/src/font/face/web_canvas.zig
index 30540191d..7ea2f0426 100644
--- a/src/font/face/web_canvas.zig
+++ b/src/font/face/web_canvas.zig
@@ -235,7 +235,6 @@ pub const Face = struct {
.offset_y = 0,
.atlas_x = region.x,
.atlas_y = region.y,
- .advance_x = 0,
};
}
diff --git a/src/font/nerd_font_attributes.zig b/src/font/nerd_font_attributes.zig
new file mode 100644
index 000000000..4ec55d2ff
--- /dev/null
+++ b/src/font/nerd_font_attributes.zig
@@ -0,0 +1,1073 @@
+//! This is a generated file, produced by nerd_font_codegen.py
+//! DO NOT EDIT BY HAND!
+//!
+//! This file provides info extracted from the nerd fonts patcher script,
+//! specifying the scaling/positioning attributes of various glyphs.
+
+const Constraint = @import("face.zig").RenderOptions.Constraint;
+
+/// Get the a constraints for the provided codepoint.
+pub fn getConstraint(cp: u21) Constraint {
+ return switch (cp) {
+ 0x2500...0x259f,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .pad_left = -0.02,
+ .pad_right = -0.02,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ },
+ 0x2630,
+ => .{
+ .size_horizontal = .cover,
+ .size_vertical = .fit,
+ .height = .icon,
+ .max_constraint_width = 1,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .pad_left = 0.1,
+ .pad_right = 0.1,
+ .pad_top = 0.1,
+ .pad_bottom = 0.1,
+ },
+ 0x276c...0x276d,
+ => .{
+ .size_horizontal = .cover,
+ .size_vertical = .fit,
+ .max_constraint_width = 1,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.4028056112224450,
+ .group_height = 1.1222570532915361,
+ .group_x = 0.1428571428571428,
+ .group_y = 0.0349162011173184,
+ .pad_top = 0.15,
+ .pad_bottom = 0.15,
+ },
+ 0x276e...0x276f,
+ => .{
+ .size_horizontal = .cover,
+ .size_vertical = .fit,
+ .max_constraint_width = 1,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0115606936416186,
+ .group_height = 1.1222570532915361,
+ .group_x = 0.0057142857142857,
+ .group_y = 0.0125698324022346,
+ .pad_top = 0.15,
+ .pad_bottom = 0.15,
+ },
+ 0x2770...0x2771,
+ => .{
+ .size_horizontal = .cover,
+ .size_vertical = .fit,
+ .max_constraint_width = 1,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .pad_top = 0.15,
+ .pad_bottom = 0.15,
+ },
+ 0xe0b0,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .pad_left = -0.06,
+ .pad_right = -0.06,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ .max_xy_ratio = 0.7,
+ },
+ 0xe0b1,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .max_xy_ratio = 0.7,
+ },
+ 0xe0b2,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ .pad_left = -0.06,
+ .pad_right = -0.06,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ .max_xy_ratio = 0.7,
+ },
+ 0xe0b3,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ .max_xy_ratio = 0.7,
+ },
+ 0xe0b4,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .pad_left = -0.06,
+ .pad_right = -0.06,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ .max_xy_ratio = 0.59,
+ },
+ 0xe0b5,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .max_xy_ratio = 0.5,
+ },
+ 0xe0b6,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ .pad_left = -0.06,
+ .pad_right = -0.06,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ .max_xy_ratio = 0.59,
+ },
+ 0xe0b7,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ .max_xy_ratio = 0.5,
+ },
+ 0xe0b8,
+ 0xe0bc,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .pad_left = -0.05,
+ .pad_right = -0.05,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ },
+ 0xe0b9,
+ 0xe0bd,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ },
+ 0xe0ba,
+ 0xe0be,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ .pad_left = -0.05,
+ .pad_right = -0.05,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ },
+ 0xe0bb,
+ 0xe0bf,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ },
+ 0xe0c0,
+ 0xe0c8,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .pad_left = -0.05,
+ .pad_right = -0.05,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ },
+ 0xe0c1,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ },
+ 0xe0c2,
+ 0xe0ca,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ .pad_left = -0.05,
+ .pad_right = -0.05,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ },
+ 0xe0c3,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ },
+ 0xe0c4,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .pad_left = 0.03,
+ .pad_right = 0.03,
+ .pad_top = 0.03,
+ .pad_bottom = 0.03,
+ .max_xy_ratio = 0.86,
+ },
+ 0xe0c5,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ .pad_left = 0.03,
+ .pad_right = 0.03,
+ .pad_top = 0.03,
+ .pad_bottom = 0.03,
+ .max_xy_ratio = 0.86,
+ },
+ 0xe0c6,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .pad_left = 0.03,
+ .pad_right = 0.03,
+ .pad_top = 0.03,
+ .pad_bottom = 0.03,
+ .max_xy_ratio = 0.78,
+ },
+ 0xe0c7,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ .pad_left = 0.03,
+ .pad_right = 0.03,
+ .pad_top = 0.03,
+ .pad_bottom = 0.03,
+ .max_xy_ratio = 0.78,
+ },
+ 0xe0cc,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .pad_left = -0.02,
+ .pad_right = -0.02,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ .max_xy_ratio = 0.85,
+ },
+ 0xe0cd,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .max_xy_ratio = 0.865,
+ },
+ 0xe0ce,
+ 0xe0d0...0xe0d1,
+ => .{
+ .size_horizontal = .cover,
+ .size_vertical = .fit,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ },
+ 0xe0cf,
+ 0xe0d3,
+ 0xe0d5,
+ => .{
+ .size_horizontal = .cover,
+ .size_vertical = .fit,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ },
+ 0xe0d2,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .pad_left = -0.02,
+ .pad_right = -0.02,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ .max_xy_ratio = 0.7,
+ },
+ 0xe0d4,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ .pad_left = -0.02,
+ .pad_right = -0.02,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ .max_xy_ratio = 0.7,
+ },
+ 0xe0d6,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .start,
+ .align_vertical = .center,
+ .pad_left = -0.05,
+ .pad_right = -0.05,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ .max_xy_ratio = 0.7,
+ },
+ 0xe0d7,
+ => .{
+ .size_horizontal = .stretch,
+ .size_vertical = .stretch,
+ .max_constraint_width = 1,
+ .align_horizontal = .end,
+ .align_vertical = .center,
+ .pad_left = -0.05,
+ .pad_right = -0.05,
+ .pad_top = -0.01,
+ .pad_bottom = -0.01,
+ .max_xy_ratio = 0.7,
+ },
+ 0x23fb...0x23fe,
+ 0x2665,
+ 0x26a1,
+ 0x2b58,
+ 0xe000...0xe0a9,
+ 0xe4fa...0xe7ef,
+ 0xea60,
+ 0xea62...0xea7c,
+ 0xea7e...0xea98,
+ 0xeaa3...0xeab3,
+ 0xeab8...0xead3,
+ 0xead7...0xeb42,
+ 0xeb44...0xeb6d,
+ 0xeb72...0xeb89,
+ 0xeb8b...0xeb99,
+ 0xeb9b...0xebd4,
+ 0xebd6,
+ 0xebd8...0xec06,
+ 0xec08...0xec0a,
+ 0xec0d...0xec1e,
+ 0xed00...0xf018,
+ 0xf01a...0xf02f,
+ 0xf031...0xf03c,
+ 0xf041...0xf043,
+ 0xf045...0xf049,
+ 0xf04b...0xf050,
+ 0xf054...0xf059,
+ 0xf05c...0xf070,
+ 0xf072...0xf077,
+ 0xf079...0xf07a,
+ 0xf07c...0xf080,
+ 0xf082...0xf08b,
+ 0xf08d...0xf091,
+ 0xf093...0xf09b,
+ 0xf09d...0xf09e,
+ 0xf0a0,
+ 0xf0a5...0xf0a9,
+ 0xf0ab...0xf0c9,
+ 0xf0cb...0xf0d5,
+ 0xf0d7...0xf0dd,
+ 0xf0df...0xf0e6,
+ 0xf0e8...0xf295,
+ 0xf297...0xf2c1,
+ 0xf2c6...0xf2ef,
+ 0xf2f1...0xf305,
+ 0xf307...0xf847,
+ 0xf0001...0xf1af0,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ },
+ 0xea61,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.3315669947009841,
+ .group_height = 1.0763840224246670,
+ .group_x = 0.0847072200113701,
+ .group_y = 0.0709635416666667,
+ },
+ 0xea7d,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.1913145539906103,
+ .group_height = 1.1428571428571428,
+ .group_x = 0.0916256157635468,
+ .group_y = 0.0415039062500000,
+ },
+ 0xea99,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0639412997903563,
+ .group_height = 2.0940695296523519,
+ .group_x = 0.0295566502463054,
+ .group_y = 0.2270507812500000,
+ },
+ 0xea9a,
+ 0xeaa1,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.3029525032092426,
+ .group_height = 1.1729667812142039,
+ .group_x = 0.1527093596059113,
+ .group_y = 0.0751953125000000,
+ },
+ 0xea9b,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.1639908256880733,
+ .group_height = 1.3128205128205128,
+ .group_x = 0.0719211822660099,
+ .group_y = 0.0869140625000000,
+ },
+ 0xea9c,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.1639908256880733,
+ .group_height = 1.3195876288659794,
+ .group_x = 0.0719211822660099,
+ .group_y = 0.0830078125000000,
+ },
+ 0xea9d,
+ 0xeaa0,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 2.4457831325301207,
+ .group_height = 1.9692307692307693,
+ .group_x = 0.2857142857142857,
+ .group_y = 0.2763671875000000,
+ },
+ 0xea9e...0xea9f,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.9556840077071291,
+ .group_height = 2.4674698795180725,
+ .group_x = 0.2137931034482759,
+ .group_y = 0.3066406250000000,
+ },
+ 0xeaa2,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.2412121212121212,
+ .group_height = 1.0591799039527152,
+ .group_x = 0.0683593750000000,
+ .group_y = 0.0146484375000000,
+ },
+ 0xeab4,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0049115913555993,
+ .group_height = 1.8998144712430427,
+ .group_y = 0.2026367187500000,
+ },
+ 0xeab5,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.8979591836734695,
+ .group_height = 1.0054000981836033,
+ .group_x = 0.2023460410557185,
+ .group_y = 0.0053710937500000,
+ },
+ 0xeab6,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.8979591836734695,
+ .group_height = 1.0054000981836033,
+ .group_x = 0.2707722385141740,
+ },
+ 0xeab7,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0049115913555993,
+ .group_height = 1.8980537534754403,
+ .group_x = 0.0048875855327468,
+ .group_y = 0.2709960937500000,
+ },
+ 0xead4...0xead5,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.4152542372881356,
+ .group_x = 0.1486118671747414,
+ },
+ 0xead6,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_height = 1.1390433815350389,
+ .group_y = 0.0688476562500000,
+ },
+ 0xeb43,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.3635153129161119,
+ .group_height = 1.0002360944082516,
+ .group_x = 0.1992187500000000,
+ .group_y = 0.0002360386808388,
+ },
+ 0xeb6e,
+ 0xeb71,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_height = 2.0197238658777121,
+ .group_y = 0.2524414062500000,
+ },
+ 0xeb6f,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 2.0098619329388558,
+ .group_x = 0.2492639842983317,
+ },
+ 0xeb70,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 2.0098619329388558,
+ .group_height = 1.0039215686274510,
+ .group_x = 0.2492639842983317,
+ .group_y = 0.0039062500000000,
+ },
+ 0xeb8a,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 2.8826979472140764,
+ .group_height = 2.9804097167804766,
+ .group_x = 0.2634791454730417,
+ .group_y = 0.3314678485576923,
+ },
+ 0xeb9a,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.1441340782122904,
+ .group_height = 1.0591799039527152,
+ .group_x = 0.0683593750000000,
+ .group_y = 0.0146484375000000,
+ },
+ 0xebd5,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0723270440251573,
+ .group_height = 1.0728129910948141,
+ .group_y = 0.0678710937500000,
+ },
+ 0xebd7,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_height = 1.0000418544302916,
+ .group_y = 0.0000418526785714,
+ },
+ 0xec07,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 2.8615369874243446,
+ .group_height = 2.9789458113505249,
+ .group_x = 0.2609446802539727,
+ .group_y = 0.3313029661016949,
+ },
+ 0xec0b,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0722513089005237,
+ .group_height = 1.0002360944082516,
+ .group_y = 0.0002360386808388,
+ },
+ 0xec0c,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.2487804878048780,
+ .group_x = 0.1992187500000000,
+ },
+ 0xf019,
+ 0xf08c,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0004882812500000,
+ },
+ 0xf030,
+ 0xf03e,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0004882812500000,
+ .group_height = 1.1428571428571428,
+ .group_y = 0.0625000000000000,
+ },
+ 0xf03d,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0004882812500000,
+ .group_height = 1.5014662756598240,
+ .group_y = 0.1669921875000000,
+ },
+ 0xf03f,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.6018762826150690,
+ .group_x = 0.1876220107369448,
+ },
+ 0xf040,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0006976906439684,
+ .group_height = 1.0001808776182035,
+ .group_x = 0.0006972042111134,
+ .group_y = 0.0001808449074074,
+ },
+ 0xf044,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.1029147024980515,
+ .group_height = 1.1024142703367676,
+ .group_x = 0.0463592039005675,
+ .group_y = 0.0430325010461710,
+ },
+ 0xf04a,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0004882812500000,
+ .group_height = 1.3312975252838291,
+ .group_y = 0.1245571402616279,
+ },
+ 0xf051,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.6007812500000000,
+ .group_height = 1.3312170271945341,
+ .group_x = 0.1874084919472914,
+ .group_y = 0.1245117187500000,
+ },
+ 0xf052,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.1436671384194865,
+ .group_height = 1.1430165816326530,
+ .group_x = 0.0624629273607646,
+ .group_y = 0.0625610266424885,
+ },
+ 0xf053,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.8765709864847797,
+ .group_height = 1.0707191397207079,
+ .group_x = 0.2332599943628554,
+ .group_y = 0.0332682382480123,
+ },
+ 0xf05a...0xf05b,
+ 0xf081,
+ 0xf092,
+ 0xf0aa,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0005935142780173,
+ .group_height = 1.0001395089285714,
+ .group_y = 0.0000697447342726,
+ },
+ 0xf071,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0014662756598240,
+ .group_height = 1.1428571428571428,
+ .group_x = 0.0004880429477794,
+ .group_y = 0.0625000000000000,
+ },
+ 0xf078,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0717654378877508,
+ .group_height = 1.8757195185766613,
+ .group_x = 0.0331834301604062,
+ .group_y = 0.1670386385827870,
+ },
+ 0xf07b,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_height = 1.1428571428571428,
+ .group_y = 0.0625000000000000,
+ },
+ 0xf09c,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_height = 1.0810546875000000,
+ },
+ 0xf09f,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.7506617925122907,
+ .group_height = 1.0810546875000000,
+ .group_x = 0.2143937211981567,
+ },
+ 0xf0a1,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0009775171065494,
+ .group_x = 0.0004882812500000,
+ },
+ 0xf0a2,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.1433271023627367,
+ .group_height = 1.0001395089285714,
+ .group_x = 0.0624235731978609,
+ .group_y = 0.0000697447342726,
+ },
+ 0xf0a3,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0005760656161586,
+ .group_height = 1.0001220681837999,
+ .group_x = 0.0004792774839344,
+ .group_y = 0.0000610266424885,
+ },
+ 0xf0a4,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0005935142780173,
+ .group_height = 1.3335193452380951,
+ .group_y = 0.1250523085507044,
+ },
+ 0xf0ca,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0005935142780173,
+ .group_height = 1.1922501247297521,
+ .group_y = 0.0806249128190822,
+ },
+ 0xf0d6,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_height = 1.5014662756598240,
+ .group_y = 0.1669921875000000,
+ },
+ 0xf0de,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.2253421114919656,
+ .group_height = 2.5216400911161729,
+ .group_x = 0.0918898809523810,
+ .group_y = 0.6034327009936766,
+ },
+ 0xf0e7,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.3336843856081169,
+ .group_x = 0.1247597299147187,
+ },
+ 0xf296,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0005148743038617,
+ .group_height = 1.0385966606705219,
+ .group_x = 0.0005146093447336,
+ .group_y = 0.0186218440507742,
+ },
+ 0xf2c2...0xf2c3,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0000770970394737,
+ .group_height = 1.2864321608040201,
+ .group_y = 0.1113281250000000,
+ },
+ 0xf2c4,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0344231791600214,
+ .group_x = 0.0166002826673519,
+ },
+ 0xf2c5,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0004538836055876,
+ .group_height = 1.4840579710144928,
+ .group_x = 0.0004536776887225,
+ .group_y = 0.1630859375000000,
+ },
+ 0xf2f0,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.0005935142780173,
+ .group_height = 1.0334438518091393,
+ .group_y = 0.0161807783512345,
+ },
+ 0xf306,
+ => .{
+ .size_horizontal = .fit,
+ .size_vertical = .fit,
+ .height = .icon,
+ .align_horizontal = .center,
+ .align_vertical = .center,
+ .group_width = 1.2427184466019416,
+ .group_x = 0.0976562500000000,
+ },
+ else => .none,
+ };
+}
diff --git a/src/font/nerd_font_codegen.py b/src/font/nerd_font_codegen.py
new file mode 100644
index 000000000..ad5cd0814
--- /dev/null
+++ b/src/font/nerd_font_codegen.py
@@ -0,0 +1,358 @@
+"""
+This file extracts the patch sets from the nerd fonts font patcher file in order to
+extract scaling rules and attributes for different codepoint ranges which it then
+codegens in to a Zig file with a function that switches over codepoints and returns the
+attributes and scaling rules.
+
+This does include an `eval` call! This is spooky, but we trust the nerd fonts code to
+be safe and not malicious or anything.
+
+This script requires Python 3.12 or greater, requires that the `fontTools`
+python module is installed, and requires that the path to a copy of the
+SymbolsNerdFontMono font is passed as the first argument to the script.
+"""
+
+import ast
+import sys
+import math
+from fontTools.ttLib import TTFont
+from fontTools.pens.boundsPen import BoundsPen
+from collections import defaultdict
+from contextlib import suppress
+from pathlib import Path
+from types import SimpleNamespace
+from typing import Literal, TypedDict, cast
+
+type PatchSetAttributes = dict[Literal["default"] | int, PatchSetAttributeEntry]
+type AttributeHash = tuple[
+ str | None,
+ str | None,
+ str,
+ float,
+ float,
+ float,
+ float,
+ float,
+ float,
+ float,
+]
+type ResolvedSymbol = PatchSetAttributes | PatchSetScaleRules | int | None
+
+
+class PatchSetScaleRules(TypedDict):
+ ShiftMode: str
+ ScaleGroups: list[list[int] | range]
+
+
+class PatchSetAttributeEntry(TypedDict):
+ align: str
+ valign: str
+ stretch: str
+ params: dict[str, float | bool]
+
+ group_x: float
+ group_y: float
+ group_width: float
+ group_height: float
+
+
+class PatchSet(TypedDict):
+ SymStart: int
+ SymEnd: int
+ SrcStart: int | None
+ ScaleRules: PatchSetScaleRules | None
+ Attributes: PatchSetAttributes
+
+
+class PatchSetExtractor(ast.NodeVisitor):
+ def __init__(self) -> None:
+ self.symbol_table: dict[str, ast.expr] = {}
+ self.patch_set_values: list[PatchSet] = []
+
+ def visit_ClassDef(self, node: ast.ClassDef) -> None:
+ if node.name != "font_patcher":
+ return
+ for item in node.body:
+ if isinstance(item, ast.FunctionDef) and item.name == "setup_patch_set":
+ self.visit_setup_patch_set(item)
+
+ def visit_setup_patch_set(self, node: ast.FunctionDef) -> None:
+ # First pass: gather variable assignments
+ for stmt in node.body:
+ match stmt:
+ case ast.Assign(targets=[ast.Name(id=symbol)]):
+ # Store simple variable assignments in the symbol table
+ self.symbol_table[symbol] = stmt.value
+
+ # Second pass: process self.patch_set
+ for stmt in node.body:
+ if not isinstance(stmt, ast.Assign):
+ continue
+ for target in stmt.targets:
+ if (
+ isinstance(target, ast.Attribute)
+ and target.attr == "patch_set"
+ and isinstance(stmt.value, ast.List)
+ ):
+ for elt in stmt.value.elts:
+ if isinstance(elt, ast.Dict):
+ self.process_patch_entry(elt)
+
+ def resolve_symbol(self, node: ast.expr) -> ResolvedSymbol:
+ """Resolve named variables to their actual values from the symbol table."""
+ if isinstance(node, ast.Name) and node.id in self.symbol_table:
+ return self.safe_literal_eval(self.symbol_table[node.id])
+ return self.safe_literal_eval(node)
+
+ def safe_literal_eval(self, node: ast.expr) -> ResolvedSymbol:
+ """Try to evaluate or stringify an AST node."""
+ try:
+ return ast.literal_eval(node)
+ except ValueError:
+ # Spooky eval! But we trust nerd fonts to be safe...
+ if hasattr(ast, "unparse"):
+ return eval(
+ ast.unparse(node),
+ {"box_keep": True},
+ {"self": SimpleNamespace(args=SimpleNamespace(careful=True))},
+ )
+ msg = f""
+ raise ValueError(msg) from None
+
+ def process_patch_entry(self, dict_node: ast.Dict) -> None:
+ entry = {}
+ disallowed_key_nodes = frozenset({"Enabled", "Name", "Filename", "Exact"})
+ for key_node, value_node in zip(dict_node.keys, dict_node.values):
+ if (
+ isinstance(key_node, ast.Constant)
+ and key_node.value not in disallowed_key_nodes
+ ):
+ key = ast.literal_eval(cast("ast.Constant", key_node))
+ entry[key] = self.resolve_symbol(value_node)
+ self.patch_set_values.append(cast("PatchSet", entry))
+
+
+def extract_patch_set_values(source_code: str) -> list[PatchSet]:
+ tree = ast.parse(source_code)
+ extractor = PatchSetExtractor()
+ extractor.visit(tree)
+ return extractor.patch_set_values
+
+
+def parse_alignment(val: str) -> str | None:
+ return {
+ "l": ".start",
+ "r": ".end",
+ "c": ".center",
+ "": None,
+ }.get(val, ".none")
+
+
+def attr_key(attr: PatchSetAttributeEntry) -> AttributeHash:
+ """Convert attributes to a hashable key for grouping."""
+ params = attr.get("params", {})
+ return (
+ parse_alignment(attr.get("align", "")),
+ parse_alignment(attr.get("valign", "")),
+ attr.get("stretch", ""),
+ float(params.get("overlap", 0.0)),
+ float(params.get("xy-ratio", -1.0)),
+ float(params.get("ypadding", 0.0)),
+ float(attr.get("group_x", 0.0)),
+ float(attr.get("group_y", 0.0)),
+ float(attr.get("group_width", 1.0)),
+ float(attr.get("group_height", 1.0)),
+ )
+
+
+def coalesce_codepoints_to_ranges(codepoints: list[int]) -> list[tuple[int, int]]:
+ """Convert a sorted list of integers to a list of single values and ranges."""
+ ranges: list[tuple[int, int]] = []
+ cp_iter = iter(sorted(codepoints))
+ with suppress(StopIteration):
+ start = prev = next(cp_iter)
+ for cp in cp_iter:
+ if cp == prev + 1:
+ prev = cp
+ else:
+ ranges.append((start, prev))
+ start = prev = cp
+ ranges.append((start, prev))
+ return ranges
+
+
+def emit_zig_entry_multikey(codepoints: list[int], attr: PatchSetAttributeEntry) -> str:
+ align = parse_alignment(attr.get("align", ""))
+ valign = parse_alignment(attr.get("valign", ""))
+ stretch = attr.get("stretch", "")
+ params = attr.get("params", {})
+
+ group_x = attr.get("group_x", 0.0)
+ group_y = attr.get("group_y", 0.0)
+ group_width = attr.get("group_width", 1.0)
+ group_height = attr.get("group_height", 1.0)
+
+ overlap = params.get("overlap", 0.0)
+ xy_ratio = params.get("xy-ratio", -1.0)
+ y_padding = params.get("ypadding", 0.0)
+
+ ranges = coalesce_codepoints_to_ranges(codepoints)
+ keys = "\n".join(
+ f" {start:#x}...{end:#x}," if start != end else f" {start:#x},"
+ for start, end in ranges
+ )
+
+ s = f"{keys}\n => .{{\n"
+
+ # These translations don't quite capture the way
+ # the actual patcher does scaling, but they're a
+ # good enough compromise.
+ if "xy" in stretch:
+ s += " .size_horizontal = .stretch,\n"
+ s += " .size_vertical = .stretch,\n"
+ elif "!" in stretch or "^" in stretch:
+ s += " .size_horizontal = .cover,\n"
+ s += " .size_vertical = .fit,\n"
+ else:
+ s += " .size_horizontal = .fit,\n"
+ s += " .size_vertical = .fit,\n"
+
+ # `^` indicates that scaling should fill
+ # the whole cell, not just the icon height.
+ if "^" not in stretch:
+ s += " .height = .icon,\n"
+
+ # There are two cases where we want to limit the constraint width to 1:
+ # - If there's a `1` in the stretch mode string.
+ # - If the stretch mode is `xy` and there's not an explicit `2`.
+ if "1" in stretch or ("xy" in stretch and "2" not in stretch):
+ s += " .max_constraint_width = 1,\n"
+
+ if align is not None:
+ s += f" .align_horizontal = {align},\n"
+ if valign is not None:
+ s += f" .align_vertical = {valign},\n"
+
+ if group_width != 1.0:
+ s += f" .group_width = {group_width:.16f},\n"
+ if group_height != 1.0:
+ s += f" .group_height = {group_height:.16f},\n"
+ if group_x != 0.0:
+ s += f" .group_x = {group_x:.16f},\n"
+ if group_y != 0.0:
+ s += f" .group_y = {group_y:.16f},\n"
+
+ # `overlap` and `ypadding` are mutually exclusive,
+ # this is asserted in the nerd fonts patcher itself.
+ if overlap:
+ pad = -overlap
+ s += f" .pad_left = {pad},\n"
+ s += f" .pad_right = {pad},\n"
+ # In the nerd fonts patcher, overlap values
+ # are capped at 0.01 in the vertical direction.
+ v_pad = -min(0.01, overlap)
+ s += f" .pad_top = {v_pad},\n"
+ s += f" .pad_bottom = {v_pad},\n"
+ elif y_padding:
+ s += f" .pad_top = {y_padding / 2},\n"
+ s += f" .pad_bottom = {y_padding / 2},\n"
+
+ if xy_ratio > 0:
+ s += f" .max_xy_ratio = {xy_ratio},\n"
+
+ s += " },"
+ return s
+
+
+def generate_zig_switch_arms(
+ patch_sets: list[PatchSet],
+ nerd_font: TTFont,
+) -> str:
+ cmap = nerd_font.getBestCmap()
+ glyphs = nerd_font.getGlyphSet()
+
+ entries: dict[int, PatchSetAttributeEntry] = {}
+ for entry in patch_sets:
+ attributes = entry["Attributes"]
+
+ for cp in range(entry["SymStart"], entry["SymEnd"] + 1):
+ entries[cp] = attributes["default"].copy()
+
+ entries |= {k: v for k, v in attributes.items() if isinstance(k, int)}
+
+ if entry["ScaleRules"] is not None and "ScaleGroups" in entry["ScaleRules"]:
+ for group in entry["ScaleRules"]["ScaleGroups"]:
+ xMin = math.inf
+ yMin = math.inf
+ xMax = -math.inf
+ yMax = -math.inf
+ individual_bounds: dict[int, tuple[int, int, int ,int]] = {}
+ for cp in group:
+ if cp not in cmap:
+ continue
+ glyph = glyphs[cmap[cp]]
+ bounds = BoundsPen(glyphSet=glyphs)
+ glyph.draw(bounds)
+ individual_bounds[cp] = bounds.bounds
+ xMin = min(bounds.bounds[0], xMin)
+ yMin = min(bounds.bounds[1], yMin)
+ xMax = max(bounds.bounds[2], xMax)
+ yMax = max(bounds.bounds[3], yMax)
+ group_width = xMax - xMin
+ group_height = yMax - yMin
+ for cp in group:
+ if cp not in cmap or cp not in entries:
+ continue
+ this_bounds = individual_bounds[cp]
+ this_width = this_bounds[2] - this_bounds[0]
+ this_height = this_bounds[3] - this_bounds[1]
+ entries[cp]["group_width"] = group_width / this_width
+ entries[cp]["group_height"] = group_height / this_height
+ entries[cp]["group_x"] = (this_bounds[0] - xMin) / group_width
+ entries[cp]["group_y"] = (this_bounds[1] - yMin) / group_height
+
+ del entries[0]
+
+ # Group codepoints by attribute key
+ grouped = defaultdict[AttributeHash, list[int]](list)
+ for cp, attr in entries.items():
+ grouped[attr_key(attr)].append(cp)
+
+ # Emit zig switch arms
+ result: list[str] = []
+ for codepoints in sorted(grouped.values()):
+ # Use one of the attrs in the group to emit the value
+ attr = entries[codepoints[0]]
+ result.append(emit_zig_entry_multikey(codepoints, attr))
+
+ return "\n".join(result)
+
+
+if __name__ == "__main__":
+ project_root = Path(__file__).resolve().parents[2]
+
+ nf_path = sys.argv[1]
+
+ nerd_font = TTFont(nf_path)
+
+ patcher_path = project_root / "vendor" / "nerd-fonts" / "font-patcher.py"
+ source = patcher_path.read_text(encoding="utf-8")
+ patch_set = extract_patch_set_values(source)
+
+ out_path = project_root / "src" / "font" / "nerd_font_attributes.zig"
+
+ with out_path.open("w", encoding="utf-8") as f:
+ f.write("""//! This is a generated file, produced by nerd_font_codegen.py
+//! DO NOT EDIT BY HAND!
+//!
+//! This file provides info extracted from the nerd fonts patcher script,
+//! specifying the scaling/positioning attributes of various glyphs.
+
+const Constraint = @import("face.zig").RenderOptions.Constraint;
+
+/// Get the a constraints for the provided codepoint.
+pub fn getConstraint(cp: u21) Constraint {
+ return switch (cp) {
+""")
+ f.write(generate_zig_switch_arms(patch_set, nerd_font))
+ f.write("\n else => .none,\n };\n}\n")
diff --git a/src/font/opentype/sfnt.zig b/src/font/opentype/sfnt.zig
index 14a3b795a..82c118bce 100644
--- a/src/font/opentype/sfnt.zig
+++ b/src/font/opentype/sfnt.zig
@@ -76,24 +76,22 @@ fn FixedPoint(comptime T: type, int_bits: u64, frac_bits: u64) type {
));
const half = @as(T, 1) << @intCast(frac_bits - 1);
- frac: std.meta.Int(.unsigned, frac_bits),
- int: std.meta.Int(type_info.signedness, int_bits),
+ const Frac = std.meta.Int(.unsigned, frac_bits);
+ const Int = std.meta.Int(type_info.signedness, int_bits);
+
+ frac: Frac,
+ int: Int,
pub fn to(self: Self, comptime FloatType: type) FloatType {
- const i: FloatType = @floatFromInt(self.int);
- const f: FloatType = @floatFromInt(self.frac);
-
- return i + f / frac_factor;
+ return @as(FloatType, @floatFromInt(
+ @as(T, @bitCast(self)),
+ )) / frac_factor;
}
pub fn from(float: anytype) Self {
- const int = @floor(float);
- const frac = @abs(float - int);
-
- return .{
- .int = @intFromFloat(int),
- .frac = @intFromFloat(@round(frac * frac_factor)),
- };
+ return @bitCast(
+ @as(T, @intFromFloat(@round(float * frac_factor))),
+ );
}
/// Round to the nearest integer, .5 rounds away from 0.
diff --git a/src/font/shaper/coretext.zig b/src/font/shaper/coretext.zig
index 1fd9719bb..f4f01d105 100644
--- a/src/font/shaper/coretext.zig
+++ b/src/font/shaper/coretext.zig
@@ -109,7 +109,8 @@ pub const Shaper = struct {
/// settings the font features of a CoreText font.
fn makeFeaturesDict(feats: []const Feature) !*macos.foundation.Dictionary {
const list = try macos.foundation.MutableArray.create();
- errdefer list.release();
+ // The list will be retained by the dict once we add it to it.
+ defer list.release();
for (feats) |feat| {
const value_num: c_int = @intCast(feat.value);
@@ -1768,7 +1769,7 @@ fn testShaperWithFont(alloc: Allocator, font_req: TestFont) !TestShaper {
.geist_mono => font.embedded.geist_mono,
.jetbrains_mono => font.embedded.jetbrains_mono,
.monaspace_neon => font.embedded.monaspace_neon,
- .nerd_font => font.embedded.nerd_font,
+ .nerd_font => font.embedded.test_nerd_font,
};
var lib = try Library.init(alloc);
diff --git a/src/font/sprite/Face.zig b/src/font/sprite/Face.zig
index 1463fb38b..dfff8fa75 100644
--- a/src/font/sprite/Face.zig
+++ b/src/font/sprite/Face.zig
@@ -195,7 +195,6 @@ pub fn renderGlyph(
.offset_y = 0,
.atlas_x = 0,
.atlas_y = 0,
- .advance_x = 0,
};
const metrics = self.metrics;
@@ -227,8 +226,6 @@ pub fn renderGlyph(
.offset_y = @as(i32, @intCast(region.height +| canvas.clip_bottom)) - @as(i32, @intCast(padding_y)),
.atlas_x = region.x,
.atlas_y = region.y,
- .advance_x = @floatFromInt(width),
- .sprite = true,
};
}
diff --git a/src/font/sprite/canvas.zig b/src/font/sprite/canvas.zig
index b981449bc..a77b90a56 100644
--- a/src/font/sprite/canvas.zig
+++ b/src/font/sprite/canvas.zig
@@ -140,24 +140,7 @@ pub const Canvas = struct {
const region_height = sfc_height -| self.clip_top -| self.clip_bottom;
// Allocate our texture atlas region
- const region = region: {
- // Reserve a region with a 1px margin on the bottom and right edges
- // so that we can avoid interpolation between adjacent glyphs during
- // texture sampling.
- var region = try atlas.reserve(
- alloc,
- region_width + 1,
- region_height + 1,
- );
-
- // Modify the region to remove the margin so that we write to the
- // non-zero location. The data in an Altlas is always initialized
- // to zero (Atlas.clear) so we don't need to worry about zero-ing
- // that.
- region.width -= 1;
- region.height -= 1;
- break :region region;
- };
+ const region = try atlas.reserve(alloc, region_width, region_height);
if (region.width > 0 and region.height > 0) {
const buffer: []u8 = @ptrCast(self.sfc.image_surface_alpha8.buf);
diff --git a/src/input/Binding.zig b/src/input/Binding.zig
index 7cdb8047c..f76da360a 100644
--- a/src/input/Binding.zig
+++ b/src/input/Binding.zig
@@ -281,6 +281,10 @@ pub const Action = union(enum) {
/// If there is a URL under the cursor, copy it to the default clipboard.
copy_url_to_clipboard,
+ /// Copy the terminal title to the clipboard. If the terminal title is not
+ /// set or is empty this has no effect.
+ copy_title_to_clipboard,
+
/// Increase the font size by the specified amount in points (pt).
///
/// For example, `increase_font_size:1.5` will increase the font size
@@ -296,6 +300,12 @@ pub const Action = union(enum) {
/// Reset the font size to the original configured size.
reset_font_size,
+ /// Set the font size to the specified size in points (pt).
+ ///
+ /// For example, `set_font_size:14.5` will set the font size
+ /// to 14.5 points.
+ set_font_size: f32,
+
/// Clear the screen and all scrollback.
clear_screen,
@@ -999,11 +1009,13 @@ pub const Action = union(enum) {
.reset,
.copy_to_clipboard,
.copy_url_to_clipboard,
+ .copy_title_to_clipboard,
.paste_from_clipboard,
.paste_from_selection,
.increase_font_size,
.decrease_font_size,
.reset_font_size,
+ .set_font_size,
.prompt_surface_title,
.clear_screen,
.select_all,
@@ -3065,6 +3077,7 @@ test "set: getEvent codepoint case folding" {
try testing.expect(action == null);
}
}
+
test "Action: clone" {
const testing = std.testing;
var arena = std.heap.ArenaAllocator.init(testing.allocator);
@@ -3083,3 +3096,42 @@ test "Action: clone" {
try testing.expect(b == .text);
}
}
+
+test "parse: increase_font_size" {
+ const testing = std.testing;
+
+ {
+ const binding = try parseSingle("a=increase_font_size:1.5");
+ try testing.expect(binding.action == .increase_font_size);
+ try testing.expectEqual(1.5, binding.action.increase_font_size);
+ }
+}
+
+test "parse: decrease_font_size" {
+ const testing = std.testing;
+
+ {
+ const binding = try parseSingle("a=decrease_font_size:2.5");
+ try testing.expect(binding.action == .decrease_font_size);
+ try testing.expectEqual(2.5, binding.action.decrease_font_size);
+ }
+}
+
+test "parse: reset_font_size" {
+ const testing = std.testing;
+
+ {
+ const binding = try parseSingle("a=reset_font_size");
+ try testing.expect(binding.action == .reset_font_size);
+ }
+}
+
+test "parse: set_font_size" {
+ const testing = std.testing;
+
+ {
+ const binding = try parseSingle("a=set_font_size:13.5");
+ try testing.expect(binding.action == .set_font_size);
+ try testing.expectEqual(13.5, binding.action.set_font_size);
+ }
+}
diff --git a/src/input/command.zig b/src/input/command.zig
index 693d5c8d4..84e9afc79 100644
--- a/src/input/command.zig
+++ b/src/input/command.zig
@@ -1,4 +1,5 @@
const std = @import("std");
+const builtin = @import("builtin");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Action = @import("Binding.zig").Action;
@@ -131,6 +132,12 @@ fn actionCommands(action: Action.Key) []const Command {
.description = "Copy the URL under the cursor to the clipboard.",
}},
+ .copy_title_to_clipboard => comptime &.{.{
+ .action = .copy_title_to_clipboard,
+ .title = "Copy Terminal Title to Clipboard",
+ .description = "Copy the terminal title to the clipboard. If the terminal title is not set this has no effect.",
+ }},
+
.paste_from_clipboard => comptime &.{.{
.action = .paste_from_clipboard,
.title = "Paste from Clipboard",
@@ -460,6 +467,7 @@ fn actionCommands(action: Action.Key) []const Command {
.esc,
.text,
.cursor_key,
+ .set_font_size,
.scroll_page_fractional,
.scroll_page_lines,
.adjust_selection,
diff --git a/src/main_c.zig b/src/main_c.zig
index 1b73d7327..2c266cfb5 100644
--- a/src/main_c.zig
+++ b/src/main_c.zig
@@ -19,7 +19,12 @@ const internal_os = @import("os/main.zig");
// Some comptime assertions that our C API depends on.
comptime {
- assert(apprt.runtime == apprt.embedded);
+ // We allow tests to reference this file because we unit test
+ // some of the C API. At runtime though we should never get these
+ // functions unless we are building libghostty.
+ if (!builtin.is_test) {
+ assert(apprt.runtime == apprt.embedded);
+ }
}
/// Global options so we can log. This is identical to main.
@@ -29,7 +34,9 @@ comptime {
// These structs need to be referenced so the `export` functions
// are truly exported by the C API lib.
_ = @import("config.zig").CAPI;
- _ = apprt.runtime.CAPI;
+ if (@hasDecl(apprt.runtime, "CAPI")) {
+ _ = apprt.runtime.CAPI;
+ }
}
/// ghostty_info_s
@@ -46,17 +53,29 @@ const Info = extern struct {
};
};
-/// Initialize ghostty global state. It is possible to have more than
-/// one global state but it has zero practical benefit.
-export fn ghostty_init() c_int {
+/// ghostty_string_s
+pub const String = extern struct {
+ ptr: ?[*]const u8,
+ len: usize,
+
+ pub const empty: String = .{
+ .ptr = null,
+ .len = 0,
+ };
+
+ pub fn fromSlice(slice: []const u8) String {
+ return .{
+ .ptr = slice.ptr,
+ .len = slice.len,
+ };
+ }
+};
+
+/// Initialize ghostty global state.
+export fn ghostty_init(argc: usize, argv: [*][*:0]u8) c_int {
assert(builtin.link_libc);
- // Since in the lib we don't go through start.zig, we need
- // to populate argv so that inspecting std.os.argv doesn't
- // touch uninitialized memory.
- var argv: [0][*:0]u8 = .{};
- std.os.argv = &argv;
-
+ std.os.argv = argv[0..argc];
state.init() catch |err| {
std.log.err("failed to initialize ghostty error={}", .{err});
return 1;
@@ -65,15 +84,17 @@ export fn ghostty_init() c_int {
return 0;
}
-/// This is the entrypoint for the CLI version of Ghostty. This
-/// is mutually exclusive to ghostty_init. Do NOT run ghostty_init
-/// if you are going to run this. This will not return.
-export fn ghostty_cli_main(argc: usize, argv: [*][*:0]u8) noreturn {
- std.os.argv = argv[0..argc];
- main.main() catch |err| {
- std.log.err("failed to run ghostty error={}", .{err});
+/// Runs an action if it is specified. If there is no action this returns
+/// false. If there is an action then this doesn't return.
+export fn ghostty_cli_try_action() void {
+ const action = state.action orelse return;
+ std.log.info("executing CLI action={}", .{action});
+ posix.exit(action.run(state.alloc) catch |err| {
+ std.log.err("CLI action failed error={}", .{err});
posix.exit(1);
- };
+ });
+
+ posix.exit(0);
}
/// Return metadata about Ghostty, such as version, build mode, etc.
@@ -99,3 +120,8 @@ export fn ghostty_info() Info {
export fn ghostty_translate(msgid: [*:0]const u8) [*:0]const u8 {
return internal_os.i18n._(msgid);
}
+
+/// Free a string allocated by Ghostty.
+export fn ghostty_string_free(str: String) void {
+ state.alloc.free(str.ptr.?[0..str.len]);
+}
diff --git a/src/main_ghostty.zig b/src/main_ghostty.zig
index 567eec5f9..b747fe6f0 100644
--- a/src/main_ghostty.zig
+++ b/src/main_ghostty.zig
@@ -7,7 +7,6 @@ const Allocator = std.mem.Allocator;
const posix = std.posix;
const build_config = @import("build_config.zig");
const options = @import("build_options");
-const glfw = @import("glfw");
const glslang = @import("glslang");
const macos = @import("macos");
const oni = @import("oniguruma");
diff --git a/src/os/desktop.zig b/src/os/desktop.zig
index 3bc843e5c..93bfb74bc 100644
--- a/src/os/desktop.zig
+++ b/src/os/desktop.zig
@@ -24,8 +24,15 @@ pub fn launchedFromDesktop() bool {
// This special case is so that if we launch the app via the
// app bundle (i.e. via open) then we still treat it as if it
// was launched from the desktop.
- if (build_config.artifact == .lib and
- posix.getenv("GHOSTTY_MAC_APP") != null) break :macos true;
+ if (build_config.artifact == .lib) lib: {
+ const env = "GHOSTTY_MAC_LAUNCH_SOURCE";
+ const source = posix.getenv(env) orelse break :lib;
+
+ // Source can be "app", "cli", or "zig_run". We assume
+ // its the desktop only if its "app". We may want to do
+ // "zig_run" but at the moment there's no reason.
+ if (std.mem.eql(u8, source, "app")) break :macos true;
+ }
break :macos c.getppid() == 1;
},
diff --git a/src/os/i18n.zig b/src/os/i18n.zig
index f5c8ffdea..2ecae27ac 100644
--- a/src/os/i18n.zig
+++ b/src/os/i18n.zig
@@ -47,7 +47,9 @@ pub const locales = [_][:0]const u8{
"es_AR.UTF-8",
"pt_BR.UTF-8",
"ca_ES.UTF-8",
+ "bg_BG.UTF-8",
"ga_IE.UTF-8",
+ "he_IL.UTF-8",
};
/// Set for faster membership lookup of locales.
diff --git a/src/os/kernel_info.zig b/src/os/kernel_info.zig
new file mode 100644
index 000000000..9e3933dde
--- /dev/null
+++ b/src/os/kernel_info.zig
@@ -0,0 +1,27 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+pub fn getKernelInfo(alloc: std.mem.Allocator) ?[]const u8 {
+ if (comptime builtin.os.tag != .linux) return null;
+ const path = "/proc/sys/kernel/osrelease";
+ var file = std.fs.openFileAbsolute(path, .{}) catch return null;
+ defer file.close();
+
+ // 128 bytes should be enough to hold the kernel information
+ const kernel_info = file.readToEndAlloc(alloc, 128) catch return null;
+ defer alloc.free(kernel_info);
+ return alloc.dupe(u8, std.mem.trim(u8, kernel_info, &std.ascii.whitespace)) catch return null;
+}
+
+test "read /proc/sys/kernel/osrelease" {
+ if (comptime builtin.os.tag != .linux) return null;
+ const allocator = std.testing.allocator;
+
+ const kernel_info = try getKernelInfo(allocator);
+ defer allocator.free(kernel_info);
+
+ // Since we can't hardcode the info in tests, just check
+ // if something was read from the file
+ try std.testing.expect(kernel_info.len > 0);
+ try std.testing.expect(!std.mem.eql(u8, kernel_info, ""));
+}
diff --git a/src/os/main.zig b/src/os/main.zig
index 906e3d150..7398fc779 100644
--- a/src/os/main.zig
+++ b/src/os/main.zig
@@ -14,6 +14,7 @@ const openpkg = @import("open.zig");
const pipepkg = @import("pipe.zig");
const resourcesdir = @import("resourcesdir.zig");
const systemd = @import("systemd.zig");
+const kernelInfo = @import("kernel_info.zig");
// Namespaces
pub const args = @import("args.zig");
@@ -58,6 +59,7 @@ pub const pipe = pipepkg.pipe;
pub const resourcesDir = resourcesdir.resourcesDir;
pub const ResourcesDir = resourcesdir.ResourcesDir;
pub const ShellEscapeWriter = shell.ShellEscapeWriter;
+pub const getKernelInfo = kernelInfo.getKernelInfo;
test {
_ = i18n;
diff --git a/src/os/open.zig b/src/os/open.zig
index ce62a7e0b..9b069c80f 100644
--- a/src/os/open.zig
+++ b/src/os/open.zig
@@ -1,24 +1,23 @@
const std = @import("std");
const builtin = @import("builtin");
const Allocator = std.mem.Allocator;
+const apprt = @import("../apprt.zig");
const log = std.log.scoped(.@"os-open");
-/// The type of the data at the URL to open. This is used as a hint
-/// to potentially open the URL in a different way.
-pub const Type = enum {
- text,
- unknown,
-};
-
/// Open a URL in the default handling application.
///
/// Any output on stderr is logged as a warning in the application logs.
/// Output on stdout is ignored. The allocator is used to buffer the
/// log output and may allocate from another thread.
+///
+/// This function is purposely simple for the sake of providing
+/// some portable way to open URLs. If you are implementing an
+/// apprt for Ghostty, you should consider doing something special-cased
+/// for your platform.
pub fn open(
alloc: Allocator,
- typ: Type,
+ kind: apprt.action.OpenUrl.Kind,
url: []const u8,
) !void {
var exe: std.process.Child = switch (builtin.os.tag) {
@@ -33,7 +32,7 @@ pub fn open(
),
.macos => .init(
- switch (typ) {
+ switch (kind) {
.text => &.{ "open", "-t", url },
.unknown => &.{ "open", url },
},
diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig
index 3899bb8c5..70be1a96b 100644
--- a/src/renderer/Metal.zig
+++ b/src/renderer/Metal.zig
@@ -5,7 +5,6 @@ const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const builtin = @import("builtin");
-const glfw = @import("glfw");
const objc = @import("objc");
const macos = @import("macos");
const graphics = macos.graphics;
@@ -38,11 +37,6 @@ pub const swap_chain_count = 3;
const log = std.log.scoped(.metal);
-// Get native API access on certain platforms so we can do more customization.
-const glfwNative = glfw.Native(.{
- .cocoa = builtin.os.tag == .macos,
-});
-
layer: IOSurfaceLayer,
/// MTLDevice
@@ -87,27 +81,6 @@ pub fn init(alloc: Allocator, opts: rendererpkg.Options) !Metal {
// Get the metadata about our underlying view that we'll be rendering to.
const info: ViewInfo = switch (apprt.runtime) {
- apprt.glfw => info: {
- // Everything in glfw is window-oriented so we grab the backing
- // window, then derive everything from that.
- const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(
- opts.rt_surface.window,
- ).?);
-
- const contentView = objc.Object.fromId(
- nswindow.getProperty(?*anyopaque, "contentView").?,
- );
- const scaleFactor = nswindow.getProperty(
- graphics.c.CGFloat,
- "backingScaleFactor",
- );
-
- break :info .{
- .view = contentView,
- .scaleFactor = scaleFactor,
- };
- },
-
apprt.embedded => .{
.scaleFactor = @floatCast(opts.rt_surface.content_scale.x),
.view = switch (opts.rt_surface.platform) {
diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig
index cf195361e..882d6fc03 100644
--- a/src/renderer/OpenGL.zig
+++ b/src/renderer/OpenGL.zig
@@ -5,7 +5,6 @@ const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const builtin = @import("builtin");
-const glfw = @import("glfw");
const gl = @import("opengl");
const shadertoy = @import("shadertoy.zig");
const apprt = @import("../apprt.zig");
@@ -60,18 +59,6 @@ pub fn deinit(self: *OpenGL) void {
self.* = undefined;
}
-/// Returns the hints that we want for this
-pub fn glfwWindowHints(config: *const configpkg.Config) glfw.Window.Hints {
- _ = config;
- return .{
- .context_version_major = MIN_VERSION_MAJOR,
- .context_version_minor = MIN_VERSION_MINOR,
- .opengl_profile = .opengl_core_profile,
- .opengl_forward_compat = true,
- .transparent_framebuffer = true,
- };
-}
-
/// 32-bit windows cross-compilation breaks with `.c` for some reason, so...
const gl_debug_proc_callconv =
@typeInfo(
@@ -172,8 +159,7 @@ fn prepareContext(getProcAddress: anytype) !void {
/// This is called early right after surface creation.
pub fn surfaceInit(surface: *apprt.Surface) !void {
- // Treat this like a thread entry
- const self: OpenGL = undefined;
+ _ = surface;
switch (apprt.runtime) {
else => @compileError("unsupported app runtime for OpenGL"),
@@ -181,8 +167,6 @@ pub fn surfaceInit(surface: *apprt.Surface) !void {
// GTK uses global OpenGL context so we load from null.
apprt.gtk => try prepareContext(null),
- apprt.glfw => try self.threadEnter(surface),
-
apprt.embedded => {
// TODO(mitchellh): this does nothing today to allow libghostty
// to compile for OpenGL targets but libghostty is strictly
@@ -205,17 +189,12 @@ pub fn surfaceInit(surface: *apprt.Surface) !void {
pub fn finalizeSurfaceInit(self: *const OpenGL, surface: *apprt.Surface) !void {
_ = self;
_ = surface;
-
- // For GLFW, we grabbed the OpenGL context in surfaceInit and
- // we need to release it before we start the renderer thread.
- if (apprt.runtime == apprt.glfw) {
- glfw.makeContextCurrent(null);
- }
}
/// Callback called by renderer.Thread when it begins.
pub fn threadEnter(self: *const OpenGL, surface: *apprt.Surface) !void {
_ = self;
+ _ = surface;
switch (apprt.runtime) {
else => @compileError("unsupported app runtime for OpenGL"),
@@ -227,21 +206,6 @@ pub fn threadEnter(self: *const OpenGL, surface: *apprt.Surface) !void {
// on the main thread. As such, we don't do anything here.
},
- apprt.glfw => {
- // We need to make the OpenGL context current. OpenGL requires
- // that a single thread own the a single OpenGL context (if any).
- // This ensures that the context switches over to our thread.
- // Important: the prior thread MUST have detached the context
- // prior to calling this entrypoint.
- glfw.makeContextCurrent(surface.window);
- errdefer glfw.makeContextCurrent(null);
- glfw.swapInterval(1);
-
- // Load OpenGL bindings. This API is context-aware so this sets
- // a threadlocal context for these pointers.
- try prepareContext(&glfw.getProcAddress);
- },
-
apprt.embedded => {
// TODO(mitchellh): this does nothing today to allow libghostty
// to compile for OpenGL targets but libghostty is strictly
@@ -262,11 +226,6 @@ pub fn threadExit(self: *const OpenGL) void {
// be sharing the global bindings with other windows.
},
- apprt.glfw => {
- gl.glad.unload();
- glfw.makeContextCurrent(null);
- },
-
apprt.embedded => {
// TODO: see threadEnter
},
@@ -397,6 +356,10 @@ pub inline fn textureOptions(self: OpenGL) Texture.Options {
.format = .rgba,
.internal_format = .srgba,
.target = .@"2D",
+ .min_filter = .linear,
+ .mag_filter = .linear,
+ .wrap_s = .clamp_to_edge,
+ .wrap_t = .clamp_to_edge,
};
}
@@ -429,6 +392,16 @@ pub inline fn imageTextureOptions(
.format = format.toPixelFormat(),
.internal_format = if (srgb) .srgba else .rgba,
.target = .@"2D",
+ // TODO: Generate mipmaps for image textures and use
+ // linear_mipmap_linear filtering so that they
+ // look good even when scaled way down.
+ .min_filter = .linear,
+ .mag_filter = .linear,
+ // TODO: Separate out background image options, use
+ // repeating coordinate modes so we don't have
+ // to do the modulus in the shader.
+ .wrap_s = .clamp_to_edge,
+ .wrap_t = .clamp_to_edge,
};
}
@@ -450,6 +423,10 @@ pub fn initAtlasTexture(
.format = format,
.internal_format = internal_format,
.target = .Rectangle,
+ .min_filter = .nearest,
+ .mag_filter = .nearest,
+ .wrap_s = .clamp_to_edge,
+ .wrap_t = .clamp_to_edge,
},
atlas.size,
atlas.size,
diff --git a/src/renderer/cell.zig b/src/renderer/cell.zig
index ef7122699..43d744176 100644
--- a/src/renderer/cell.zig
+++ b/src/renderer/cell.zig
@@ -103,11 +103,12 @@ pub const Contents = struct {
// form a single grapheme, and multi-substitutions in fonts, the number
// of glyphs in a row is theoretically unlimited.
//
- // We have size.rows + 1 lists because index 0 is used for a special
- // list containing the cursor cell which needs to be first in the buffer.
+ // We have size.rows + 2 lists because indexes 0 and size.rows - 1 are
+ // used for special lists containing the cursor cell which need to
+ // be first and last in the buffer, respectively.
var fg_rows = try ArrayListCollection(shaderpkg.CellText).init(
alloc,
- size.rows + 1,
+ size.rows + 2,
size.columns * 3,
);
errdefer fg_rows.deinit(alloc);
@@ -118,14 +119,19 @@ pub const Contents = struct {
self.bg_cells = bg_cells;
self.fg_rows = fg_rows;
- // We don't need 3*cols worth of cells for the cursor list, so we can
- // replace it with a smaller list. This is technically a tiny bit of
+ // We don't need 3*cols worth of cells for the cursor lists, so we can
+ // replace them with smaller lists. This is technically a tiny bit of
// extra work but resize is not a hot function so it's worth it to not
// waste the memory.
self.fg_rows.lists[0].deinit(alloc);
self.fg_rows.lists[0] = try std.ArrayListUnmanaged(
shaderpkg.CellText,
).initCapacity(alloc, 1);
+
+ self.fg_rows.lists[size.rows + 1].deinit(alloc);
+ self.fg_rows.lists[size.rows + 1] = try std.ArrayListUnmanaged(
+ shaderpkg.CellText,
+ ).initCapacity(alloc, 1);
}
/// Reset the cell contents to an empty state without resizing.
@@ -135,11 +141,18 @@ pub const Contents = struct {
}
/// Set the cursor value. If the value is null then the cursor is hidden.
- pub fn setCursor(self: *Contents, v: ?shaderpkg.CellText) void {
+ pub fn setCursor(self: *Contents, v: ?shaderpkg.CellText, cursor_style: ?renderer.CursorStyle) void {
self.fg_rows.lists[0].clearRetainingCapacity();
+ self.fg_rows.lists[self.size.rows + 1].clearRetainingCapacity();
- if (v) |cell| {
- self.fg_rows.lists[0].appendAssumeCapacity(cell);
+ const cell = v orelse return;
+ const style = cursor_style orelse return;
+
+ switch (style) {
+ // Block cursors should be drawn first
+ .block => self.fg_rows.lists[0].appendAssumeCapacity(cell),
+ // Other cursor styles should be drawn last
+ .block_hollow, .bar, .underline, .lock => self.fg_rows.lists[self.size.rows + 1].appendAssumeCapacity(cell),
}
}
@@ -205,103 +218,64 @@ pub fn isCovering(cp: u21) bool {
};
}
-pub const FgMode = enum {
- /// Normal non-colored text rendering. The text can leave the cell
- /// size if it is larger than the cell to allow for ligatures.
- normal,
+/// Returns the appropriate `constraint_width` for
+/// the provided cell when rendering its glyph(s).
+pub fn constraintWidth(cell_pin: terminal.Pin) u2 {
+ const cell = cell_pin.rowAndCell().cell;
+ const cp = cell.codepoint();
- /// Colored text rendering, specifically Emoji.
- color,
+ if (!ziglyph.general_category.isPrivateUse(cp) and
+ !ziglyph.blocks.isDingbats(cp))
+ {
+ return cell.gridWidth();
+ }
- /// Similar to normal but the text must be constrained to the cell
- /// size. If a glyph is larger than the cell then it must be resized
- /// to fit.
- constrained,
+ // If we are at the end of the screen it must be constrained to one cell.
+ if (cell_pin.x == cell_pin.node.data.size.cols - 1) return 1;
- /// Similar to normal, but the text consists of Powerline glyphs and is
- /// optionally exempt from padding color extension and minimum contrast requirements.
- powerline,
-};
+ // If we have a previous cell and it was PUA then we need to
+ // also constrain. This is so that multiple PUA glyphs align.
+ // As an exception, we ignore powerline glyphs since they are
+ // used for box drawing and we consider them whitespace.
+ if (cell_pin.x > 0) prev: {
+ const prev_cp = prev_cp: {
+ var copy = cell_pin;
+ copy.x -= 1;
+ const prev_cell = copy.rowAndCell().cell;
+ break :prev_cp prev_cell.codepoint();
+ };
-/// Returns the appropriate foreground mode for the given cell. This is
-/// meant to be called from the typical updateCell function within a
-/// renderer.
-pub fn fgMode(
- presentation: font.Presentation,
- cell_pin: terminal.Pin,
-) FgMode {
- return switch (presentation) {
- // Emoji is always full size and color.
- .emoji => .color,
+ // We consider powerline glyphs whitespace.
+ if (isPowerline(prev_cp)) break :prev;
- // If it is text it is slightly more complex. If we are a codepoint
- // in the private use area and we are at the end or the next cell
- // is not empty, we need to constrain rendering.
- //
- // We do this specifically so that Nerd Fonts can render their
- // icons without overlapping with subsequent characters. But if
- // the subsequent character is empty, then we allow it to use
- // the full glyph size. See #1071.
- .text => text: {
- const cell = cell_pin.rowAndCell().cell;
- const cp = cell.codepoint();
+ if (ziglyph.general_category.isPrivateUse(prev_cp)) {
+ return 1;
+ }
+ }
- if (!ziglyph.general_category.isPrivateUse(cp) and
- !ziglyph.blocks.isDingbats(cp))
- {
- break :text .normal;
- }
-
- // Special-case Powerline glyphs. They exhibit box drawing behavior
- // and should not be constrained. They have their own special category
- // though because they're used for other logic (i.e. disabling
- // min contrast).
- if (isPowerline(cp)) {
- break :text .powerline;
- }
-
- // If we are at the end of the screen its definitely constrained
- if (cell_pin.x == cell_pin.node.data.size.cols - 1) break :text .constrained;
-
- // If we have a previous cell and it was PUA then we need to
- // also constrain. This is so that multiple PUA glyphs align.
- // As an exception, we ignore powerline glyphs since they are
- // used for box drawing and we consider them whitespace.
- if (cell_pin.x > 0) prev: {
- const prev_cp = prev_cp: {
- var copy = cell_pin;
- copy.x -= 1;
- const prev_cell = copy.rowAndCell().cell;
- break :prev_cp prev_cell.codepoint();
- };
-
- // Powerline is whitespace
- if (isPowerline(prev_cp)) break :prev;
-
- if (ziglyph.general_category.isPrivateUse(prev_cp)) {
- break :text .constrained;
- }
- }
-
- // If the next cell is empty, then we allow it to use the
- // full glyph size.
- const next_cp = next_cp: {
- var copy = cell_pin;
- copy.x += 1;
- const next_cell = copy.rowAndCell().cell;
- break :next_cp next_cell.codepoint();
- };
- if (next_cp == 0 or
- isSpace(next_cp) or
- isPowerline(next_cp))
- {
- break :text .normal;
- }
-
- // Must be constrained
- break :text .constrained;
- },
+ // If the next cell is whitespace, then
+ // we allow it to be up to two cells wide.
+ const next_cp = next_cp: {
+ var copy = cell_pin;
+ copy.x += 1;
+ const next_cell = copy.rowAndCell().cell;
+ break :next_cp next_cell.codepoint();
};
+ if (next_cp == 0 or
+ isSpace(next_cp) or
+ isPowerline(next_cp))
+ {
+ return 2;
+ }
+
+ // Must be constrained
+ return 1;
+}
+
+/// Whether min contrast should be disabled for a given glyph.
+pub fn noMinContrast(cp: u21) bool {
+ // TODO: We should disable for all box drawing type characters.
+ return isPowerline(cp);
}
// Some general spaces, others intentionally kept
@@ -348,7 +322,7 @@ test Contents {
// Add some contents.
const bg_cell: shaderpkg.CellBg = .{ 0, 0, 0, 1 };
const fg_cell: shaderpkg.CellText = .{
- .mode = .fg,
+ .atlas = .grayscale,
.grid_pos = .{ 4, 1 },
.color = .{ 0, 0, 0, 1 },
};
@@ -367,18 +341,23 @@ test Contents {
}
}
- // Add a cursor.
+ // Add a block cursor.
const cursor_cell: shaderpkg.CellText = .{
- .mode = .cursor,
+ .atlas = .grayscale,
+ .bools = .{ .is_cursor_glyph = true },
.grid_pos = .{ 2, 3 },
.color = .{ 0, 0, 0, 1 },
};
- c.setCursor(cursor_cell);
+ c.setCursor(cursor_cell, .block);
try testing.expectEqual(cursor_cell, c.fg_rows.lists[0].items[0]);
// And remove it.
- c.setCursor(null);
+ c.setCursor(null, null);
try testing.expectEqual(0, c.fg_rows.lists[0].items.len);
+
+ // Add a hollow cursor.
+ c.setCursor(cursor_cell, .block_hollow);
+ try testing.expectEqual(cursor_cell, c.fg_rows.lists[rows + 1].items[0]);
}
test "Contents clear retains other content" {
@@ -396,7 +375,7 @@ test "Contents clear retains other content" {
// bg and fg cells in row 1
const bg_cell_1: shaderpkg.CellBg = .{ 0, 0, 0, 1 };
const fg_cell_1: shaderpkg.CellText = .{
- .mode = .fg,
+ .atlas = .grayscale,
.grid_pos = .{ 4, 1 },
.color = .{ 0, 0, 0, 1 },
};
@@ -405,7 +384,7 @@ test "Contents clear retains other content" {
// bg and fg cells in row 2
const bg_cell_2: shaderpkg.CellBg = .{ 0, 0, 0, 1 };
const fg_cell_2: shaderpkg.CellText = .{
- .mode = .fg,
+ .atlas = .grayscale,
.grid_pos = .{ 4, 2 },
.color = .{ 0, 0, 0, 1 },
};
@@ -436,7 +415,7 @@ test "Contents clear last added content" {
// bg and fg cells in row 1
const bg_cell_1: shaderpkg.CellBg = .{ 0, 0, 0, 1 };
const fg_cell_1: shaderpkg.CellText = .{
- .mode = .fg,
+ .atlas = .grayscale,
.grid_pos = .{ 4, 1 },
.color = .{ 0, 0, 0, 1 },
};
@@ -445,7 +424,7 @@ test "Contents clear last added content" {
// bg and fg cells in row 2
const bg_cell_2: shaderpkg.CellBg = .{ 0, 0, 0, 1 };
const fg_cell_2: shaderpkg.CellText = .{
- .mode = .fg,
+ .atlas = .grayscale,
.grid_pos = .{ 4, 2 },
.color = .{ 0, 0, 0, 1 },
};
diff --git a/src/renderer/generic.zig b/src/renderer/generic.zig
index 810e17686..3965d302a 100644
--- a/src/renderer/generic.zig
+++ b/src/renderer/generic.zig
@@ -1,6 +1,5 @@
const std = @import("std");
const builtin = @import("builtin");
-const glfw = @import("glfw");
const xev = @import("xev");
const wuffs = @import("wuffs");
const apprt = @import("../apprt.zig");
@@ -13,7 +12,8 @@ const math = @import("../math.zig");
const Surface = @import("../Surface.zig");
const link = @import("link.zig");
const cellpkg = @import("cell.zig");
-const fgMode = cellpkg.fgMode;
+const noMinContrast = cellpkg.noMinContrast;
+const constraintWidth = cellpkg.constraintWidth;
const isCovering = cellpkg.isCovering;
const imagepkg = @import("image.zig");
const Image = imagepkg.Image;
@@ -26,6 +26,8 @@ const ArenaAllocator = std.heap.ArenaAllocator;
const Terminal = terminal.Terminal;
const Health = renderer.Health;
+const getConstraint = @import("../font/nerd_font_attributes.zig").getConstraint;
+
const FileType = @import("../file_type.zig").FileType;
const macos = switch (builtin.os.tag) {
@@ -133,12 +135,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
/// This is cursor color as set in the user's config, if any. If no cursor color
/// is set in the user's config, then the cursor color is determined by the
/// current foreground color.
- default_cursor_color: ?terminal.color.RGB,
-
- /// When `cursor_color` is null, swap the foreground and background colors of
- /// the cell under the cursor for the cursor color. Otherwise, use the default
- /// foreground color as the cursor color.
- cursor_invert: bool,
+ default_cursor_color: ?configpkg.Config.TerminalColor,
/// The current set of cells to render. This is rebuilt on every frame
/// but we keep this around so that we don't reallocate. Each set of
@@ -514,17 +511,15 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
font_features: std.ArrayListUnmanaged([:0]const u8),
font_styles: font.CodepointResolver.StyleStatus,
font_shaping_break: configpkg.FontShapingBreak,
- cursor_color: ?terminal.color.RGB,
- cursor_invert: bool,
+ cursor_color: ?configpkg.Config.TerminalColor,
cursor_opacity: f64,
- cursor_text: ?terminal.color.RGB,
+ cursor_text: ?configpkg.Config.TerminalColor,
background: terminal.color.RGB,
background_opacity: f64,
foreground: terminal.color.RGB,
- selection_background: ?terminal.color.RGB,
- selection_foreground: ?terminal.color.RGB,
- invert_selection_fg_bg: bool,
- bold_is_bright: bool,
+ selection_background: ?configpkg.Config.TerminalColor,
+ selection_foreground: ?configpkg.Config.TerminalColor,
+ bold_color: ?configpkg.BoldColor,
min_contrast: f32,
padding_color: configpkg.WindowPaddingColor,
custom_shaders: configpkg.RepeatablePath,
@@ -571,8 +566,6 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
config.link.links.items,
);
- const cursor_invert = config.@"cursor-invert-fg-bg";
-
return .{
.background_opacity = @max(0, @min(1, config.@"background-opacity")),
.font_thicken = config.@"font-thicken",
@@ -581,36 +574,19 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
.font_styles = font_styles,
.font_shaping_break = config.@"font-shaping-break",
- .cursor_color = if (!cursor_invert and config.@"cursor-color" != null)
- config.@"cursor-color".?.toTerminalRGB()
- else
- null,
-
- .cursor_invert = cursor_invert,
-
- .cursor_text = if (config.@"cursor-text") |txt|
- txt.toTerminalRGB()
- else
- null,
-
+ .cursor_color = config.@"cursor-color",
+ .cursor_text = config.@"cursor-text",
.cursor_opacity = @max(0, @min(1, config.@"cursor-opacity")),
.background = config.background.toTerminalRGB(),
.foreground = config.foreground.toTerminalRGB(),
- .invert_selection_fg_bg = config.@"selection-invert-fg-bg",
- .bold_is_bright = config.@"bold-is-bright",
+ .bold_color = config.@"bold-color",
+
.min_contrast = @floatCast(config.@"minimum-contrast"),
.padding_color = config.@"window-padding-color",
- .selection_background = if (config.@"selection-background") |bg|
- bg.toTerminalRGB()
- else
- null,
-
- .selection_foreground = if (config.@"selection-foreground") |bg|
- bg.toTerminalRGB()
- else
- null,
+ .selection_background = config.@"selection-background",
+ .selection_foreground = config.@"selection-foreground",
.custom_shaders = custom_shaders,
.bg_image = bg_image,
@@ -633,20 +609,6 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
}
};
- /// Returns the hints that we want for this window.
- pub fn glfwWindowHints(config: *const configpkg.Config) glfw.Window.Hints {
- // If our graphics API provides hints, use them,
- // otherwise fall back to generic hints.
- if (@hasDecl(GraphicsAPI, "glfwWindowHints")) {
- return GraphicsAPI.glfwWindowHints(config);
- }
-
- return .{
- .client_api = .no_api,
- .transparent_framebuffer = config.@"background-opacity" < 1,
- };
- }
-
pub fn init(alloc: Allocator, options: renderer.Options) !Self {
// Initialize our graphics API wrapper, this will prepare the
// surface provided by the apprt and set up any API-specific
@@ -703,7 +665,6 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
.default_background_color = options.config.background,
.cursor_color = null,
.default_cursor_color = options.config.cursor_color,
- .cursor_invert = options.config.cursor_invert,
// Render state
.cells = .{},
@@ -2079,8 +2040,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
// Set our new colors
self.default_background_color = config.background;
self.default_foreground_color = config.foreground;
- self.default_cursor_color = if (!config.cursor_invert) config.cursor_color else null;
- self.cursor_invert = config.cursor_invert;
+ self.default_cursor_color = config.cursor_color;
const bg_image_config_changed =
self.config.bg_image_fit != config.bg_image_fit or
@@ -2577,28 +2537,32 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
else
false;
+ // The `_style` suffixed values are the colors based on
+ // the cell style (SGR), before applying any additional
+ // configuration, inversions, selections, etc.
const bg_style = style.bg(cell, color_palette);
- const fg_style = style.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color;
+ const fg_style = style.fg(.{
+ .default = self.foreground_color orelse self.default_foreground_color,
+ .palette = color_palette,
+ .bold = self.config.bold_color,
+ });
// The final background color for the cell.
const bg = bg: {
if (selected) {
- break :bg if (self.config.invert_selection_fg_bg)
- if (style.flags.inverse)
- // Cell is selected with invert selection fg/bg
- // enabled, and the cell has the inverse style
- // flag, so they cancel out and we get the normal
- // bg color.
- bg_style
- else
- // If it doesn't have the inverse style
- // flag then we use the fg color instead.
- fg_style
- else
- // If we don't have invert selection fg/bg set then we
- // just use the selection background if set, otherwise
- // the default fg color.
- break :bg self.config.selection_background orelse self.foreground_color orelse self.default_foreground_color;
+ // If we have an explicit selection background color
+ // specified int he config, use that
+ if (self.config.selection_background) |v| {
+ break :bg switch (v) {
+ .color => |color| color.toTerminalRGB(),
+ .@"cell-foreground" => if (style.flags.inverse) bg_style else fg_style,
+ .@"cell-background" => if (style.flags.inverse) fg_style else bg_style,
+ };
+ }
+
+ // If no configuration, then our selection background
+ // is our foreground color.
+ break :bg self.foreground_color orelse self.default_foreground_color;
}
// Not selected
@@ -2618,20 +2582,31 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
};
const fg = fg: {
- if (selected and !self.config.invert_selection_fg_bg) {
- // If we don't have invert selection fg/bg set
- // then we just use the selection foreground if
- // set, otherwise the default bg color.
- break :fg self.config.selection_foreground orelse self.background_color orelse self.default_background_color;
- }
+ // Our happy-path non-selection background color
+ // is our style or our configured defaults.
+ const final_bg = bg_style orelse
+ self.background_color orelse
+ self.default_background_color;
// Whether we need to use the bg color as our fg color:
+ // - Cell is selected, inverted, and set to cell-foreground
+ // - Cell is selected, not inverted, and set to cell-background
// - Cell is inverted and not selected
- // - Cell is selected and not inverted
- // Note: if selected then invert sel fg / bg must be
- // false since we separately handle it if true above.
- break :fg if (style.flags.inverse != selected)
- bg_style orelse self.background_color orelse self.default_background_color
+ if (selected) {
+ // Use the selection foreground if set
+ if (self.config.selection_foreground) |v| {
+ break :fg switch (v) {
+ .color => |color| color.toTerminalRGB(),
+ .@"cell-foreground" => if (style.flags.inverse) final_bg else fg_style,
+ .@"cell-background" => if (style.flags.inverse) fg_style else final_bg,
+ };
+ }
+
+ break :fg self.background_color orelse self.default_background_color;
+ }
+
+ break :fg if (style.flags.inverse)
+ final_bg
else
fg_style;
};
@@ -2806,7 +2781,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
// Setup our cursor rendering information.
cursor: {
// By default, we don't handle cursor inversion on the shader.
- self.cells.setCursor(null);
+ self.cells.setCursor(null, null);
self.uniforms.cursor_pos = .{
std.math.maxInt(u16),
std.math.maxInt(u16),
@@ -2817,18 +2792,36 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
// Prepare the cursor cell contents.
const style = cursor_style_ orelse break :cursor;
- const cursor_color = self.cursor_color orelse self.default_cursor_color orelse color: {
- if (self.cursor_invert) {
- // Use the foreground color from the cell under the cursor, if any.
- const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
- break :color if (sty.flags.inverse)
- // If the cell is reversed, use background color instead.
- (sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color)
- else
- (sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color);
- } else {
- break :color self.foreground_color orelse self.default_foreground_color;
- }
+ const cursor_color = cursor_color: {
+ // If an explicit cursor color was set by OSC 12, use that.
+ if (self.cursor_color) |v| break :cursor_color v;
+
+ // Use our configured color if specified
+ if (self.default_cursor_color) |v| switch (v) {
+ .color => |color| break :cursor_color color.toTerminalRGB(),
+ inline .@"cell-foreground",
+ .@"cell-background",
+ => |_, tag| {
+ const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
+ const fg_style = sty.fg(.{
+ .default = self.foreground_color orelse self.default_foreground_color,
+ .palette = color_palette,
+ .bold = self.config.bold_color,
+ });
+ const bg_style = sty.bg(
+ screen.cursor.page_cell,
+ color_palette,
+ ) orelse self.background_color orelse self.default_background_color;
+
+ break :cursor_color switch (tag) {
+ .color => unreachable,
+ .@"cell-foreground" => if (sty.flags.inverse) bg_style else fg_style,
+ .@"cell-background" => if (sty.flags.inverse) fg_style else bg_style,
+ };
+ },
+ };
+
+ break :cursor_color self.foreground_color orelse self.default_foreground_color;
};
self.addCursor(screen, style, cursor_color);
@@ -2853,18 +2846,29 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
.wide, .spacer_tail => true,
};
- const uniform_color = if (self.cursor_invert) blk: {
- // Use the background color from the cell under the cursor, if any.
+ const uniform_color = if (self.config.cursor_text) |txt| blk: {
+ // If cursor-text is set, then compute the correct color.
+ // Otherwise, use the background color.
+ if (txt == .color) {
+ // Use the color set by cursor-text, if any.
+ break :blk txt.color.toTerminalRGB();
+ }
+
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
- break :blk if (sty.flags.inverse)
- // If the cell is reversed, use foreground color instead.
- (sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color)
- else
- (sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color);
- } else if (self.config.cursor_text) |txt|
- txt
- else
- self.background_color orelse self.default_background_color;
+ const fg_style = sty.fg(.{
+ .default = self.foreground_color orelse self.default_foreground_color,
+ .palette = color_palette,
+ .bold = self.config.bold_color,
+ });
+ const bg_style = sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color;
+
+ break :blk switch (txt) {
+ // If the cell is reversed, use the opposite cell color instead.
+ .@"cell-foreground" => if (sty.flags.inverse) bg_style else fg_style,
+ .@"cell-background" => if (sty.flags.inverse) fg_style else bg_style,
+ else => unreachable,
+ };
+ } else self.background_color orelse self.default_background_color;
self.uniforms.cursor_color = .{
uniform_color.r,
@@ -2930,9 +2934,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
);
try self.cells.add(self.alloc, .underline, .{
- .mode = .fg,
+ .atlas = .grayscale,
.grid_pos = .{ @intCast(x), @intCast(y) },
- .constraint_width = 1,
.color = .{ color.r, color.g, color.b, alpha },
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
.glyph_size = .{ render.glyph.width, render.glyph.height },
@@ -2962,9 +2965,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
);
try self.cells.add(self.alloc, .overline, .{
- .mode = .fg,
+ .atlas = .grayscale,
.grid_pos = .{ @intCast(x), @intCast(y) },
- .constraint_width = 1,
.color = .{ color.r, color.g, color.b, alpha },
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
.glyph_size = .{ render.glyph.width, render.glyph.height },
@@ -2994,9 +2996,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
);
try self.cells.add(self.alloc, .strikethrough, .{
- .mode = .fg,
+ .atlas = .grayscale,
.grid_pos = .{ @intCast(x), @intCast(y) },
- .constraint_width = 1,
.color = .{ color.r, color.g, color.b, alpha },
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
.glyph_size = .{ render.glyph.width, render.glyph.height },
@@ -3021,6 +3022,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
const rac = cell_pin.rowAndCell();
const cell = rac.cell;
+ const cp = cell.codepoint();
+
// Render
const render = try self.font_grid.renderGlyph(
self.alloc,
@@ -3030,6 +3033,9 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
.grid_metrics = self.grid_metrics,
.thicken = self.config.font_thicken,
.thicken_strength = self.config.font_thicken_strength,
+ .cell_width = cell.gridWidth(),
+ .constraint = getConstraint(cp),
+ .constraint_width = constraintWidth(cell_pin),
},
);
@@ -3039,27 +3045,13 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
return;
}
- // We always use fg mode for sprite glyphs, since we know we never
- // need to constrain them, and we don't have any color sprites.
- //
- // Otherwise we defer to `fgMode`.
- const mode: shaderpkg.CellText.Mode =
- if (render.glyph.sprite)
- .fg
- else switch (fgMode(
- render.presentation,
- cell_pin,
- )) {
- .normal => .fg,
- .color => .fg_color,
- .constrained => .fg_constrained,
- .powerline => .fg_powerline,
- };
-
try self.cells.add(self.alloc, .text, .{
- .mode = mode,
+ .atlas = switch (render.presentation) {
+ .emoji => .color,
+ .text => .grayscale,
+ },
+ .bools = .{ .no_min_contrast = noMinContrast(cp) },
.grid_pos = .{ @intCast(x), @intCast(y) },
- .constraint_width = cell.gridWidth(),
.color = .{ color.r, color.g, color.b, alpha },
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
.glyph_size = .{ render.glyph.width, render.glyph.height },
@@ -3144,7 +3136,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
};
self.cells.setCursor(.{
- .mode = .cursor,
+ .atlas = .grayscale,
+ .bools = .{ .is_cursor_glyph = true },
.grid_pos = .{ x, screen.cursor.y },
.color = .{ cursor_color.r, cursor_color.g, cursor_color.b, alpha },
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
@@ -3153,7 +3146,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
@intCast(render.glyph.offset_x),
@intCast(render.glyph.offset_y),
},
- });
+ }, cursor_style);
}
fn addPreeditCell(
@@ -3193,7 +3186,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
// Add our text
try self.cells.add(self.alloc, .text, .{
- .mode = .fg,
+ .atlas = .grayscale,
.grid_pos = .{ @intCast(coord.x), @intCast(coord.y) },
.color = .{ fg.r, fg.g, fg.b, 255 },
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
diff --git a/src/renderer/metal/Frame.zig b/src/renderer/metal/Frame.zig
index 81b38e7b6..c766fb8ed 100644
--- a/src/renderer/metal/Frame.zig
+++ b/src/renderer/metal/Frame.zig
@@ -28,7 +28,7 @@ pub const Options = struct {
/// MTLCommandBuffer
buffer: objc.Object,
-block: CompletionBlock,
+block: CompletionBlock.Context,
/// Begin encoding a frame.
pub fn begin(
@@ -47,7 +47,7 @@ pub fn begin(
// Create our block to register for completion updates.
// The block is deallocated by the objC runtime on success.
- const block = try CompletionBlock.init(
+ const block = CompletionBlock.init(
.{
.renderer = renderer,
.target = target,
@@ -55,7 +55,6 @@ pub fn begin(
},
&bufferCompleted,
);
- errdefer block.deinit();
return .{ .buffer = buffer, .block = block };
}
@@ -114,24 +113,23 @@ pub inline fn complete(self: *Self, sync: bool) void {
// If we don't need to complete synchronously,
// we add our block as a completion handler.
//
- // It will be deallocated by the objc runtime on success.
+ // It will be copied when we add the handler, and then the
+ // copy will be deallocated by the objc runtime on success.
if (!sync) {
self.buffer.msgSend(
void,
objc.sel("addCompletedHandler:"),
- .{self.block.context},
+ .{&self.block},
);
}
self.buffer.msgSend(void, objc.sel("commit"), .{});
// If we need to complete synchronously, we wait until
- // the buffer is completed and call the callback directly,
- // deiniting the block after we're done.
+ // the buffer is completed and invoke the block directly.
if (sync) {
self.buffer.msgSend(void, "waitUntilCompleted", .{});
- self.block.context.sync = true;
- bufferCompleted(self.block.context, self.buffer.value);
- self.block.deinit();
+ self.block.sync = true;
+ CompletionBlock.invoke(&self.block, .{self.buffer.value});
}
}
diff --git a/src/renderer/metal/IOSurfaceLayer.zig b/src/renderer/metal/IOSurfaceLayer.zig
index 9212bd5e1..5a6bf7307 100644
--- a/src/renderer/metal/IOSurfaceLayer.zig
+++ b/src/renderer/metal/IOSurfaceLayer.zig
@@ -54,13 +54,11 @@ pub inline fn setSurface(self: *IOSurfaceLayer, surface: *IOSurface) !void {
//
// We release in the callback after setting the contents.
surface.retain();
- // We also need to retain the layer itself to make sure it
- // isn't destroyed before the callback completes, since if
- // that happens it will try to interact with a deallocated
- // object.
- _ = self.layer.retain();
+ // NOTE: Since `self.layer` is passed as an `objc.c.id`, it's
+ // automatically retained when the block is copied, so we
+ // don't need to retain it ourselves like with the surface.
- var block = try SetSurfaceBlock.init(.{
+ var block = SetSurfaceBlock.init(.{
.layer = self.layer.value,
.surface = surface,
}, &setSurfaceCallback);
@@ -68,15 +66,15 @@ pub inline fn setSurface(self: *IOSurfaceLayer, surface: *IOSurface) !void {
// We check if we're on the main thread and run the block directly if so.
const NSThread = objc.getClass("NSThread").?;
if (NSThread.msgSend(bool, "isMainThread", .{})) {
- setSurfaceCallback(block.context);
- block.deinit();
+ setSurfaceCallback(&block);
} else {
- // NOTE: The block will automatically be deallocated by the objc
- // runtime once it's executed, so there's no need to deinit it.
+ // NOTE: The block will be copied when we pass it to dispatch_async,
+ // and then automatically be deallocated by the objc runtime
+ // once it's executed.
macos.dispatch.dispatch_async(
@ptrCast(macos.dispatch.queue.getMain()),
- @ptrCast(block.context),
+ @ptrCast(&block),
);
}
}
@@ -100,10 +98,7 @@ fn setSurfaceCallback(
const surface: *IOSurface = block.surface;
// See explanation of why we retain and release in `setSurface`.
- defer {
- surface.release();
- layer.release();
- }
+ defer surface.release();
// We check to see if the surface is the appropriate size for
// the layer, if it's not then we discard it. This is because
diff --git a/src/renderer/metal/Target.zig b/src/renderer/metal/Target.zig
index fa62d3014..15780189b 100644
--- a/src/renderer/metal/Target.zig
+++ b/src/renderer/metal/Target.zig
@@ -68,7 +68,7 @@ pub fn init(opts: Options) !Self {
const id_init = id_alloc.msgSend(objc.Object, objc.sel("init"), .{});
break :init id_init;
};
- errdefer desc.msgSend(void, objc.sel("release"), .{});
+ defer desc.release();
// Set our properties
desc.setProperty("width", @as(c_ulong, @intCast(opts.width)));
diff --git a/src/renderer/metal/Texture.zig b/src/renderer/metal/Texture.zig
index 32820f8fc..5e6ef78d0 100644
--- a/src/renderer/metal/Texture.zig
+++ b/src/renderer/metal/Texture.zig
@@ -50,7 +50,7 @@ pub fn init(
const id_init = id_alloc.msgSend(objc.Object, objc.sel("init"), .{});
break :init id_init;
};
- errdefer desc.msgSend(void, objc.sel("release"), .{});
+ defer desc.release();
// Set our properties
desc.setProperty("pixelFormat", @intFromEnum(opts.pixel_format));
diff --git a/src/renderer/metal/shaders.zig b/src/renderer/metal/shaders.zig
index 9fe0862ed..bf3bcc6e4 100644
--- a/src/renderer/metal/shaders.zig
+++ b/src/renderer/metal/shaders.zig
@@ -269,15 +269,16 @@ pub const CellText = extern struct {
bearings: [2]i16 align(4) = .{ 0, 0 },
grid_pos: [2]u16 align(4),
color: [4]u8 align(4),
- mode: Mode align(1),
- constraint_width: u8 align(1) = 0,
+ atlas: Atlas align(1),
+ bools: packed struct(u8) {
+ no_min_contrast: bool = false,
+ is_cursor_glyph: bool = false,
+ _padding: u6 = 0,
+ } align(1) = .{},
- pub const Mode = enum(u8) {
- fg = 1,
- fg_constrained = 2,
- fg_color = 3,
- cursor = 4,
- fg_powerline = 5,
+ pub const Atlas = enum(u8) {
+ grayscale = 0,
+ color = 1,
};
test {
diff --git a/src/renderer/opengl/Texture.zig b/src/renderer/opengl/Texture.zig
index 9be2b7078..2f3e7f46a 100644
--- a/src/renderer/opengl/Texture.zig
+++ b/src/renderer/opengl/Texture.zig
@@ -16,6 +16,10 @@ pub const Options = struct {
format: gl.Texture.Format,
internal_format: gl.Texture.InternalFormat,
target: gl.Texture.Target,
+ min_filter: gl.Texture.MinFilter,
+ mag_filter: gl.Texture.MagFilter,
+ wrap_s: gl.Texture.Wrap,
+ wrap_t: gl.Texture.Wrap,
};
texture: gl.Texture,
@@ -48,10 +52,10 @@ pub fn init(
{
const texbind = tex.bind(opts.target) catch return error.OpenGLFailed;
defer texbind.unbind();
- texbind.parameter(.WrapS, gl.c.GL_CLAMP_TO_EDGE) catch return error.OpenGLFailed;
- texbind.parameter(.WrapT, gl.c.GL_CLAMP_TO_EDGE) catch return error.OpenGLFailed;
- texbind.parameter(.MinFilter, gl.c.GL_LINEAR) catch return error.OpenGLFailed;
- texbind.parameter(.MagFilter, gl.c.GL_LINEAR) catch return error.OpenGLFailed;
+ texbind.parameter(.WrapS, @intFromEnum(opts.wrap_s)) catch return error.OpenGLFailed;
+ texbind.parameter(.WrapT, @intFromEnum(opts.wrap_t)) catch return error.OpenGLFailed;
+ texbind.parameter(.MinFilter, @intFromEnum(opts.min_filter)) catch return error.OpenGLFailed;
+ texbind.parameter(.MagFilter, @intFromEnum(opts.mag_filter)) catch return error.OpenGLFailed;
texbind.image2D(
0,
opts.internal_format,
diff --git a/src/renderer/opengl/shaders.zig b/src/renderer/opengl/shaders.zig
index 0b67eaff0..80980bac7 100644
--- a/src/renderer/opengl/shaders.zig
+++ b/src/renderer/opengl/shaders.zig
@@ -237,15 +237,16 @@ pub const CellText = extern struct {
bearings: [2]i16 align(4) = .{ 0, 0 },
grid_pos: [2]u16 align(4),
color: [4]u8 align(4),
- mode: Mode align(4),
- constraint_width: u32 align(4) = 0,
+ atlas: Atlas align(1),
+ bools: packed struct(u8) {
+ no_min_contrast: bool = false,
+ is_cursor_glyph: bool = false,
+ _padding: u6 = 0,
+ } align(1) = .{},
- pub const Mode = enum(u32) {
- fg = 1,
- fg_constrained = 2,
- fg_color = 3,
- cursor = 4,
- fg_powerline = 5,
+ pub const Atlas = enum(u8) {
+ grayscale = 0,
+ color = 1,
};
// test {
diff --git a/src/renderer/shaders/glsl/cell_bg.f.glsl b/src/renderer/shaders/glsl/cell_bg.f.glsl
index 7ba6caaa6..fa48c6736 100644
--- a/src/renderer/shaders/glsl/cell_bg.f.glsl
+++ b/src/renderer/shaders/glsl/cell_bg.f.glsl
@@ -1,7 +1,7 @@
#include "common.glsl"
// Position the origin to the upper left
-layout(origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;
+layout(origin_upper_left) in vec4 gl_FragCoord;
// Must declare this output for some versions of OpenGL.
layout(location = 0) out vec4 out_FragColor;
diff --git a/src/renderer/shaders/glsl/cell_text.f.glsl b/src/renderer/shaders/glsl/cell_text.f.glsl
index fda6d8134..176efcbde 100644
--- a/src/renderer/shaders/glsl/cell_text.f.glsl
+++ b/src/renderer/shaders/glsl/cell_text.f.glsl
@@ -4,21 +4,15 @@ layout(binding = 0) uniform sampler2DRect atlas_grayscale;
layout(binding = 1) uniform sampler2DRect atlas_color;
in CellTextVertexOut {
- flat uint mode;
+ flat uint atlas;
flat vec4 color;
flat vec4 bg_color;
vec2 tex_coord;
} in_data;
-// These are the possible modes that "mode" can be set to. This is
-// used to multiplex multiple render modes into a single shader.
-//
-// NOTE: this must be kept in sync with the fragment shader
-const uint MODE_TEXT = 1u;
-const uint MODE_TEXT_CONSTRAINED = 2u;
-const uint MODE_TEXT_COLOR = 3u;
-const uint MODE_TEXT_CURSOR = 4u;
-const uint MODE_TEXT_POWERLINE = 5u;
+// Values `atlas` can take.
+const uint ATLAS_GRAYSCALE = 0u;
+const uint ATLAS_COLOR = 1u;
// Must declare this output for some versions of OpenGL.
layout(location = 0) out vec4 out_FragColor;
@@ -27,12 +21,9 @@ void main() {
bool use_linear_blending = (bools & USE_LINEAR_BLENDING) != 0;
bool use_linear_correction = (bools & USE_LINEAR_CORRECTION) != 0;
- switch (in_data.mode) {
+ switch (in_data.atlas) {
default:
- case MODE_TEXT_CURSOR:
- case MODE_TEXT_CONSTRAINED:
- case MODE_TEXT_POWERLINE:
- case MODE_TEXT:
+ case ATLAS_GRAYSCALE:
{
// Our input color is always linear.
vec4 color = in_data.color;
@@ -84,7 +75,7 @@ void main() {
return;
}
- case MODE_TEXT_COLOR:
+ case ATLAS_COLOR:
{
// For now, we assume that color glyphs
// are already premultiplied linear colors.
diff --git a/src/renderer/shaders/glsl/cell_text.v.glsl b/src/renderer/shaders/glsl/cell_text.v.glsl
index 10965ddd2..7e38e2f0c 100644
--- a/src/renderer/shaders/glsl/cell_text.v.glsl
+++ b/src/renderer/shaders/glsl/cell_text.v.glsl
@@ -15,22 +15,22 @@ layout(location = 3) in uvec2 grid_pos;
// The color of the rendered text glyph.
layout(location = 4) in uvec4 color;
-// The mode for this cell.
-layout(location = 5) in uint mode;
+// Which atlas this glyph is in.
+layout(location = 5) in uint atlas;
-// The width to constrain the glyph to, in cells, or 0 for no constraint.
-layout(location = 6) in uint constraint_width;
+// Misc glyph properties.
+layout(location = 6) in uint glyph_bools;
-// These are the possible modes that "mode" can be set to. This is
-// used to multiplex multiple render modes into a single shader.
-const uint MODE_TEXT = 1u;
-const uint MODE_TEXT_CONSTRAINED = 2u;
-const uint MODE_TEXT_COLOR = 3u;
-const uint MODE_TEXT_CURSOR = 4u;
-const uint MODE_TEXT_POWERLINE = 5u;
+// Values `atlas` can take.
+const uint ATLAS_GRAYSCALE = 0u;
+const uint ATLAS_COLOR = 1u;
+
+// Masks for the `glyph_bools` attribute
+const uint NO_MIN_CONTRAST = 1u;
+const uint IS_CURSOR_GLYPH = 2u;
out CellTextVertexOut {
- flat uint mode;
+ flat uint atlas;
flat vec4 color;
flat vec4 bg_color;
vec2 tex_coord;
@@ -69,7 +69,7 @@ void main() {
corner.x = float(vid == 1 || vid == 3);
corner.y = float(vid == 2 || vid == 3);
- out_data.mode = mode;
+ out_data.atlas = atlas;
// === Grid Cell ===
// +X
@@ -102,25 +102,6 @@ void main() {
offset.y = cell_size.y - offset.y;
- // If we're constrained then we need to scale the glyph.
- if (mode == MODE_TEXT_CONSTRAINED) {
- float max_width = cell_size.x * constraint_width;
- // If this glyph is wider than the constraint width,
- // fit it to the width and remove its horizontal offset.
- if (size.x > max_width) {
- float new_y = size.y * (max_width / size.x);
- offset.y += (size.y - new_y) / 2.0;
- offset.x = 0.0;
- size.y = new_y;
- size.x = max_width;
- } else if (max_width - size.x > offset.x) {
- // However, if it does fit in the constraint width, make
- // sure the offset is small enough to not push it over the
- // right edge of the constraint width.
- offset.x = max_width - size.x;
- }
- }
-
// Calculate the final position of the cell which uses our glyph size
// and glyph offset to create the correct bounding box for the glyph.
cell_pos = cell_pos + size * corner + offset;
@@ -149,11 +130,7 @@ void main() {
// If we have a minimum contrast, we need to check if we need to
// change the color of the text to ensure it has enough contrast
// with the background.
- // We only apply this adjustment to "normal" text with MODE_TEXT,
- // since we want color glyphs to appear in their original color
- // and Powerline glyphs to be unaffected (else parts of the line would
- // have different colors as some parts are displayed via background colors).
- if (min_contrast > 1.0f && mode == MODE_TEXT) {
+ if (min_contrast > 1.0f && (glyph_bools & NO_MIN_CONTRAST) == 0) {
// Ensure our minimum contrast
out_data.color = contrasted_color(min_contrast, out_data.color, out_data.bg_color);
}
@@ -161,8 +138,9 @@ void main() {
// Check if current position is under cursor (including wide cursor)
bool is_cursor_pos = ((grid_pos.x == cursor_pos.x) || (cursor_wide && (grid_pos.x == (cursor_pos.x + 1)))) && (grid_pos.y == cursor_pos.y);
- // If this cell is the cursor cell, then we need to change the color.
- if (mode != MODE_TEXT_CURSOR && is_cursor_pos) {
+ // If this cell is the cursor cell, but we're not processing
+ // the cursor glyph itself, then we need to change the color.
+ if ((glyph_bools & IS_CURSOR_GLYPH) == 0 && is_cursor_pos) {
out_data.color = load_color(unpack4u8(cursor_color_packed_4u8), use_linear_blending);
}
}
diff --git a/src/renderer/shaders/shaders.metal b/src/renderer/shaders/shaders.metal
index b62e0c3cf..4797f89e4 100644
--- a/src/renderer/shaders/shaders.metal
+++ b/src/renderer/shaders/shaders.metal
@@ -509,13 +509,17 @@ fragment float4 cell_bg_fragment(
//-------------------------------------------------------------------
#pragma mark - Cell Text Shader
-// The possible modes that a cell fg entry can take.
-enum CellTextMode : uint8_t {
- MODE_TEXT = 1u,
- MODE_TEXT_CONSTRAINED = 2u,
- MODE_TEXT_COLOR = 3u,
- MODE_TEXT_CURSOR = 4u,
- MODE_TEXT_POWERLINE = 5u,
+enum CellTextAtlas : uint8_t {
+ ATLAS_GRAYSCALE = 0u,
+ ATLAS_COLOR = 1u,
+};
+
+// We use a packed struct of bools for misc properties of the glyph.
+enum CellTextBools : uint8_t {
+ // Don't apply min contrast to this glyph.
+ NO_MIN_CONTRAST = 1u,
+ // This is the cursor glyph.
+ IS_CURSOR_GLYPH = 2u,
};
struct CellTextVertexIn {
@@ -534,16 +538,16 @@ struct CellTextVertexIn {
// The color of the rendered text glyph.
uchar4 color [[attribute(4)]];
- // The mode for this cell.
- uint8_t mode [[attribute(5)]];
+ // Which atlas to sample for our glyph.
+ uint8_t atlas [[attribute(5)]];
- // The width to constrain the glyph to, in cells, or 0 for no constraint.
- uint8_t constraint_width [[attribute(6)]];
+ // Misc properties of the glyph.
+ uint8_t bools [[attribute(6)]];
};
struct CellTextVertexOut {
float4 position [[position]];
- uint8_t mode [[flat]];
+ uint8_t atlas [[flat]];
float4 color [[flat]];
float4 bg_color [[flat]];
float2 tex_coord;
@@ -577,7 +581,7 @@ vertex CellTextVertexOut cell_text_vertex(
corner.y = float(vid == 2 || vid == 3);
CellTextVertexOut out;
- out.mode = in.mode;
+ out.atlas = in.atlas;
// === Grid Cell ===
// +X
@@ -610,25 +614,6 @@ vertex CellTextVertexOut cell_text_vertex(
offset.y = uniforms.cell_size.y - offset.y;
- // If we're constrained then we need to scale the glyph.
- if (in.mode == MODE_TEXT_CONSTRAINED) {
- float max_width = uniforms.cell_size.x * in.constraint_width;
- // If this glyph is wider than the constraint width,
- // fit it to the width and remove its horizontal offset.
- if (size.x > max_width) {
- float new_y = size.y * (max_width / size.x);
- offset.y += (size.y - new_y) / 2;
- offset.x = 0;
- size.y = new_y;
- size.x = max_width;
- } else if (max_width - size.x > offset.x) {
- // However, if it does fit in the constraint width, make
- // sure the offset is small enough to not push it over the
- // right edge of the constraint width.
- offset.x = max_width - size.x;
- }
- }
-
// Calculate the final position of the cell which uses our glyph size
// and glyph offset to create the correct bounding box for the glyph.
cell_pos = cell_pos + size * corner + offset;
@@ -665,11 +650,7 @@ vertex CellTextVertexOut cell_text_vertex(
// If we have a minimum contrast, we need to check if we need to
// change the color of the text to ensure it has enough contrast
// with the background.
- // We only apply this adjustment to "normal" text with MODE_TEXT,
- // since we want color glyphs to appear in their original color
- // and Powerline glyphs to be unaffected (else parts of the line would
- // have different colors as some parts are displayed via background colors).
- if (uniforms.min_contrast > 1.0f && in.mode == MODE_TEXT) {
+ if (uniforms.min_contrast > 1.0f && (in.bools & NO_MIN_CONTRAST) == 0) {
// Ensure our minimum contrast
out.color = contrasted_color(uniforms.min_contrast, out.color, out.bg_color);
}
@@ -681,8 +662,9 @@ vertex CellTextVertexOut cell_text_vertex(
in.grid_pos.x == uniforms.cursor_pos.x + 1
) && in.grid_pos.y == uniforms.cursor_pos.y;
- // If this cell is the cursor cell, then we need to change the color.
- if (in.mode != MODE_TEXT_CURSOR && is_cursor_pos) {
+ // If this cell is the cursor cell, but we're not processing
+ // the cursor glyph itself, then we need to change the color.
+ if ((in.bools & IS_CURSOR_GLYPH) == 0 && is_cursor_pos) {
out.color = load_color(
uniforms.cursor_color,
uniforms.use_display_p3,
@@ -702,19 +684,12 @@ fragment float4 cell_text_fragment(
constexpr sampler textureSampler(
coord::pixel,
address::clamp_to_edge,
- // TODO(qwerasd): This can be changed back to filter::nearest when
- // we move the constraint logic out of the GPU code
- // which should once again guarantee pixel perfect
- // sizing.
- filter::linear
+ filter::nearest
);
- switch (in.mode) {
+ switch (in.atlas) {
default:
- case MODE_TEXT_CURSOR:
- case MODE_TEXT_CONSTRAINED:
- case MODE_TEXT_POWERLINE:
- case MODE_TEXT: {
+ case ATLAS_GRAYSCALE: {
// Our input color is always linear.
float4 color = in.color;
@@ -764,7 +739,7 @@ fragment float4 cell_text_fragment(
return color;
}
- case MODE_TEXT_COLOR: {
+ case ATLAS_COLOR: {
// For now, we assume that color glyphs
// are already premultiplied linear colors.
float4 color = textureColor.sample(textureSampler, in.tex_coord);
diff --git a/src/shell-integration/bash/ghostty.bash b/src/shell-integration/bash/ghostty.bash
index 0766198f9..df4c7f9a7 100644
--- a/src/shell-integration/bash/ghostty.bash
+++ b/src/shell-integration/bash/ghostty.bash
@@ -106,7 +106,6 @@ _ghostty_last_reported_cwd=""
function __ghostty_precmd() {
local ret="$?"
if test "$_ghostty_executing" != "0"; then
- _GHOSTTY_SAVE_PS0="$PS0"
_GHOSTTY_SAVE_PS1="$PS1"
_GHOSTTY_SAVE_PS2="$PS2"
@@ -123,8 +122,8 @@ function __ghostty_precmd() {
# Cursor
if [[ "$GHOSTTY_SHELL_FEATURES" == *"cursor"* ]]; then
- PS1=$PS1'\[\e[5 q\]'
- PS0=$PS0'\[\e[0 q\]'
+ [[ "$PS1" != *'\[\e[5 q\]'* ]] && PS1=$PS1'\[\e[5 q\]' # input
+ [[ "$PS0" != *'\[\e[0 q\]'* ]] && PS0=$PS0'\[\e[0 q\]' # reset
fi
# Title (working directory)
@@ -154,7 +153,6 @@ function __ghostty_precmd() {
function __ghostty_preexec() {
builtin local cmd="$1"
- PS0="$_GHOSTTY_SAVE_PS0"
PS1="$_GHOSTTY_SAVE_PS1"
PS2="$_GHOSTTY_SAVE_PS2"
diff --git a/src/terminal/style.zig b/src/terminal/style.zig
index 865e15f64..deb2b8ec5 100644
--- a/src/terminal/style.zig
+++ b/src/terminal/style.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const assert = std.debug.assert;
+const configpkg = @import("../config.zig");
const color = @import("color.zig");
const sgr = @import("sgr.zig");
const page = @import("page.zig");
@@ -115,24 +116,65 @@ pub const Style = struct {
};
}
- /// Returns the fg color for a cell with this style given the palette.
+ pub const Fg = struct {
+ /// The default color to use if the style doesn't specify a
+ /// foreground color and no configuration options override
+ /// it.
+ default: color.RGB,
+
+ /// The current color palette. Required to map palette indices to
+ /// real color values.
+ palette: *const color.Palette,
+
+ /// If specified, the color to use for bold text.
+ bold: ?configpkg.BoldColor = null,
+ };
+
+ /// Returns the fg color for a cell with this style given the palette
+ /// and various configuration options.
pub fn fg(
self: Style,
- palette: *const color.Palette,
- bold_is_bright: bool,
- ) ?color.RGB {
+ opts: Fg,
+ ) color.RGB {
+ // Note we don't pull the bold check to the top-level here because
+ // we don't want to duplicate the conditional multiple times since
+ // certain colors require more checks (e.g. `bold_is_bright`).
+
return switch (self.fg_color) {
- .none => null,
- .palette => |idx| palette: {
- if (bold_is_bright and self.flags.bold) {
- const bright_offset = @intFromEnum(color.Name.bright_black);
- if (idx < bright_offset)
- break :palette palette[idx + bright_offset];
+ .none => default: {
+ if (self.flags.bold) {
+ if (opts.bold) |bold| switch (bold) {
+ .bright => {},
+ .color => |v| break :default v.toTerminalRGB(),
+ };
}
- break :palette palette[idx];
+ break :default opts.default;
+ },
+
+ .palette => |idx| palette: {
+ if (self.flags.bold) {
+ if (opts.bold) |_| {
+ const bright_offset = @intFromEnum(color.Name.bright_black);
+ if (idx < bright_offset) {
+ break :palette opts.palette[idx + bright_offset];
+ }
+ }
+ }
+
+ break :palette opts.palette[idx];
+ },
+
+ .rgb => |rgb| rgb: {
+ if (self.flags.bold and rgb.eql(opts.default)) {
+ if (opts.bold) |bold| switch (bold) {
+ .color => |v| break :rgb v.toTerminalRGB(),
+ .bright => {},
+ };
+ }
+
+ break :rgb rgb;
},
- .rgb => |rgb| rgb,
};
}
diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig
index b8f838cf9..15b6b8cd4 100644
--- a/src/termio/Exec.zig
+++ b/src/termio/Exec.zig
@@ -90,15 +90,13 @@ pub fn threadEnter(
// Start our subprocess
const pty_fds = self.subprocess.start(alloc) catch |err| {
// If we specifically got this error then we are in the forked
- // process and our child failed to execute. In that case
- if (err != error.Termio) return err;
+ // process and our child failed to execute. If we DIDN'T
+ // get this specific error then we're in the parent and
+ // we need to bubble it up.
+ if (err != error.ExecFailedInChild) return err;
- // Output an error message about the exec faililng and exit.
- // This generally should NOT happen because we always wrap
- // our command execution either in login (macOS) or /bin/sh
- // (Linux) which are usually guaranteed to exist. Still, we
- // want to handle this scenario.
- execFailedInChild() catch {};
+ // We're in the child. Nothing more we can do but abnormal exit.
+ // The Command will output some additional information.
posix.exit(1);
};
errdefer self.subprocess.stop();
@@ -272,25 +270,6 @@ pub fn resize(
return try self.subprocess.resize(grid_size, screen_size);
}
-/// This outputs an error message when exec failed and we are the
-/// child process. This returns so the caller should probably exit
-/// after calling this.
-///
-/// Note that this usually is only called under very very rare
-/// circumstances because we wrap our command execution in login
-/// (macOS) or /bin/sh (Linux). So this output can be pretty crude
-/// because it should never happen. Notably, this is not the error
-/// users see when `command` is invalid.
-fn execFailedInChild() !void {
- const stderr = std.io.getStdErr().writer();
- try stderr.writeAll("exec failed\n");
- try stderr.writeAll("press any key to exit\n");
-
- var buf: [1]u8 = undefined;
- var reader = std.io.getStdIn().reader();
- _ = try reader.read(&buf);
-}
-
fn processExitCommon(td: *termio.Termio.ThreadData, exit_code: u32) void {
assert(td.backend == .exec);
const execdata = &td.backend.exec;
@@ -847,6 +826,15 @@ const Subprocess = struct {
else
null;
+ // Propagate the current working directory (CWD) to the shell, enabling
+ // the shell to display the current directory name rather than the
+ // resolved path for symbolic links. This is important and based
+ // on the same behavior in Konsole and Kitty (see the linked issues):
+ // https://bugs.kde.org/show_bug.cgi?id=242114
+ // https://github.com/kovidgoyal/kitty/issues/1595
+ // https://github.com/ghostty-org/ghostty/discussions/7769
+ if (cwd) |pwd| try env.put("PWD", pwd);
+
// If we have a cgroup, then we copy that into our arena so the
// memory remains valid when we start.
const linux_cgroup: Command.LinuxCgroup = cgroup: {
@@ -886,6 +874,12 @@ const Subprocess = struct {
} {
assert(self.pty == null and self.command == null);
+ // This function is funny because on POSIX systems it can
+ // fail in the forked process. This is flipped to true if
+ // we're in an error state in the forked process (child
+ // process).
+ var in_child: bool = false;
+
// Create our pty
var pty = try Pty.open(.{
.ws_row = @intCast(self.grid_size.rows),
@@ -894,14 +888,14 @@ const Subprocess = struct {
.ws_ypixel = @intCast(self.screen_size.height),
});
self.pty = pty;
- errdefer {
+ errdefer if (!in_child) {
if (comptime builtin.os.tag != .windows) {
_ = posix.close(pty.slave);
}
pty.deinit();
self.pty = null;
- }
+ };
log.debug("starting command command={s}", .{self.args});
@@ -1004,7 +998,22 @@ const Subprocess = struct {
.data = self,
.linux_cgroup = self.linux_cgroup,
};
- try cmd.start(alloc);
+
+ cmd.start(alloc) catch |err| {
+ // We have to do this because start on Windows can't
+ // ever return ExecFailedInChild
+ const StartError = error{ExecFailedInChild} || @TypeOf(err);
+ switch (@as(StartError, err)) {
+ // If we fail in our child we need to flag it so our
+ // errdefers don't run.
+ error.ExecFailedInChild => {
+ in_child = true;
+ return err;
+ },
+
+ else => return err,
+ }
+ };
errdefer killCommand(&cmd) catch |err| {
log.warn("error killing command during cleanup err={}", .{err});
};
diff --git a/src/termio/Termio.zig b/src/termio/Termio.zig
index 8aaa87011..4b5b93641 100644
--- a/src/termio/Termio.zig
+++ b/src/termio/Termio.zig
@@ -163,8 +163,7 @@ pub const DerivedConfig = struct {
image_storage_limit: usize,
cursor_style: terminalpkg.CursorStyle,
cursor_blink: ?bool,
- cursor_color: ?configpkg.Config.Color,
- cursor_invert: bool,
+ cursor_color: ?configpkg.Config.TerminalColor,
foreground: configpkg.Config.Color,
background: configpkg.Config.Color,
osc_color_report_format: configpkg.Config.OSCColorReportFormat,
@@ -185,7 +184,6 @@ pub const DerivedConfig = struct {
.cursor_style = config.@"cursor-style",
.cursor_blink = config.@"cursor-style-blink",
.cursor_color = config.@"cursor-color",
- .cursor_invert = config.@"cursor-invert-fg-bg",
.foreground = config.foreground,
.background = config.background,
.osc_color_report_format = config.@"osc-color-report-format",
@@ -265,10 +263,16 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
// Create our stream handler. This points to memory in self so it
// isn't safe to use until self.* is set.
const handler: StreamHandler = handler: {
- const default_cursor_color = if (!opts.config.cursor_invert and opts.config.cursor_color != null)
- opts.config.cursor_color.?.toTerminalRGB()
- else
- null;
+ const default_cursor_color: ?terminalpkg.color.RGB = color: {
+ if (opts.config.cursor_color) |color| switch (color) {
+ .color => break :color color.color.toTerminalRGB(),
+ .@"cell-foreground",
+ .@"cell-background",
+ => {},
+ };
+
+ break :color null;
+ };
break :handler .{
.alloc = alloc,
diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig
index 1b4fdd3aa..039b11c03 100644
--- a/src/termio/stream_handler.zig
+++ b/src/termio/stream_handler.zig
@@ -15,11 +15,6 @@ const posix = std.posix;
const log = std.log.scoped(.io_handler);
-/// True if we should disable the kitty keyboard protocol. We have to
-/// disable this on GLFW because GLFW input events don't support the
-/// correct granularity of events.
-const disable_kitty_keyboard_protocol = apprt.runtime == apprt.glfw;
-
/// This is used as the handler for the terminal.Stream type. This is
/// stateful and is expected to live for the entire lifetime of the terminal.
/// It is NOT VALID to stop a stream handler, create a new one, and use that
@@ -121,10 +116,16 @@ pub const StreamHandler = struct {
self.default_background_color = config.background.toTerminalRGB();
self.default_cursor_style = config.cursor_style;
self.default_cursor_blink = config.cursor_blink;
- self.default_cursor_color = if (!config.cursor_invert and config.cursor_color != null)
- config.cursor_color.?.toTerminalRGB()
- else
- null;
+ self.default_cursor_color = color: {
+ if (config.cursor_color) |color| switch (color) {
+ .color => break :color color.color.toTerminalRGB(),
+ .@"cell-foreground",
+ .@"cell-background",
+ => {},
+ };
+
+ break :color null;
+ };
// If our cursor is the default, then we update it immediately.
if (self.default_cursor) self.setCursorStyle(.default) catch |err| {
@@ -907,8 +908,6 @@ pub const StreamHandler = struct {
}
pub fn queryKittyKeyboard(self: *StreamHandler) !void {
- if (comptime disable_kitty_keyboard_protocol) return;
-
log.debug("querying kitty keyboard mode", .{});
var data: termio.Message.WriteReq.Small.Array = undefined;
const resp = try std.fmt.bufPrint(&data, "\x1b[?{}u", .{
@@ -927,15 +926,11 @@ pub const StreamHandler = struct {
self: *StreamHandler,
flags: terminal.kitty.KeyFlags,
) !void {
- if (comptime disable_kitty_keyboard_protocol) return;
-
log.debug("pushing kitty keyboard mode: {}", .{flags});
self.terminal.screen.kitty_keyboard.push(flags);
}
pub fn popKittyKeyboard(self: *StreamHandler, n: u16) !void {
- if (comptime disable_kitty_keyboard_protocol) return;
-
log.debug("popping kitty keyboard mode n={}", .{n});
self.terminal.screen.kitty_keyboard.pop(@intCast(n));
}
@@ -945,8 +940,6 @@ pub const StreamHandler = struct {
mode: terminal.kitty.KeySetMode,
flags: terminal.kitty.KeyFlags,
) !void {
- if (comptime disable_kitty_keyboard_protocol) return;
-
log.debug("setting kitty keyboard mode: {} {}", .{ mode, flags });
self.terminal.screen.kitty_keyboard.set(mode, flags);
}
diff --git a/vendor/nerd-fonts/LICENSE b/vendor/nerd-fonts/LICENSE
new file mode 100644
index 000000000..d163912b3
--- /dev/null
+++ b/vendor/nerd-fonts/LICENSE
@@ -0,0 +1,126 @@
+# Nerd Fonts Licensing
+
+There are various sources used under various licenses:
+
+* Nerd Fonts source fonts, patched fonts, and folders with explict OFL SIL files are licensed under SIL OPEN FONT LICENSE Version 1.1 (see below).
+* Nerd Fonts original source code files (such as `.sh`, `.py`, `font-patcher` and others) are licensed under the MIT License (MIT) (see below).
+* Many other licenses are present in this project for even more detailed breakdown see: [License Audit](https://github.com/ryanoasis/nerd-fonts/blob/-/license-audit.md).
+
+## Source files not in folders containing an explicit license are using the MIT License (MIT)
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Ryan L McIntyre
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+## Various Fonts, Patched Fonts, SVGs, Glyph Fonts, and any files in a folder with explicit SIL OFL 1.1 License
+
+Copyright (c) 2014, Ryan L McIntyre (https://ryanlmcintyre.com).
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/vendor/nerd-fonts/README.md b/vendor/nerd-fonts/README.md
new file mode 100644
index 000000000..66dec54cb
--- /dev/null
+++ b/vendor/nerd-fonts/README.md
@@ -0,0 +1,10 @@
+We have a copy of the `font-patcher` file from `nerd-fonts` here, fetched from
+https://github.com/ryanoasis/nerd-fonts/blob/master/font-patcher.
+
+This is MIT licensed, see `LICENSE` in this directory.
+
+We use parse a section of this file to codegen a lookup table of the nerd font
+scaling rules. See `src/font/nerd_font_codegen.py` in the main Ghostty source
+tree for more info.
+
+Last fetched commit: ebc376cbd43f609d8084f47dd348646595ce066e
diff --git a/vendor/nerd-fonts/font-patcher.py b/vendor/nerd-fonts/font-patcher.py
new file mode 100644
index 000000000..6c7ebfe37
--- /dev/null
+++ b/vendor/nerd-fonts/font-patcher.py
@@ -0,0 +1,2296 @@
+#!/usr/bin/env python
+# coding=utf8
+# Nerd Fonts Version: 3.4.0
+# Script version is further down
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+# Change the script version when you edit this script:
+script_version = "4.20.5"
+
+version = "3.4.0"
+projectName = "Nerd Fonts"
+projectNameAbbreviation = "NF"
+projectNameSingular = projectName[:-1]
+
+import sys
+import re
+import os
+import argparse
+from argparse import RawTextHelpFormatter
+import errno
+import subprocess
+import json
+from enum import Enum
+import logging
+try:
+ import configparser
+except ImportError:
+ sys.exit(projectName + ": configparser module is probably not installed. Try `pip install configparser` or equivalent")
+try:
+ import psMat
+ import fontforge
+except ImportError:
+ sys.exit(
+ projectName + (
+ ": FontForge module could not be loaded. Try installing fontforge python bindings "
+ "[e.g. on Linux Debian or Ubuntu: `sudo apt install fontforge python3-fontforge`]"
+ )
+ )
+
+sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'bin', 'scripts', 'name_parser'))
+try:
+ from FontnameParser import FontnameParser
+ from FontnameTools import FontnameTools
+ FontnameParserOK = True
+except ImportError:
+ FontnameParserOK = False
+
+class TableHEADWriter:
+ """ Access to the HEAD table without external dependencies """
+ def getlong(self, pos = None):
+ """ Get four bytes from the font file as integer number """
+ if pos:
+ self.goto(pos)
+ return (ord(self.f.read(1)) << 24) + (ord(self.f.read(1)) << 16) + (ord(self.f.read(1)) << 8) + ord(self.f.read(1))
+
+ def getshort(self, pos = None):
+ """ Get two bytes from the font file as integer number """
+ if pos:
+ self.goto(pos)
+ return (ord(self.f.read(1)) << 8) + ord(self.f.read(1))
+
+ def putlong(self, num, pos = None):
+ """ Put number as four bytes into font file """
+ if pos:
+ self.goto(pos)
+ self.f.write(bytearray([(num >> 24) & 0xFF, (num >> 16) & 0xFF ,(num >> 8) & 0xFF, num & 0xFF]))
+ self.modified = True
+
+ def putshort(self, num, pos = None):
+ """ Put number as two bytes into font file """
+ if pos:
+ self.goto(pos)
+ self.f.write(bytearray([(num >> 8) & 0xFF, num & 0xFF]))
+ self.modified = True
+
+ def calc_checksum(self, start, end, checksum = 0):
+ """ Calculate a font table checksum, optionally ignoring another embedded checksum value (for table 'head') """
+ self.f.seek(start)
+ for i in range(start, end - 4, 4):
+ checksum += self.getlong()
+ checksum &= 0xFFFFFFFF
+ i += 4
+ extra = 0
+ for j in range(4):
+ extra = extra << 8
+ if i + j <= end:
+ extra += ord(self.f.read(1))
+ checksum = (checksum + extra) & 0xFFFFFFFF
+ return checksum
+
+ def find_table(self, tablenames, idx):
+ """ Search all tables for one of the tables in tablenames and store its metadata """
+ # Use font with index idx if this is a font collection file
+ self.f.seek(0, 0)
+ tag = self.f.read(4)
+ if tag == b'ttcf':
+ self.f.seek(2*2, 1)
+ self.num_fonts = self.getlong()
+ if (idx >= self.num_fonts):
+ raise Exception('Trying to access subfont index {} but have only {} fonts'.format(idx, num_fonts))
+ for _ in range(idx + 1):
+ offset = self.getlong()
+ self.f.seek(offset, 0)
+ elif idx != 0:
+ raise Exception('Trying to access subfont but file is no collection')
+ else:
+ self.f.seek(0, 0)
+ self.num_fonts = 1
+
+ self.f.seek(4, 1)
+ numtables = self.getshort()
+ self.f.seek(3*2, 1)
+
+ for i in range(numtables):
+ tab_name = self.f.read(4)
+ self.tab_check_offset = self.f.tell()
+ self.tab_check = self.getlong()
+ self.tab_offset = self.getlong()
+ self.tab_length = self.getlong()
+ if tab_name in tablenames:
+ return True
+ return False
+
+ def find_head_table(self, idx):
+ """ Search all tables for the HEAD table and store its metadata """
+ # Use font with index idx if this is a font collection file
+ found = self.find_table([ b'head' ], idx)
+ if not found:
+ raise Exception('No HEAD table found in font idx {}'.format(idx))
+
+
+ def goto(self, where):
+ """ Go to a named location in the file or to the specified index """
+ if isinstance(where, str):
+ positions = {'checksumAdjustment': 2+2+4,
+ 'flags': 2+2+4+4+4,
+ 'lowestRecPPEM': 2+2+4+4+4+2+2+8+8+2+2+2+2+2,
+ 'avgWidth': 2,
+ }
+ where = self.tab_offset + positions[where]
+ self.f.seek(where)
+
+
+ def calc_full_checksum(self, check = False):
+ """ Calculate the whole file's checksum """
+ self.f.seek(0, 2)
+ self.end = self.f.tell()
+ full_check = self.calc_checksum(0, self.end, (-self.checksum_adj) & 0xFFFFFFFF)
+ if check and (0xB1B0AFBA - full_check) & 0xFFFFFFFF != self.checksum_adj:
+ sys.exit("Checksum of whole font is bad")
+ return full_check
+
+ def calc_table_checksum(self, check = False):
+ tab_check_new = self.calc_checksum(self.tab_offset, self.tab_offset + self.tab_length - 1, (-self.checksum_adj) & 0xFFFFFFFF)
+ if check and tab_check_new != self.tab_check:
+ sys.exit("Checksum of 'head' in font is bad")
+ return tab_check_new
+
+ def reset_table_checksum(self):
+ new_check = self.calc_table_checksum()
+ self.putlong(new_check, self.tab_check_offset)
+
+ def reset_full_checksum(self):
+ new_adj = (0xB1B0AFBA - self.calc_full_checksum()) & 0xFFFFFFFF
+ self.putlong(new_adj, 'checksumAdjustment')
+
+ def close(self):
+ self.f.close()
+
+
+ def __init__(self, filename):
+ self.modified = False
+ self.f = open(filename, 'r+b')
+
+ self.find_head_table(0)
+
+ self.flags = self.getshort('flags')
+ self.lowppem = self.getshort('lowestRecPPEM')
+ self.checksum_adj = self.getlong('checksumAdjustment')
+
+def check_panose_monospaced(font):
+ """ Check if the font's Panose flags say it is monospaced """
+ # https://forum.high-logic.com/postedfiles/Panose.pdf
+ panose = list(font.os2_panose)
+ if panose[0] < 2 or panose[0] > 5:
+ return -1 # invalid Panose info
+ panose_mono = ((panose[0] == 2 and panose[3] == 9) or
+ (panose[0] == 3 and panose[3] == 3))
+ return 1 if panose_mono else 0
+
+def panose_check_to_text(value, panose = False):
+ """ Convert value from check_panose_monospaced() to human readable string """
+ if value == 0:
+ return "Panose says \"not monospaced\""
+ if value == 1:
+ return "Panose says \"monospaced\""
+ return "Panose is invalid" + (" ({})".format(list(panose)) if panose else "")
+
+def panose_proportion_to_text(value):
+ """ Interpret a Panose proportion value (4th value) for family 2 (latin text) """
+ proportion = {
+ 0: "Any", 1: "No Fit", 2: "Old Style", 3: "Modern", 4: "Even Width",
+ 5: "Extended", 6: "Condensed", 7: "Very Extended", 8: "Very Condensed",
+ 9: "Monospaced" }
+ return proportion.get(value, "??? {}".format(value))
+
+def is_monospaced(font):
+ """ Check if a font is probably monospaced """
+ # Some fonts lie (or have not any Panose flag set), spot check monospaced:
+ width = -1
+ width_mono = True
+ for glyph in [ 0x49, 0x4D, 0x57, 0x61, 0x69, 0x6d, 0x2E ]: # wide and slim glyphs 'I', 'M', 'W', 'a', 'i', 'm', '.'
+ if not glyph in font:
+ # A 'strange' font, believe Panose
+ return (check_panose_monospaced(font) == 1, None)
+ # print(" -> {} {}".format(glyph, font[glyph].width))
+ if width < 0:
+ width = font[glyph].width
+ continue
+ if font[glyph].width != width:
+ # Exception for fonts like Code New Roman Regular or Hermit Light/Bold:
+ # Allow small 'i' and dot to be smaller than normal
+ # I believe the source fonts are buggy
+ if glyph in [ 0x69, 0x2E ]:
+ if width > font[glyph].width:
+ continue
+ (xmin, _, xmax, _) = font[glyph].boundingBox()
+ if width > xmax - xmin:
+ continue
+ width_mono = False
+ break
+ # We believe our own check more then Panose ;-D
+ return (width_mono, None if width_mono else glyph)
+
+def force_panose_monospaced(font):
+ """ Forces the Panose flag to monospaced if they are unset or halfway ok already """
+ # For some Windows applications (e.g. 'cmd'), they seem to honour the Panose table
+ # https://forum.high-logic.com/postedfiles/Panose.pdf
+ panose = list(font.os2_panose)
+ if panose[0] == 0: # 0 (1st value) = family kind; 0 = any (default)
+ panose[0] = 2 # make kind latin text and display
+ logger.info("Setting Panose 'Family Kind' to 'Latin Text and Display' (was 'Any')")
+ font.os2_panose = tuple(panose)
+ if panose[0] == 2 and panose[3] != 9:
+ logger.info("Setting Panose 'Proportion' to 'Monospaced' (was '%s')", panose_proportion_to_text(panose[3]))
+ panose[3] = 9 # 3 (4th value) = proportion; 9 = monospaced
+ font.os2_panose = tuple(panose)
+
+def get_advance_width(font, extended, minimum):
+ """ Get the maximum/minimum advance width in the extended(?) range """
+ width = 0
+ if not extended:
+ r = range(0x021, 0x07e)
+ else:
+ r = range(0x07f, 0x17f)
+ for glyph in r:
+ if not glyph in font:
+ continue
+ if glyph in range(0x7F, 0xBF):
+ continue # ignore special characters like '1/4' etc
+ if width == 0:
+ width = font[glyph].width
+ continue
+ if not minimum and width < font[glyph].width:
+ width = font[glyph].width
+ elif minimum and width > font[glyph].width:
+ width = font[glyph].width
+ return width
+
+def report_advance_widths(font):
+ return "Advance widths (base/extended): {} - {} / {} - {}".format(
+ get_advance_width(font, False, True), get_advance_width(font, False, False),
+ get_advance_width(font, True, True), get_advance_width(font, True, False))
+
+def get_btb_metrics(font):
+ """ Get the baseline to baseline distance for all three metrics """
+ hhea_height = font.hhea_ascent - font.hhea_descent
+ typo_height = font.os2_typoascent - font.os2_typodescent
+ win_height = font.os2_winascent + font.os2_windescent
+ win_gap = max(0, font.hhea_linegap - win_height + hhea_height)
+ hhea_btb = hhea_height + font.hhea_linegap
+ typo_btb = typo_height + font.os2_typolinegap
+ win_btb = win_height + win_gap
+ return (hhea_btb, typo_btb, win_btb, win_gap)
+
+def get_metrics_names():
+ """ Helper to get the line metrics names consistent """
+ return ['HHEA','TYPO','WIN']
+
+def get_old_average_x_width(font):
+ """ Determine xAvgCharWidth of the OS/2 table """
+ # Fontforge can not create fonts with old (i.e. prior to OS/2 version 3)
+ # table values, but some very old applications do need them sometimes
+ # https://learn.microsoft.com/en-us/typography/opentype/spec/os2#xavgcharwidth
+ s = 0
+ weights = {
+ 'a': 64, 'b': 14, 'c': 27, 'd': 35, 'e': 100, 'f': 20, 'g': 14, 'h': 42, 'i': 63,
+ 'j': 3, 'k': 6, 'l': 35, 'm': 20, 'n': 56, 'o': 56, 'p': 17, 'q': 4, 'r': 49,
+ 's': 56, 't': 71, 'u': 31, 'v': 10, 'w': 18, 'x': 3, 'y': 18, 'z': 2, 32: 166,
+ }
+ for g in weights:
+ if g not in font:
+ logger.critical("Can not determine ancient style xAvgCharWidth")
+ sys.exit(1)
+ s += font[g].width * weights[g]
+ return int(s / 1000)
+
+def create_filename(fonts):
+ """ Determine filename from font object(s) """
+ # Only consider the standard (i.e. English-US) names
+ sfnt = { k: v for l, k, v in fonts[0].sfnt_names if l == 'English (US)' }
+ sfnt_pfam = sfnt.get('Preferred Family', sfnt['Family'])
+ sfnt_psubfam = sfnt.get('Preferred Styles', sfnt['SubFamily'])
+ if len(fonts) > 1:
+ return sfnt_pfam
+ if len(sfnt_psubfam) > 0:
+ sfnt_psubfam = '-' + sfnt_psubfam
+ return (sfnt_pfam + sfnt_psubfam).replace(' ', '')
+
+def fetch_glyphnames():
+ """ Read the glyphname database and put it into a dictionary """
+ try:
+ glyphnamefile = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), 'glyphnames.json'))
+ with open(glyphnamefile, 'rb') as f:
+ namelist = json.load(f)
+ return { int(v['code'], 16): k for k, v in namelist.items() if 'code' in v }
+ except Exception as error:
+ logger.warning("Can not read glyphnames file (%s)", repr(error))
+ return {}
+
+class font_patcher:
+ def __init__(self, args, conf):
+ self.args = args # class 'argparse.Namespace'
+ self.sym_font_args = []
+ self.config = conf # class 'configparser.ConfigParser'
+ self.sourceFont = None # class 'fontforge.font'
+ self.patch_set = None # class 'list'
+ self.font_dim = None # class 'dict'
+ self.font_extrawide = False
+ self.source_monospaced = None # Later True or False
+ self.symbolsonly = False # Are we generating the SymbolsOnly font?
+ self.onlybitmaps = 0
+ self.essential = set()
+ self.xavgwidth = [] # list of ints
+ self.glyphnames = fetch_glyphnames()
+
+ def patch(self, font):
+ self.sourceFont = font
+ self.setup_version()
+ self.assert_monospace()
+ self.remove_ligatures()
+ self.manipulate_hints()
+ self.get_essential_references()
+ self.get_sourcefont_dimensions()
+ self.setup_patch_set()
+ self.improve_line_dimensions()
+ self.sourceFont.encoding = 'UnicodeFull' # Update the font encoding to ensure that the Unicode glyphs are available
+ self.onlybitmaps = self.sourceFont.onlybitmaps # Fetch this property before adding outlines. NOTE self.onlybitmaps initialized and never used
+
+ if self.args.forcemono:
+ # Force width to be equal on all glyphs to ensure the font is considered monospaced on Windows.
+ # This needs to be done on all characters, as some information seems to be lost from the original font file.
+ self.set_sourcefont_glyph_widths()
+
+ # For very wide (almost square or wider) fonts we do not want to generate 2 cell wide Powerline glyphs
+ if self.font_dim['height'] * 1.8 < self.font_dim['width'] * 2:
+ logger.warning("Very wide and short font, disabling 2 cell Powerline glyphs")
+ self.font_extrawide = True
+
+ # Prevent opening and closing the fontforge font. Makes things faster when patching
+ # multiple ranges using the same symbol font.
+ PreviousSymbolFilename = ""
+ symfont = None
+
+ if not os.path.isdir(self.args.glyphdir):
+ logger.critical("Can not find symbol glyph directory %s "
+ "(probably you need to download the src/glyphs/ directory?)", self.args.glyphdir)
+ sys.exit(1)
+
+ if self.args.dry_run:
+ return
+
+ for patch in self.patch_set:
+ if patch['Enabled']:
+ if PreviousSymbolFilename != patch['Filename']:
+ # We have a new symbol font, so close the previous one if it exists
+ if symfont:
+ symfont.close()
+ symfont = None
+ symfont_file = os.path.join(self.args.glyphdir, patch['Filename'])
+ if not os.path.isfile(symfont_file):
+ logger.critical("Can not find symbol source for '%s' (i.e. %s)",
+ patch['Name'], symfont_file)
+ sys.exit(1)
+ if not os.access(symfont_file, os.R_OK):
+ logger.critical("Can not open symbol source for '%s' (i.e. %s)",
+ patch['Name'], symfont_file)
+ sys.exit(1)
+ symfont = fontforge.open(symfont_file)
+ symfont.encoding = 'UnicodeFull'
+
+ # Match the symbol font size to the source font size
+ symfont.em = self.sourceFont.em
+ PreviousSymbolFilename = patch['Filename']
+
+ # If patch table doesn't include a source start, re-use the symbol font values
+ SrcStart = patch['SrcStart']
+ if not SrcStart:
+ SrcStart = patch['SymStart']
+ self.copy_glyphs(SrcStart, symfont, patch['SymStart'], patch['SymEnd'], patch['Exact'], patch['ScaleRules'], patch['Name'], patch['Attributes'])
+
+ if symfont:
+ symfont.close()
+
+ # The grave accent and fontforge:
+ # If the type is 'auto' fontforge changes it to 'mark' on export.
+ # We can not prevent this. So set it to 'baseglyph' instead, as
+ # that resembles the most common expectations.
+ # This is not needed with fontforge March 2022 Release anymore.
+ if "grave" in self.sourceFont:
+ self.sourceFont["grave"].glyphclass="baseglyph"
+
+
+ def generate(self, sourceFonts):
+ sourceFont = sourceFonts[0]
+ # the `PfEd-comments` flag is required for Fontforge to save '.comment' and '.fontlog'.
+ if int(fontforge.version()) >= 20201107:
+ gen_flags = (str('opentype'), str('PfEd-comments'), str('no-FFTM-table'))
+ else:
+ gen_flags = (str('opentype'), str('PfEd-comments'))
+ if len(sourceFonts) > 1:
+ layer = None
+ # use first non-background layer
+ for l in sourceFont.layers:
+ if not sourceFont.layers[l].is_background:
+ layer = l
+ break
+ outfile = os.path.normpath(os.path.join(
+ sanitize_filename(self.args.outputdir, True),
+ sanitize_filename(create_filename(sourceFonts)) + ".ttc"))
+ sourceFonts[0].generateTtc(outfile, sourceFonts[1:], flags=gen_flags, layer=layer)
+ message = " Generated {} fonts\n \\===> '{}'".format(len(sourceFonts), outfile)
+ else:
+ fontname = create_filename(sourceFonts)
+ if not fontname:
+ fontname = sourceFont.cidfontname
+ outfile = os.path.normpath(os.path.join(
+ sanitize_filename(self.args.outputdir, True),
+ sanitize_filename(fontname) + self.args.extension))
+ bitmaps = str()
+ if len(sourceFont.bitmapSizes):
+ logger.debug("Preserving bitmaps %s", repr(sourceFont.bitmapSizes))
+ bitmaps = str('otf') # otf/ttf, both is bf_ttf
+ if self.args.dry_run:
+ logger.debug("=====> Filename '%s'", outfile)
+ return
+ sourceFont.generate(outfile, bitmap_type=bitmaps, flags=gen_flags)
+ message = " {}\n \\===> '{}'".format(sourceFont.fullname, outfile)
+
+ # Adjust flags that can not be changed via fontforge
+ if re.search(r'\.[ot]tf$', self.args.font, re.IGNORECASE) and re.search(r'\.[ot]tf$', outfile, re.IGNORECASE):
+ if not os.path.isfile(outfile) or os.path.getsize(outfile) < 1:
+ logger.critical("Something went wrong and Fontforge did not generate the new font - look for messages above")
+ sys.exit(1)
+ try:
+ source_font = TableHEADWriter(self.args.font)
+ dest_font = TableHEADWriter(outfile)
+ for idx in range(source_font.num_fonts):
+ logger.debug("Tweaking %d/%d", idx + 1, source_font.num_fonts)
+ xwidth_s = ''
+ xwidth = self.xavgwidth[idx] if len(self.xavgwidth) > idx else None
+ if isinstance(xwidth, int):
+ if isinstance(xwidth, bool) and xwidth:
+ source_font.find_table([b'OS/2'], idx)
+ xwidth = source_font.getshort('avgWidth')
+ xwidth_s = ' (copied from source)'
+ dest_font.find_table([b'OS/2'], idx)
+ d_xwidth = dest_font.getshort('avgWidth')
+ if d_xwidth != xwidth:
+ logger.debug("Changing xAvgCharWidth from %d to %d%s", d_xwidth, xwidth, xwidth_s)
+ dest_font.putshort(xwidth, 'avgWidth')
+ dest_font.reset_table_checksum()
+ source_font.find_head_table(idx)
+ dest_font.find_head_table(idx)
+ if source_font.flags & 0x08 == 0 and dest_font.flags & 0x08 != 0:
+ logger.debug("Changing flags from 0x%X to 0x%X", dest_font.flags, dest_font.flags & ~0x08)
+ dest_font.putshort(dest_font.flags & ~0x08, 'flags') # clear 'ppem_to_int'
+ if source_font.lowppem != dest_font.lowppem:
+ logger.debug("Changing lowestRecPPEM from %d to %d", dest_font.lowppem, source_font.lowppem)
+ dest_font.putshort(source_font.lowppem, 'lowestRecPPEM')
+ if dest_font.modified:
+ dest_font.reset_table_checksum()
+ if dest_font.modified:
+ dest_font.reset_full_checksum()
+ except Exception as error:
+ logger.error("Can not handle font flags (%s)", repr(error))
+ finally:
+ try:
+ source_font.close()
+ dest_font.close()
+ except:
+ pass
+ if self.args.is_variable:
+ logger.critical("Source font is a variable open type font (VF) and the patch results will most likely not be what you want")
+ print(message)
+
+ if self.args.postprocess:
+ subprocess.call([self.args.postprocess, outfile])
+ print("\n")
+ logger.info("Post Processed: %s", outfile)
+
+
+ def setup_name_backup(self, font):
+ """ Store the original font names to be able to rename the font multiple times """
+ font.persistent = {
+ "fontname": font.fontname,
+ "fullname": font.fullname,
+ "familyname": font.familyname,
+ }
+
+
+ def setup_font_names(self, font):
+ font.fontname = font.persistent["fontname"]
+ if isinstance(font.persistent["fullname"], str):
+ font.fullname = font.persistent["fullname"]
+ if isinstance(font.persistent["familyname"], str):
+ font.familyname = font.persistent["familyname"]
+ verboseAdditionalFontNameSuffix = ""
+ additionalFontNameSuffix = ""
+ if not self.args.complete:
+ # NOTE not all symbol fonts have appended their suffix here
+ if self.args.fontawesome:
+ additionalFontNameSuffix += " A"
+ verboseAdditionalFontNameSuffix += " Plus Font Awesome"
+ if self.args.fontawesomeextension:
+ additionalFontNameSuffix += " AE"
+ verboseAdditionalFontNameSuffix += " Plus Font Awesome Extension"
+ if self.args.octicons:
+ additionalFontNameSuffix += " O"
+ verboseAdditionalFontNameSuffix += " Plus Octicons"
+ if self.args.powersymbols:
+ additionalFontNameSuffix += " PS"
+ verboseAdditionalFontNameSuffix += " Plus Power Symbols"
+ if self.args.codicons:
+ additionalFontNameSuffix += " C"
+ verboseAdditionalFontNameSuffix += " Plus Codicons"
+ if self.args.pomicons:
+ additionalFontNameSuffix += " P"
+ verboseAdditionalFontNameSuffix += " Plus Pomicons"
+ if self.args.fontlogos:
+ additionalFontNameSuffix += " L"
+ verboseAdditionalFontNameSuffix += " Plus Font Logos"
+ if self.args.material:
+ additionalFontNameSuffix += " MDI"
+ verboseAdditionalFontNameSuffix += " Plus Material Design Icons"
+ if self.args.weather:
+ additionalFontNameSuffix += " WEA"
+ verboseAdditionalFontNameSuffix += " Plus Weather Icons"
+
+ # add mono signifier to beginning of name suffix
+ if self.args.single:
+ variant_abbrev = "M"
+ variant_full = " Mono"
+ elif self.args.nonmono and not self.symbolsonly:
+ variant_abbrev = "P"
+ variant_full = " Propo"
+ else:
+ variant_abbrev = ""
+ variant_full = ""
+
+ ps_suffix = projectNameAbbreviation + variant_abbrev + additionalFontNameSuffix
+
+ # add 'Nerd Font' to beginning of name suffix
+ verboseAdditionalFontNameSuffix = " " + projectNameSingular + variant_full + verboseAdditionalFontNameSuffix
+ additionalFontNameSuffix = " " + projectNameSingular + variant_full + additionalFontNameSuffix
+
+ if FontnameParserOK and self.args.makegroups > 0:
+ user_supplied_name = False # User supplied names are kept unchanged
+ if not isinstance(self.args.force_name, str):
+ use_fullname = isinstance(font.fullname, str) # Usually the fullname is better to parse
+ # Use fullname if it is 'equal' to the fontname
+ if font.fullname:
+ use_fullname |= font.fontname.lower() == FontnameTools.postscript_char_filter(font.fullname).lower()
+ # Use fullname for any of these source fonts (that are impossible to disentangle from the fontname, we need the blanks)
+ for hit in [ 'Meslo' ]:
+ use_fullname |= font.fontname.lower().startswith(hit.lower())
+ parser_name = font.fullname if use_fullname else font.fontname
+ # Gohu fontnames hide the weight, but the file names are ok...
+ if parser_name.startswith('Gohu'):
+ parser_name = os.path.splitext(os.path.basename(self.args.font))[0]
+ else:
+ if self.args.force_name == 'full':
+ parser_name = font.fullname
+ elif self.args.force_name == 'postscript':
+ parser_name = font.fontname
+ elif self.args.force_name == 'filename':
+ parser_name = os.path.basename(font.path).split('.')[0]
+ else:
+ parser_name = self.args.force_name
+ user_supplied_name = True
+ if not isinstance(parser_name, str) or len(parser_name) < 1:
+ logger.critical("Specified --name not usable because the name will be empty")
+ sys.exit(2)
+ n = FontnameParser(parser_name, logger)
+ if not n.parse_ok:
+ logger.warning("Have only minimal naming information, check resulting name. Maybe specify --makegroups 0")
+ n.drop_for_powerline()
+ n.enable_short_families(not user_supplied_name, self.args.makegroups in [ 2, 3, 5, 6, ], self.args.makegroups in [ 3, 6, ])
+ if not n.set_expect_no_italic(self.args.noitalic):
+ logger.critical("Detected 'Italic' slant but --has-no-italic specified")
+ sys.exit(1)
+
+ # All the following stuff is ignored in makegroups-mode
+
+ # basically split the font name around the dash "-" to get the fontname and the style (e.g. Bold)
+ # this does not seem very reliable so only use the style here as a fallback if the font does not
+ # have an internal style defined (in sfnt_names)
+ # using '([^-]*?)' to get the item before the first dash "-"
+ # using '([^-]*(?!.*-))' to get the item after the last dash "-"
+ fontname, fallbackStyle = re.match("^([^-]*).*?([^-]*(?!.*-))$", font.fontname).groups()
+
+ # dont trust 'font.familyname'
+ familyname = fontname
+
+ # fullname (filename) can always use long/verbose font name, even in windows
+ if font.fullname != None:
+ fullname = font.fullname + verboseAdditionalFontNameSuffix
+ else:
+ fullname = font.cidfontname + verboseAdditionalFontNameSuffix
+
+ fontname = fontname + additionalFontNameSuffix.replace(" ", "")
+
+ # let us try to get the 'style' from the font info in sfnt_names and fallback to the
+ # parse fontname if it fails:
+ try:
+ # search tuple:
+ subFamilyTupleIndex = [x[1] for x in font.sfnt_names].index("SubFamily")
+
+ # String ID is at the second index in the Tuple lists
+ sfntNamesStringIDIndex = 2
+
+ # now we have the correct item:
+ subFamily = font.sfnt_names[subFamilyTupleIndex][sfntNamesStringIDIndex]
+ except IndexError:
+ sys.stderr.write("{}: Could not find 'SubFamily' for given font, falling back to parsed fontname\n".format(projectName))
+ subFamily = fallbackStyle
+
+ # some fonts have inaccurate 'SubFamily', if it is Regular let us trust the filename more:
+ if subFamily == "Regular" and len(fallbackStyle):
+ subFamily = fallbackStyle
+
+ # This is meant to cover the case where the SubFamily is "Italic" and the filename is *-BoldItalic.
+ if len(subFamily) < len(fallbackStyle):
+ subFamily = fallbackStyle
+
+ if len(subFamily) == 0:
+ subFamily = "Regular"
+
+ familyname += " " + projectNameSingular + variant_full
+
+ # Don't truncate the subfamily to keep fontname unique. MacOS treats fonts with
+ # the same name as the same font, even if subFamily is different. Make sure to
+ # keep the resulting fontname (PostScript name) valid by removing spaces.
+ fontname += '-' + subFamily.replace(' ', '')
+
+ # rename font
+ #
+ # comply with SIL Open Font License (OFL)
+ reservedFontNameReplacements = {
+ 'source' : 'sauce',
+ 'Source' : 'Sauce',
+ 'Bitstream Vera Sans Mono' : 'Bitstrom Wera',
+ 'BitstreamVeraSansMono' : 'BitstromWera',
+ 'bitstream vera sans mono' : 'bitstrom wera',
+ 'bitstreamverasansmono' : 'bitstromwera',
+ 'hermit' : 'hurmit',
+ 'Hermit' : 'Hurmit',
+ 'hasklig' : 'hasklug',
+ 'Hasklig' : 'Hasklug',
+ 'Share' : 'Shure',
+ 'share' : 'shure',
+ 'IBMPlex' : 'Blex',
+ 'ibmplex' : 'blex',
+ 'IBM-Plex' : 'Blex',
+ 'IBM Plex' : 'Blex',
+ 'terminus' : 'terminess',
+ 'Terminus' : 'Terminess',
+ 'liberation' : 'literation',
+ 'Liberation' : 'Literation',
+ 'iAWriter' : 'iMWriting',
+ 'iA Writer' : 'iM Writing',
+ 'iA-Writer' : 'iM-Writing',
+ 'Anka/Coder' : 'AnaConder',
+ 'anka/coder' : 'anaconder',
+ 'Cascadia Code' : 'Caskaydia Cove',
+ 'cascadia code' : 'caskaydia cove',
+ 'CascadiaCode' : 'CaskaydiaCove',
+ 'cascadiacode' : 'caskaydiacove',
+ 'Cascadia Mono' : 'Caskaydia Mono',
+ 'cascadia mono' : 'caskaydia mono',
+ 'CascadiaMono' : 'CaskaydiaMono',
+ 'cascadiamono' : 'caskaydiamono',
+ 'Fira Mono' : 'Fura Mono',
+ 'Fira Sans' : 'Fura Sans',
+ 'FiraMono' : 'FuraMono',
+ 'FiraSans' : 'FuraSans',
+ 'fira mono' : 'fura mono',
+ 'fira sans' : 'fura sans',
+ 'firamono' : 'furamono',
+ 'firasans' : 'furasans',
+ 'IntelOneMono' : 'IntoneMono',
+ 'IntelOne Mono' : 'Intone Mono',
+ 'Intel One Mono' : 'Intone Mono',
+ }
+
+ # remove overly verbose font names
+ # particularly regarding Powerline sourced Fonts (https://github.com/powerline/fonts)
+ additionalFontNameReplacements = {
+ 'for Powerline': '',
+ 'ForPowerline': ''
+ }
+
+ additionalFontNameReplacements2 = {
+ 'Powerline': ''
+ }
+
+ projectInfo = (
+ "Patched with '" + projectName + " Patcher' (https://github.com/ryanoasis/nerd-fonts)\n\n"
+ "* Website: https://www.nerdfonts.com\n"
+ "* Version: " + version + "\n"
+ "* Development Website: https://github.com/ryanoasis/nerd-fonts\n"
+ "* Changelog: https://github.com/ryanoasis/nerd-fonts/blob/-/changelog.md"
+ )
+
+ familyname = replace_font_name(familyname, reservedFontNameReplacements)
+ fullname = replace_font_name(fullname, reservedFontNameReplacements)
+ fontname = replace_font_name(fontname, reservedFontNameReplacements)
+ familyname = replace_font_name(familyname, additionalFontNameReplacements)
+ fullname = replace_font_name(fullname, additionalFontNameReplacements)
+ fontname = replace_font_name(fontname, additionalFontNameReplacements)
+ familyname = replace_font_name(familyname, additionalFontNameReplacements2)
+ fullname = replace_font_name(fullname, additionalFontNameReplacements2)
+ fontname = replace_font_name(fontname, additionalFontNameReplacements2)
+
+ if self.args.makegroups < 0:
+ logger.warning("Renaming disabled! Make sure to comply with font license, esp RFN clause!")
+ elif not (FontnameParserOK and self.args.makegroups > 0):
+ # replace any extra whitespace characters:
+ font.familyname = " ".join(familyname.split())
+ font.fullname = " ".join(fullname.split())
+ font.fontname = " ".join(fontname.split())
+
+ font.appendSFNTName(str('English (US)'), str('Preferred Family'), font.familyname)
+ font.appendSFNTName(str('English (US)'), str('Family'), font.familyname)
+ font.appendSFNTName(str('English (US)'), str('Compatible Full'), font.fullname)
+ font.appendSFNTName(str('English (US)'), str('SubFamily'), subFamily)
+ else:
+ # Add Nerd Font suffix unless user specifically asked for some excplicit name via --name
+ if not user_supplied_name:
+ short_family = projectNameAbbreviation + variant_abbrev if self.args.makegroups >= 4 else projectNameSingular + variant_full
+ # inject_suffix(family, ps_fontname, short_family)
+ n.inject_suffix(verboseAdditionalFontNameSuffix, ps_suffix, short_family)
+ n.rename_font(font)
+
+ font.comment = projectInfo
+ font.fontlog = projectInfo
+
+
+ def setup_version(self):
+ """ Add the Nerd Font version to the original version """
+ # print("Version was {}".format(sourceFont.version))
+ if self.sourceFont.version != None:
+ self.sourceFont.version += ";" + projectName + " " + version
+ else:
+ self.sourceFont.version = str(self.sourceFont.cidversion) + ";" + projectName + " " + version
+ self.sourceFont.sfntRevision = None # Auto-set (refreshed) by fontforge
+ self.sourceFont.appendSFNTName(str('English (US)'), str('Version'), "Version " + self.sourceFont.version)
+ # The Version SFNT name is later reused by the NameParser for UniqueID
+ # print("Version now is {}".format(sourceFont.version))
+
+
+ def remove_ligatures(self):
+ # let's deal with ligatures (mostly for monospaced fonts)
+ # Usually removes 'fi' ligs that end up being only one cell wide, and 'ldot'
+ if self.args.removeligatures:
+ logger.info("Removing ligatures from configfile `Subtables` section")
+ if 'Subtables' not in self.config:
+ logger.warning("No ligature data (config file missing?)")
+ return
+ ligature_subtables = json.loads(self.config.get('Subtables', 'ligatures', fallback='[]'))
+ for subtable in ligature_subtables:
+ logger.debug("Removing subtable: %s", subtable)
+ try:
+ self.sourceFont.removeLookupSubtable(subtable)
+ logger.debug("Successfully removed subtable: %s", subtable)
+ except Exception:
+ logger.error("Failed to remove subtable: %s", subtable)
+
+
+ def manipulate_hints(self):
+ """ Redo the hinting on some problematic glyphs """
+ if 'Hinting' not in self.config:
+ return
+ redo = json.loads(self.config.get('Hinting', 're_hint', fallback='[]'))
+ if not len(redo):
+ return
+ logger.debug("Working on {} rehinting rules (this may create a lot of fontforge warnings)".format(len(redo)))
+ count = 0
+ for gname in self.sourceFont:
+ for regex in redo:
+ if re.fullmatch(regex, gname):
+ glyph = self.sourceFont[gname]
+ glyph.autoHint()
+ glyph.autoInstr()
+ count += 1
+ break
+ logger.info("Rehinted {} glyphs".format(count))
+
+ def assert_monospace(self):
+ # Check if the sourcefont is monospaced
+ width_mono, offending_char = is_monospaced(self.sourceFont)
+ self.source_monospaced = width_mono
+ if self.args.nonmono:
+ return
+ panose_mono = check_panose_monospaced(self.sourceFont)
+ logger.debug("Monospace check: %s; glyph-width-mono %s",
+ panose_check_to_text(panose_mono, self.sourceFont.os2_panose), repr(width_mono))
+ # The following is in fact "width_mono != panose_mono", but only if panose_mono is not 'unknown'
+ if (width_mono and panose_mono == 0) or (not width_mono and panose_mono == 1):
+ logger.warning("Monospaced check: Panose assumed to be wrong")
+ logger.warning("Monospaced check: %s and %s",
+ report_advance_widths(self.sourceFont),
+ panose_check_to_text(panose_mono, self.sourceFont.os2_panose))
+ if self.args.forcemono and not width_mono:
+ logger.warning("Sourcefont is not monospaced - forcing to monospace not advisable, "
+ "results might be useless%s",
+ " - offending char: {:X}".format(offending_char) if offending_char is not None else "")
+ if self.args.forcemono <= 1:
+ logger.critical("Font will not be patched! Give --mono (or -s) twice to force patching")
+ sys.exit(1)
+ if width_mono:
+ force_panose_monospaced(self.sourceFont)
+
+
+ def setup_patch_set(self):
+ """ Creates list of dicts to with instructions on copying glyphs from each symbol font into self.sourceFont """
+
+ box_enabled = self.source_monospaced and not self.symbolsonly # Box glyph only for monospaced and not for Symbols Only
+ box_keep = False
+ if box_enabled or self.args.forcebox:
+ self.sourceFont.selection.select(("ranges",), 0x2500, 0x259f)
+ box_glyphs_target = len(list(self.sourceFont.selection))
+ box_glyphs_current = len(list(self.sourceFont.selection.byGlyphs))
+ if box_glyphs_target > box_glyphs_current or self.args.forcebox:
+ # Sourcefont does not have all of these glyphs, do not mix sets (overwrite existing)
+ if box_glyphs_current > 0:
+ logger.debug("%d/%d box drawing glyphs will be replaced",
+ box_glyphs_current, box_glyphs_target)
+ box_enabled = True
+ else:
+ # Sourcefont does have all of these glyphs
+ # box_keep = True # just scale do not copy (need to scale to fit new cell size)
+ box_enabled = False # Cowardly not scaling existing glyphs, although the code would allow this
+
+ # Stretch 'xz' or 'pa' (preserve aspect ratio)
+ # Supported params: overlap | careful | xy-ratio | dont_copy | ypadding
+ # Overlap value is used horizontally but vertically limited to 0.01
+ # Careful does not overwrite/modify existing glyphs
+ # The xy-ratio limits the x-scale for a given y-scale to make the ratio <= this value (to prevent over-wide glyphs)
+ # '1' means occupu 1 cell (default for 'xy')
+ # '2' means occupy 2 cells (default for 'pa')
+ # '!' means do the 'pa' scaling even with non mono fonts (else it just scales down, never up)
+ # '^' means that scaling shall fill the whole cell and not only the icon-cap-height (for mono fonts, other always use the whole cell)
+ # Dont_copy does not overwrite existing glyphs but rescales the preexisting ones
+ #
+ # Be careful, stretch may not change within a ScaleRule!
+
+ SYM_ATTR_DEFAULT = {
+ 'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': {}}
+ }
+ SYM_ATTR_POWERLINE = {
+ 'default': {'align': 'c', 'valign': 'c', 'stretch': '^pa', 'params': {}},
+
+ # Arrow tips
+ 0xe0b0: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.06, 'xy-ratio': 0.7}},
+ 0xe0b1: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'xy-ratio': 0.7}},
+ 0xe0b2: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.06, 'xy-ratio': 0.7}},
+ 0xe0b3: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'xy-ratio': 0.7}},
+
+ # Inverse arrow tips
+ 0xe0d6: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'xy-ratio': 0.7}},
+ 0xe0d7: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'xy-ratio': 0.7}},
+
+ # Rounded arcs
+ 0xe0b4: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.06, 'xy-ratio': 0.59}},
+ 0xe0b5: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'xy-ratio': 0.5}},
+ 0xe0b6: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.06, 'xy-ratio': 0.59}},
+ 0xe0b7: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'xy-ratio': 0.5}},
+
+ # Bottom Triangles
+ 0xe0b8: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05}},
+ 0xe0b9: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {}},
+ 0xe0ba: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05}},
+ 0xe0bb: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {}},
+
+ # Top Triangles
+ 0xe0bc: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05}},
+ 0xe0bd: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {}},
+ 0xe0be: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05}},
+ 0xe0bf: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {}},
+
+ # Flames
+ 0xe0c0: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': 0.05}},
+ 0xe0c1: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {}},
+ 0xe0c2: {'align': 'r', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': 0.05}},
+ 0xe0c3: {'align': 'r', 'valign': 'c', 'stretch': '^xy2', 'params': {}},
+
+ # Small squares
+ 0xe0c4: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': -0.03, 'xy-ratio': 0.86}},
+ 0xe0c5: {'align': 'r', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': -0.03, 'xy-ratio': 0.86}},
+
+ # Bigger squares
+ 0xe0c6: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': -0.03, 'xy-ratio': 0.78}},
+ 0xe0c7: {'align': 'r', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': -0.03, 'xy-ratio': 0.78}},
+
+ # Waveform
+ 0xe0c8: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': 0.05}},
+ 0xe0ca: {'align': 'r', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': 0.05}},
+
+ # Hexagons
+ 0xe0cc: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': 0.02, 'xy-ratio': 0.85}},
+ 0xe0cd: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'xy-ratio': 0.865}},
+
+ # Legos
+ 0xe0ce: {'align': 'l', 'valign': 'c', 'stretch': '^pa', 'params': {}},
+ 0xe0cf: {'align': 'c', 'valign': 'c', 'stretch': '^pa', 'params': {}},
+ 0xe0d0: {'align': 'l', 'valign': 'c', 'stretch': '^pa', 'params': {}},
+ 0xe0d1: {'align': 'l', 'valign': 'c', 'stretch': '^pa', 'params': {}},
+
+ # Top and bottom trapezoid
+ 0xe0d2: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.02, 'xy-ratio': 0.7}},
+ 0xe0d4: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.02, 'xy-ratio': 0.7}}
+ }
+ SYM_ATTR_TRIGRAPH = {
+ 'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa1!', 'params': {'overlap': -0.10, 'careful': True}}
+ }
+ SYM_ATTR_FONTA = {
+ # 'pa' == preserve aspect ratio
+ 'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': {}},
+
+ # Don't center these arrows vertically
+ 0xf0dc: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}},
+ 0xf0dd: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}},
+ 0xf0de: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}}
+ }
+ SYM_ATTR_HEAVYBRACKETS = {
+ 'default': {'align': 'c', 'valign': 'c', 'stretch': '^pa1!', 'params': {'ypadding': 0.3, 'careful': True}}
+ }
+ SYM_ATTR_BOX = {
+ 'default': {'align': 'c', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.02, 'dont_copy': box_keep}},
+ # No overlap with checkered greys (commented out because that raises problems on rescaling clients)
+ # 0x2591: {'align': 'c', 'valign': 'c', 'stretch': 'xy', 'params': {'dont_copy': box_keep}},
+ # 0x2592: {'align': 'c', 'valign': 'c', 'stretch': 'xy', 'params': {'dont_copy': box_keep}},
+ # 0x2593: {'align': 'c', 'valign': 'c', 'stretch': 'xy', 'params': {'dont_copy': box_keep}},
+ }
+ SYM_ATTR_PROGRESS = {
+ 'default': {'align': 'c', 'valign': 'c', 'stretch': '^pa1!', 'params': {'overlap': -0.03, 'careful': True}}, # Cirles
+ # All the squares:
+ 0xee00: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'careful': True}},
+ 0xee01: {'align': 'c', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.10, 'careful': True}},
+ 0xee02: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'careful': True}},
+ 0xee03: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'careful': True}},
+ 0xee04: {'align': 'c', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.10, 'careful': True}},
+ 0xee05: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'careful': True}},
+ }
+ CUSTOM_ATTR = {
+ # previous custom scaling => do not touch the icons
+ # 'default': {'align': 'c', 'valign': '', 'stretch': '', 'params': {}}
+ 'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': {'careful': self.args.careful}}
+ }
+
+ # Most glyphs we want to maximize (individually) during the scale
+ # However, there are some that need to be small or stay relative in
+ # size to each other.
+ # The glyph-specific behavior can be given as ScaleRules in the patch-set.
+ #
+ # ScaleRules can contain two different kind of rules (possibly in parallel):
+ # - ScaleGlyph:
+ # Here one specific glyph is used as 'scale blueprint'. Other glyphs are
+ # scaled by the same factor as this glyph. This is useful if you have one
+ # 'biggest' glyph and all others should stay relatively in size.
+ # Shifting in addition to scaling can be selected too (see below).
+ # - ScaleGroups:
+ # Here you specify a group of glyphs that should be handled together
+ # with the same scaling and shifting (see bottom). The basis for it is
+ # a 'combined bounding box' of all glyphs in that group. All glyphs are
+ # handled as if they fill that combined bounding box.
+ # (- ScaleGroupsVert: Removed with this commit)
+ #
+ # The ScaleGlyph method: You set 'ScaleGlyph' to the unicode of the reference glyph.
+ # Note that there can be only one per patch-set.
+ # Additionally you set 'GlyphsToScale' that contains all the glyphs that shall be
+ # handled (scaled) like the reference glyph.
+ # It is a List of: ((glyph code) or (tuple of two glyph codes that form a closed range))
+ # 'GlyphsToScale': [
+ # 0x0100, 0x0300, 0x0400, # The single glyphs 0x0100, 0x0300, and 0x0400
+ # (0x0200, 0x0210), # All glyphs 0x0200 to 0x0210 including both 0x0200 and 0x0210
+ # ]}
+ # If you want to not only scale but also shift as the reference glyph you give the
+ # data as 'GlyphsToScale+'. Note that only one set is used and the plus version is preferred.
+ #
+ # For the ScaleGroup method you define any number groups of glyphs and each group is
+ # handled separately. The combined bounding box of all glyphs in the group is determined
+ # and based on that the scale and shift (see bottom) for all the glyphs in the group.
+ # You define the groups as value of 'ScaleGroups'.
+ # It is a List of: ((lists of glyph codes) or (ranges of glyph codes))
+ # 'ScaleGroups': [
+ # [0x0100, 0x0300, 0x0400], # One group consists of glyphs 0x0100, 0x0300, and 0x0400
+ # range(0x0200, 0x0210 + 1), # Another group contains glyphs 0x0200 to 0x0210 incl.
+ #
+ # Note the subtle differences: tuple vs. range; closed vs open range; etc
+ # See prepareScaleRules() for some more details.
+ # For historic reasons ScaleGroups is sometimes called 'new method' and ScaleGlyph 'old'.
+ # The codepoints mentioned here are symbol-font-codepoints.
+ #
+ # Shifting:
+ # If we have a combined bounding box stored in a range, that
+ # box is used to align all symbols in the range identically.
+ # - If the symbol font is proportinal only the v alignment is synced.
+ # - If the symbol font is monospaced v and h alignemnts are synced.
+ # To make sure the behavior is as expected you are required to set a ShiftMode property
+ # accordingly. It just checks, you can not (!) select what is done with that property.
+
+ BOX_SCALE_LIST = {'ShiftMode': 'xy', 'ScaleGroups': [
+ [*range(0x2500, 0x2570 + 1), *range(0x2574, 0x257f + 1)], # box drawing
+ range(0x2571, 0x2573 + 1), # diagonals
+ range(0x2580, 0x259f + 1), # blocks and greys (greys are less tall originally, so overlap will be less)
+ ]}
+ CODI_SCALE_LIST = {'ShiftMode': 'xy', 'ScaleGroups': [
+ [0xea61, 0xeb13], # lightbulb
+ range(0xeab4, 0xeab7 + 1), # chevrons
+ [0xea7d, *range(0xea99, 0xeaa1 + 1), 0xebcb], # arrows
+ [0xeaa2, 0xeb9a, 0xec08, 0xec09], # bells
+ range(0xead4, 0xead6 + 1), # dot and arrow
+ [0xeb43, 0xec0b, 0xec0c], # (pull) request changes
+ range(0xeb6e, 0xeb71 + 1), # triangles
+ [*range(0xeb89, 0xeb8b + 1), 0xec07], # smallish dots
+ range(0xebd5, 0xebd7 + 1), # compasses
+ ]}
+ DEVI_SCALE_LIST = None
+ FONTA_SCALE_LIST = {'ShiftMode': '', 'ScaleGroups': [
+ [0xf005, 0xf006, 0xf089], # star, star empty, half star
+ range(0xf026, 0xf028 + 1), # volume off, down, up
+ range(0xf02b, 0xf02c + 1), # tag, tags
+ range(0xf031, 0xf035 + 1), # font et al
+ range(0xf044, 0xf046 + 1), # edit, share, check (boxes)
+ range(0xf048, 0xf052 + 1), # multimedia buttons
+ range(0xf060, 0xf063 + 1), # arrows
+ [0xf053, 0xf054, 0xf077, 0xf078], # chevron all directions
+ range(0xf07d, 0xf07e + 1), # resize
+ range(0xf0a4, 0xf0a7 + 1), # pointing hands
+ [0xf0d7, 0xf0d8, 0xf0d9, 0xf0da, 0xf0dc, 0xf0dd, 0xf0de], # caret all directions and same looking sort
+ range(0xf100, 0xf107 + 1), # angle
+ range(0xf130, 0xf131 + 1), # mic
+ range(0xf141, 0xf142 + 1), # ellipsis
+ range(0xf153, 0xf15a + 1), # currencies
+ range(0xf175, 0xf178 + 1), # long arrows
+ range(0xf182, 0xf183 + 1), # male and female
+ range(0xf221, 0xf22d + 1), # gender or so
+ range(0xf255, 0xf25b + 1), # hand symbols
+ ]}
+ HEAVY_SCALE_LIST = {'ShiftMode': 'xy', 'ScaleGroups': [
+ range(0x276c, 0x2771+1)
+ ]}
+ OCTI_SCALE_LIST = {'ShiftMode': '', 'ScaleGroups': [
+ [*range(0xf03d, 0xf040 + 1), 0xf019, 0xf030, 0xf04a, 0xf051, 0xf071, 0xf08c ], # arrows
+ [0xF0E7, # Smily and ...
+ 0xf044, 0xf05a, 0xf05b, 0xf0aa, # triangles
+ 0xf052, 0xf053, 0xf296, 0xf2f0, # small stuff
+ 0xf078, 0xf0a2, 0xf0a3, 0xf0a4, # chevrons
+ 0xf0ca, 0xf081, 0xf092, # dash, X, github-text
+ ],
+ [0xf09c, 0xf09f, 0xf0de], # bells
+ range(0xf2c2, 0xf2c5 + 1), # move to
+ [0xf07b, 0xf0a1, 0xf0d6, 0xf306], # bookmarks
+ ]}
+ PROGR_SCALE_LIST = {'ShiftMode': 'xy', 'ScaleGroups': [
+ range(0xedff, 0xee05 + 1), # boxes... with helper glyph EDFF for Y padding
+ range(0xee06, 0xee0b + 1), # circles
+ ]}
+ WEATH_SCALE_LIST = {'ShiftMode': '', 'ScaleGroups': [
+ [0xf03c, 0xf042, 0xf045 ], # degree signs
+ [0xf043, 0xf044, 0xf048, 0xf04b, 0xf04c, 0xf04d, 0xf057, 0xf058, 0xf087, 0xf088], # arrows
+ range(0xf053, 0xf055 + 1), # thermometers
+ [*range(0xf059, 0xf061 + 1), 0xf0b1], # wind directions
+ range(0xf089, 0xf094 + 1), # clocks
+ range(0xf095, 0xf0b0 + 1), # moon phases
+ range(0xf0b7, 0xf0c3 + 1), # wind strengths
+ [0xf06e, 0xf070 ], # solar/lunar eclipse
+ [0xf051, 0xf052, 0xf0c9, 0xf0ca, 0xf072 ], # sun/moon up/down
+ [0xf049, 0xf056, 0xf071, *range(0xf073, 0xf07c + 1), 0xf08a], # other things
+ # Note: Codepoints listed before that are also in the following range
+ # will take the scaling of the previous group (the ScaleGroups are
+ # searched through in definition order).
+ # But be careful, the combined bounding box for the following group
+ # _will_ include all glyphs in its definition: Make sure the exempt
+ # glyphs from above are smaller (do not extend) the combined bounding
+ # box of this range:
+ [ *range(0xf000, 0xf041 + 1),
+ *range(0xf064, 0xf06d + 1),
+ *range(0xf07d, 0xf083 + 1),
+ *range(0xf085, 0xf086 + 1),
+ *range(0xf0b2, 0xf0b6 + 1)
+ ], # lots of clouds (weather states) (Please read note above!)
+ ]}
+ MDI_SCALE_LIST = None # Maybe later add some selected ScaleGroups
+
+
+ # Define the character ranges
+ # Symbol font ranges
+ self.patch_set = [
+ {'Enabled': True, 'Name': "Seti-UI + Custom", 'Filename': "original-source.otf", 'Exact': False, 'SymStart': 0xE4FA, 'SymEnd': 0xE5FF, 'SrcStart': 0xE5FA, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT},
+ {'Enabled': True, 'Name': "Heavy Angle Brackets", 'Filename': "extraglyphs.sfd", 'Exact': True, 'SymStart': 0x276C, 'SymEnd': 0x2771, 'SrcStart': None, 'ScaleRules': HEAVY_SCALE_LIST, 'Attributes': SYM_ATTR_HEAVYBRACKETS},
+ {'Enabled': box_enabled, 'Name': "Box Drawing", 'Filename': "extraglyphs.sfd", 'Exact': True, 'SymStart': 0x2500, 'SymEnd': 0x259F, 'SrcStart': None, 'ScaleRules': BOX_SCALE_LIST, 'Attributes': SYM_ATTR_BOX},
+ {'Enabled': True, 'Name': "Progress Indicators", 'Filename': "extraglyphs.sfd", 'Exact': True, 'SymStart': 0xEE00, 'SymEnd': 0xEE0B, 'SrcStart': None, 'ScaleRules': PROGR_SCALE_LIST, 'Attributes': SYM_ATTR_PROGRESS},
+ {'Enabled': True, 'Name': "Devicons", 'Filename': "devicons/devicons.otf", 'Exact': False, 'SymStart': 0xE600, 'SymEnd': 0xE7EF, 'SrcStart': 0xE700, 'ScaleRules': DEVI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT},
+ {'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "powerline-symbols/PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE},
+ {'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "powerline-symbols/PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE},
+ {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "powerline-extra/PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0A3, 'SymEnd': 0xE0A3, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE},
+ {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "powerline-extra/PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0B4, 'SymEnd': 0xE0C8, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE},
+ {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "powerline-extra/PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0CA, 'SymEnd': 0xE0CA, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE},
+ {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "powerline-extra/PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0CC, 'SymEnd': 0xE0D7, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE},
+ {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "powerline-extra/PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0x2630, 'SymEnd': 0x2630, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_TRIGRAPH},
+ {'Enabled': self.args.pomicons, 'Name': "Pomicons", 'Filename': "pomicons/Pomicons.otf", 'Exact': True, 'SymStart': 0xE000, 'SymEnd': 0xE00A, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT},
+ {'Enabled': self.args.fontawesome, 'Name': "Font Awesome", 'Filename': "font-awesome/FontAwesome.otf", 'Exact': True, 'SymStart': 0xED00, 'SymEnd': 0xF2FF, 'SrcStart': None, 'ScaleRules': FONTA_SCALE_LIST, 'Attributes': SYM_ATTR_FONTA},
+ {'Enabled': self.args.fontawesomeextension, 'Name': "Font Awesome Extension", 'Filename': "font-awesome-extension.ttf", 'Exact': False, 'SymStart': 0xE000, 'SymEnd': 0xE0A9, 'SrcStart': 0xE200, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Maximize
+ {'Enabled': self.args.powersymbols, 'Name': "Power Symbols", 'Filename': "Unicode_IEC_symbol_font.otf", 'Exact': True, 'SymStart': 0x23FB, 'SymEnd': 0x23FE, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Power, Power On/Off, Power On, Sleep
+ {'Enabled': self.args.powersymbols, 'Name': "Power Symbols", 'Filename': "Unicode_IEC_symbol_font.otf", 'Exact': True, 'SymStart': 0x2B58, 'SymEnd': 0x2B58, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Heavy Circle (aka Power Off)
+ {'Enabled': False , 'Name': "Material legacy", 'Filename': "materialdesign/materialdesignicons-webfont.ttf", 'Exact': False, 'SymStart': 0xF001, 'SymEnd': 0xF847, 'SrcStart': 0xF500, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT},
+ {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0001,'SymEnd': 0xF1AF0,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT},
+ {'Enabled': self.args.weather, 'Name': "Weather Icons", 'Filename': "weather-icons/weathericons-regular-webfont.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF0EB, 'SrcStart': 0xE300, 'ScaleRules': WEATH_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT},
+ {'Enabled': self.args.fontlogos, 'Name': "Font Logos", 'Filename': "font-logos.ttf", 'Exact': True, 'SymStart': 0xF300, 'SymEnd': 0xF381, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT},
+ {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.otf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF105, 'SrcStart': 0xF400, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Magnifying glass
+ {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.otf", 'Exact': True, 'SymStart': 0x2665, 'SymEnd': 0x2665, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Heart
+ {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.otf", 'Exact': True, 'SymStart': 0X26A1, 'SymEnd': 0X26A1, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Zap
+ {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.otf", 'Exact': False, 'SymStart': 0xF27C, 'SymEnd': 0xF306, 'SrcStart': 0xF4A9, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT},
+ {'Enabled': self.args.codicons, 'Name': "Codicons", 'Filename': "codicons/codicon.ttf", 'Exact': True, 'SymStart': 0xEA60, 'SymEnd': 0xEC1E, 'SrcStart': None, 'ScaleRules': CODI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT},
+ {'Enabled': self.args.custom, 'Name': "Custom", 'Filename': self.args.custom, 'Exact': True, 'SymStart': 0x0000, 'SymEnd': 0x0000, 'SrcStart': None, 'ScaleRules': None, 'Attributes': CUSTOM_ATTR}
+ ]
+
+ def improve_line_dimensions(self):
+ # Make the total line size even. This seems to make the powerline separators
+ # center more evenly.
+ if self.args.adjustLineHeight:
+ if (self.sourceFont.os2_winascent + self.sourceFont.os2_windescent) % 2 != 0:
+ # All three are equal before due to get_sourcefont_dimensions()
+ self.sourceFont.hhea_ascent += 1
+ self.sourceFont.os2_typoascent += 1
+ self.sourceFont.os2_winascent += 1
+
+ def add_glyphrefs_to_essential(self, unicode):
+ self.essential.add(unicode)
+ # According to fontforge spec, altuni is either None or a tuple of tuples
+ # Those tuples contained in altuni are of the following "format":
+ # (unicode-value, variation-selector, reserved-field)
+ altuni = self.sourceFont[unicode].altuni
+ if altuni is not None:
+ for altcode in [ v for v, s, r in altuni if v >= 0 ]:
+ # If alternate unicode already exists in self.essential,
+ # that means it has gone through this function before.
+ # Therefore we skip it to avoid infinite loop.
+ # A unicode value of -1 basically means unused and is also worth skipping.
+ if altcode not in self.essential:
+ self.add_glyphrefs_to_essential(altcode)
+ # From fontforge documentation:
+ # glyph.references return a tuple of tuples containing, for each reference in foreground,
+ # a glyph name, a transformation matrix, and (depending on ff version) whether the
+ # reference is currently selected.
+ references = self.sourceFont[unicode].references
+ for refcode in [ self.sourceFont[n].unicode for n, *_ in references ]: # tuple of 2 or 3 depending on ff version
+ if refcode not in self.essential and refcode >= 0:
+ self.add_glyphrefs_to_essential(refcode)
+
+ def get_essential_references(self):
+ """Find glyphs that are needed for the basic glyphs"""
+ # Sometimes basic glyphs are constructed from multiple other glyphs.
+ # Find out which other glyphs are also needed to keep the basic
+ # glyphs intact.
+ # 0x0000-0x017f is the Latin Extended-A range
+ # 0xfb00-0xfb06 are 'fi' and other ligatures
+ basic_glyphs = { c for c in range(0x21, 0x17f + 1) if c in self.sourceFont }
+ # Collect substitution destinations
+ for glyph in list(basic_glyphs) + [*range(0xfb00, 0xfb06 + 1)]:
+ if not glyph in self.sourceFont:
+ continue
+ for possub in self.sourceFont[glyph].getPosSub('*'):
+ if possub[1] == 'Substitution' or possub[1] == 'Ligature':
+ basic_glyphs.add(glyph)
+ basic_glyphs.add(self.sourceFont[possub[2]].unicode)
+ basic_glyphs.discard(-1) # the .notdef glyph
+ for glyph in basic_glyphs:
+ self.add_glyphrefs_to_essential(glyph)
+
+ def get_sourcefont_dimensions(self):
+ """ This gets the font dimensions (cell width and height), and makes them equal on all platforms """
+ # Step 1
+ # There are three ways to describe the baseline to baseline distance
+ # (a.k.a. line spacing) of a font. That is all a kuddelmuddel
+ # and we try to sort this out here
+ # See also https://glyphsapp.com/learn/vertical-metrics
+ # See also https://github.com/source-foundry/font-line
+ (hhea_btb, typo_btb, win_btb, win_gap) = get_btb_metrics(self.sourceFont)
+ use_typo = self.sourceFont.os2_use_typo_metrics != 0
+
+ Metric = Enum('Metric', get_metrics_names())
+
+ if not self.args.metrics:
+ # We use either TYPO (1) or WIN (2) and compare with HHEA
+ # and use HHEA (0) if the fonts seems broken - no WIN, see #1056
+ our_btb = typo_btb if use_typo else win_btb
+ if our_btb == hhea_btb:
+ metrics = Metric.TYPO if use_typo else Metric.WIN # conforming font
+ elif abs(our_btb - hhea_btb) / our_btb < 0.03:
+ logger.info("Font vertical metrics slightly off (%.1f%%)", (our_btb - hhea_btb) / our_btb * 100.0)
+ metrics = Metric.TYPO if use_typo else Metric.WIN
+ else:
+ # Try the other metric
+ our_btb = typo_btb if not use_typo else win_btb
+ if our_btb == hhea_btb:
+ use_typo = not use_typo
+ logger.warning("Font vertical metrics probably wrong USE TYPO METRICS, assume opposite (i.e. %s)", repr(use_typo))
+ self.sourceFont.os2_use_typo_metrics = 1 if use_typo else 0
+ metrics = Metric.TYPO if use_typo else Metric.WIN
+ else:
+ # We trust the WIN metric more, see experiments in #1056
+ logger.warning("Font vertical metrics inconsistent (HHEA %d / TYPO %d / WIN %d), using WIN", hhea_btb, typo_btb, win_btb)
+ our_btb = win_btb
+ metrics = Metric.WIN
+ else:
+ metrics = Metric[self.args.metrics]
+ logger.debug("Metrics in the font: HHEA %d / TYPO %d / WIN %d", hhea_btb, typo_btb, win_btb)
+ if metrics == Metric.HHEA:
+ our_btb = hhea_btb
+ elif metrics == Metric.TYPO:
+ our_btb = typo_btb
+ else:
+ our_btb = win_btb
+ logger.info("Manually selected metrics: %s (%d)", self.args.metrics, our_btb)
+
+ # print("FINI hhea {} typo {} win {} use {} {} {}".format(hhea_btb, typo_btb, win_btb, use_typo, our_btb != hhea_btb, self.sourceFont.fontname))
+
+ self.font_dim = {'xmin': 0, 'ymin': 0, 'xmax': 0, 'ymax': 0, 'width' : 0, 'height': 0, 'iconheight': 0, 'ypadding': 0}
+
+ if metrics == Metric.HHEA:
+ self.font_dim['ymin'] = self.sourceFont.hhea_descent - half_gap(self.sourceFont.hhea_linegap, False)
+ self.font_dim['ymax'] = self.sourceFont.hhea_ascent + half_gap(self.sourceFont.hhea_linegap, True)
+ elif metrics == Metric.TYPO:
+ self.font_dim['ymin'] = self.sourceFont.os2_typodescent - half_gap(self.sourceFont.os2_typolinegap, False)
+ self.font_dim['ymax'] = self.sourceFont.os2_typoascent + half_gap(self.sourceFont.os2_typolinegap, True)
+ elif metrics == Metric.WIN:
+ self.font_dim['ymin'] = -self.sourceFont.os2_windescent - half_gap(win_gap, False)
+ self.font_dim['ymax'] = self.sourceFont.os2_winascent + half_gap(win_gap, True)
+ else:
+ logger.debug("Metrics is strange")
+ pass # Will fail the metrics check some line later
+
+ if isinstance(self.args.cellopt, list):
+ logger.debug("Overriding cell Y{%d:%d} with Y{%d:%d}",
+ self.font_dim['ymin'], self.font_dim['ymax'],
+ self.args.cellopt[2], self.args.cellopt[3])
+ self.font_dim['ymin'] = self.args.cellopt[2]
+ self.font_dim['ymax'] = self.args.cellopt[3]
+ our_btb = self.args.cellopt[3] - self.args.cellopt[2]
+
+ # Calculate font height
+ self.font_dim['height'] = -self.font_dim['ymin'] + self.font_dim['ymax']
+ if self.font_dim['height'] == 0:
+ # This can only happen if the input font is empty
+ # Assume we are using our prepared templates
+ self.symbolsonly = True
+ self.font_dim = {
+ 'xmin' : 0,
+ 'ymin' : -self.sourceFont.descent,
+ 'xmax' : self.sourceFont.em,
+ 'ymax' : self.sourceFont.ascent,
+ 'width' : self.sourceFont.em,
+ 'height' : self.sourceFont.descent + self.sourceFont.ascent,
+ 'iconheight': self.sourceFont.descent + self.sourceFont.ascent,
+ 'ypadding' : 0,
+ }
+ our_btb = self.sourceFont.descent + self.sourceFont.ascent
+ if self.font_dim['height'] <= 0:
+ logger.critical("Can not detect sane font height")
+ sys.exit(1)
+
+ self.font_dim['iconheight'] = self.font_dim['height']
+ if self.args.single and self.sourceFont.capHeight > 0 and not isinstance(self.args.cellopt, list):
+ # Limit the icon height on monospaced fonts because very slender and tall icons render
+ # excessively tall otherwise. We ignore that effect for the other variants because it
+ # does not look so much out of place there.
+ # Icons can be bigger than the letter capitals, but not the whole cell:
+ self.font_dim['iconheight'] = (self.sourceFont.capHeight * 2 + self.font_dim['height']) / 3
+
+ # Make all metrics equal
+ self.sourceFont.os2_typolinegap = 0
+ self.sourceFont.os2_typoascent = self.font_dim['ymax']
+ self.sourceFont.os2_typodescent = self.font_dim['ymin']
+ self.sourceFont.os2_winascent = self.sourceFont.os2_typoascent
+ self.sourceFont.os2_windescent = -self.sourceFont.os2_typodescent
+ self.sourceFont.hhea_ascent = self.sourceFont.os2_typoascent
+ self.sourceFont.hhea_descent = self.sourceFont.os2_typodescent
+ self.sourceFont.hhea_linegap = self.sourceFont.os2_typolinegap
+ self.sourceFont.os2_use_typo_metrics = 1
+ (check_hhea_btb, check_typo_btb, check_win_btb, _) = get_btb_metrics(self.sourceFont)
+ if check_hhea_btb != check_typo_btb or check_typo_btb != check_win_btb or check_win_btb != our_btb:
+ logger.critical("Error in baseline to baseline code detected")
+ sys.exit(1)
+
+ # Step 2
+ # Find the biggest char width and advance width
+ # 0x00-0x17f is the Latin Extended-A range
+ warned1 = self.args.nonmono # Do not warn if proportional target
+ warned2 = warned1
+ for glyph in range(0x21, 0x17f):
+ if glyph in range(0x7F, 0xBF) or glyph in [
+ 0x132, 0x133, # IJ, ij (in Overpass Mono)
+ 0x022, 0x027, 0x060, # Single and double quotes in Inconsolata LGC
+ 0x0D0, 0x10F, 0x110, 0x111, 0x127, 0x13E, 0x140, 0x165, # Eth and others with stroke or caron in RobotoMono
+ 0x149, # napostrophe in DaddyTimeMono
+ 0x02D, # hyphen for Monofur
+ ]:
+ continue # ignore special characters like '1/4' etc and some specifics
+ try:
+ (_, _, xmax, _) = self.sourceFont[glyph].boundingBox()
+ except TypeError:
+ continue
+ # print("WIDTH {:X} {} ({} {})".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax))
+ if self.font_dim['width'] < self.sourceFont[glyph].width:
+ self.font_dim['width'] = self.sourceFont[glyph].width
+ if not warned1 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z
+ logger.debug("Extended glyphs wider than basic glyphs, results might be useless")
+ logger.debug("%s", report_advance_widths(self.sourceFont))
+ warned1 = True
+ # print("New MAXWIDTH-A {:X} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax))
+ if xmax > self.font_dim['xmax']:
+ self.font_dim['xmax'] = xmax
+ if not warned2 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z
+ logger.debug("Extended glyphs wider bounding box than basic glyphs")
+ warned2 = True
+ # print("New MAXWIDTH-B {:X} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax))
+ if self.font_dim['width'] < self.font_dim['xmax']:
+ logger.debug("Font has negative right side bearing in extended glyphs")
+ self.font_dim['xmax'] = self.font_dim['width'] # In fact 'xmax' is never used
+ if self.font_dim['width'] <= 0:
+ logger.critical("Can not detect sane font width")
+ sys.exit(1)
+ if isinstance(self.args.cellopt, list):
+ logger.debug("Overriding cell X{%d:%d} with X{%d:%d}",
+ self.font_dim['xmin'], self.font_dim['xmin'] + self.font_dim['width'],
+ self.args.cellopt[0], self.args.cellopt[1])
+ self.font_dim['xmin'] = self.args.cellopt[0]
+ self.font_dim['xmax'] = self.args.cellopt[1]
+ self.font_dim['width'] = self.args.cellopt[1]
+ if self.args.cellopt:
+ logger.info("Cell coordinates (Xmin:Xmax:Ymin:Ymax) %s%d:%d:%d:%d",
+ '' if not isinstance(self.args.cellopt, list) else 'overridden with ',
+ self.font_dim['xmin'], self.font_dim['width'],
+ self.font_dim['ymax'] - self.font_dim['height'], self.font_dim['ymax'])
+ logger.debug("Final font cell dimensions %d w x %d h%s",
+ self.font_dim['width'], self.font_dim['height'],
+ ' (with icon cell {} h)'.format(int(self.font_dim['iconheight'])) if self.font_dim['iconheight'] != self.font_dim['height'] else '')
+ try:
+ middle = lambda x, y: abs(x - y) / 2 + min(x, y)
+ x_bb = self.sourceFont['x'].boundingBox();
+ X_bb = self.sourceFont['X'].boundingBox();
+ logger.debug("Center x-height/cell/capitals %d/%d/%d",
+ middle(x_bb[1], x_bb[3]),
+ middle(self.font_dim['ymin'], self.font_dim['ymax']),
+ middle(X_bb[1], X_bb[3]))
+ except:
+ pass
+
+ self.xavgwidth.append(self.args.xavgwidth)
+ if isinstance(self.xavgwidth[-1], int) and self.xavgwidth[-1] == 0:
+ self.xavgwidth[-1] = get_old_average_x_width(self.sourceFont)
+
+
+ def get_target_width(self, stretch):
+ """ Get the target width (1 or 2 'cell') for a given stretch parameter """
+ # For monospaced fonts all chars need to be maximum 'one' space wide
+ # other fonts allows double width glyphs for 'pa' or if requested with '2'
+ if self.args.single or ('pa' not in stretch and '2' not in stretch) or '1' in stretch:
+ return 1
+ return 2
+
+ def get_scale_factors(self, sym_dim, stretch, overlap=None):
+ """ Get scale in x and y as tuple """
+ # It is possible to have empty glyphs, so we need to skip those.
+ if not sym_dim['width'] or not sym_dim['height']:
+ return (1.0, 1.0)
+
+ target_width = self.font_dim['width'] * self.get_target_width(stretch)
+ if overlap:
+ target_width += self.font_dim['width'] * overlap
+ scale_ratio_x = target_width / sym_dim['width']
+
+ # font_dim['height'] represents total line height, keep our symbols sized based upon font's em
+ # Use the font_dim['height'] only for explicit 'y' scaling (not 'pa')
+ target_height = self.font_dim['height'] if '^' in stretch else self.font_dim['iconheight']
+ target_height *= 1.0 - self.font_dim['ypadding']
+ if overlap:
+ target_height *= 1.0 + min(0.01, overlap) # never aggressive vertical overlap
+ scale_ratio_y = target_height / sym_dim['height']
+
+ if 'pa' in stretch:
+ # We want to preserve x/y aspect ratio, so find biggest scale factor that allows symbol to fit
+ scale_ratio_x = min(scale_ratio_x, scale_ratio_y)
+ if not self.args.single and not '!' in stretch and not overlap:
+ # non monospaced fonts just scale down on 'pa', not up
+ scale_ratio_x = min(scale_ratio_x, 1.0)
+ scale_ratio_y = scale_ratio_x
+ else:
+ # Keep the not-stretched direction
+ if not 'x' in stretch:
+ scale_ratio_x = 1.0
+ if not 'y' in stretch:
+ scale_ratio_y = 1.0
+
+ return (scale_ratio_x, scale_ratio_y)
+
+
+ def copy_glyphs(self, sourceFontStart, symbolFont, symbolFontStart, symbolFontEnd, exactEncoding, scaleRules, setName, attributes):
+ """ Copies symbol glyphs into self.sourceFont """
+ progressText = ''
+ careful = False
+ sourceFontCounter = 0
+
+ if self.args.careful:
+ careful = True
+
+ # Create glyphs from symbol font
+ #
+ # If we are going to copy all Glyphs, then assume we want to be careful
+ # and only copy those that are not already contained in the source font
+ if symbolFontStart == 0:
+ symbolFont.selection.all()
+ careful = True
+ else:
+ symbolFont.selection.select((str("ranges"), str("unicode")), symbolFontStart, symbolFontEnd)
+
+ # Get number of selected non-empty glyphs with codes >=0 (i.e. not -1 == notdef)
+ symbolFontSelection = [ x for x in symbolFont.selection.byGlyphs if x.unicode >= 0 ]
+ glyphSetLength = len(symbolFontSelection)
+
+ if not self.args.quiet:
+ modify = attributes['default']['params'].get('dont_copy')
+ sys.stdout.write("{} {} Glyphs from {} Set\n".format(
+ "Adding" if not modify else "Rescaling", glyphSetLength, setName))
+
+ currentSourceFontGlyph = -1 # initialize for the exactEncoding case
+ width_warning = False
+
+ for index, sym_glyph in enumerate(symbolFontSelection):
+ sym_attr = attributes.get(sym_glyph.unicode)
+ if sym_attr is None:
+ sym_attr = attributes['default']
+
+ if self.font_extrawide:
+ # Do not allow 'xy2' scaling
+ sym_attr['stretch'] = sym_attr['stretch'].replace('2', '')
+
+ if exactEncoding:
+ # Use the exact same hex values for the source font as for the symbol font.
+ # Problem is we do not know the codepoint of the sym_glyph and because it
+ # came from a selection.byGlyphs there might be skipped over glyphs.
+ # The iteration is still in the order of the selection by codepoint,
+ # so we take the next allowed codepoint of the current glyph
+ possible_codes = [ ]
+ if sym_glyph.unicode > currentSourceFontGlyph:
+ possible_codes += [ sym_glyph.unicode ]
+ if sym_glyph.altuni:
+ possible_codes += [ v for v, s, r in sym_glyph.altuni if v > currentSourceFontGlyph ]
+ if len(possible_codes) == 0:
+ logger.warning("Can not determine codepoint of %X. Skipping...", sym_glyph.unicode)
+ continue
+ currentSourceFontGlyph = min(possible_codes)
+ else:
+ # use source font defined hex values based on passed in start (fills gaps; symbols are packed)
+ currentSourceFontGlyph = sourceFontStart + sourceFontCounter
+ sourceFontCounter += 1
+
+ # For debugging process only limited glyphs
+ # if currentSourceFontGlyph != 0xe7bd:
+ # continue
+
+ ypadding = sym_attr['params'].get('ypadding')
+ self.font_dim['ypadding'] = ypadding or 0.0
+
+ if not self.args.quiet:
+ if self.args.progressbars:
+ update_progress(round(float(index + 1) / glyphSetLength, 2))
+ else:
+ progressText = "\nUpdating glyph: {} {} putting at: {:X}".format(sym_glyph, sym_glyph.glyphname, currentSourceFontGlyph)
+ sys.stdout.write(progressText)
+ sys.stdout.flush()
+
+ # check if a glyph already exists in this location
+ do_careful = sym_attr['params'].get('careful', careful) # params take precedence
+ if do_careful or currentSourceFontGlyph in self.essential:
+ if currentSourceFontGlyph in self.sourceFont:
+ careful_type = 'essential' if currentSourceFontGlyph in self.essential else 'existing'
+ logger.debug("Found %s Glyph at %X. Skipping...", careful_type, currentSourceFontGlyph)
+ # We don't want to touch anything so move to next Glyph
+ continue
+ else:
+ # If we overwrite an existing glyph all subtable entries regarding it will be wrong
+ # (Probably; at least if we add a symbol and do not substitute a ligature or such)
+ if currentSourceFontGlyph in self.sourceFont:
+ self.sourceFont[currentSourceFontGlyph].removePosSub("*")
+
+ stretch = sym_attr['stretch']
+ dont_copy = sym_attr['params'].get('dont_copy')
+
+ if dont_copy:
+ # Just prepare scaling of existing glyphs
+ glyph_scale_data = self.get_glyph_scale(sym_glyph.encoding, scaleRules, stretch, self.sourceFont, currentSourceFontGlyph) if scaleRules is not None else None
+ else:
+ # Break apart multiple unicodes linking to one glyph
+ if currentSourceFontGlyph in self.sourceFont:
+ altuni = self.sourceFont[currentSourceFontGlyph].altuni
+ if altuni:
+ codes = { v for v, s, r in altuni if v >= 0 }
+ codes.add(self.sourceFont[currentSourceFontGlyph].unicode)
+ codes.remove(currentSourceFontGlyph)
+ codes = [ "{:04X}".format(c) for c in sorted(list(codes)) ]
+ logger.debug("Removing alternate unicode on %X (%s)", currentSourceFontGlyph, ' '.join(codes));
+ self.sourceFont[currentSourceFontGlyph].altuni = None
+ self.sourceFont.encoding = 'UnicodeFull' # Rebuild encoding table (needed after altuni changes)
+
+ # This will destroy any content currently in currentSourceFontGlyph, so do it first
+ glyph_scale_data = self.get_glyph_scale(sym_glyph.encoding, scaleRules, stretch, symbolFont, currentSourceFontGlyph) if scaleRules is not None else None
+
+ # Select and copy symbol from its encoding point
+ # We need to do this select after the careful check, this way we don't
+ # reset our selection before starting the next loop
+ symbolFont.selection.select(sym_glyph.encoding)
+ symbolFont.copy()
+
+ # Paste it
+ self.sourceFont.selection.select(currentSourceFontGlyph)
+ self.sourceFont.paste()
+ self.sourceFont[currentSourceFontGlyph].glyphname = \
+ self.glyphnames.get(currentSourceFontGlyph, sym_glyph.glyphname) if setName != 'Custom' else sym_glyph.glyphname
+ self.sourceFont[currentSourceFontGlyph].manualHints = True # No autohints for symbols
+
+ # Prepare symbol glyph dimensions
+ sym_dim = get_glyph_dimensions(self.sourceFont[currentSourceFontGlyph])
+ overlap = sym_attr['params'].get('overlap')
+ if overlap and ypadding:
+ logger.critical("Conflicting params: overlap and ypadding")
+ sys.exit(1)
+
+ if glyph_scale_data is not None:
+ if glyph_scale_data[1] is not None:
+ sym_dim = glyph_scale_data[1] # Use combined bounding box
+ (scale_ratio_x, scale_ratio_y) = self.get_scale_factors(sym_dim, stretch, overlap)
+ else:
+ # This is roughly alike get_scale_factors(glyph_scale_data[1], 'pa')
+ # Except we do not have glyph_scale_data[1] always...
+ (scale_ratio_x, scale_ratio_y) = (glyph_scale_data[0], glyph_scale_data[0])
+ if overlap:
+ scale_ratio_x *= 1.0 + (self.font_dim['width'] / (sym_dim['width'] * scale_ratio_x)) * overlap
+ y_overlap = min(0.01, overlap) # never aggressive vertical overlap
+ scale_ratio_y *= 1.0 + (self.font_dim['height'] / (sym_dim['height'] * scale_ratio_y)) * y_overlap
+ else:
+ (scale_ratio_x, scale_ratio_y) = self.get_scale_factors(sym_dim, stretch, overlap)
+
+
+ # Size in x to size in y ratio limit (to prevent over-wide glyphs)
+ xy_ratio_max = sym_attr['params'].get('xy-ratio')
+ if (xy_ratio_max):
+ xy_ratio = sym_dim['width'] * scale_ratio_x / (sym_dim['height'] * scale_ratio_y)
+ if xy_ratio > xy_ratio_max:
+ scale_ratio_x = scale_ratio_x * xy_ratio_max / xy_ratio
+
+ if scale_ratio_x != 1.0 or scale_ratio_y != 1.0:
+ scale_ratio_x *= self.sourceFont.em / (self.sourceFont.em + 1) # scale a tiny bit too small to avoid rounding problems
+ self.sourceFont[currentSourceFontGlyph].transform(psMat.scale(scale_ratio_x, scale_ratio_y))
+
+ # Drop nonintegral part of nodes' coordinates; ttf will do it anyhow, otf will be much smaller
+ self.sourceFont[currentSourceFontGlyph].round()
+
+ if self.args.single:
+ # Check and correct the scaling after rounding (if all 3 tries fail we will get a warning later on)
+ destmaxsize = self.font_dim['width'] * max(1, 1 + (overlap or 0))
+ for increaser in range(3):
+ (xmin, _, xmax, _) = self.sourceFont[currentSourceFontGlyph].boundingBox()
+ sizeerror = (xmax - xmin) - destmaxsize
+ if sizeerror <= 0:
+ break
+ # Start from scratch with a new unscaled glyph
+ scale_ratio_x /= 1 + ((sizeerror + increaser) / destmaxsize)
+ self.sourceFont.paste()
+ self.sourceFont[currentSourceFontGlyph].transform(psMat.scale(scale_ratio_x, scale_ratio_y))
+ self.sourceFont[currentSourceFontGlyph].round()
+
+ # We pasted and scaled now we want to align/move
+ # Use the dimensions from the newly pasted and stretched glyph to avoid any rounding errors
+ sym_dim = get_glyph_dimensions(self.sourceFont[currentSourceFontGlyph])
+ # Use combined bounding box?
+ if glyph_scale_data is not None and glyph_scale_data[1] is not None:
+ scaleglyph_dim = scale_bounding_box(glyph_scale_data[1], scale_ratio_x, scale_ratio_y)
+ if scaleglyph_dim['advance'] is None:
+ # On monospaced symbol collections use their advance with, otherwise align horizontally individually
+ scaleglyph_dim['xmin'] = sym_dim['xmin']
+ scaleglyph_dim['xmax'] = sym_dim['xmax']
+ scaleglyph_dim['width'] = sym_dim['width']
+ sym_dim = scaleglyph_dim
+
+ y_align_distance = 0
+ if sym_attr['valign'] == 'c':
+ # Center the symbol vertically by matching the center of the line height and center of symbol
+ sym_ycenter = sym_dim['ymax'] - (sym_dim['height'] / 2)
+ font_ycenter = self.font_dim['ymax'] - (self.font_dim['height'] / 2)
+ y_align_distance = font_ycenter - sym_ycenter
+
+ # Handle glyph l/r/c alignment
+ x_align_distance = 0
+ simple_nonmono = self.args.nonmono and sym_dim['advance'] is None
+ if simple_nonmono:
+ # Remove left side bearing
+ # (i.e. do not remove left side bearing when combined BB is in use)
+ x_align_distance = -self.sourceFont[currentSourceFontGlyph].left_side_bearing
+ elif sym_attr['align']:
+ # First find the baseline x-alignment (left alignment amount)
+ x_align_distance = self.font_dim['xmin'] - sym_dim['xmin']
+ if self.args.nonmono and 'pa' in stretch:
+ cell_width = sym_dim['advance'] or sym_dim['width']
+ else:
+ cell_width = self.font_dim['width']
+ if sym_attr['align'] == 'c':
+ # Center align
+ x_align_distance += (cell_width / 2) - (sym_dim['width'] / 2)
+ elif sym_attr['align'] == 'r':
+ # Right align
+ # (not really supported with pa scaling and 2x stretch in NFP)
+ x_align_distance += cell_width * self.get_target_width(stretch) - sym_dim['width']
+ if not overlap:
+ # If symbol glyph is wider than target font cell, just left-align
+ x_align_distance = max(self.font_dim['xmin'] - sym_dim['xmin'], x_align_distance)
+
+ if overlap:
+ overlap_width = self.font_dim['width'] * overlap
+ if sym_attr['align'] == 'l':
+ x_align_distance -= overlap_width
+ elif sym_attr['align'] == 'c':
+ # center aligned keeps being center aligned even with overlap
+ if overlap_width < 0 and simple_nonmono: # Keep positive bearing due to negative overlap (propo)
+ x_align_distance -= overlap_width / 2
+ elif sym_attr['align'] == 'r' and not simple_nonmono:
+ # Check and correct overlap; it can go wrong if we have a xy-ratio limit
+ target_xmax = (self.font_dim['xmin'] + self.font_dim['width']) * self.get_target_width(stretch)
+ target_xmax += overlap_width
+ glyph_xmax = sym_dim['xmax'] + x_align_distance
+ correction = target_xmax - glyph_xmax
+ x_align_distance += correction
+
+ align_matrix = psMat.translate(x_align_distance, y_align_distance)
+ self.sourceFont[currentSourceFontGlyph].transform(align_matrix)
+
+ # Ensure after horizontal adjustments and centering that the glyph
+ # does not overlap the bearings (edges)
+ if not overlap:
+ self.remove_glyph_neg_bearings(self.sourceFont[currentSourceFontGlyph])
+
+ # Needed for setting 'advance width' on each glyph so they do not overlap,
+ # also ensures the font is considered monospaced on Windows by setting the
+ # same width for all character glyphs. This needs to be done for all glyphs,
+ # even the ones that are empty and didn't go through the scaling operations.
+ # It should come after setting the glyph bearings
+ if not self.args.nonmono:
+ self.set_glyph_width_mono(self.sourceFont[currentSourceFontGlyph])
+ else:
+ # Target font with variable advance width get the icons with their native widths
+ # and keeping possible (right and/or negative) bearings in effect
+ if sym_dim['advance'] is not None:
+ # 'Width' from monospaced scale group
+ width = sym_dim['advance']
+ else:
+ width = sym_dim['width']
+ # If we have overlap we need to subtract that to keep/get negative bearings
+ if overlap:
+ width -= overlap_width
+ # Fontforge handles the width change like this:
+ # - Keep existing left_side_bearing
+ # - Set width
+ # - Calculate and set new right_side_bearing
+ self.sourceFont[currentSourceFontGlyph].width = int(width)
+
+ # Check if the inserted glyph is scaled correctly for monospace
+ if self.args.single:
+ (xmin, _, xmax, _) = self.sourceFont[currentSourceFontGlyph].boundingBox()
+ if (xmax - xmin) > self.font_dim['width'] * max(1, 1 + (overlap or 0)):
+ logger.warning("Scaled glyph %X wider than one monospace width (%d / %d (overlap %s))",
+ currentSourceFontGlyph, int(xmax - xmin), self.font_dim['width'], repr(overlap))
+
+ # end for
+
+ if not self.args.quiet:
+ sys.stdout.write("\n")
+
+
+ def set_sourcefont_glyph_widths(self):
+ """ Makes self.sourceFont monospace compliant """
+
+ for glyph in self.sourceFont.glyphs():
+ if (glyph.width == self.font_dim['width']):
+ # Don't touch the (negative) bearings if the width is ok
+ # Ligatures will have these.
+ continue
+
+ if (glyph.width != 0):
+ # If the width is zero this glyph is intended to be printed on top of another one.
+ # In this case we need to keep the negative bearings to shift it 'left'.
+ # Things like Ä have these: composed of U+0041 'A' and U+0308 'double dot above'
+ #
+ # If width is not zero, correct the bearings such that they are within the width:
+ self.remove_glyph_neg_bearings(glyph)
+
+ self.set_glyph_width_mono(glyph)
+
+
+ def remove_glyph_neg_bearings(self, glyph):
+ """ Sets passed glyph's bearings 0 if they are negative. """
+ try:
+ if glyph.left_side_bearing < 0:
+ glyph.left_side_bearing = 0
+ if glyph.right_side_bearing < 0:
+ glyph.right_side_bearing = 0
+ except:
+ pass
+
+
+ def set_glyph_width_mono(self, glyph):
+ """ Sets passed glyph.width to self.font_dim.width.
+
+ self.font_dim.width is set with self.get_sourcefont_dimensions().
+ """
+ try:
+ # Fontforge handles the width change like this:
+ # - Keep existing left_side_bearing
+ # - Set width
+ # - Calculate and set new right_side_bearing
+ glyph.width = self.font_dim['width']
+ except:
+ pass
+
+ def prepareScaleRules(self, scaleRules, stretch, symbolFont, destGlyph):
+ """ Prepare raw ScaleRules data for use """
+ # The scaleRules is/will be a dict with these (possible) entries:
+ # 'ScaleGroups': List of ((lists of glyph codes) or (ranges of glyph codes)) that shall be scaled
+ # 'scales': List of associated scale factors, one for each entry in 'ScaleGroups' (generated by this function)
+ # 'bbdims': List of associated sym_dim dicts, one for each entry in 'ScaleGroups' (generated by this function)
+ # Each dim_dict describes the combined bounding box of all glyphs in one ScaleGroups group
+ # Example:
+ # { 'ScaleGroups': [ range(1, 3), [ 7, 10 ], ],
+ # 'scales': [ 1.23, 1.33, ],
+ # 'bbdims': [ dim_dict1, dim_dict2, ] }
+ #
+ # Each item in 'ScaleGroups' (a range or an explicit list) forms a group of glyphs that shall be
+ # as rescaled all with the same and maximum possible (for the included glyphs) 'pa' factor.
+ # If the 'bbdims' is present they all shall be shifted in the same way.
+ #
+ # Previously this structure has been used:
+ # 'ScaleGlyph' Lead glyph, which scaling factor is taken
+ # 'GlyphsToScale': List of ((glyph code) or (tuple of two glyph codes that form a closed range)) that shall be scaled
+ # Note that this allows only one group for the whle symbol font, and that the scaling factor is defined by
+ # a specific character, which needs to be manually selected (on each symbol font update).
+ # Previous entries are automatically rewritten to the new style.
+ #
+ # Note that scaleRules is overwritten with the added data.
+ if 'scales' in scaleRules:
+ # Already prepared... must not happen, ignore call
+ return
+
+ scaleRules['scales'] = []
+ scaleRules['bbdims'] = []
+ if 'ScaleGroups' not in scaleRules:
+ scaleRules['ScaleGroups'] = []
+
+ mode = scaleRules['ShiftMode'] # Mode is only documentary
+ for group in scaleRules['ScaleGroups']:
+ sym_dim = get_multiglyph_boundingBox([ symbolFont[g] if g in symbolFont else None for g in group ], destGlyph)
+ scale = self.get_scale_factors(sym_dim, stretch)[0]
+ scaleRules['scales'].append(scale)
+ scaleRules['bbdims'].append(sym_dim)
+ if (mode):
+ if ('x' in mode) != (sym_dim['advance'] is not None):
+ d = '0x{:X} - 0x{:X}'.format(group[0], group[-1])
+ if ('x' in mode) :
+ logger.critical("Scaling in group %s is expected to do horizontal shifts but can not", d)
+ else:
+ logger.critical("Scaling in group %s is expected to not do horizontal shifts but will", d)
+ sys.exit(1)
+
+ if 'ScaleGlyph' in scaleRules:
+ # Rewrite to equivalent ScaleGroup
+ group_list = []
+ if 'GlyphsToScale+' in scaleRules:
+ key = 'GlyphsToScale+'
+ plus = True
+ else:
+ key = 'GlyphsToScale'
+ plus = False
+ for i in scaleRules[key]:
+ if isinstance(i, tuple):
+ group_list.append(range(i[0], i[1] + 1))
+ else:
+ group_list.append(i)
+ sym_dim = get_glyph_dimensions(symbolFont[scaleRules['ScaleGlyph']])
+ scale = self.get_scale_factors(sym_dim, stretch)[0]
+ scaleRules['ScaleGroups'].append(group_list)
+ scaleRules['scales'].append(scale)
+ if plus:
+ scaleRules['bbdims'].append(sym_dim)
+ else:
+ scaleRules['bbdims'].append(None) # The 'old' style keeps just the scale, not the positioning
+
+ def get_glyph_scale(self, symbol_unicode, scaleRules, stretch, symbolFont, dest_unicode):
+ """ Determines whether or not to use scaled glyphs for glyph in passed symbol_unicode """
+ # Potentially destroys the contents of self.sourceFont[dest_unicode]
+ if not 'scales' in scaleRules:
+ if not dest_unicode in self.sourceFont:
+ self.sourceFont.createChar(dest_unicode)
+ self.prepareScaleRules(scaleRules, stretch, symbolFont, self.sourceFont[dest_unicode])
+ for glyph_list, scale, box in zip(scaleRules['ScaleGroups'], scaleRules['scales'], scaleRules['bbdims']):
+ for e in glyph_list:
+ if isinstance(e, range):
+ if symbol_unicode in e:
+ return (scale, box)
+ elif symbol_unicode == e:
+ return (scale, box)
+ return None
+
+
+def half_gap(gap, top):
+ """ Divides integer value into two new integers """
+ # Line gap add extra space on the bottom of the line which
+ # doesn't allow the powerline glyphs to fill the entire line.
+ # Put half of the gap into the 'cell', each top and bottom
+ if gap <= 0:
+ return 0
+ gap_top = int(gap / 2)
+ gap_bottom = gap - gap_top
+ if top:
+ logger.info("Redistributing line gap of %d (%d top and %d bottom)", gap, gap_top, gap_bottom)
+ return gap_top
+ return gap_bottom
+
+def replace_font_name(font_name, replacement_dict):
+ """ Replaces all keys with vals from replacement_dict in font_name. """
+ for key, val in replacement_dict.items():
+ font_name = font_name.replace(key, val)
+ return font_name
+
+
+def make_sure_path_exists(path):
+ """ Verifies path passed to it exists. """
+ try:
+ os.makedirs(path)
+ except OSError as exception:
+ if exception.errno != errno.EEXIST:
+ raise
+
+def sanitize_filename(filename, allow_dirs = False):
+ """ Enforces to not use forbidden characters in a filename/path. """
+ if filename == '.' and not allow_dirs:
+ return '_'
+ restore_colon = sys.platform == 'win32' and re.match('[a-z]:', filename, re.I)
+ trans = filename.maketrans('<>:"|?*', '_______')
+ for i in range(0x00, 0x20):
+ trans[i] = ord('_')
+ if not allow_dirs:
+ trans[ord('/')] = ord('_')
+ trans[ord('\\')] = ord('_')
+ else:
+ trans[ord('\\')] = ord('/') # We use Posix paths
+ new_filename = filename.translate(trans)
+ if restore_colon:
+ new_filename = new_filename[ :1] + ':' + new_filename[2: ]
+ return new_filename
+
+def get_multiglyph_boundingBox(glyphs, destGlyph = None):
+ """ Returns dict of the dimensions of multiple glyphs combined(, as if they are copied into destGlyph) """
+ # If destGlyph is given the glyph(s) are first copied over into that
+ # glyph and measured in that font (to avoid rounding errors)
+ # Leaves the destGlyph in unknown state!
+ bbox = [ None, None, None, None, None ]
+ for glyph in glyphs:
+ if glyph is None:
+ # Glyph has been in defining range but is not in the actual font
+ continue
+ if destGlyph and glyph.font != destGlyph.font:
+ glyph.font.selection.select(glyph)
+ glyph.font.copy()
+ destGlyph.font.selection.select(destGlyph)
+ destGlyph.font.paste()
+ glyph = destGlyph
+ gbb = glyph.boundingBox()
+ gadvance = glyph.width
+ if len(glyphs) > 1 and gbb[0] == gbb[2] and gbb[1] == gbb[3]:
+ # Ignore empty glyphs if we examine more than one glyph
+ continue
+ bbox[0] = gbb[0] if bbox[0] is None or bbox[0] > gbb[0] else bbox[0]
+ bbox[1] = gbb[1] if bbox[1] is None or bbox[1] > gbb[1] else bbox[1]
+ bbox[2] = gbb[2] if bbox[2] is None or bbox[2] < gbb[2] else bbox[2]
+ bbox[3] = gbb[3] if bbox[3] is None or bbox[3] < gbb[3] else bbox[3]
+ if not bbox[4]:
+ bbox[4] = -gadvance # Negative for one/first glyph
+ else:
+ if abs(bbox[4]) != gadvance:
+ bbox[4] = -1 # Marker for not-monospaced
+ else:
+ bbox[4] = gadvance # Positive for 2 or more glyphs
+ if bbox[4] and bbox[4] < 0:
+ # Not monospaced when only one glyph is used or multiple glyphs with different advance widths
+ bbox[4] = None
+ return {
+ 'xmin' : bbox[0],
+ 'ymin' : bbox[1],
+ 'xmax' : bbox[2],
+ 'ymax' : bbox[3],
+ 'width' : bbox[2] + (-bbox[0]),
+ 'height' : bbox[3] + (-bbox[1]),
+ 'advance': bbox[4], # advance width if monospaced
+ }
+
+def get_glyph_dimensions(glyph):
+ """ Returns dict of the dimensions of the glyph passed to it. """
+ return get_multiglyph_boundingBox([ glyph ])
+
+def scale_bounding_box(bbox, scale_x, scale_y):
+ """ Return a scaled version of a glyph dimensions dict """
+ # Simulate scaling on combined bounding box, round values for better simulation
+ new_dim = {
+ 'xmin' : int(bbox['xmin'] * scale_x),
+ 'ymin' : int(bbox['ymin'] * scale_y),
+ 'xmax' : int(bbox['xmax'] * scale_x),
+ 'ymax' : int(bbox['ymax'] * scale_y),
+ 'advance': int(bbox['advance'] * scale_x) if bbox['advance'] is not None else None,
+ }
+ new_dim['width'] = new_dim['xmax'] + (-new_dim['xmin'])
+ new_dim['height'] = new_dim['ymax'] + (-new_dim['ymin'])
+ return new_dim
+
+def update_progress(progress):
+ """ Updates progress bar length.
+
+ Accepts a float between 0.0 and 1.0. Any int will be converted to a float.
+ A value at 1 or bigger represents 100%
+ modified from: https://stackoverflow.com/questions/3160699/python-progress-bar
+ """
+ barLength = 40 # Modify this to change the length of the progress bar
+ if isinstance(progress, int):
+ progress = float(progress)
+ if progress >= 1:
+ progress = 1
+ status = "Done...\r\n" # NOTE: status initialized and never used
+ block = int(round(barLength * progress))
+ text = "\r╢{0}╟ {1}%".format("█" * block + "░" * (barLength - block), int(progress * 100))
+ sys.stdout.write(text)
+ sys.stdout.flush()
+
+
+def check_fontforge_min_version():
+ """ Verifies installed FontForge version meets minimum requirement. """
+ minimumVersion = 20141231
+ actualVersion = int(fontforge.version())
+
+ # un-comment following line for testing invalid version error handling
+ # actualVersion = 20120731
+
+ # versions tested: 20150612, 20150824
+ if actualVersion < minimumVersion:
+ logger.critical("You seem to be using an unsupported (old) version of fontforge: %d", actualVersion)
+ logger.critical("Please use at least version: %d", minimumVersion)
+ sys.exit(1)
+
+def check_version_with_git(version):
+ """ Upgraded the version to the current git tag version (starting with 'v') """
+ git = subprocess.run("git describe --tags",
+ cwd=os.path.dirname(__file__),
+ shell=True,
+ stdout=subprocess.PIPE, stderr=subprocess.DEVNULL
+ ).stdout.decode('utf-8')
+ if len(git) == 0:
+ return False
+ tag = git.strip()
+ if len(tag) == 0 or not tag.startswith('v'):
+ return False
+ tag = tag[1:]
+ r = re.search('(.*?)(-[0-9]+)-g[0-9a-fA-F]+$', tag)
+ if r:
+ tag = r.group(1)
+ patchlevel = r.group(2)
+ else:
+ patchlevel = ""
+ # Inspired by Phaxmohdem's versiontuple https://stackoverflow.com/a/28568003
+
+ versiontuple = lambda v: tuple( p.zfill(8) for p in v.split(".") )
+ if versiontuple(tag) > versiontuple(version):
+ return tag + patchlevel
+ if versiontuple(tag) == versiontuple(version) and len(patchlevel) > 0:
+ return tag + patchlevel
+ return False
+
+def setup_arguments():
+ """ Parse the command line parameters and load the config file if needed """
+ parser = argparse.ArgumentParser(
+ description=(
+ 'Nerd Fonts Font Patcher: patches a given font with programming and development related glyphs\n\n'
+ '* Website: https://www.nerdfonts.com\n'
+ '* Version: ' + version + '\n'
+ '* Development Website: https://github.com/ryanoasis/nerd-fonts\n'
+ '* Changelog: https://github.com/ryanoasis/nerd-fonts/blob/-/changelog.md'),
+ formatter_class=RawTextHelpFormatter,
+ add_help=False,
+ )
+
+ parser.add_argument('font', help='The path to the font to patch (e.g., Inconsolata.otf)')
+ # optional arguments
+ parser.add_argument('--careful', dest='careful', default=False, action='store_true', help='Do not overwrite existing glyphs if detected')
+ parser.add_argument('--debug', dest='debugmode', default=0, type=int, nargs='?', help='Verbose mode (optional: 1=just to file; 2*=just to terminal; 3=display and file)', const=2, choices=range(0, 3 + 1))
+ parser.add_argument('--extension', '-ext', dest='extension', default="", type=str, help='Change font file type to create (e.g., ttf, otf)')
+ parser.add_argument('--help', '-h', action='help', default=argparse.SUPPRESS, help='Show this help message and exit')
+ parser.add_argument('--makegroups', dest='makegroups', default=1, type=int, nargs='?', help='Use alternative method to name patched fonts (default=1)', const=1, choices=range(-1, 6 + 1))
+ parser.add_argument('--mono', '-s', dest='forcemono', default=False, action='count', help='Create monospaced font, existing and added glyphs are single-width (implies --single-width-glyphs)')
+ parser.add_argument('--outputdir', '-out', dest='outputdir', default=".", type=str, help='The directory to output the patched font file to')
+ parser.add_argument('--quiet', '-q', dest='quiet', default=False, action='store_true', help='Do not generate verbose output')
+ parser.add_argument('--single-width-glyphs', dest='single', default=False, action='store_true', help='Whether to generate the glyphs as single-width not double-width (default is double-width) (Nerd Font Mono)')
+ parser.add_argument('--use-single-width-glyphs', dest='forcemono', default=False, action='count', help=argparse.SUPPRESS)
+ parser.add_argument('--variable-width-glyphs', dest='nonmono', default=False, action='store_true', help='Do not adjust advance width (no "overhang") (Nerd Font Propo)')
+ parser.add_argument('--version', '-v', action='version', version=projectName + ': %(prog)s (' + version + ')', help='Show program\'s version number and exit')
+ # --makegroup has an additional undocumented numeric specifier. '--makegroup' is in fact '--makegroup 1'.
+ # Original font name: Hugo Sans Mono ExtraCondensed Light Italic
+ # NF Fam agg.
+ # -1 no renaming at all (keep old names and versions etc) --- --- ---
+ # 0 turned off, use old naming scheme [-] [-] [-]
+ # 1 HugoSansMono Nerd Font ExtraCondensed Light Italic [ ] [ ] [ ]
+ # 2 HugoSansMono Nerd Font ExtCn Light Italic [ ] [X] [ ]
+ # 3 HugoSansMono Nerd Font XCn Lt It [ ] [X] [X]
+ # 4 HugoSansMono NF ExtraCondensed Light Italic [X] [ ] [ ]
+ # 5 HugoSansMono NF ExtCn Light Italic [X] [X] [ ]
+ # 6 HugoSansMono NF XCn Lt It [X] [X] [X]
+
+ sym_font_group = parser.add_argument_group('Symbol Fonts')
+ sym_font_group.add_argument('--complete', '-c', dest='complete', default=False, action='store_true', help='Add all available Glyphs')
+ sym_font_group.add_argument('--codicons', dest='codicons', default=False, action='store_true', help='Add Codicons Glyphs (https://github.com/microsoft/vscode-codicons)')
+ sym_font_group.add_argument('--fontawesome', dest='fontawesome', default=False, action='store_true', help='Add Font Awesome Glyphs (http://fontawesome.io/)')
+ sym_font_group.add_argument('--fontawesomeext', dest='fontawesomeextension', default=False, action='store_true', help='Add Font Awesome Extension Glyphs (https://andrelzgava.github.io/font-awesome-extension/)')
+ sym_font_group.add_argument('--fontlogos', dest='fontlogos', default=False, action='store_true', help='Add Font Logos Glyphs (https://github.com/Lukas-W/font-logos)')
+ sym_font_group.add_argument('--material', '--mdi', dest='material', default=False, action='store_true', help='Add Material Design Icons (https://github.com/templarian/MaterialDesign)')
+ sym_font_group.add_argument('--octicons', dest='octicons', default=False, action='store_true', help='Add Octicons Glyphs (https://octicons.github.com)')
+ sym_font_group.add_argument('--pomicons', dest='pomicons', default=False, action='store_true', help='Add Pomicon Glyphs (https://github.com/gabrielelana/pomicons)')
+ sym_font_group.add_argument('--powerline', dest='powerline', default=False, action='store_true', help='Add Powerline Glyphs')
+ sym_font_group.add_argument('--powerlineextra', dest='powerlineextra', default=False, action='store_true', help='Add Powerline Extra Glyphs (https://github.com/ryanoasis/powerline-extra-symbols)')
+ sym_font_group.add_argument('--powersymbols', dest='powersymbols', default=False, action='store_true', help='Add IEC Power Symbols (https://unicodepowersymbol.com/)')
+ sym_font_group.add_argument('--weather', dest='weather', default=False, action='store_true', help='Add Weather Icons (https://github.com/erikflowers/weather-icons)')
+
+ expert_group = parser.add_argument_group('Expert Options')
+ expert_group.add_argument('--adjust-line-height', '-l', dest='adjustLineHeight', default=False, action='store_true', help='Whether to adjust line heights (attempt to center powerline separators more evenly)')
+ expert_group.add_argument('--boxdrawing', dest='forcebox', default=False, action='store_true', help='Force patching in (over existing) box drawing glyphs')
+ expert_group.add_argument('--cell', dest='cellopt', default=None, type=str, help='Adjust or query the cell size, e.g. use "0:1000:-200:800" or "?"')
+ expert_group.add_argument('--configfile', dest='configfile', default=False, type=str, help='Specify a file path for configuration file (see sample: src/config.sample.cfg)')
+ expert_group.add_argument('--custom', dest='custom', default=False, type=str, help='Specify a custom symbol font, all glyphs will be copied; absolute path suggested')
+ expert_group.add_argument('--dry', dest='dry_run', default=False, action='store_true', help='Do neither patch nor store the font, to check naming')
+ expert_group.add_argument('--glyphdir', dest='glyphdir', default=__dir__ + "/src/glyphs/", type=str, help='Path to glyphs to be used for patching')
+ expert_group.add_argument('--has-no-italic', dest='noitalic', default=False, action='store_true', help='Font family does not have Italic (but Oblique), to help create correct RIBBI set')
+ expert_group.add_argument('--metrics', dest='metrics', default=None, choices=get_metrics_names(), help='Select vertical metrics source (for problematic cases)')
+ expert_group.add_argument('--name', dest='force_name', default=None, type=str, help='Specify naming source (\'full\', \'postscript\', \'filename\', or concrete free name-string)')
+ expert_group.add_argument('--postprocess', dest='postprocess', default=False, type=str, help='Specify a Script for Post Processing')
+ progressbars_group_parser = expert_group.add_mutually_exclusive_group(required=False)
+ expert_group.add_argument('--removeligs', '--removeligatures', dest='removeligatures', default=False, action='store_true', help='Removes ligatures specified in configuration file (needs --configfile)')
+ expert_group.add_argument('--xavgcharwidth', dest='xavgwidth', default=None, type=int, nargs='?', help='Adjust xAvgCharWidth (optional: concrete value)', const=True)
+ # --xavgcharwidth for compatibility with old applications like notepad and non-latin fonts
+ # Possible values with examples:
+ # - copy from sourcefont (default)
+ # 0 - calculate from font according to OS/2-version-2
+ # 500 - set to 500
+
+ # progress bar arguments - https://stackoverflow.com/questions/15008758/parsing-boolean-values-with-argparse
+ progressbars_group_parser.add_argument('--progressbars', dest='progressbars', action='store_true', help='Show percentage completion progress bars per Glyph Set (default)')
+ progressbars_group_parser.add_argument('--no-progressbars', dest='progressbars', action='store_false', help='Don\'t show percentage completion progress bars per Glyph Set')
+ expert_group.set_defaults(progressbars=True)
+
+ args = parser.parse_args()
+ setup_global_logger(args)
+
+ # if we have a config file: fetch commandline arguments from there and process again with all arguments
+ config = configparser.ConfigParser(empty_lines_in_values=False, allow_no_value=True)
+ if args.configfile:
+ if not os.path.isfile(args.configfile):
+ logger.critical("Configfile does not exist: %s", args.configfile)
+ sys.exit(1)
+ if not os.access(args.configfile, os.R_OK):
+ logger.critical("Can not open configfile for reading: %s", args.configfile)
+ sys.exit(1)
+ config.read(args.configfile)
+ extraflags = config.get("Config", "commandline", fallback='')
+ if len(extraflags):
+ logger.info("Adding config commandline options: %s", extraflags)
+ extraflags += ' ' + args.font # Need to re-add the mandatory argument
+ args = parser.parse_args(extraflags.split(), args)
+
+ if args.makegroups > 0 and not FontnameParserOK:
+ logger.critical("FontnameParser module missing (bin/scripts/name_parser/Fontname*), specify --makegroups 0")
+ sys.exit(1)
+
+ # if you add a new font, set it to True here inside the if condition
+ if args.complete:
+ args.fontawesome = True
+ args.fontawesomeextension = True
+ args.fontlogos = True
+ args.octicons = True
+ args.codicons = True
+ args.powersymbols = True
+ args.pomicons = True
+ args.powerline = True
+ args.powerlineextra = True
+ args.material = True
+ args.weather = True
+
+ if not args.complete:
+ sym_font_args = []
+ # add the list of arguments for each symbol font to the list sym_font_args
+ for action in sym_font_group._group_actions:
+ sym_font_args.append(action.__dict__['option_strings'])
+
+ # determine whether or not all symbol fonts are to be used
+ font_complete = True
+ for sym_font_arg_aliases in sym_font_args:
+ found = False
+ for alias in sym_font_arg_aliases:
+ if alias in sys.argv:
+ found = True
+ if not found:
+ font_complete = False
+ args.complete = font_complete
+
+ if args.forcemono:
+ args.single = True
+ if args.nonmono and args.single:
+ logger.warning("Specified contradicting --variable-width-glyphs together with --mono or --single-width-glyphs. Ignoring --variable-width-glyphs.")
+ args.nonmono = False
+
+ if args.cellopt:
+ if args.cellopt != '?':
+ try:
+ parts = [ int(v) for v in args.cellopt.split(':') ]
+ if len(parts) != 4:
+ raise
+ except:
+ logger.critical("Parameter for --cell is not 4 colon separated integer numbers: '%s'", args.cellopt)
+ sys.exit(2)
+ if parts[0] >= parts[1] or parts[2] >= parts[3]:
+ logger.critical("Parameter for --cell do not result in positive cell size: %d x %d",
+ parts[1] - parts[0], parts[3] - parts[2])
+ sys.exit(2)
+ if parts[0] != 0:
+ logger.warn("First parameter for --cell should be zero, this is probably not working")
+ args.cellopt = parts
+
+ make_sure_path_exists(args.outputdir)
+ if not os.path.isfile(args.font):
+ logger.critical("Font file does not exist: %s", args.font)
+ sys.exit(1)
+ if not os.access(args.font, os.R_OK):
+ logger.critical("Can not open font file for reading: %s", args.font)
+ sys.exit(1)
+ is_ttc = len(fontforge.fontsInFile(args.font)) > 1
+ try:
+ source_font_test = TableHEADWriter(args.font)
+ args.is_variable = source_font_test.find_table([b'avar', b'cvar', b'fvar', b'gvarb', b'HVAR', b'MVAR', b'VVAR'], 0)
+ if args.is_variable:
+ logger.warning("Source font is a variable open type font (VF), opening might fail...")
+ except:
+ args.is_variable = False
+ finally:
+ try:
+ source_font_test.close()
+ except:
+ pass
+
+ if args.extension == "":
+ args.extension = os.path.splitext(args.font)[1]
+ else:
+ args.extension = '.' + args.extension
+ if re.match(r'\.ttc$', args.extension, re.IGNORECASE):
+ if not is_ttc:
+ logger.critical("Can not create True Type Collections from single font files")
+ sys.exit(1)
+ else:
+ if is_ttc:
+ logger.critical("Can not create single font files from True Type Collections")
+ sys.exit(1)
+
+ # The if might look ridiculous, but isinstance(False, int) is True!
+ if isinstance(args.xavgwidth, int) and not isinstance(args.xavgwidth, bool):
+ if args.xavgwidth < 0:
+ logger.critical("--xavgcharwidth takes no negative numbers")
+ sys.exit(2)
+ if args.xavgwidth > 16384:
+ logger.critical("--xavgcharwidth takes only numbers up to 16384")
+ sys.exit(2)
+
+ return (args, config)
+
+def setup_global_logger(args):
+ """ Set up the logger and take options into account """
+ global logger
+ logger = logging.getLogger(os.path.basename(args.font))
+ logger.setLevel(logging.DEBUG)
+ log_to_file = (args.debugmode & 1 == 1)
+ if log_to_file:
+ try:
+ f_handler = logging.FileHandler('font-patcher-log.txt')
+ f_handler.setFormatter(logging.Formatter('%(levelname)s: %(name)s %(message)s'))
+ logger.addHandler(f_handler)
+ except:
+ log_to_file = False
+ logger.debug(allversions)
+ logger.debug("Options %s", repr(sys.argv[1:]))
+ c_handler = logging.StreamHandler(stream=sys.stdout)
+ c_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
+ if not (args.debugmode & 2 == 2):
+ c_handler.setLevel(logging.INFO)
+ logger.addHandler(c_handler)
+ if (args.debugmode & 1 == 1) and not log_to_file:
+ logger.info("Can not write logfile, disabling")
+
+def main():
+ global logger
+ logger = logging.getLogger("start") # Use start logger until we can set up something sane
+ s_handler = logging.StreamHandler(stream=sys.stdout)
+ s_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
+ logger.addHandler(s_handler)
+
+ global version
+ git_version = check_version_with_git(version)
+ global allversions
+ allversions = "Patcher v{} ({}) (ff {})".format(
+ git_version if git_version else version, script_version, fontforge.version())
+ print("{} {}".format(projectName, allversions))
+ if git_version:
+ version = git_version
+ check_fontforge_min_version()
+ (args, conf) = setup_arguments()
+ logger.debug("Naming mode %d", args.makegroups)
+
+ patcher = font_patcher(args, conf)
+
+ sourceFonts = []
+ all_fonts = fontforge.fontsInFile(args.font)
+ if not all_fonts:
+ if re.match(".*\\.woff2?", args.font, re.I):
+ all_fonts=[ "" ]
+ else:
+ logger.critical("Can not find any fonts in '%s'", args.font)
+ sys.exit(1)
+ for i, subfont in enumerate(all_fonts):
+ if len(all_fonts) > 1:
+ print("\n")
+ logger.info("Processing %s (%d/%d)", subfont, i + 1, len(all_fonts))
+ try:
+ sourceFonts.append(fontforge.open("{}({})".format(args.font, i), 1)) # 1 = ("fstypepermitted",))
+ except Exception:
+ logger.critical("Can not open font '%s', try to open with fontforge interactively to get more information",
+ subfont)
+ sys.exit(1)
+
+ patcher.setup_name_backup(sourceFonts[-1])
+ patcher.patch(sourceFonts[-1])
+
+ print("Done with Patch Sets, generating font...")
+ for f in sourceFonts:
+ patcher.setup_font_names(f)
+ patcher.generate(sourceFonts)
+
+ for f in sourceFonts:
+ f.close()
+
+
+if __name__ == "__main__":
+ __dir__ = os.path.dirname(os.path.abspath(__file__))
+ main()