Guest User

Untitled

a guest
Oct 15th, 2016
253
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.63 KB | None | 0 0
  1. #include <xcb/xcb.h>
  2. #include <xcb/xcb_aux.h>
  3. #include <xcb/xcb_event.h>
  4. #include <sys/cdefs.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <stdbool.h>
  8.  
  9. #include "list.h"
  10. #include "config.h"
  11.  
  12. #define LENGTH(a) (sizeof(a) / sizeof(a[0]))
  13.  
  14. #ifdef DEBUG
  15. #define LOG(...) printf(__VA_ARGS__)
  16. #else
  17. #define LOG(...)
  18. #endif
  19.  
  20. #define XCB_REQUEST_AND_CHECK(conn, request, ...) \
  21. xcb_request_check(conn, xcb_ ## request ## _checked(conn, __VA_ARGS__))
  22.  
  23. #define XCB_REQUEST_AND_REPLY(conn, request, e, ...) \
  24. xcb_ ## request ## _reply(conn, xcb_ ## request ## _unchecked(conn, \
  25. __VA_ARGS__), e)
  26.  
  27. #define MOUSE_BUTTON(id, index, modifier) \
  28. xcb_grab_button(wm.conn, false, id, XCB_EVENT_MASK_BUTTON_PRESS, \
  29. XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, index, \
  30. modifier)
  31.  
  32. /* ---- Beállítások ---- */
  33.  
  34. struct window_manager {
  35.  
  36. xcb_connection_t *conn; // Csatlakozás az X szerverhez
  37. xcb_screen_t *screen; // Jelenlegi képernyő
  38. int mode; // Egérmutató
  39. int16_t x, y; // Egér kordinálása
  40. uint32_t border_active; // Aktív ablak keret szín
  41. uint32_t border_inactive; // Inaktív ablak keret szín
  42. };
  43.  
  44. struct window {
  45.  
  46. xcb_window_t id; // XID of the window
  47. int16_t x, y; // Ablak kordinálása az X és Y tengelyen
  48. uint16_t w, h; // Ablak szélesége és magasága
  49. TAILQ_ENTRY(window) link; // Link a listázot ablakokra
  50. };
  51.  
  52. enum {
  53. NO_GRAB,
  54. GRAB_MOVE, // Ablak mozgatás
  55. GRAB_RESIZE // Ablak méretezés
  56. };
  57.  
  58.  
  59. extern struct window_manager wm;
  60. struct window_manager wm;
  61. static struct window *current;
  62.  
  63. static TAILQ_HEAD(windows, window) windows; // Listáza az ablakokat
  64.  
  65. /* ---- Funkciók ---- */
  66.  
  67. void window_init(void);
  68. struct window *window_get_current(void);
  69. struct window *window_find(xcb_window_t id);
  70. struct window *window_manage(xcb_window_t id);
  71. void window_unmanage(struct window *win);
  72. void window_unmanage_all(void);
  73. void window_map(struct window *win);
  74. void window_move(struct window *win, int16_t x, int16_t y);
  75. void window_resize(struct window *win, uint16_t w, uint16_t h);
  76. void window_raise(struct window *win);
  77. void window_focus(struct window *win);
  78. void window_close(struct window *win);
  79. static uint32_t alloc_color(char *rgb_string);
  80. void handle_map_request(xcb_map_request_event_t *ev);
  81. void handle_unmap_notify(xcb_unmap_notify_event_t *ev);
  82. void handle_destroy_notify(xcb_destroy_notify_event_t *ev);
  83. void handle_configure_request(xcb_configure_request_event_t *ev);
  84. void handle_button_press(xcb_button_press_event_t *ev);
  85. void handle_button_release(xcb_button_release_event_t *ev);
  86. void handle_motion_notify(xcb_motion_notify_event_t *ev);
  87.  
  88. /* ---- Funkciók végrehajtása ---- */
  89.  
  90. void
  91. window_init(void)
  92. {
  93. TAILQ_INIT(&windows);
  94. current = NULL;
  95. }
  96.  
  97. struct window *
  98. window_get_current(void)
  99. {
  100. return current;
  101. }
  102.  
  103. struct window *
  104. window_find(xcb_window_t id)
  105. {
  106. struct window *win;
  107.  
  108. TAILQ_FOREACH(win, &windows, link) {
  109. if (win->id == id)
  110. return win;
  111. }
  112. return NULL;
  113. }
  114.  
  115. struct window *
  116. window_manage(xcb_window_t id)
  117. {
  118. struct window *win;
  119. xcb_get_geometry_reply_t *r;
  120.  
  121. LOG("manage %x\n", id);
  122.  
  123. win = malloc(sizeof(struct window));
  124. if (win == NULL)
  125. return NULL;
  126.  
  127. r = XCB_REQUEST_AND_REPLY(wm.conn, get_geometry, NULL, id);
  128. if (r == NULL) {
  129. free(win);
  130. return NULL;
  131. }
  132.  
  133. win->id = id;
  134. win->x = r->x;
  135. win->y = r->y;
  136. win->w = r->width;
  137. win->h = r->height;
  138.  
  139. mouse_buttons(win->id);
  140.  
  141. TAILQ_INSERT_HEAD(&windows, win, link);
  142.  
  143. free(r);
  144. return win;
  145. }
  146.  
  147. void
  148. window_unmanage(struct window *win)
  149. {
  150. LOG("unmanage %x\n", win->id);
  151.  
  152. if (win == current)
  153. window_focus(NULL);
  154.  
  155. TAILQ_REMOVE(&windows, win, link);
  156. free(win);
  157. }
  158.  
  159. void
  160. window_unmanage_all(void)
  161. {
  162. while (TAILQ_FIRST(&windows) != NULL)
  163. window_unmanage(TAILQ_FIRST(&windows));
  164. }
  165.  
  166. void
  167. window_move(struct window *win, int16_t x, int16_t y)
  168. {
  169. win->x = x;
  170. win->y = y;
  171. xcb_configure_window(wm.conn, win->id,
  172. XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
  173. (const uint32_t []) { x, y });
  174. }
  175.  
  176. void
  177. window_resize(struct window *win, uint16_t w, uint16_t h)
  178. {
  179. win->w = w;
  180. win->h = h;
  181. xcb_configure_window(wm.conn, win->id,
  182. XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
  183. (const uint32_t []) { w, h });
  184. }
  185.  
  186. void
  187. window_raise(struct window *win)
  188. {
  189. xcb_configure_window(wm.conn, win->id,
  190. XCB_CONFIG_WINDOW_STACK_MODE,
  191. (const uint32_t []) { XCB_STACK_MODE_ABOVE });
  192. }
  193.  
  194. void
  195. window_focus(struct window *win)
  196. {
  197. xcb_window_t to_focus;
  198.  
  199. if (win && win == current)
  200. return;
  201.  
  202. if (current != NULL) {
  203. xcb_change_window_attributes(wm.conn, current->id,
  204. XCB_CW_BORDER_PIXEL, &wm.border_inactive);
  205. }
  206.  
  207. if (win) {
  208. xcb_change_window_attributes(wm.conn, win->id, XCB_CW_BORDER_PIXEL,
  209. &wm.border_active);
  210. current = win;
  211. to_focus = win->id;
  212. } else {
  213. current = NULL;
  214. to_focus = wm.screen->root;
  215. }
  216.  
  217. LOG("focus %x\n", to_focus);
  218.  
  219. xcb_set_input_focus(wm.conn, XCB_INPUT_FOCUS_PARENT, to_focus,
  220. XCB_CURRENT_TIME);
  221. }
  222.  
  223. // Ablak bezárás
  224. void
  225. window_close(struct window *win)
  226. {
  227. LOG("close %x\n", win->id);
  228.  
  229. xcb_kill_client(wm.conn, win->id);
  230. }
  231.  
  232. // Szín meghatározás (RGB-ben)
  233. static uint32_t
  234. alloc_color(char *rgb_string)
  235. {
  236. xcb_alloc_color_reply_t *reply;
  237. uint16_t r, g, b;
  238. uint32_t pixel;
  239.  
  240. xcb_aux_parse_color(rgb_string, &r, &g, &b);
  241. reply = XCB_REQUEST_AND_REPLY(wm.conn, alloc_color, NULL,
  242. wm.screen->default_colormap, r, g, b);
  243. pixel = (reply != NULL) ? reply->pixel : 0;
  244. free(reply);
  245. return pixel;
  246. }
  247.  
  248. static void
  249. mouse_buttons(xcb_window_t id)
  250. {
  251. uint8_t buttons[] = { BUTTON_MOVE, BUTTON_RESIZE, BUTTON_CLOSE };
  252. uint16_t modifiers[] = { 0, XCB_MOD_MASK_LOCK };
  253.  
  254. for (int i = 0; i < LENGTH(buttons); ++i) {
  255. for (int j = 0; j < LENGTH(modifiers); ++j) {
  256. MOUSE_BUTTON(id, buttons[i], modifiers[j]);
  257. MOUSE_BUTTON(id, buttons[i], MODKEY_MASK | modifiers[j]);
  258. }
  259. }
  260. }
  261.  
  262. void
  263. handle_map_request(xcb_map_request_event_t *ev)
  264. {
  265. struct window *win;
  266. xcb_get_window_attributes_reply_t *r;
  267.  
  268. LOG("MapRequest on %x\n", ev->window);
  269.  
  270. r = XCB_REQUEST_AND_REPLY(wm.conn, get_window_attributes, NULL, ev->window);
  271. if (r != NULL) {
  272. if (!r->override_redirect) {
  273. win = window_manage(ev->window);
  274. if (win != NULL) {
  275. xcb_map_window(wm.conn, win->id);
  276. window_focus(win);
  277. }
  278. }
  279. }
  280.  
  281. if (r == NULL || (!r->override_redirect && win == NULL))
  282. xcb_map_window(wm.conn, ev->window);
  283.  
  284. free(r);
  285. }
  286.  
  287. // Feltérképezetlen ablak értesítése.
  288. void
  289. handle_unmap_notify(xcb_unmap_notify_event_t *ev)
  290. {
  291. struct window *win;
  292.  
  293. LOG("UnmapNotify on %x\n", ev->window);
  294.  
  295. win = window_find(ev->window);
  296. if (win != NULL)
  297. window_unmanage(win);
  298. }
  299.  
  300. // Értesítés ha egy ablak bezárult.
  301. void
  302. handle_destroy_notify(xcb_destroy_notify_event_t *ev)
  303. {
  304. struct window *win;
  305.  
  306. LOG("DestroyNotify on %x\n", ev->window);
  307.  
  308. win = window_find(ev->window);
  309. if (win != NULL)
  310. window_unmanage(win);
  311. }
  312.  
  313. // Konfigurációs ablak kérésének a beállítása
  314. void
  315. handle_configure_request(xcb_configure_request_event_t *ev)
  316. {
  317. uint32_t values[6];
  318. int i = 0;
  319.  
  320. LOG("ConfigureRequest on %x\n", ev->window);
  321.  
  322. if (ev->value_mask & XCB_CONFIG_WINDOW_X)
  323. values[i++] = ev->x;
  324. if (ev->value_mask & XCB_CONFIG_WINDOW_Y)
  325. values[i++] = ev->y;
  326. if (ev->value_mask & XCB_CONFIG_WINDOW_WIDTH)
  327. values[i++] = ev->width;
  328. if (ev->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
  329. values[i++] = ev->height;
  330. if (ev->value_mask & XCB_CONFIG_WINDOW_SIBLING)
  331. values[i++] = ev->sibling;
  332. if (ev->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
  333. values[i++] = ev->stack_mode;
  334. xcb_configure_window(wm.conn, ev->window, ev->value_mask, values);
  335. }
  336.  
  337. // Egér használat engedélyezés
  338. static void
  339. start_pointer_grab(int mode, int16_t x, int16_t y)
  340. {
  341. xcb_grab_pointer_reply_t *r;
  342.  
  343. wm.mode = mode;
  344. wm.x = x;
  345. wm.y = y;
  346.  
  347. r = XCB_REQUEST_AND_REPLY(wm.conn, grab_pointer, NULL, false,
  348. wm.screen->root, XCB_EVENT_MASK_BUTTON_RELEASE |
  349. XCB_EVENT_MASK_POINTER_MOTION, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
  350. wm.screen->root, XCB_NONE, XCB_CURRENT_TIME);
  351. if (r == NULL)
  352. wm.mode = NO_GRAB;
  353. free(r);
  354. }
  355.  
  356. static void
  357. stop_pointer_grab()
  358. {
  359. xcb_ungrab_pointer(wm.conn, XCB_CURRENT_TIME);
  360. wm.mode = NO_GRAB;
  361. }
  362.  
  363. // Egér gombok használata
  364. void
  365. handle_button_press(xcb_button_press_event_t *ev)
  366. {
  367. struct window *win;
  368.  
  369. LOG("ButtonPress on %x, modifier=%x, button=%x\n", ev->event, ev->state,
  370. ev->detail);
  371.  
  372. win = window_find(ev->event);
  373. if (win != NULL) {
  374. window_raise(win);
  375. window_focus(win);
  376.  
  377. if (ev->state & MODKEY_MASK) {
  378. int mode;
  379.  
  380. switch (ev->detail) {
  381. case BUTTON_MOVE:
  382. mode = GRAB_MOVE;
  383. break;
  384. case BUTTON_RESIZE:
  385. mode = GRAB_RESIZE;
  386. break;
  387. case BUTTON_CLOSE:
  388. mode = NO_GRAB;
  389. window_close(win);
  390. }
  391. if (mode != NO_GRAB)
  392. start_pointer_grab(mode, ev->root_x, ev->root_y);
  393. }
  394. xcb_allow_events(wm.conn, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME);
  395. }
  396. }
  397.  
  398.  
  399. void
  400. handle_button_release(xcb_button_release_event_t *ev)
  401. {
  402. LOG("ButtonRelease on %x\n", ev->event);
  403.  
  404. if (wm.mode != NO_GRAB)
  405. stop_pointer_grab();
  406. }
  407.  
  408. // Egérmutato mozgás
  409. void
  410. handle_motion_notify(xcb_motion_notify_event_t *ev)
  411. {
  412. if (wm.mode != NO_GRAB) {
  413. struct window *win = window_get_current();
  414. int16_t dx, dy;
  415.  
  416. dx = ev->root_x - wm.x;
  417. dy = ev->root_y - wm.y;
  418.  
  419. if (wm.mode == GRAB_MOVE)
  420. window_move(win, win->x + dx, win->y + dy);
  421. else
  422. window_resize(win, win->w + dx, win->h + dy);
  423.  
  424. wm.x = ev->root_x;
  425. wm.y = ev->root_y;
  426. }
  427. }
  428.  
  429. /* ---- Előkészítés ---- */
  430. static void
  431. init(void)
  432. {
  433. int screen_num;
  434. xcb_generic_error_t *e;
  435. // Root ablak meghatázozás
  436. uint32_t root_event_mask =
  437. XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | // Értesítések
  438. XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; // Konfigurálás kérések
  439.  
  440. wm.conn = xcb_connect(NULL, &screen_num);
  441. if (xcb_connection_has_error(wm.conn)) {
  442. fputs("cannot open display\n", stderr);
  443. exit(1);
  444. }
  445. wm.screen = xcb_aux_get_screen(wm.conn, screen_num);
  446.  
  447. e = XCB_REQUEST_AND_CHECK(wm.conn, change_window_attributes,
  448. wm.screen->root, XCB_CW_EVENT_MASK, &root_event_mask);
  449. if (e != NULL) {
  450. fputs("another window manager is running\n", stderr);
  451. exit(1);
  452. }
  453.  
  454. wm.mode = NO_GRAB;
  455. wm.border_active = alloc_color(COLOR_ACTIVE);
  456. wm.border_inactive = alloc_color(COLOR_INACTIVE);
  457.  
  458. window_init();
  459. }
  460.  
  461. // keresi a meglévő ablakokat és kezeli is őket
  462. static void
  463. scan(void)
  464. {
  465. xcb_query_tree_reply_t *tree;
  466. xcb_window_t *children;
  467. int n;
  468. struct window *win = NULL;
  469.  
  470. tree = XCB_REQUEST_AND_REPLY(wm.conn, query_tree, NULL, wm.screen->root);
  471. children = xcb_query_tree_children(tree);
  472. n = xcb_query_tree_children_length(tree);
  473. for (int i = 0; i < n; ++i) {
  474. xcb_get_window_attributes_reply_t *r;
  475.  
  476. r = XCB_REQUEST_AND_REPLY(wm.conn, get_window_attributes, NULL,
  477. children[i]);
  478.  
  479. if (!r->override_redirect && r->map_state == XCB_MAP_STATE_VIEWABLE)
  480. win = window_manage(children[i]);
  481. free(r);
  482. }
  483. free(tree);
  484. window_focus(win);
  485. }
  486.  
  487. static void
  488. run(void)
  489. {
  490. xcb_generic_event_t *event;
  491.  
  492. while ((event = xcb_wait_for_event(wm.conn)) != NULL) {
  493. if (event->response_type == 0) {
  494. xcb_generic_error_t *e = (xcb_generic_error_t *)event;
  495.  
  496. if (e->error_code != XCB_WINDOW) {
  497. fprintf(stderr, "X protocol error: request=%s, error=%s\n",
  498. xcb_event_get_request_label(e->major_code),
  499. xcb_event_get_error_label(e->error_code));
  500. }
  501. } else {
  502. #define HANDLE_EVENT(type, handler) case type: handler((void *)event); break
  503.  
  504. switch (XCB_EVENT_RESPONSE_TYPE(event)) {
  505. HANDLE_EVENT(XCB_MAP_REQUEST, handle_map_request);
  506. HANDLE_EVENT(XCB_UNMAP_NOTIFY, handle_unmap_notify);
  507. HANDLE_EVENT(XCB_DESTROY_NOTIFY, handle_destroy_notify);
  508. HANDLE_EVENT(XCB_CONFIGURE_REQUEST, handle_configure_request);
  509. HANDLE_EVENT(XCB_BUTTON_PRESS, handle_button_press);
  510. HANDLE_EVENT(XCB_BUTTON_RELEASE, handle_button_release);
  511. HANDLE_EVENT(XCB_MOTION_NOTIFY, handle_motion_notify);
  512. }
  513.  
  514. #undef HANDLE_EVENT
  515.  
  516. xcb_flush(wm.conn);
  517. }
  518. free(event);
  519. }
  520. }
  521.  
  522. // Eltávolítás
  523. static void
  524. cleanup(void)
  525. {
  526. window_unmanage_all();
  527. xcb_disconnect(wm.conn);
  528. }
  529.  
  530. int
  531. main(void)
  532. {
  533. init();
  534. scan();
  535. run();
  536. cleanup();
  537. return 0;
  538. }
Advertisement
Add Comment
Please, Sign In to add comment