Skip to content

Commit 853a29c

Browse files
committed
Add --background option to run kitty on the Wayland desktop (#1)
--background-monitor can be used to specify exactly which monitor to run kitty on.
1 parent 3ce04c3 commit 853a29c

File tree

14 files changed

+447
-9
lines changed

14 files changed

+447
-9
lines changed

glfw/glfw.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class Env:
3131
wayland_scanner: str = ''
3232
wayland_scanner_code: str = ''
3333
wayland_protocols: Tuple[str, ...] = ()
34+
custom_wayland_protocols: Tuple[str, ...] = ()
3435

3536
def __init__(
3637
self, cc: str = '', cppflags: List[str] = [], cflags: List[str] = [], ldflags: List[str] = [],
@@ -95,7 +96,8 @@ def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_co
9596
scanner_version = tuple(map(int, pkg_config('wayland-scanner', '--modversion')[0].strip().split('.')))
9697
ans.wayland_scanner_code = 'private-code' if scanner_version >= (1, 14, 91) else 'code'
9798
ans.wayland_protocols = tuple(sinfo[module]['protocols'])
98-
for p in ans.wayland_protocols:
99+
ans.custom_wayland_protocols = tuple(sinfo[module]['custom_protocols'])
100+
for p in ans.wayland_protocols + ans.custom_wayland_protocols:
99101
ans.sources.append(wayland_protocol_file_name(p))
100102
ans.all_headers.append(wayland_protocol_file_name(p, 'h'))
101103
for dep in 'wayland-client wayland-cursor xkbcommon dbus-1'.split():
@@ -115,8 +117,11 @@ def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_co
115117

116118
def build_wayland_protocols(env: Env, Command: Callable, parallel_run: Callable, emphasis: Callable, newer: Callable, dest_dir: str) -> None:
117119
items = []
118-
for protocol in env.wayland_protocols:
119-
src = os.path.join(env.wayland_packagedir, protocol)
120+
protocols = [(protocol, os.path.join(env.wayland_packagedir, protocol))
121+
for protocol in env.wayland_protocols]
122+
protocols += [(protocol, os.path.join(base, protocol))
123+
for protocol in env.custom_wayland_protocols]
124+
for protocol, src in protocols:
120125
if not os.path.exists(src):
121126
raise SystemExit('The wayland-protocols package on your system is missing the {} protocol definition file'.format(protocol))
122127
for ext in 'hc':

glfw/glfw3.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,8 @@ extern "C" {
11231123
#define GLFW_X11_INSTANCE_NAME 0x00024002
11241124

11251125
#define GLFW_WAYLAND_APP_ID 0x00025001
1126+
#define GLFW_WAYLAND_BACKGROUND 0x00025002
1127+
#define GLFW_WAYLAND_BACKGROUND_MONITOR 0x00025003
11261128
/*! @} */
11271129

11281130
#define GLFW_NO_API 0

glfw/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ struct _GLFWwndconfig
314314
} x11;
315315
struct {
316316
char appId[256];
317+
bool background;
318+
char backgroundMonitor[256];
317319
} wl;
318320
};
319321

glfw/source-info.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
"unstable/xdg-decoration/xdg-decoration-unstable-v1.xml",
7676
"unstable/primary-selection/primary-selection-unstable-v1.xml"
7777
],
78+
"custom_protocols": [
79+
"wlr-layer-shell-unstable-v1.xml"
80+
],
7881
"sources": [
7982
"wl_init.c",
8083
"wl_monitor.c",

glfw/window.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,9 @@ GLFWAPI void glfwWindowHint(int hint, int value)
462462
case GLFW_REFRESH_RATE:
463463
_glfw.hints.refreshRate = value;
464464
return;
465+
case GLFW_WAYLAND_BACKGROUND:
466+
_glfw.hints.window.wl.background = value;
467+
return;
465468
}
466469

467470
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint);
@@ -491,6 +494,10 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value)
491494
strncpy(_glfw.hints.window.wl.appId, value,
492495
sizeof(_glfw.hints.window.wl.appId) - 1);
493496
return;
497+
case GLFW_WAYLAND_BACKGROUND_MONITOR:
498+
strncpy(_glfw.hints.window.wl.backgroundMonitor, value,
499+
sizeof(_glfw.hints.window.wl.backgroundMonitor) - 1);
500+
return;
494501
}
495502

496503
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint);

glfw/wl_init.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,13 @@ static void registryHandleGlobal(void* data UNUSED,
642642
_glfwSetupWaylandPrimarySelectionDevice();
643643
}
644644
}
645+
else if (strcmp(interface, "zwlr_layer_shell_v1") == 0)
646+
{
647+
_glfw.wl.layer_shell =
648+
wl_registry_bind(registry, name,
649+
&zwlr_layer_shell_v1_interface,
650+
1);
651+
}
645652

646653
}
647654

glfw/wl_platform.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
5959
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
6060
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
6161
#include "wayland-primary-selection-unstable-v1-client-protocol.h"
62+
#include "wayland-wlr-layer-shell-unstable-v1-client-protocol.h"
6263

6364
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
6465
#define _glfw_dlclose(handle) dlclose(handle)
@@ -130,6 +131,10 @@ typedef struct _GLFWwindowWayland
130131
struct zxdg_toplevel_decoration_v1* decoration;
131132
} xdg;
132133

134+
struct {
135+
struct zwlr_layer_surface_v1* surface;
136+
} layer;
137+
133138
_GLFWcursor* currentCursor;
134139
double cursorPosX, cursorPosY;
135140

@@ -216,6 +221,7 @@ typedef struct _GLFWlibraryWayland
216221
struct zwp_primary_selection_device_manager_v1* primarySelectionDeviceManager;
217222
struct zwp_primary_selection_device_v1* primarySelectionDevice;
218223
struct zwp_primary_selection_source_v1* dataSourceForPrimarySelection;
224+
struct zwlr_layer_shell_v1* layer_shell;
219225

220226
int compositorVersion;
221227
int seatVersion;
@@ -298,6 +304,7 @@ typedef struct _GLFWcursorWayland
298304
void _glfwAddOutputWayland(uint32_t name, uint32_t version);
299305
void _glfwSetupWaylandDataDevice(void);
300306
void _glfwSetupWaylandPrimarySelectionDevice(void);
307+
struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle);
301308
void animateCursorImage(id_type timer_id, void *data);
302309
struct wl_cursor* _glfwLoadCursor(GLFWCursorShape, struct wl_cursor_theme*);
303310
void destroy_data_offer(_GLFWWaylandDataOffer*);

glfw/wl_window.c

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,87 @@ static bool createXdgSurface(_GLFWwindow* window)
738738
return true;
739739
}
740740

741+
static void layerSurfaceHandleConfigure(void* data,
742+
struct zwlr_layer_surface_v1* surface,
743+
uint32_t serial,
744+
uint32_t width,
745+
uint32_t height) {
746+
_GLFWwindow* window = data;
747+
window->wl.fullscreened = true;
748+
dispatchChangesAfterConfigure(window, width, height);
749+
zwlr_layer_surface_v1_ack_configure(surface, serial);
750+
}
751+
752+
753+
static void layerSurfaceHandleClosed(void* data,
754+
struct zwlr_layer_surface_v1* surface UNUSED) {
755+
_GLFWwindow* window = data;
756+
_glfwInputWindowCloseRequest(window);
757+
}
758+
759+
static const struct zwlr_layer_surface_v1_listener layerSurfaceListener = {
760+
layerSurfaceHandleConfigure,
761+
layerSurfaceHandleClosed,
762+
};
763+
764+
static struct wl_output* findWlOutput(const char* name)
765+
{
766+
int count;
767+
GLFWmonitor** monitors = glfwGetMonitors(&count);
768+
769+
for (int i = 0; i < count; ++i)
770+
{
771+
if (strcmp(glfwGetMonitorName(monitors[i]), name) == 0)
772+
{
773+
return glfwGetWaylandMonitor(monitors[i]);
774+
}
775+
}
776+
return NULL;
777+
}
778+
779+
static bool createLayerSurface(_GLFWwindow* window,
780+
const _GLFWwndconfig* wndconfig)
781+
{
782+
if (!_glfw.wl.layer_shell)
783+
{
784+
_glfwInputError(GLFW_PLATFORM_ERROR,
785+
"Wayland: layer-shell protocol unsupported");
786+
return false;
787+
}
788+
789+
struct wl_output* output = findWlOutput(wndconfig->wl.backgroundMonitor);
790+
window->wl.layer.surface =
791+
zwlr_layer_shell_v1_get_layer_surface(_glfw.wl.layer_shell,
792+
window->wl.surface, output, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM,
793+
"kitty");
794+
795+
if (!window->wl.layer.surface)
796+
{
797+
_glfwInputError(GLFW_PLATFORM_ERROR,
798+
"Wayland: layer-surface creation failed");
799+
return false;
800+
}
801+
802+
zwlr_layer_surface_v1_set_size(window->wl.layer.surface, 0, 0);
803+
zwlr_layer_surface_v1_set_anchor(window->wl.layer.surface,
804+
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
805+
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
806+
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
807+
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
808+
zwlr_layer_surface_v1_set_exclusive_zone(window->wl.layer.surface, -1);
809+
zwlr_layer_surface_v1_set_margin(window->wl.layer.surface, 0, 0, 0, 0);
810+
zwlr_layer_surface_v1_set_keyboard_interactivity(window->wl.layer.surface, 0);
811+
812+
zwlr_layer_surface_v1_add_listener(window->wl.layer.surface,
813+
&layerSurfaceListener,
814+
window);
815+
816+
wl_surface_commit(window->wl.surface);
817+
wl_display_roundtrip(_glfw.wl.display);
818+
819+
return true;
820+
}
821+
741822
static void incrementCursorImage(_GLFWwindow* window)
742823
{
743824
if (window && window->wl.decorations.focus == mainWindow && window->cursorMode != GLFW_CURSOR_HIDDEN) {
@@ -913,8 +994,16 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
913994

914995
if (wndconfig->visible)
915996
{
916-
if (!createXdgSurface(window))
917-
return false;
997+
if (wndconfig->wl.background)
998+
{
999+
if (!createLayerSurface(window, wndconfig))
1000+
return false;
1001+
}
1002+
else
1003+
{
1004+
if (!createXdgSurface(window))
1005+
return false;
1006+
}
9181007

9191008
window->wl.visible = true;
9201009
}

0 commit comments

Comments
 (0)