Wayland: Mark windows in which a bell as urgent on compositors that support the xdg-activation protocol
This commit is contained in:
parent
983ab3c67d
commit
4d30ae55f3
@ -38,6 +38,8 @@ Detailed list of changes
|
||||
0.27.0 [future]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Wayland: Mark windows in which a bell as urgent on compositors that support the xdg-activation protocol
|
||||
|
||||
- Allow passing null bytes through the system clipboard (:iss:`5483`)
|
||||
|
||||
- ssh kitten: Fix :envvar:`KITTY_PUBLIC_KEY` not being encoded properly when transmitting (:iss:`5496`)
|
||||
@ -51,6 +53,7 @@ Detailed list of changes
|
||||
|
||||
- Wayland: Fix for a bug preventing kitty from starting on Hyprland when using a non-unit scale (:iss:`5467`)
|
||||
|
||||
|
||||
0.26.2 [2022-09-05]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
1
glfw/glfw3.h
vendored
1
glfw/glfw3.h
vendored
@ -1716,6 +1716,7 @@ typedef void (* GLFWjoystickfun)(int,int);
|
||||
|
||||
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
|
||||
typedef void (* GLFWtickcallback)(void*);
|
||||
typedef void (* GLFWactivationcallback)(GLFWwindow *window, const char *token, void *data);
|
||||
typedef bool (* GLFWdrawtextfun)(GLFWwindow *window, const char *text, uint32_t fg, uint32_t bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin);
|
||||
typedef char* (* GLFWcurrentselectionfun)(void);
|
||||
typedef void (* GLFWclipboarddatafreefun)(void* data);
|
||||
|
||||
13
glfw/wl_init.c
vendored
13
glfw/wl_init.c
vendored
@ -719,6 +719,9 @@ static void registryHandleGlobal(void* data UNUSED,
|
||||
_glfwSetupWaylandPrimarySelectionDevice();
|
||||
}
|
||||
}
|
||||
else if (strstr(interface, "xdg_activation_v1") != 0) {
|
||||
_glfw.wl.xdg_activation_v1 = wl_registry_bind(registry, name, &xdg_activation_v1_interface, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -882,6 +885,14 @@ int _glfwPlatformInit(void)
|
||||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
if (_glfw.wl.activation_requests.array) {
|
||||
for (size_t i=0; i < _glfw.wl.activation_requests.sz; i++) {
|
||||
glfw_wl_xdg_activation_request *r = _glfw.wl.activation_requests.array + i;
|
||||
if (r->callback) r->callback(NULL, NULL, r->callback_data);
|
||||
xdg_activation_token_v1_destroy(r->token);
|
||||
}
|
||||
free(_glfw.wl.activation_requests.array);
|
||||
}
|
||||
_glfwTerminateEGL();
|
||||
if (_glfw.wl.egl.handle)
|
||||
{
|
||||
@ -941,6 +952,8 @@ void _glfwPlatformTerminate(void)
|
||||
zwp_primary_selection_device_v1_destroy(_glfw.wl.primarySelectionDevice);
|
||||
if (_glfw.wl.primarySelectionDeviceManager)
|
||||
zwp_primary_selection_device_manager_v1_destroy(_glfw.wl.primarySelectionDeviceManager);
|
||||
if (_glfw.wl.xdg_activation_v1)
|
||||
xdg_activation_v1_destroy(_glfw.wl.xdg_activation_v1);
|
||||
if (_glfw.wl.registry)
|
||||
wl_registry_destroy(_glfw.wl.registry);
|
||||
if (_glfw.wl.display)
|
||||
|
||||
16
glfw/wl_platform.h
vendored
16
glfw/wl_platform.h
vendored
@ -58,7 +58,9 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
|
||||
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
|
||||
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
|
||||
#include "wayland-primary-selection-unstable-v1-client-protocol.h"
|
||||
#include "wayland-primary-selection-unstable-v1-client-protocol.h"
|
||||
#include "wl_text_input.h"
|
||||
#include "wayland-xdg-activation-v1-client-protocol.h"
|
||||
|
||||
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||
#define _glfw_dlclose(handle) dlclose(handle)
|
||||
@ -124,6 +126,14 @@ typedef enum WaylandWindowState {
|
||||
TOPLEVEL_STATE_TILED_BOTTOM = 128,
|
||||
} WaylandWindowState;
|
||||
|
||||
typedef struct glfw_wl_xdg_activation_request {
|
||||
GLFWid window_id;
|
||||
GLFWactivationcallback callback;
|
||||
void *callback_data;
|
||||
uintptr_t request_id;
|
||||
void *token;
|
||||
} glfw_wl_xdg_activation_request;
|
||||
|
||||
|
||||
static const WaylandWindowState TOPLEVEL_STATE_DOCKED = TOPLEVEL_STATE_MAXIMIZED | TOPLEVEL_STATE_FULLSCREEN | TOPLEVEL_STATE_TILED_TOP | TOPLEVEL_STATE_TILED_LEFT | TOPLEVEL_STATE_TILED_RIGHT | TOPLEVEL_STATE_TILED_BOTTOM;
|
||||
|
||||
@ -276,6 +286,7 @@ typedef struct _GLFWlibraryWayland
|
||||
struct zwp_primary_selection_device_manager_v1* primarySelectionDeviceManager;
|
||||
struct zwp_primary_selection_device_v1* primarySelectionDevice;
|
||||
struct zwp_primary_selection_source_v1* dataSourceForPrimarySelection;
|
||||
struct xdg_activation_v1* xdg_activation_v1;
|
||||
|
||||
int compositorVersion;
|
||||
int seatVersion;
|
||||
@ -316,6 +327,11 @@ typedef struct _GLFWlibraryWayland
|
||||
PFN_wl_egl_window_resize window_resize;
|
||||
} egl;
|
||||
|
||||
struct {
|
||||
glfw_wl_xdg_activation_request *array;
|
||||
size_t capacity, sz;
|
||||
} activation_requests;
|
||||
|
||||
EventLoopData eventLoopData;
|
||||
size_t dataOffersCounter;
|
||||
_GLFWWaylandDataOffer dataOffers[8];
|
||||
|
||||
78
glfw/wl_window.c
vendored
78
glfw/wl_window.c
vendored
@ -44,6 +44,59 @@
|
||||
|
||||
#define debug(...) if (_glfw.hints.init.debugRendering) fprintf(stderr, __VA_ARGS__);
|
||||
|
||||
static void
|
||||
activation_token_done(void *data, struct xdg_activation_token_v1 *xdg_token, const char *token) {
|
||||
for (size_t i = 0; i < _glfw.wl.activation_requests.sz; i++) {
|
||||
glfw_wl_xdg_activation_request *r = _glfw.wl.activation_requests.array + i;
|
||||
if (r->request_id == (uintptr_t)data) {
|
||||
_GLFWwindow *window = _glfwWindowForId(r->window_id);
|
||||
if (r->callback) r->callback((GLFWwindow*)window, token, r->callback_data);
|
||||
remove_i_from_array(_glfw.wl.activation_requests.array, i, _glfw.wl.activation_requests.sz);
|
||||
break;
|
||||
}
|
||||
}
|
||||
xdg_activation_token_v1_destroy(xdg_token);
|
||||
}
|
||||
|
||||
|
||||
static const struct
|
||||
xdg_activation_token_v1_listener activation_token_listener = {
|
||||
.done = &activation_token_done,
|
||||
};
|
||||
|
||||
|
||||
static bool
|
||||
get_activation_token(
|
||||
_GLFWwindow *window, uint32_t serial, GLFWactivationcallback cb, void *cb_data
|
||||
) {
|
||||
#define fail(msg) { _glfwInputError(GLFW_PLATFORM_ERROR, msg); if (cb) cb((GLFWwindow*)window, NULL, cb_data); return false; }
|
||||
if (_glfw.wl.xdg_activation_v1 == NULL) fail("Wayland: activation requests not supported by this Wayland compositor");
|
||||
struct xdg_activation_token_v1 *token = xdg_activation_v1_get_activation_token(_glfw.wl.xdg_activation_v1);
|
||||
if (token == NULL) fail("Wayland: failed to create activation request token");
|
||||
if (_glfw.wl.activation_requests.capacity < _glfw.wl.activation_requests.sz + 1) {
|
||||
_glfw.wl.activation_requests.capacity = MAX(64u, _glfw.wl.activation_requests.capacity * 2);
|
||||
_glfw.wl.activation_requests.array = realloc(_glfw.wl.activation_requests.array, _glfw.wl.activation_requests.capacity);
|
||||
if (!_glfw.wl.activation_requests.array) {
|
||||
_glfw.wl.activation_requests.capacity = 0;
|
||||
fail("Wayland: Out of memory while allocation activation request");
|
||||
}
|
||||
}
|
||||
glfw_wl_xdg_activation_request *r = _glfw.wl.activation_requests.array + _glfw.wl.activation_requests.sz++;
|
||||
memset(r, 0, sizeof(*r));
|
||||
static uintptr_t rq = 0;
|
||||
r->window_id = window->id;
|
||||
r->callback = cb; r->callback_data = cb_data;
|
||||
r->request_id = ++rq; r->token = token;
|
||||
if (serial != 0)
|
||||
xdg_activation_token_v1_set_serial(token, serial, _glfw.wl.seat);
|
||||
|
||||
xdg_activation_token_v1_set_surface(token, window->wl.surface);
|
||||
xdg_activation_token_v1_add_listener(token, &activation_token_listener, (void*)r->request_id);
|
||||
xdg_activation_token_v1_commit(token);
|
||||
return true;
|
||||
#undef fail
|
||||
}
|
||||
|
||||
static struct wl_buffer* createShmBuffer(const GLFWimage* image, bool is_opaque, bool init_data)
|
||||
{
|
||||
struct wl_shm_pool* pool;
|
||||
@ -1102,27 +1155,22 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
|
||||
window->wl.visible = false;
|
||||
}
|
||||
|
||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
// TODO
|
||||
static bool notified = false;
|
||||
if (!notified) {
|
||||
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
|
||||
"Wayland: Window attention request not implemented yet");
|
||||
notified = true;
|
||||
static void
|
||||
request_attention(GLFWwindow *window, const char *token, void *data UNUSED) {
|
||||
if (window && token && token[0]) xdg_activation_v1_activate(_glfw.wl.xdg_activation_v1, token, ((_GLFWwindow*)window)->wl.surface);
|
||||
}
|
||||
|
||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) {
|
||||
for (size_t i = 0; i < _glfw.wl.activation_requests.sz; i++) {
|
||||
glfw_wl_xdg_activation_request *r = _glfw.wl.activation_requests.array + i;
|
||||
if (r->window_id == window->id && r->callback == request_attention) return;
|
||||
}
|
||||
get_activation_token(window, 0, request_attention, NULL);
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
// TODO: Use an actual Wayland API to implement this when one becomes available
|
||||
static char tty[L_ctermid + 1];
|
||||
int fd = open(ctermid(tty), O_WRONLY | O_CLOEXEC);
|
||||
if (fd > -1) {
|
||||
int ret = write(fd, "\x07", 1) == 1 ? true : false;
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user