Update X-kutu.c

This commit is contained in:
2025-09-29 11:20:05 +00:00
parent f8258e79cf
commit 908e1d39e2

316
X-kutu.c
View File

@@ -1,21 +1,32 @@
#define CLEANMASK(m) ((m & ~0x80)) #define CLEANMASK(m) ((m & ~0x80))
// Definitions for modifier keys
#define SUPER XCB_MOD_MASK_4 #define SUPER XCB_MOD_MASK_4
#define ALT XCB_MOD_MASK_1 #define ALT XCB_MOD_MASK_1
#define CTRL XCB_MOD_MASK_CONTROL #define CTRL XCB_MOD_MASK_CONTROL
#define SHIFT XCB_MOD_MASK_SHIFT #define SHIFT XCB_MOD_MASK_SHIFT
// Change this to change the modifier key you want to use
#define MOD SUPER #define MOD SUPER
// Standard headers
#include <err.h> #include <err.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
// XCB headers
#include <xcb/randr.h> #include <xcb/randr.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
// Global variables
// Connection to X server
xcb_connection_t *conn; xcb_connection_t *conn;
// Screen of the X server
xcb_screen_t *scr; xcb_screen_t *scr;
// Currently focused window
xcb_window_t focuswin; xcb_window_t focuswin;
// Geometry structure for rectangles and positions
typedef struct Geometry { typedef struct Geometry {
int16_t x; int16_t x;
int16_t y; int16_t y;
@@ -23,161 +34,7 @@ typedef struct Geometry {
uint16_t height; uint16_t height;
} Geometry; } Geometry;
void cleanup(void) { // Event structure to represent various X events
if (conn != NULL)
xcb_disconnect(conn);
}
void add_keybind(int key) {
xcb_grab_key(conn, 0, scr->root, MOD, key, XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC);
}
void add_mousebind(int button) {
xcb_grab_button(conn, 0, scr->root,
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, scr->root, XCB_NONE,
button, MOD);
}
int deploy(void) {
uint32_t values[2];
int mask;
if (xcb_connection_has_error(conn = xcb_connect(NULL, NULL)))
return -1;
scr = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
focuswin = scr->root;
mask = XCB_CW_EVENT_MASK;
values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes_checked(conn, scr->root, mask, values);
xcb_flush(conn);
return 0;
}
void free_geometry(Geometry *g) { free(g); }
Geometry *xrandr_get_monitors(void) {
xcb_randr_get_screen_resources_current_cookie_t res_cookie =
xcb_randr_get_screen_resources_current(conn, scr->root);
xcb_randr_get_screen_resources_current_reply_t *res =
xcb_randr_get_screen_resources_current_reply(conn, res_cookie, NULL);
if (!res)
return NULL;
int num_outputs = xcb_randr_get_screen_resources_current_outputs_length(res);
xcb_randr_output_t *outputs =
xcb_randr_get_screen_resources_current_outputs(res);
Geometry *all = calloc(2, sizeof(Geometry));
int count = 0;
for (int i = 0; i < num_outputs && count < 2; i++) {
xcb_randr_get_output_info_cookie_t ocookie =
xcb_randr_get_output_info(conn, outputs[i], XCB_CURRENT_TIME);
xcb_randr_get_output_info_reply_t *oinfo =
xcb_randr_get_output_info_reply(conn, ocookie, NULL);
if (!oinfo)
continue;
if (oinfo->connection == XCB_RANDR_CONNECTION_CONNECTED &&
oinfo->crtc != XCB_NONE) {
xcb_randr_get_crtc_info_cookie_t ccookie =
xcb_randr_get_crtc_info(conn, oinfo->crtc, XCB_CURRENT_TIME);
xcb_randr_get_crtc_info_reply_t *cinfo =
xcb_randr_get_crtc_info_reply(conn, ccookie, NULL);
if (cinfo) {
all[count].x = cinfo->x;
all[count].y = cinfo->y;
all[count].width = cinfo->width;
all[count].height = cinfo->height;
free(cinfo);
count++;
}
}
free(oinfo);
}
free(res);
return all;
}
void focus(xcb_window_t win) {
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, win,
XCB_CURRENT_TIME);
if (win != focuswin)
focuswin = win;
}
xcb_window_t get_focus(void) { return focuswin; }
void subscribe(xcb_window_t win) {
uint32_t values[2];
values[0] = XCB_EVENT_MASK_ENTER_WINDOW;
values[1] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes(conn, win, XCB_CW_EVENT_MASK, values);
}
void kill(xcb_window_t window) {
xcb_kill_client(conn, window);
xcb_flush(conn);
}
void show(xcb_window_t window) {
xcb_map_window(conn, window);
xcb_flush(conn);
}
void hide(xcb_window_t window) {
xcb_unmap_window(conn, window);
xcb_flush(conn);
}
void send_to_top(xcb_window_t win) {
uint32_t values[1] = {XCB_STACK_MODE_ABOVE};
xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_STACK_MODE, values);
xcb_flush(conn);
}
Geometry get_geometry(xcb_window_t win) {
xcb_get_geometry_reply_t *geom =
xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
Geometry g = {geom->x, geom->y, geom->width, geom->height};
free(geom);
return g;
}
Geometry get_pointer(void) {
xcb_query_pointer_reply_t *geom;
geom = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, scr->root), 0);
Geometry g = {geom->root_x, geom->root_y, 0, 0};
free(geom);
return g;
}
Geometry get_screen(void) {
return (Geometry){0, 0, scr->width_in_pixels, scr->height_in_pixels};
}
void warp_pointer(xcb_window_t win, int x, int y) {
xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0, x, y);
xcb_flush(conn);
}
void move_window(xcb_window_t win, int x, int y) {
uint32_t values[2] = {x, y};
xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
values);
xcb_flush(conn);
}
void resize_window(xcb_window_t win, int width, int height) {
uint32_t values[2] = {width, height};
xcb_configure_window(
conn, win, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
xcb_flush(conn);
}
typedef struct Event { typedef struct Event {
int32_t type; int32_t type;
uint32_t window; uint32_t window;
@@ -191,6 +48,151 @@ typedef struct Event {
int8_t is_root; int8_t is_root;
} Event; } Event;
// Cleanup function to close the X connection on exit
void cleanup(void) {
if (conn != NULL)
xcb_disconnect(conn);
}
// Keybind function to setup a key grab if the keycode is clicked along with the MOD key
void add_keybind(int key) {
xcb_grab_key(conn, 0, scr->root, MOD, key, XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC);
}
// Mousebind function to setup a mouse button grab if the button is clicked along with the MOD key
void add_mousebind(int button) {
xcb_grab_button(conn, 0, scr->root,
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, scr->root, XCB_NONE,
button, MOD);
}
// Deploy function to initialize the X connection, set up event masks, and prepare the window manager
int deploy(void) {
uint32_t values[2];
int mask;
// Start X connection and return -1 if it fails
if (xcb_connection_has_error(conn = xcb_connect(NULL, NULL)))
return -1;
// Define screen and focus window
scr = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
focuswin = scr->root;
// Setuup event masks
mask = XCB_CW_EVENT_MASK;
values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes_checked(conn, scr->root, mask, values);
xcb_flush(conn);
return 0;
}
// Free a geometry structure
void free_geometry(Geometry *g) { free(g); }
// Get monitor geometries using XRandR, returns an array of Geometry structures
// The caller is responsible for freeing the returned array
Geometry *xrandr_get_monitors(void) {
// TODO: Loop through monitors and return their geometries
return all;
}
// Set input focus to a window
void focus(xcb_window_t win) {
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, win,
XCB_CURRENT_TIME);
focuswin = win;
}
// Get the currently focused window
xcb_window_t get_focus(void) { return focuswin; }
// Subscribe to events on a window
void subscribe(xcb_window_t win) {
uint32_t values[2];
values[0] = XCB_EVENT_MASK_ENTER_WINDOW;
values[1] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes(conn, win, XCB_CW_EVENT_MASK, values);
}
// Kill a window
void kill(xcb_window_t window) {
xcb_kill_client(conn, window);
xcb_flush(conn);
}
// Show a window
void show(xcb_window_t window) {
xcb_map_window(conn, window);
xcb_flush(conn);
}
// Hide a window
void hide(xcb_window_t window) {
xcb_unmap_window(conn, window);
xcb_flush(conn);
}
// Bring a window to the top of the stack
void send_to_top(xcb_window_t win) {
uint32_t values[1] = {XCB_STACK_MODE_ABOVE};
xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_STACK_MODE, values);
xcb_flush(conn);
}
// Get the geometry of a window
Geometry get_geometry(xcb_window_t win) {
xcb_get_geometry_reply_t *geom =
xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
Geometry g = {geom->x, geom->y, geom->width, geom->height};
free(geom);
return g;
}
// Get the current pointer position
Geometry get_pointer(void) {
xcb_query_pointer_reply_t *geom;
geom = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, scr->root), 0);
Geometry g = {geom->root_x, geom->root_y, 0, 0};
free(geom);
return g;
}
// Get the screen geometry
Geometry get_screen(void) {
return (Geometry){0, 0, scr->width_in_pixels, scr->height_in_pixels};
}
// Warp the pointer to a specific position in a window
// Can be used with get_geometry to warp to a specific position in a window (eg. the center)
void warp_pointer(xcb_window_t win, int x, int y) {
xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0, x, y);
xcb_flush(conn);
}
// Move a window to a specific position
void move_window(xcb_window_t win, int x, int y) {
uint32_t values[2] = {x, y};
xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
values);
xcb_flush(conn);
}
// Resize a window to specific dimensions
void resize_window(xcb_window_t win, int width, int height) {
uint32_t values[2] = {width, height};
xcb_configure_window(
conn, win, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
xcb_flush(conn);
}
// Wait for an event and return it as an Event structure
// This function is blocking
// The event is sent by value, so no need to free anything
Event wait_for_event(void) { Event wait_for_event(void) {
Event ret = {0}; Event ret = {0};
@@ -235,6 +237,7 @@ Event wait_for_event(void) {
xcb_button_press_event_t *e = (xcb_button_press_event_t *)ev; xcb_button_press_event_t *e = (xcb_button_press_event_t *)ev;
if (!e->child) if (!e->child)
break; break;
// Grab pointer for dragging
xcb_grab_pointer(conn, 0, e->child, xcb_grab_pointer(conn, 0, e->child,
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_BUTTON_MOTION |
@@ -260,6 +263,7 @@ Event wait_for_event(void) {
case XCB_BUTTON_RELEASE: { case XCB_BUTTON_RELEASE: {
xcb_button_release_event_t *e = (xcb_button_release_event_t *)ev; xcb_button_release_event_t *e = (xcb_button_release_event_t *)ev;
// Ungrab pointer after dragging
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
ret.type = 7; ret.type = 7;
ret.x = e->event_x; ret.x = e->event_x;
@@ -300,4 +304,4 @@ Event wait_for_event(void) {
xcb_flush(conn); xcb_flush(conn);
free(ev); free(ev);
return ret; return ret;
} }