Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <xcb/xcb.h>
- #include <xcb/xcb_aux.h>
- #include <xcb/xcb_event.h>
- #include <sys/cdefs.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include "list.h"
- #include "config.h"
- #define LENGTH(a) (sizeof(a) / sizeof(a[0]))
- #ifdef DEBUG
- #define LOG(...) printf(__VA_ARGS__)
- #else
- #define LOG(...)
- #endif
- #define XCB_REQUEST_AND_CHECK(conn, request, ...) \
- xcb_request_check(conn, xcb_ ## request ## _checked(conn, __VA_ARGS__))
- #define XCB_REQUEST_AND_REPLY(conn, request, e, ...) \
- xcb_ ## request ## _reply(conn, xcb_ ## request ## _unchecked(conn, \
- __VA_ARGS__), e)
- #define MOUSE_BUTTON(id, index, modifier) \
- xcb_grab_button(wm.conn, false, id, XCB_EVENT_MASK_BUTTON_PRESS, \
- XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, index, \
- modifier)
- /* ---- Beállítások ---- */
- struct window_manager {
- xcb_connection_t *conn; // Csatlakozás az X szerverhez
- xcb_screen_t *screen; // Jelenlegi képernyő
- int mode; // Egérmutató
- int16_t x, y; // Egér kordinálása
- uint32_t border_active; // Aktív ablak keret szín
- uint32_t border_inactive; // Inaktív ablak keret szín
- };
- struct window {
- xcb_window_t id; // XID of the window
- int16_t x, y; // Ablak kordinálása az X és Y tengelyen
- uint16_t w, h; // Ablak szélesége és magasága
- TAILQ_ENTRY(window) link; // Link a listázot ablakokra
- };
- enum {
- NO_GRAB,
- GRAB_MOVE, // Ablak mozgatás
- GRAB_RESIZE // Ablak méretezés
- };
- extern struct window_manager wm;
- struct window_manager wm;
- static struct window *current;
- static TAILQ_HEAD(windows, window) windows; // Listáza az ablakokat
- /* ---- Funkciók ---- */
- void window_init(void);
- struct window *window_get_current(void);
- struct window *window_find(xcb_window_t id);
- struct window *window_manage(xcb_window_t id);
- void window_unmanage(struct window *win);
- void window_unmanage_all(void);
- void window_map(struct window *win);
- void window_move(struct window *win, int16_t x, int16_t y);
- void window_resize(struct window *win, uint16_t w, uint16_t h);
- void window_raise(struct window *win);
- void window_focus(struct window *win);
- void window_close(struct window *win);
- static uint32_t alloc_color(char *rgb_string);
- void handle_map_request(xcb_map_request_event_t *ev);
- void handle_unmap_notify(xcb_unmap_notify_event_t *ev);
- void handle_destroy_notify(xcb_destroy_notify_event_t *ev);
- void handle_configure_request(xcb_configure_request_event_t *ev);
- void handle_button_press(xcb_button_press_event_t *ev);
- void handle_button_release(xcb_button_release_event_t *ev);
- void handle_motion_notify(xcb_motion_notify_event_t *ev);
- /* ---- Funkciók végrehajtása ---- */
- void
- window_init(void)
- {
- TAILQ_INIT(&windows);
- current = NULL;
- }
- struct window *
- window_get_current(void)
- {
- return current;
- }
- struct window *
- window_find(xcb_window_t id)
- {
- struct window *win;
- TAILQ_FOREACH(win, &windows, link) {
- if (win->id == id)
- return win;
- }
- return NULL;
- }
- struct window *
- window_manage(xcb_window_t id)
- {
- struct window *win;
- xcb_get_geometry_reply_t *r;
- LOG("manage %x\n", id);
- win = malloc(sizeof(struct window));
- if (win == NULL)
- return NULL;
- r = XCB_REQUEST_AND_REPLY(wm.conn, get_geometry, NULL, id);
- if (r == NULL) {
- free(win);
- return NULL;
- }
- win->id = id;
- win->x = r->x;
- win->y = r->y;
- win->w = r->width;
- win->h = r->height;
- mouse_buttons(win->id);
- TAILQ_INSERT_HEAD(&windows, win, link);
- free(r);
- return win;
- }
- void
- window_unmanage(struct window *win)
- {
- LOG("unmanage %x\n", win->id);
- if (win == current)
- window_focus(NULL);
- TAILQ_REMOVE(&windows, win, link);
- free(win);
- }
- void
- window_unmanage_all(void)
- {
- while (TAILQ_FIRST(&windows) != NULL)
- window_unmanage(TAILQ_FIRST(&windows));
- }
- void
- window_move(struct window *win, int16_t x, int16_t y)
- {
- win->x = x;
- win->y = y;
- xcb_configure_window(wm.conn, win->id,
- XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
- (const uint32_t []) { x, y });
- }
- void
- window_resize(struct window *win, uint16_t w, uint16_t h)
- {
- win->w = w;
- win->h = h;
- xcb_configure_window(wm.conn, win->id,
- XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
- (const uint32_t []) { w, h });
- }
- void
- window_raise(struct window *win)
- {
- xcb_configure_window(wm.conn, win->id,
- XCB_CONFIG_WINDOW_STACK_MODE,
- (const uint32_t []) { XCB_STACK_MODE_ABOVE });
- }
- void
- window_focus(struct window *win)
- {
- xcb_window_t to_focus;
- if (win && win == current)
- return;
- if (current != NULL) {
- xcb_change_window_attributes(wm.conn, current->id,
- XCB_CW_BORDER_PIXEL, &wm.border_inactive);
- }
- if (win) {
- xcb_change_window_attributes(wm.conn, win->id, XCB_CW_BORDER_PIXEL,
- &wm.border_active);
- current = win;
- to_focus = win->id;
- } else {
- current = NULL;
- to_focus = wm.screen->root;
- }
- LOG("focus %x\n", to_focus);
- xcb_set_input_focus(wm.conn, XCB_INPUT_FOCUS_PARENT, to_focus,
- XCB_CURRENT_TIME);
- }
- // Ablak bezárás
- void
- window_close(struct window *win)
- {
- LOG("close %x\n", win->id);
- xcb_kill_client(wm.conn, win->id);
- }
- // Szín meghatározás (RGB-ben)
- static uint32_t
- alloc_color(char *rgb_string)
- {
- xcb_alloc_color_reply_t *reply;
- uint16_t r, g, b;
- uint32_t pixel;
- xcb_aux_parse_color(rgb_string, &r, &g, &b);
- reply = XCB_REQUEST_AND_REPLY(wm.conn, alloc_color, NULL,
- wm.screen->default_colormap, r, g, b);
- pixel = (reply != NULL) ? reply->pixel : 0;
- free(reply);
- return pixel;
- }
- static void
- mouse_buttons(xcb_window_t id)
- {
- uint8_t buttons[] = { BUTTON_MOVE, BUTTON_RESIZE, BUTTON_CLOSE };
- uint16_t modifiers[] = { 0, XCB_MOD_MASK_LOCK };
- for (int i = 0; i < LENGTH(buttons); ++i) {
- for (int j = 0; j < LENGTH(modifiers); ++j) {
- MOUSE_BUTTON(id, buttons[i], modifiers[j]);
- MOUSE_BUTTON(id, buttons[i], MODKEY_MASK | modifiers[j]);
- }
- }
- }
- void
- handle_map_request(xcb_map_request_event_t *ev)
- {
- struct window *win;
- xcb_get_window_attributes_reply_t *r;
- LOG("MapRequest on %x\n", ev->window);
- r = XCB_REQUEST_AND_REPLY(wm.conn, get_window_attributes, NULL, ev->window);
- if (r != NULL) {
- if (!r->override_redirect) {
- win = window_manage(ev->window);
- if (win != NULL) {
- xcb_map_window(wm.conn, win->id);
- window_focus(win);
- }
- }
- }
- if (r == NULL || (!r->override_redirect && win == NULL))
- xcb_map_window(wm.conn, ev->window);
- free(r);
- }
- // Feltérképezetlen ablak értesítése.
- void
- handle_unmap_notify(xcb_unmap_notify_event_t *ev)
- {
- struct window *win;
- LOG("UnmapNotify on %x\n", ev->window);
- win = window_find(ev->window);
- if (win != NULL)
- window_unmanage(win);
- }
- // Értesítés ha egy ablak bezárult.
- void
- handle_destroy_notify(xcb_destroy_notify_event_t *ev)
- {
- struct window *win;
- LOG("DestroyNotify on %x\n", ev->window);
- win = window_find(ev->window);
- if (win != NULL)
- window_unmanage(win);
- }
- // Konfigurációs ablak kérésének a beállítása
- void
- handle_configure_request(xcb_configure_request_event_t *ev)
- {
- uint32_t values[6];
- int i = 0;
- LOG("ConfigureRequest on %x\n", ev->window);
- if (ev->value_mask & XCB_CONFIG_WINDOW_X)
- values[i++] = ev->x;
- if (ev->value_mask & XCB_CONFIG_WINDOW_Y)
- values[i++] = ev->y;
- if (ev->value_mask & XCB_CONFIG_WINDOW_WIDTH)
- values[i++] = ev->width;
- if (ev->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
- values[i++] = ev->height;
- if (ev->value_mask & XCB_CONFIG_WINDOW_SIBLING)
- values[i++] = ev->sibling;
- if (ev->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
- values[i++] = ev->stack_mode;
- xcb_configure_window(wm.conn, ev->window, ev->value_mask, values);
- }
- // Egér használat engedélyezés
- static void
- start_pointer_grab(int mode, int16_t x, int16_t y)
- {
- xcb_grab_pointer_reply_t *r;
- wm.mode = mode;
- wm.x = x;
- wm.y = y;
- r = XCB_REQUEST_AND_REPLY(wm.conn, grab_pointer, NULL, false,
- wm.screen->root, XCB_EVENT_MASK_BUTTON_RELEASE |
- XCB_EVENT_MASK_POINTER_MOTION, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
- wm.screen->root, XCB_NONE, XCB_CURRENT_TIME);
- if (r == NULL)
- wm.mode = NO_GRAB;
- free(r);
- }
- static void
- stop_pointer_grab()
- {
- xcb_ungrab_pointer(wm.conn, XCB_CURRENT_TIME);
- wm.mode = NO_GRAB;
- }
- // Egér gombok használata
- void
- handle_button_press(xcb_button_press_event_t *ev)
- {
- struct window *win;
- LOG("ButtonPress on %x, modifier=%x, button=%x\n", ev->event, ev->state,
- ev->detail);
- win = window_find(ev->event);
- if (win != NULL) {
- window_raise(win);
- window_focus(win);
- if (ev->state & MODKEY_MASK) {
- int mode;
- switch (ev->detail) {
- case BUTTON_MOVE:
- mode = GRAB_MOVE;
- break;
- case BUTTON_RESIZE:
- mode = GRAB_RESIZE;
- break;
- case BUTTON_CLOSE:
- mode = NO_GRAB;
- window_close(win);
- }
- if (mode != NO_GRAB)
- start_pointer_grab(mode, ev->root_x, ev->root_y);
- }
- xcb_allow_events(wm.conn, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME);
- }
- }
- void
- handle_button_release(xcb_button_release_event_t *ev)
- {
- LOG("ButtonRelease on %x\n", ev->event);
- if (wm.mode != NO_GRAB)
- stop_pointer_grab();
- }
- // Egérmutato mozgás
- void
- handle_motion_notify(xcb_motion_notify_event_t *ev)
- {
- if (wm.mode != NO_GRAB) {
- struct window *win = window_get_current();
- int16_t dx, dy;
- dx = ev->root_x - wm.x;
- dy = ev->root_y - wm.y;
- if (wm.mode == GRAB_MOVE)
- window_move(win, win->x + dx, win->y + dy);
- else
- window_resize(win, win->w + dx, win->h + dy);
- wm.x = ev->root_x;
- wm.y = ev->root_y;
- }
- }
- /* ---- Előkészítés ---- */
- static void
- init(void)
- {
- int screen_num;
- xcb_generic_error_t *e;
- // Root ablak meghatázozás
- uint32_t root_event_mask =
- XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | // Értesítések
- XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; // Konfigurálás kérések
- wm.conn = xcb_connect(NULL, &screen_num);
- if (xcb_connection_has_error(wm.conn)) {
- fputs("cannot open display\n", stderr);
- exit(1);
- }
- wm.screen = xcb_aux_get_screen(wm.conn, screen_num);
- e = XCB_REQUEST_AND_CHECK(wm.conn, change_window_attributes,
- wm.screen->root, XCB_CW_EVENT_MASK, &root_event_mask);
- if (e != NULL) {
- fputs("another window manager is running\n", stderr);
- exit(1);
- }
- wm.mode = NO_GRAB;
- wm.border_active = alloc_color(COLOR_ACTIVE);
- wm.border_inactive = alloc_color(COLOR_INACTIVE);
- window_init();
- }
- // keresi a meglévő ablakokat és kezeli is őket
- static void
- scan(void)
- {
- xcb_query_tree_reply_t *tree;
- xcb_window_t *children;
- int n;
- struct window *win = NULL;
- tree = XCB_REQUEST_AND_REPLY(wm.conn, query_tree, NULL, wm.screen->root);
- children = xcb_query_tree_children(tree);
- n = xcb_query_tree_children_length(tree);
- for (int i = 0; i < n; ++i) {
- xcb_get_window_attributes_reply_t *r;
- r = XCB_REQUEST_AND_REPLY(wm.conn, get_window_attributes, NULL,
- children[i]);
- if (!r->override_redirect && r->map_state == XCB_MAP_STATE_VIEWABLE)
- win = window_manage(children[i]);
- free(r);
- }
- free(tree);
- window_focus(win);
- }
- static void
- run(void)
- {
- xcb_generic_event_t *event;
- while ((event = xcb_wait_for_event(wm.conn)) != NULL) {
- if (event->response_type == 0) {
- xcb_generic_error_t *e = (xcb_generic_error_t *)event;
- if (e->error_code != XCB_WINDOW) {
- fprintf(stderr, "X protocol error: request=%s, error=%s\n",
- xcb_event_get_request_label(e->major_code),
- xcb_event_get_error_label(e->error_code));
- }
- } else {
- #define HANDLE_EVENT(type, handler) case type: handler((void *)event); break
- switch (XCB_EVENT_RESPONSE_TYPE(event)) {
- HANDLE_EVENT(XCB_MAP_REQUEST, handle_map_request);
- HANDLE_EVENT(XCB_UNMAP_NOTIFY, handle_unmap_notify);
- HANDLE_EVENT(XCB_DESTROY_NOTIFY, handle_destroy_notify);
- HANDLE_EVENT(XCB_CONFIGURE_REQUEST, handle_configure_request);
- HANDLE_EVENT(XCB_BUTTON_PRESS, handle_button_press);
- HANDLE_EVENT(XCB_BUTTON_RELEASE, handle_button_release);
- HANDLE_EVENT(XCB_MOTION_NOTIFY, handle_motion_notify);
- }
- #undef HANDLE_EVENT
- xcb_flush(wm.conn);
- }
- free(event);
- }
- }
- // Eltávolítás
- static void
- cleanup(void)
- {
- window_unmanage_all();
- xcb_disconnect(wm.conn);
- }
- int
- main(void)
- {
- init();
- scan();
- run();
- cleanup();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment