Update X-kutu.c
This commit is contained in:
316
X-kutu.c
316
X-kutu.c
@@ -1,21 +1,32 @@
|
||||
#define CLEANMASK(m) ((m & ~0x80))
|
||||
|
||||
// Definitions for modifier keys
|
||||
#define SUPER XCB_MOD_MASK_4
|
||||
#define ALT XCB_MOD_MASK_1
|
||||
#define CTRL XCB_MOD_MASK_CONTROL
|
||||
#define SHIFT XCB_MOD_MASK_SHIFT
|
||||
|
||||
// Change this to change the modifier key you want to use
|
||||
#define MOD SUPER
|
||||
|
||||
// Standard headers
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// XCB headers
|
||||
#include <xcb/randr.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
// Global variables
|
||||
// Connection to X server
|
||||
xcb_connection_t *conn;
|
||||
// Screen of the X server
|
||||
xcb_screen_t *scr;
|
||||
// Currently focused window
|
||||
xcb_window_t focuswin;
|
||||
|
||||
// Geometry structure for rectangles and positions
|
||||
typedef struct Geometry {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
@@ -23,161 +34,7 @@ typedef struct Geometry {
|
||||
uint16_t height;
|
||||
} Geometry;
|
||||
|
||||
void cleanup(void) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Event structure to represent various X events
|
||||
typedef struct Event {
|
||||
int32_t type;
|
||||
uint32_t window;
|
||||
@@ -191,6 +48,151 @@ typedef struct Event {
|
||||
int8_t is_root;
|
||||
} 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 ret = {0};
|
||||
|
||||
@@ -235,6 +237,7 @@ Event wait_for_event(void) {
|
||||
xcb_button_press_event_t *e = (xcb_button_press_event_t *)ev;
|
||||
if (!e->child)
|
||||
break;
|
||||
// Grab pointer for dragging
|
||||
xcb_grab_pointer(conn, 0, e->child,
|
||||
XCB_EVENT_MASK_BUTTON_RELEASE |
|
||||
XCB_EVENT_MASK_BUTTON_MOTION |
|
||||
@@ -260,6 +263,7 @@ Event wait_for_event(void) {
|
||||
|
||||
case XCB_BUTTON_RELEASE: {
|
||||
xcb_button_release_event_t *e = (xcb_button_release_event_t *)ev;
|
||||
// Ungrab pointer after dragging
|
||||
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
|
||||
ret.type = 7;
|
||||
ret.x = e->event_x;
|
||||
@@ -300,4 +304,4 @@ Event wait_for_event(void) {
|
||||
xcb_flush(conn);
|
||||
free(ev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user