Rearrange files.
This commit is contained in:
+394
@@ -0,0 +1,394 @@
|
||||
// Self-header
|
||||
#include "X-kutu.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;
|
||||
|
||||
// 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) {
|
||||
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;
|
||||
|
||||
uint32_t values[] = {XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
|
||||
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_PROPERTY_CHANGE};
|
||||
|
||||
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); }
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Destroy a window
|
||||
void destroy(xcb_window_t win) {
|
||||
xcb_destroy_window(conn, win);
|
||||
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);
|
||||
}
|
||||
|
||||
xcb_size_hints_t get_wm_n_hints(xcb_window_t win) {
|
||||
xcb_size_hints_t hints;
|
||||
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_normal_hints(conn, win);
|
||||
xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &hints, NULL);
|
||||
return hints;
|
||||
}
|
||||
|
||||
xcb_icccm_wm_hints_t get_wm_hints(xcb_window_t win) {
|
||||
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints(conn, win);
|
||||
xcb_icccm_wm_hints_t hints;
|
||||
xcb_icccm_get_wm_hints_reply(conn, cookie, &hints, NULL);
|
||||
return hints;
|
||||
}
|
||||
|
||||
char *get_wm_name(xcb_window_t win) {
|
||||
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_name(conn, win);
|
||||
xcb_icccm_get_text_property_reply_t reply;
|
||||
xcb_icccm_get_wm_name_reply(conn, cookie, &reply, NULL);
|
||||
return reply.name;
|
||||
}
|
||||
|
||||
uint8_t get_wm_transient_for(xcb_window_t win) {
|
||||
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_transient_for(conn, win);
|
||||
return xcb_icccm_get_wm_transient_for_reply(conn, cookie, &win, NULL);
|
||||
}
|
||||
|
||||
void set_wm_state(xcb_window_t win, int state) {
|
||||
xcb_intern_atom_cookie_t cookie =
|
||||
xcb_intern_atom(conn, 0, strlen("WM_STATE"), "WM_STATE");
|
||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, cookie, NULL);
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
xcb_atom_t WM_STATE = reply->atom;
|
||||
free(reply);
|
||||
|
||||
uint32_t data[2];
|
||||
data[0] = state;
|
||||
data[1] = XCB_WINDOW_NONE;
|
||||
|
||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, WM_STATE, WM_STATE, 32,
|
||||
2, data);
|
||||
|
||||
xcb_flush(conn);
|
||||
}
|
||||
|
||||
xcb_window_t draw_rectangle(int x, int y, int width, int height,
|
||||
uint32_t color) {
|
||||
// Get the screen
|
||||
const xcb_setup_t *setup = xcb_get_setup(conn);
|
||||
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
|
||||
xcb_screen_t *screen = iter.data;
|
||||
|
||||
// Create an override-redirect window
|
||||
xcb_window_t win = xcb_generate_id(conn);
|
||||
uint32_t mask =
|
||||
XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
|
||||
uint32_t values[3];
|
||||
values[0] = screen->black_pixel; // initial background pixel
|
||||
values[1] = 1; // override_redirect = true
|
||||
values[2] = XCB_EVENT_MASK_EXPOSURE; // we want exposure events
|
||||
|
||||
xcb_create_window(conn,
|
||||
XCB_COPY_FROM_PARENT, // depth
|
||||
win, // window ID
|
||||
screen->root, // parent
|
||||
x, y, // x, y
|
||||
width, height, // width, height
|
||||
0, // border width
|
||||
XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask,
|
||||
values);
|
||||
|
||||
// Map the window (make it visible)
|
||||
xcb_map_window(conn, win);
|
||||
|
||||
// Fill it with the solid color using a Graphics Context
|
||||
xcb_gcontext_t gc = xcb_generate_id(conn);
|
||||
uint32_t gc_values[] = {color, XCB_LINE_STYLE_SOLID};
|
||||
xcb_create_gc(conn, gc, win, XCB_GC_FOREGROUND | XCB_GC_LINE_STYLE,
|
||||
gc_values);
|
||||
|
||||
xcb_rectangle_t rect = {0, 0, width, height}; // relative to window
|
||||
xcb_poly_fill_rectangle(conn, win, gc, 1, &rect);
|
||||
|
||||
// Flush the connection to send commands to the server
|
||||
xcb_flush(conn);
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
xcb_window_t get_root(void) { return scr->root; }
|
||||
|
||||
void grab_pointer(xcb_window_t win) {
|
||||
xcb_grab_pointer(conn, 0, win,
|
||||
XCB_EVENT_MASK_BUTTON_RELEASE |
|
||||
XCB_EVENT_MASK_BUTTON_MOTION |
|
||||
XCB_EVENT_MASK_POINTER_MOTION_HINT,
|
||||
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE,
|
||||
XCB_CURRENT_TIME);
|
||||
xcb_flush(conn);
|
||||
}
|
||||
|
||||
void ungrab_pointer(void) {
|
||||
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
|
||||
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};
|
||||
|
||||
xcb_generic_event_t *ev;
|
||||
ev = xcb_wait_for_event(conn);
|
||||
|
||||
if (!ev)
|
||||
errx(1, "xcb connection broken");
|
||||
|
||||
switch (CLEANMASK(ev->response_type)) {
|
||||
|
||||
case XCB_CREATE_NOTIFY: {
|
||||
xcb_create_notify_event_t *e;
|
||||
e = (xcb_create_notify_event_t *)ev;
|
||||
ret.type = 1;
|
||||
ret.window = e->window;
|
||||
ret.override_redirect = e->override_redirect;
|
||||
} break;
|
||||
|
||||
case XCB_DESTROY_NOTIFY: {
|
||||
xcb_destroy_notify_event_t *e;
|
||||
e = (xcb_destroy_notify_event_t *)ev;
|
||||
ret.type = 2;
|
||||
ret.window = e->window;
|
||||
} break;
|
||||
|
||||
case XCB_ENTER_NOTIFY: {
|
||||
xcb_enter_notify_event_t *e;
|
||||
e = (xcb_enter_notify_event_t *)ev;
|
||||
ret.type = 3;
|
||||
ret.window = e->event;
|
||||
} break;
|
||||
|
||||
case XCB_MAP_NOTIFY: {
|
||||
xcb_map_notify_event_t *e;
|
||||
e = (xcb_map_notify_event_t *)ev;
|
||||
ret.type = 4;
|
||||
ret.window = e->window;
|
||||
ret.override_redirect = e->override_redirect;
|
||||
} break;
|
||||
|
||||
case XCB_MAP_REQUEST: {
|
||||
xcb_map_request_event_t *e;
|
||||
e = (xcb_map_request_event_t *)ev;
|
||||
ret.type = 5;
|
||||
ret.window = e->window;
|
||||
} break;
|
||||
|
||||
case XCB_BUTTON_PRESS: {
|
||||
xcb_button_press_event_t *e = (xcb_button_press_event_t *)ev;
|
||||
if (!e->child)
|
||||
break;
|
||||
ret.type = 6;
|
||||
ret.window = e->child;
|
||||
ret.is_root = e->child == scr->root;
|
||||
ret.x = e->event_x;
|
||||
ret.y = e->event_y;
|
||||
ret.btn = e->detail;
|
||||
} break;
|
||||
|
||||
case XCB_MOTION_NOTIFY: {
|
||||
xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *)ev;
|
||||
ret.type = 7;
|
||||
ret.x = e->event_x;
|
||||
ret.y = e->event_y;
|
||||
ret.state = e->state;
|
||||
} break;
|
||||
|
||||
case XCB_BUTTON_RELEASE: {
|
||||
xcb_button_release_event_t *e = (xcb_button_release_event_t *)ev;
|
||||
ret.type = 8;
|
||||
ret.x = e->event_x;
|
||||
ret.y = e->event_y;
|
||||
ret.btn = e->detail;
|
||||
} break;
|
||||
|
||||
case XCB_KEY_PRESS: {
|
||||
xcb_key_press_event_t *e;
|
||||
e = (xcb_key_press_event_t *)ev;
|
||||
ret.type = 9;
|
||||
ret.window = e->child;
|
||||
ret.btn = e->detail;
|
||||
ret.state = e->state;
|
||||
} break;
|
||||
|
||||
case XCB_KEY_RELEASE: {
|
||||
xcb_key_release_event_t *e;
|
||||
e = (xcb_key_release_event_t *)ev;
|
||||
ret.type = 10;
|
||||
ret.window = e->child;
|
||||
ret.btn = e->detail;
|
||||
ret.state = e->state;
|
||||
} break;
|
||||
|
||||
case XCB_UNMAP_NOTIFY: {
|
||||
xcb_unmap_notify_event_t *e;
|
||||
e = (xcb_unmap_notify_event_t *)ev;
|
||||
ret.type = 11;
|
||||
ret.window = e->window;
|
||||
} break;
|
||||
|
||||
case XCB_CONFIGURE_REQUEST: {
|
||||
xcb_configure_request_event_t *e = (xcb_configure_request_event_t *)ev;
|
||||
ret.type = 12;
|
||||
ret.window = e->window;
|
||||
ret.x = e->x;
|
||||
ret.y = e->y;
|
||||
ret.width = e->width;
|
||||
ret.height = e->height;
|
||||
} break;
|
||||
|
||||
case XCB_RESIZE_REQUEST: {
|
||||
xcb_resize_request_event_t *e = (xcb_resize_request_event_t *)ev;
|
||||
ret.type = 13;
|
||||
ret.window = e->window;
|
||||
ret.width = e->width;
|
||||
ret.height = e->height;
|
||||
} break;
|
||||
}
|
||||
|
||||
xcb_flush(conn);
|
||||
free(ev);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#ifndef X_KUTU_H
|
||||
#define X_KUTU_H
|
||||
|
||||
// Standard headers
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// XCB headers
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
|
||||
// Macro to clean modifier masks
|
||||
#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
|
||||
|
||||
// Forward declarations of global variables
|
||||
extern xcb_connection_t *conn;
|
||||
extern xcb_screen_t *scr;
|
||||
extern xcb_window_t focuswin;
|
||||
|
||||
// Geometry structure for rectangles and positions
|
||||
typedef struct Geometry {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
} Geometry;
|
||||
|
||||
// Event structure to represent various X events
|
||||
typedef struct Event {
|
||||
int32_t type;
|
||||
uint32_t window;
|
||||
int8_t override_redirect;
|
||||
uint32_t btn;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
uint32_t height;
|
||||
uint32_t width;
|
||||
uint32_t state;
|
||||
int8_t is_root;
|
||||
} Event;
|
||||
|
||||
// Function prototypes
|
||||
int deploy(void);
|
||||
void cleanup(void);
|
||||
|
||||
void add_keybind(int key);
|
||||
void add_mousebind(int button);
|
||||
|
||||
xcb_window_t get_focus(void);
|
||||
xcb_window_t get_root(void);
|
||||
|
||||
void focus(xcb_window_t win);
|
||||
void subscribe(xcb_window_t win);
|
||||
void kill(xcb_window_t window);
|
||||
void destroy(xcb_window_t win);
|
||||
void show(xcb_window_t window);
|
||||
void hide(xcb_window_t window);
|
||||
void send_to_top(xcb_window_t win);
|
||||
|
||||
Geometry get_geometry(xcb_window_t win);
|
||||
Geometry get_pointer(void);
|
||||
Geometry get_screen(void);
|
||||
void free_geometry(Geometry *g);
|
||||
|
||||
void warp_pointer(xcb_window_t win, int x, int y);
|
||||
void move_window(xcb_window_t win, int x, int y);
|
||||
void resize_window(xcb_window_t win, int width, int height);
|
||||
|
||||
xcb_size_hints_t get_wm_n_hints(xcb_window_t win);
|
||||
xcb_icccm_wm_hints_t get_wm_hints(xcb_window_t win);
|
||||
char *get_wm_name(xcb_window_t win);
|
||||
uint8_t get_wm_transient_for(xcb_window_t win);
|
||||
void set_wm_state(xcb_window_t win, int state);
|
||||
|
||||
xcb_window_t draw_rectangle(int x, int y, int width, int height,
|
||||
uint32_t color);
|
||||
|
||||
void grab_pointer(xcb_window_t win);
|
||||
void ungrab_pointer(void);
|
||||
|
||||
Event wait_for_event(void);
|
||||
|
||||
#endif // X_KUTU_H
|
||||
Reference in New Issue
Block a user