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))
|
#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;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user