Resume Cthulhu on empty i3 workspaces

This commit is contained in:
ak47 committed 2026-11-07 19:49:00 -05:00
1 parent 7752c4e566
commit d5f8a392cf
8 files changed
+191 -44

No files matched your search

+1 -1
View File
@@ -312,7 +312,7 @@ int cthulhu_focus_metadata_unchecked(Display *display, SteamFocusSample *steam)
steam->window = window;
}
if (window == None || window == root) {
return 0;
return cthulhu_i3_no_client_focus(display) ? 2 : 0;
}
Atom classAtom = XInternAtom(display, "WM_CLASS", False);
+3
View File
@@ -37,6 +37,9 @@ typedef struct { int known, pid, steam, innerFocus; Window window, focus; } Stea
typedef struct { int xterm; SteamFocusSample steam; } CommandFocusSample;
int cthulhu_active_window_is_xterm(void);
char *cthulhu_i3_socket(void);
// Caller holds the X11 read guard and has confirmed no EWMH active client.
int cthulhu_i3_no_client_focus(Display *display);
int cthulhu_display_active_window_xterm_match(Display *display);
Foreground read_foreground(Display *display);
int cthulhu_xres_client_pids_supported(Display *display);
@@ -136,7 +136,7 @@ func (owner *commandOwner) publishFocus() steamFocusSample {
// Native xterm focus vetoes delayed accessibility requests to restore grabs.
// lastFocusMatch belongs to this owner and survives unknown focus samples;
// only a known non-xterm window ends the handoff.
// only a known non-xterm window or verified i3 no-client focus ends the handoff.
func (owner *commandOwner) commandGrabsAllowed() bool {
return owner.lastFocusMatch != 1 && owner.listener.commandsEnabled.Load() && !owner.listener.secure.Load()
}
+1 -40
View File
@@ -6,46 +6,7 @@ package xorg
/*
#include "commands_native.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdlib.h>
#include <string.h>
static unsigned char *i3_property(Display *d, Window w, const char *name, Atom wanted, int bits) {
Atom type; int format; unsigned long count, remaining;
unsigned char *value = NULL;
if (XGetWindowProperty(d, w, XInternAtom(d, name, False), 0, 1024, False,
wanted, &type, &format, &count, &remaining, &value) != Success ||
type != wanted || format != bits || remaining || !count) {
if (value) XFree(value);
return NULL;
}
return value;
}
static char *i3_socket(void) {
Display *d = XOpenDisplay(NULL);
if (!d) return NULL;
cthulhu_x11_begin_read(d);
char *socket = NULL;
Window root = DefaultRootWindow(d);
unsigned char *check = i3_property(d, root, "_NET_SUPPORTING_WM_CHECK", XA_WINDOW, 32);
if (check) {
Window wm = *(unsigned long *)check;
XFree(check);
unsigned char *self = i3_property(d, wm, "_NET_SUPPORTING_WM_CHECK", XA_WINDOW, 32);
unsigned char *name = i3_property(d, wm, "_NET_WM_NAME", XInternAtom(d, "UTF8_STRING", False), 8);
if (self && *(unsigned long *)self == wm && name && !strcmp((char *)name, "i3")) {
unsigned char *path = i3_property(d, root, "I3_SOCKET_PATH", XInternAtom(d, "UTF8_STRING", False), 8);
if (path) { socket = strdup((char *)path); XFree(path); }
}
if (self) XFree(self);
if (name) XFree(name);
}
if (cthulhu_x11_end_read(d)) { free(socket); socket = NULL; }
XCloseDisplay(d);
return socket;
}
*/
import "C"
@@ -61,7 +22,7 @@ func I3Socket() string {
if os.Getenv("DISPLAY") == "" {
return ""
}
path := C.i3_socket()
path := C.cthulhu_i3_socket()
if path == nil {
return ""
}
+63
View File
@@ -0,0 +1,63 @@
// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
#include "commands_native.h"
#include <X11/Xatom.h>
#include <stdlib.h>
#include <string.h>
static unsigned char *i3_property(Display *d, Window w, const char *name, Atom wanted, int bits) {
Atom type; int format; unsigned long count, remaining;
unsigned char *value = NULL;
if (XGetWindowProperty(d, w, XInternAtom(d, name, False), 0, 1024, False,
wanted, &type, &format, &count, &remaining, &value) != Success ||
type != wanted || format != bits || remaining || !count) {
if (value) XFree(value);
return NULL;
}
return value;
}
// Caller holds the X11 read guard. Never trust an installed executable or an
// inherited socket variable as evidence that i3 owns this display.
static Window i3_support_window(Display *d) {
Window wm = None;
unsigned char *check = i3_property(d, DefaultRootWindow(d), "_NET_SUPPORTING_WM_CHECK", XA_WINDOW, 32);
if (check) {
Window candidate = *(unsigned long *)check;
XFree(check);
unsigned char *self = i3_property(d, candidate, "_NET_SUPPORTING_WM_CHECK", XA_WINDOW, 32);
unsigned char *name = i3_property(d, candidate, "_NET_WM_NAME", XInternAtom(d, "UTF8_STRING", False), 8);
if (self && *(unsigned long *)self == candidate && name && !strcmp((char *)name, "i3"))
wm = candidate;
if (self) XFree(self);
if (name) XFree(name);
}
return wm;
}
// Called only when EWMH explicitly reports no active client. i3 focuses its
// support window on an empty workspace. Missing metadata or some other input
// focus must preserve the previous handoff, rather than restoring grabs.
int cthulhu_i3_no_client_focus(Display *d) {
Window wm = i3_support_window(d), focus = None;
if (wm == None) return 0;
int revert;
XGetInputFocus(d, &focus, &revert);
return focus == wm;
}
char *cthulhu_i3_socket(void) {
Display *d = XOpenDisplay(NULL);
if (!d) return NULL;
cthulhu_x11_begin_read(d);
char *socket = NULL;
if (i3_support_window(d) != None) {
unsigned char *path = i3_property(d, DefaultRootWindow(d), "I3_SOCKET_PATH", XInternAtom(d, "UTF8_STRING", False), 8);
if (path) { socket = strdup((char *)path); XFree(path); }
}
if (cthulhu_x11_end_read(d)) { free(socket); socket = NULL; }
XCloseDisplay(d);
return socket;
}