// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later #include "commands_native.h" #include #include #include static int steam_active_window(Display *display, Window *window) { Atom type; int format; unsigned long count, remaining; unsigned char *data = NULL; int known = XGetWindowProperty(display, DefaultRootWindow(display), XInternAtom(display, "_NET_ACTIVE_WINDOW", False), 0, 1, False, XA_WINDOW, &type, &format, &count, &remaining, &data) == Success && data != NULL && type == XA_WINDOW && format == 32 && count == 1; if (known) *window = ((Window *)data)[0]; if (data != NULL) XFree(data); return known; } static int steam_window_pid(Display *display, Window window) { Atom type; int format; unsigned long count, remaining; unsigned char *data = NULL; int pid = 0; if (XGetWindowProperty(display, window, XInternAtom(display, "_NET_WM_PID", False), 0, 1, False, XA_CARDINAL, &type, &format, &count, &remaining, &data) == Success && data != NULL && type == XA_CARDINAL && format == 32 && count == 1) { pid = (int)((unsigned long *)data)[0]; } if (data != NULL) XFree(data); return pid; } static int steam_wrapper(Display *display, Window window) { XClassHint hint = {0}; int matches = XGetClassHint(display, window, &hint) && hint.res_name != NULL && hint.res_class != NULL && strcmp(hint.res_name, "steamwebhelper") == 0 && strcmp(hint.res_class, "steam") == 0; if (hint.res_name != NULL) XFree(hint.res_name); if (hint.res_class != NULL) XFree(hint.res_class); return matches; } static int steam_browser_child(Display *display, Window wrapper, int pid, Window child) { XWindowAttributes attributes; if (child == None || child == PointerRoot || child == wrapper || !XGetWindowAttributes(display, child, &attributes) || attributes.map_state != IsViewable || attributes.class != InputOutput || steam_window_pid(display, child) != pid) return 0; for (int depth = 0; depth < 32; depth++) { Window root, parent, *children = NULL; unsigned int count; if (!XQueryTree(display, child, &root, &parent, &children, &count)) return 0; if (children != NULL) XFree(children); if (parent == wrapper) return 1; if (parent == None || parent == root) return 0; child = parent; } return 0; } CommandFocusSample cthulhu_read_command_focus(Display *display, int steam_enabled) { CommandFocusSample result = {0}; SteamFocusSample *sample = &result.steam; cthulhu_x11_begin_read(display); result.xterm = cthulhu_focus_metadata_unchecked(display, steam_enabled ? sample : NULL); if (sample->steam) { sample->pid = steam_window_pid(display, sample->window); sample->steam = sample->pid > 0; int revert; XGetInputFocus(display, &sample->focus, &revert); if (sample->steam) sample->innerFocus = steam_browser_child(display, sample->window, sample->pid, sample->focus); } if (cthulhu_x11_end_read(display)) result = (CommandFocusSample){0}; return result; } int cthulhu_restore_steam_focus(Display *display, Window wrapper, int pid, Window target) { cthulhu_x11_begin_read(display); int restored = 0, revert; Window focus, active = None; XGetInputFocus(display, &focus, &revert); char heldKeys[32]; XQueryKeymap(display, heldKeys); int keyHeld = 0; for (int i = 0; i < 32; i++) keyHeld |= heldKeys[i]; if (!keyHeld && focus == wrapper && steam_active_window(display, &active) && active == wrapper && steam_wrapper(display, wrapper) && steam_window_pid(display, wrapper) == pid && steam_browser_child(display, wrapper, pid, target)) { // Recheck foreground immediately before changing input focus: cached // children must never pull keyboard input out of a different client. if (steam_active_window(display, &active) && active == wrapper) { XGetInputFocus(display, &focus, &revert); if (focus == wrapper) { XSetInputFocus(display, target, RevertToParent, CurrentTime); XSync(display, False); XGetInputFocus(display, &focus, &revert); restored = focus == target; } } } if (cthulhu_x11_end_read(display)) restored = 0; return restored; }