├── .gitignore ├── 2bWM.png ├── 2bwm.c ├── 2bwm.man ├── Makefile ├── README.md ├── config.h ├── definitions.h ├── hidden.c ├── hidden.man ├── list.h └── types.h /.gitignore: -------------------------------------------------------------------------------- 1 | 2bwm 2 | 2bwm.o 3 | hidden 4 | -------------------------------------------------------------------------------- /2bWM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/venam/2bwm/3ef4149e60f71c74bae5f6b983dbec2fda7cfbab/2bWM.png -------------------------------------------------------------------------------- /2bwm.c: -------------------------------------------------------------------------------- 1 | /* 2bwm, a fast floating WM with the particularity of having 2 borders written 2 | * over the XCB library and derived from mcwm written by Michael Cardell. 3 | * Heavily modified version of http://www.hack.org/mc/hacks/mcwm/ 4 | * Copyright (c) 2010, 2011, 2012 Michael Cardell Widerkrantz, mc at the domain hack.org. 5 | * Copyright (c) 2014, 2020 Patrick Louis, patrick at the domain psychology dot wtf. 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "list.h" 31 | #include "definitions.h" 32 | #include "types.h" 33 | 34 | ///---Internal Constants---/// 35 | ///---Globals---/// 36 | static xcb_generic_event_t *ev = NULL; 37 | static void (*events[XCB_NO_OPERATION])(xcb_generic_event_t *e); 38 | static unsigned int numlockmask = 0; 39 | static bool is_sloppy = true; // by default use sloppy focus 40 | int sigcode = 0; // Signal code. Non-zero if we've been interruped by a signal. 41 | xcb_connection_t *conn = NULL; // Connection to X server. 42 | xcb_ewmh_connection_t *ewmh = NULL; // Ewmh Connection. 43 | xcb_screen_t *screen = NULL; // Our current screen. 44 | int randrbase = 0; // Beginning of RANDR extension events. 45 | static uint8_t curws = 0; // Current workspace. 46 | struct client *focuswin = NULL; // Current focus window. 47 | struct client *lastwin[WORKSPACES]; // Last focused window. 48 | static xcb_drawable_t top_win=0; // Window always on top. 49 | static xcb_drawable_t dock_win=0; // A single dock always on top. 50 | static struct item *winlist = NULL; // Global list of all client windows. 51 | static struct item *monlist = NULL; // List of all physical monitor outputs. 52 | static struct item *wslist[WORKSPACES]; 53 | ///---Global configuration.---/// 54 | static const char *atomnames[NB_ATOMS][1] = { 55 | {"WM_DELETE_WINDOW"}, 56 | {"WM_CHANGE_STATE"} 57 | }; 58 | 59 | xcb_atom_t ATOM[NB_ATOMS]; 60 | ///---Functions prototypes---/// 61 | static void run(void); 62 | static bool setup(int); 63 | static void install_sig_handlers(void); 64 | static void start(const Arg *); 65 | static void mousemotion(const Arg *); 66 | static void cursor_move(const Arg *); 67 | static void changeworkspace(const Arg *); 68 | static void changeworkspace_helper(const uint32_t); 69 | static void focusnext(const Arg *); 70 | static void focuslastwin(const Arg *); 71 | static void focusnext_helper(bool); 72 | static void sendtoworkspace(const Arg *); 73 | static void sendtonextworkspace(const Arg *); 74 | static void sendtoprevworkspace(const Arg *); 75 | static void resizestep(const Arg *); 76 | static void resizestep_aspect(const Arg *); 77 | static void movestep(const Arg *); 78 | static void maxvert_hor(const Arg *); 79 | static void maxhalf(const Arg *); 80 | static void teleport(const Arg *); 81 | static void changescreen(const Arg *); 82 | static void grabkeys(void); 83 | static void twobwm_restart(); 84 | static void twobwm_exit(); 85 | static void centerpointer(xcb_drawable_t, struct client *); 86 | static void always_on_top(); 87 | static bool setup_keyboard(void); 88 | static bool setupscreen(void); 89 | static int setuprandr(void); 90 | static void arrangewindows(void); 91 | static void prevworkspace(); 92 | static void nextworkspace(); 93 | static void getrandr(void); 94 | static void raise_current_window(void); 95 | static void raiseorlower(); 96 | static void setunfocus(void); 97 | static void maximize(const Arg *); 98 | static void fullscreen(const Arg *); 99 | static void unmaxwin(struct client *); 100 | static void maxwin(struct client *, uint8_t); 101 | static void maximize_helper(struct client *,uint16_t, uint16_t, uint16_t, uint16_t); 102 | static void hide(); 103 | static void clientmessage(xcb_generic_event_t *); 104 | static void deletewin(); 105 | static void unkillable(); 106 | static void fix(); 107 | static void check_name(struct client *); 108 | static void addtoclientlist(const xcb_drawable_t); 109 | static void configurerequest(xcb_generic_event_t *); 110 | static void buttonpress(xcb_generic_event_t *); 111 | static void unmapnotify(xcb_generic_event_t *); 112 | static void mapnotify(xcb_generic_event_t *); 113 | static void destroynotify(xcb_generic_event_t *); 114 | static void circulaterequest(xcb_generic_event_t *); 115 | static void newwin(xcb_generic_event_t *); 116 | static void handle_keypress(xcb_generic_event_t *); 117 | static xcb_cursor_t Create_Font_Cursor(xcb_connection_t *, uint16_t); 118 | static xcb_keycode_t *xcb_get_keycodes(xcb_keysym_t); 119 | static xcb_screen_t *xcb_screen_of_display(xcb_connection_t *, int); 120 | static struct client *setupwin(xcb_window_t); 121 | static struct client create_back_win(void); 122 | static void cleanup(void); 123 | static uint32_t getwmdesktop(xcb_drawable_t); 124 | static void addtoworkspace(struct client *, uint32_t); 125 | static void grabbuttons(struct client *); 126 | static void delfromworkspace(struct client *); 127 | static void unkillablewindow(struct client *); 128 | static void fixwindow(struct client *); 129 | static uint32_t getcolor(const char *); 130 | static void forgetclient(struct client *); 131 | static void forgetwin(xcb_window_t); 132 | static void fitonscreen(struct client *); 133 | static void getoutputs(xcb_randr_output_t *,const int, xcb_timestamp_t); 134 | static void arrbymon(struct monitor *); 135 | static struct monitor *findmonitor(xcb_randr_output_t); 136 | static struct monitor *findclones(xcb_randr_output_t, const int16_t, const int16_t); 137 | static struct monitor *findmonbycoord(const int16_t, const int16_t); 138 | static void delmonitor(struct monitor *); 139 | static struct monitor *addmonitor(xcb_randr_output_t, const int16_t, const int16_t, const uint16_t, const uint16_t); 140 | static void raisewindow(xcb_drawable_t); 141 | static void movelim(struct client *); 142 | static void movewindow(xcb_drawable_t, const int16_t, const int16_t); 143 | static struct client *findclient(const xcb_drawable_t *); 144 | static void setfocus(struct client *); 145 | static void resizelim(struct client *); 146 | static void resize(xcb_drawable_t, const uint16_t, const uint16_t); 147 | static void moveresize(xcb_drawable_t, const uint16_t, const uint16_t,const uint16_t, const uint16_t); 148 | static void mousemove(const int16_t,const int16_t); 149 | static void mouseresize(struct client *,const int16_t,const int16_t); 150 | static void setborders(struct client *,const bool); 151 | static void unmax(struct client *); 152 | static bool getpointer(const xcb_drawable_t *, int16_t *,int16_t *); 153 | static bool getgeom(const xcb_drawable_t *, int16_t *, int16_t *, uint16_t *,uint16_t *, uint8_t *); 154 | static void configwin(xcb_window_t, uint16_t,const struct winconf *); 155 | static void sigcatch(const int); 156 | static void ewmh_init(void); 157 | static xcb_atom_t getatom(const char *); 158 | static void getmonsize(int8_t, int16_t *, int16_t *, uint16_t *, uint16_t *,const struct client *); 159 | static void noborder(int16_t *,struct client *, bool); 160 | static void movepointerback(const int16_t, const int16_t, const struct client *); 161 | static void snapwindow(struct client *); 162 | #include "config.h" 163 | 164 | ///---Function bodies---/// 165 | void 166 | fix() 167 | { 168 | fixwindow(focuswin); 169 | } 170 | 171 | void 172 | unkillable() 173 | { 174 | unkillablewindow(focuswin); 175 | } 176 | 177 | void 178 | delmonitor(struct monitor *mon) 179 | { 180 | freeitem(&monlist, NULL, mon->item); 181 | } 182 | 183 | void 184 | raise_current_window(void) 185 | { 186 | raisewindow(focuswin->id); 187 | } 188 | 189 | void 190 | focusnext(const Arg *arg) 191 | { 192 | focusnext_helper(arg->i > 0); 193 | } 194 | 195 | void 196 | focuslastwin(const Arg *arg) 197 | { 198 | if (lastwin[curws] == NULL) 199 | return; 200 | raisewindow(lastwin[curws]->id); 201 | setfocus(lastwin[curws]); 202 | } 203 | 204 | void 205 | delfromworkspace(struct client *client) 206 | { 207 | if(client->ws < 0) 208 | return; 209 | delitem(&wslist[client->ws], client->wsitem); 210 | client->wsitem = NULL; 211 | client->ws = -1; 212 | } 213 | 214 | void 215 | changeworkspace(const Arg *arg) 216 | { 217 | changeworkspace_helper(arg->i); 218 | } 219 | 220 | void 221 | nextworkspace() 222 | { 223 | curws == WORKSPACES - 1 ? changeworkspace_helper(0) 224 | :changeworkspace_helper(curws+1); 225 | } 226 | 227 | void 228 | prevworkspace() 229 | { 230 | curws > 0 ? changeworkspace_helper(curws - 1) 231 | : changeworkspace_helper(WORKSPACES-1);} 232 | 233 | void 234 | twobwm_exit() 235 | { 236 | exit(EXIT_SUCCESS); 237 | } 238 | 239 | void 240 | saveorigsize(struct client *client) 241 | { 242 | client->origsize.x = client->x; 243 | client->origsize.y = client->y; 244 | client->origsize.width = client->width; 245 | client->origsize.height = client->height; 246 | } 247 | 248 | void 249 | centerpointer(xcb_drawable_t win, struct client *cl) 250 | { 251 | int16_t cur_x, cur_y; 252 | 253 | cur_x = cur_y = 0; 254 | 255 | switch(CURSOR_POSITION) { 256 | case BOTTOM_RIGHT: 257 | cur_x += cl->width; 258 | case BOTTOM_LEFT: 259 | cur_y += cl->height; break; 260 | case TOP_RIGHT: 261 | cur_x += cl->width; 262 | case TOP_LEFT: 263 | break; 264 | default: 265 | cur_x = cl->width / 2; 266 | cur_y = cl->height / 2; 267 | } 268 | 269 | xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0, cur_x, cur_y); 270 | } 271 | 272 | void 273 | updateclientlist(void) 274 | { 275 | uint32_t len,i; 276 | xcb_window_t *children; 277 | struct client *cl; 278 | 279 | /* can only be called after the first window has been spawn */ 280 | xcb_query_tree_reply_t *reply = xcb_query_tree_reply(conn, 281 | xcb_query_tree(conn, screen->root), 0); 282 | xcb_delete_property(conn, screen->root, ewmh->_NET_CLIENT_LIST); 283 | xcb_delete_property(conn, screen->root, ewmh->_NET_CLIENT_LIST_STACKING); 284 | 285 | if (reply == NULL) { 286 | addtoclientlist(0); 287 | return; 288 | } 289 | 290 | len = xcb_query_tree_children_length(reply); 291 | children = xcb_query_tree_children(reply); 292 | 293 | for (i=0; i < len; i ++) { 294 | cl = findclient(&children[i]); 295 | if(cl != NULL) 296 | addtoclientlist(cl->id); 297 | } 298 | 299 | free(reply); 300 | } 301 | 302 | /* get screen of display */ 303 | xcb_screen_t * 304 | xcb_screen_of_display(xcb_connection_t *con, int screen) 305 | { 306 | xcb_screen_iterator_t iter; 307 | iter = xcb_setup_roots_iterator(xcb_get_setup(con)); 308 | for (; iter.rem; --screen, xcb_screen_next(&iter)) 309 | if (screen == 0) 310 | return iter.data; 311 | 312 | return NULL; 313 | } 314 | 315 | void 316 | movepointerback(const int16_t startx, const int16_t starty, 317 | const struct client *client) 318 | { 319 | if (startx > (0 - conf.borderwidth - 1) && startx < (client->width 320 | + conf.borderwidth + 1) && starty > (0 321 | - conf.borderwidth - 1) && starty 322 | < (client->height + conf.borderwidth + 1)) 323 | xcb_warp_pointer(conn, XCB_NONE, client->id,0,0,0,0, startx, 324 | starty); 325 | } 326 | 327 | /* Set keyboard focus to follow mouse pointer. Then exit. We don't need to 328 | * bother mapping all windows we know about. They should all be in the X 329 | * server's Save Set and should be mapped automagically. */ 330 | void 331 | cleanup(void) 332 | { 333 | free(ev); 334 | if(monlist) 335 | delallitems(&monlist,NULL); 336 | struct item *curr,*wsitem; 337 | for(int i = 0; i < WORKSPACES; i++){ 338 | if(!wslist[i]) 339 | continue; 340 | curr = wslist[i]; 341 | while(curr){ 342 | wsitem = curr; 343 | curr = curr->next; 344 | free(wsitem); 345 | } 346 | } 347 | if(winlist){ 348 | delallitems(&winlist,NULL); 349 | } 350 | if (ewmh != NULL){ 351 | xcb_ewmh_connection_wipe(ewmh); 352 | free(ewmh); 353 | } 354 | if(!conn){ 355 | return; 356 | } 357 | xcb_set_input_focus(conn, XCB_NONE,XCB_INPUT_FOCUS_POINTER_ROOT, 358 | XCB_CURRENT_TIME); 359 | xcb_flush(conn); 360 | xcb_disconnect(conn); 361 | } 362 | 363 | /* Rearrange windows to fit new screen size. */ 364 | void 365 | arrangewindows(void) 366 | { 367 | struct client *client; 368 | struct item *item; 369 | /* Go through all windows and resize them appropriately to 370 | * fit the screen. */ 371 | 372 | for (item=winlist; item != NULL; item = item->next) { 373 | client = item->data; 374 | fitonscreen(client); 375 | } 376 | } 377 | 378 | uint32_t getwmdesktop(xcb_drawable_t win) 379 | { // Get EWWM hint so we might know what workspace window win should be visible on. 380 | // Returns either workspace, NET_WM_FIXED if this window should be 381 | // visible on all workspaces or TWOBWM_NOWS if we didn't find any hints. 382 | xcb_get_property_cookie_t cookie = xcb_get_property(conn, false, win, ewmh->_NET_WM_DESKTOP, 383 | XCB_GET_PROPERTY_TYPE_ANY, 0, sizeof(uint32_t)); 384 | xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL); 385 | if (NULL==reply || 0 == xcb_get_property_value_length(reply)) { /* 0 if we didn't find it. */ 386 | if(NULL!=reply) free(reply); 387 | return TWOBWM_NOWS; 388 | } 389 | uint32_t wsp = *(uint32_t *)xcb_get_property_value(reply); 390 | if(NULL!=reply)free(reply); 391 | return wsp; 392 | } 393 | 394 | /* check if the window is unkillable, if yes return true */ 395 | bool 396 | get_unkil_state(xcb_drawable_t win) 397 | { 398 | xcb_get_property_cookie_t cookie; 399 | xcb_get_property_reply_t *reply; 400 | uint8_t wsp; 401 | 402 | cookie = xcb_get_property(conn, false, win, ewmh->_NET_WM_STATE_DEMANDS_ATTENTION, 403 | XCB_GET_PROPERTY_TYPE_ANY, 0,sizeof(uint8_t)); 404 | 405 | reply = xcb_get_property_reply(conn, cookie, NULL); 406 | 407 | if (reply == NULL || xcb_get_property_value_length(reply) == 0) { 408 | if(reply != NULL ) 409 | free(reply); 410 | return false; 411 | } 412 | 413 | wsp = *(uint8_t *) xcb_get_property_value(reply); 414 | 415 | if (reply != NULL) 416 | free(reply); 417 | 418 | if (wsp == 1) 419 | return true; 420 | else 421 | return false; 422 | } 423 | 424 | void 425 | check_name(struct client *client) 426 | { 427 | xcb_get_property_reply_t *reply ; 428 | unsigned int reply_len; 429 | char *wm_name_window; 430 | unsigned int i; 431 | uint32_t values[1] = { 0 }; 432 | 433 | if (NULL == client) 434 | return; 435 | 436 | reply = xcb_get_property_reply(conn, xcb_get_property(conn, false, 437 | client->id, getatom(LOOK_INTO) , 438 | XCB_GET_PROPERTY_TYPE_ANY, 0,60), NULL 439 | ); 440 | 441 | if (reply == NULL || xcb_get_property_value_length(reply) == 0) { 442 | if (NULL!=reply) 443 | free(reply); 444 | return; 445 | } 446 | 447 | reply_len = xcb_get_property_value_length(reply); 448 | wm_name_window = malloc(sizeof(char*) * (reply_len+1));; 449 | memcpy(wm_name_window, xcb_get_property_value(reply), reply_len); 450 | wm_name_window[reply_len] = '\0'; 451 | 452 | if(NULL != reply) 453 | free(reply); 454 | 455 | for(i=0;iignore_borders = true; 458 | xcb_configure_window(conn, client->id, 459 | XCB_CONFIG_WINDOW_BORDER_WIDTH, values); 460 | break; 461 | } 462 | 463 | free(wm_name_window); 464 | } 465 | 466 | /* Add a window, specified by client, to workspace ws. */ 467 | void 468 | addtoworkspace(struct client *client, uint32_t ws) 469 | { 470 | if (ws < 0 || ws > WORKSPACES) { 471 | // this fixes pip mode for Chrome as it somewhat returns ws=4294967295 472 | ws = curws; 473 | } 474 | struct item *item = additem(&wslist[ws]); 475 | 476 | if (client == NULL) 477 | return; 478 | 479 | if (NULL == item) 480 | return; 481 | 482 | /* Remember our place in the workspace window list. */ 483 | client->wsitem = item; 484 | client->ws = ws; 485 | item->data = client; 486 | 487 | /* Set window hint property so we can survive a crash. Like "fixed" */ 488 | if (!client->fixed) 489 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->id, 490 | ewmh->_NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, 491 | &ws 492 | ); 493 | } 494 | static void addtoclientlist(const xcb_drawable_t id) 495 | { 496 | xcb_change_property(conn, XCB_PROP_MODE_APPEND , screen->root, ewmh->_NET_CLIENT_LIST, XCB_ATOM_WINDOW, 32, 1,&id); 497 | xcb_change_property(conn, XCB_PROP_MODE_APPEND , screen->root, ewmh->_NET_CLIENT_LIST_STACKING, XCB_ATOM_WINDOW, 32, 1,&id); 498 | } 499 | 500 | /* Change current workspace to ws */ 501 | void 502 | changeworkspace_helper(const uint32_t ws) 503 | { 504 | xcb_query_pointer_reply_t *pointer; 505 | struct client *client; 506 | struct item *item; 507 | if (ws == curws) 508 | return; 509 | xcb_ewmh_set_current_desktop(ewmh, 0, ws); 510 | /* Go through list of current ws. 511 | * Unmap everything that isn't fixed. */ 512 | for (item=wslist[curws]; item != NULL;) { 513 | client = item->data; 514 | item = item->next; 515 | setborders(client,false); 516 | if (!client->fixed){ 517 | xcb_unmap_window(conn, client->id); 518 | }else{ 519 | // correct order is delete first add later. 520 | delfromworkspace(client); 521 | addtoworkspace(client,ws); 522 | } 523 | } 524 | for (item=wslist[ws]; item != NULL; item = item->next) { 525 | client = item->data; 526 | if (!client->fixed && !client->iconic) 527 | xcb_map_window(conn, client->id); 528 | } 529 | curws = ws; 530 | pointer = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, 531 | screen->root), 0); 532 | if(pointer == NULL) 533 | setfocus(NULL); 534 | else { 535 | setfocus(findclient(&pointer->child)); 536 | free(pointer); 537 | } 538 | } 539 | 540 | void 541 | always_on_top() 542 | { 543 | struct client *cl = NULL; 544 | 545 | if(focuswin==NULL) 546 | return; 547 | 548 | if(top_win!=focuswin->id) { 549 | if (0 != top_win) cl = findclient(&top_win); 550 | 551 | top_win = focuswin->id; 552 | if (NULL!=cl) 553 | setborders(cl, false); 554 | 555 | raisewindow(top_win); 556 | } else 557 | top_win = 0; 558 | 559 | setborders(focuswin,true); 560 | } 561 | 562 | /* Fix or unfix a window client from all workspaces. If setcolour is */ 563 | void 564 | fixwindow(struct client *client) 565 | { 566 | uint32_t ws,ww; 567 | 568 | if (NULL == client) 569 | return; 570 | 571 | if (client->fixed) { 572 | client->fixed = false; 573 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->id, 574 | ewmh->_NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, 575 | &curws 576 | ); 577 | } else { 578 | /* Raise the window, if going to another desktop don't 579 | * let the fixed window behind. */ 580 | raisewindow(client->id); 581 | client->fixed = true; 582 | ww = NET_WM_FIXED; 583 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->id, 584 | ewmh->_NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, 585 | &ww 586 | ); 587 | } 588 | 589 | setborders(client,true); 590 | } 591 | 592 | /* Make unkillable or killable a window client. If setcolour is */ 593 | void 594 | unkillablewindow(struct client *client) 595 | { 596 | if (NULL == client) 597 | return; 598 | 599 | if (client->unkillable) { 600 | client->unkillable = false; 601 | xcb_delete_property(conn, client->id, ewmh->_NET_WM_STATE_DEMANDS_ATTENTION); 602 | } else { 603 | raisewindow(client->id); 604 | client->unkillable = true; 605 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->id, 606 | ewmh->_NET_WM_STATE_DEMANDS_ATTENTION, XCB_ATOM_CARDINAL, 8, 1, 607 | &client->unkillable 608 | ); 609 | } 610 | 611 | setborders(client,true); 612 | } 613 | 614 | void 615 | sendtoworkspace(const Arg *arg) 616 | { 617 | if (NULL == focuswin||focuswin->fixed||arg->i == curws) 618 | return; 619 | // correct order is delete first add later. 620 | delfromworkspace(focuswin); 621 | addtoworkspace(focuswin, arg->i); 622 | xcb_unmap_window(conn, focuswin->id); 623 | xcb_flush(conn); 624 | } 625 | 626 | void 627 | sendtonextworkspace(const Arg *arg) 628 | { 629 | Arg arg2 = { .i=0 }; 630 | Arg arg3 = { .i=curws + 1 }; 631 | curws == WORKSPACES - 1 ? sendtoworkspace(&arg2):sendtoworkspace(&arg3); 632 | } 633 | 634 | void 635 | sendtoprevworkspace(const Arg *arg) 636 | { 637 | Arg arg2 = {.i=curws-1}; 638 | Arg arg3 = {.i=WORKSPACES-1}; 639 | curws > 0 ? sendtoworkspace(&arg2) : sendtoworkspace(&arg3); 640 | } 641 | 642 | /* Get the pixel values of a named colour colstr. Returns pixel values. */ 643 | uint32_t 644 | getcolor(const char *hex) 645 | { 646 | uint32_t rgb48; 647 | char strgroups[7] = { 648 | hex[1], hex[2], hex[3], hex[4], hex[5], hex[6], '\0' 649 | }; 650 | 651 | rgb48 = strtol(strgroups, NULL, 16); 652 | return rgb48 | 0xff000000; 653 | } 654 | 655 | /* Forget everything about client client. */ 656 | void 657 | forgetclient(struct client *client) 658 | { 659 | uint32_t ws; 660 | 661 | if (NULL == client) 662 | return; 663 | if (client->id == top_win) 664 | top_win = 0; 665 | if (client->id == dock_win) 666 | dock_win = 0; 667 | /* Delete client from the workspace list it belongs to. */ 668 | delfromworkspace(client); 669 | 670 | /* Remove from global window list. */ 671 | freeitem(&winlist, NULL, client->winitem); 672 | } 673 | 674 | /* Forget everything about a client with client->id win. */ 675 | void 676 | forgetwin(xcb_window_t win) 677 | { 678 | struct client *client; 679 | struct item *item; 680 | 681 | for (item = winlist; item != NULL; item = item->next) { 682 | /* Find this window in the global window list. */ 683 | client = item->data; 684 | if (win == client->id) { 685 | /* Forget it and free allocated data, it might 686 | * already be freed by handling an UnmapNotify. */ 687 | forgetclient(client); 688 | return; 689 | } 690 | } 691 | } 692 | 693 | void 694 | getmonsize(int8_t with_offsets, int16_t *mon_x, int16_t *mon_y, 695 | uint16_t *mon_width, uint16_t *mon_height, 696 | const struct client *client) 697 | { 698 | if (NULL == client || NULL == client->monitor) { 699 | /* Window isn't attached to any monitor, so we use 700 | * the root window size. */ 701 | *mon_x = *mon_y = 0; 702 | *mon_width = screen->width_in_pixels; 703 | *mon_height = screen->height_in_pixels; 704 | } else { 705 | *mon_x = client->monitor->x; 706 | *mon_y = client->monitor->y; 707 | *mon_width = client->monitor->width; 708 | *mon_height = client->monitor->height; 709 | } 710 | 711 | if (with_offsets) { 712 | *mon_x += offsets[0]; 713 | *mon_y += offsets[1]; 714 | *mon_width -= offsets[2]; 715 | *mon_height -= offsets[3]; 716 | } 717 | } 718 | 719 | void 720 | noborder(int16_t *temp,struct client *client, bool set_unset) 721 | { 722 | if (client->ignore_borders) { 723 | if (set_unset) { 724 | *temp = conf.borderwidth; 725 | conf.borderwidth = 0; 726 | } else 727 | conf.borderwidth = *temp; 728 | } 729 | } 730 | void 731 | maximize_helper(struct client *client,uint16_t mon_x, uint16_t mon_y, 732 | uint16_t mon_width, uint16_t mon_height) 733 | { 734 | uint32_t values[4]; 735 | 736 | values[0] = 0; 737 | saveorigsize(client); 738 | xcb_configure_window(conn, client->id, XCB_CONFIG_WINDOW_BORDER_WIDTH, 739 | values); 740 | 741 | client->x = mon_x; 742 | client->y = mon_y; 743 | client->width = mon_width; 744 | client->height = mon_height; 745 | 746 | moveresize(client->id, client->x, client->y, client->width, 747 | client->height); 748 | client->maxed = true; 749 | } 750 | 751 | /* Fit client on physical screen, moving and resizing as necessary. */ 752 | void 753 | fitonscreen(struct client *client) 754 | { 755 | int16_t mon_x, mon_y,temp=0; 756 | uint16_t mon_width, mon_height; 757 | bool willmove,willresize; 758 | 759 | willmove = willresize = client->vertmaxed = client->hormaxed = false; 760 | 761 | getmonsize(1, &mon_x, &mon_y, &mon_width, &mon_height,client); 762 | 763 | if (client->maxed) { 764 | client->maxed = false; 765 | setborders(client,false); 766 | } else { 767 | /* not maxed but look as if it was maxed, then make it maxed */ 768 | if (client->width==mon_width && client->height==mon_height) 769 | willresize = true; 770 | else { 771 | getmonsize(0, &mon_x, &mon_y, &mon_width, &mon_height, 772 | client); 773 | if (client->width == mon_width && client->height 774 | == mon_height) 775 | willresize = true; 776 | } 777 | if (willresize) { 778 | client->x = mon_x; 779 | client->y = mon_y; 780 | client->width -= conf.borderwidth * 2; 781 | client->height-= conf.borderwidth * 2; 782 | maximize_helper(client, mon_x, mon_y, mon_width, 783 | mon_height); 784 | return; 785 | } else { 786 | getmonsize(1, &mon_x, &mon_y, &mon_width, 787 | &mon_height,client); 788 | } 789 | } 790 | 791 | if (client->x > mon_x + mon_width || client->y > mon_y + mon_height 792 | || client->x < mon_x||client->y < mon_y) { 793 | willmove = true; 794 | /* Is it outside the physical monitor? */ 795 | if (client->x > mon_x + mon_width) 796 | client->x = mon_x + mon_width 797 | - client->width-conf.borderwidth*2; 798 | if (client->y > mon_y + mon_height) 799 | client->y = mon_y + mon_height - client->height 800 | - conf.borderwidth*2; 801 | if (client->x < mon_x) 802 | client->x = mon_x; 803 | if (client->y < mon_y) 804 | client->y = mon_y; 805 | } 806 | 807 | /* Is it smaller than it wants to be? */ 808 | if (0 != client->min_height && client->height < client->min_height) { 809 | client->height = client->min_height; 810 | 811 | willresize = true; 812 | } 813 | 814 | if (0 != client->min_width && client->width < client->min_width) { 815 | client->width = client->min_width; 816 | willresize = true; 817 | } 818 | 819 | noborder(&temp, client, true); 820 | /* If the window is larger than our screen, just place it in 821 | * the corner and resize. */ 822 | if (client->width + conf.borderwidth * 2 > mon_width) { 823 | client->x = mon_x; 824 | client->width = mon_width - conf.borderwidth * 2;; 825 | willmove = willresize = true; 826 | } else 827 | if (client->x + client->width + conf.borderwidth * 2 828 | > mon_x + mon_width) { 829 | client->x = mon_x + mon_width - (client->width 830 | + conf.borderwidth * 2); 831 | willmove = true; 832 | } 833 | if (client->height + conf.borderwidth * 2 > mon_height) { 834 | client->y = mon_y; 835 | client->height = mon_height - conf.borderwidth * 2; 836 | willmove = willresize = true; 837 | } else 838 | if (client->y + client->height + conf.borderwidth*2 > mon_y 839 | + mon_height) { 840 | client->y = mon_y + mon_height - (client->height 841 | + conf.borderwidth * 2); 842 | willmove = true; 843 | } 844 | 845 | if (willmove) 846 | movewindow(client->id, client->x, client->y); 847 | 848 | if (willresize) 849 | resize(client->id, client->width, client->height); 850 | 851 | noborder( &temp, client, false); 852 | } 853 | 854 | 855 | /* Set position, geometry and attributes of a new window and show it on 856 | * the screen.*/ 857 | void 858 | newwin(xcb_generic_event_t *ev) 859 | { 860 | xcb_map_request_event_t *e = (xcb_map_request_event_t *) ev; 861 | struct client *client; 862 | long data[] = { 863 | XCB_ICCCM_WM_STATE_NORMAL, 864 | XCB_NONE 865 | }; 866 | 867 | 868 | /* The window is trying to map itself on the current workspace, 869 | * but since it's unmapped it probably belongs on another workspace.*/ 870 | if (NULL != findclient(&e->window)) 871 | return; 872 | 873 | client = setupwin(e->window); 874 | 875 | if (NULL == client) 876 | return; 877 | 878 | /* Add this window to the current workspace. */ 879 | addtoworkspace(client, curws); 880 | 881 | /* If we don't have specific coord map it where the pointer is.*/ 882 | if (!client->usercoord) { 883 | if (!getpointer(&screen->root, &client->x, &client->y)) 884 | client->x = client->y = 0; 885 | 886 | client->x -= client->width/2; client->y -= client->height/2; 887 | movewindow(client->id, client->x, client->y); 888 | } 889 | 890 | /* Find the physical output this window will be on if RANDR is active */ 891 | if (-1 != randrbase) { 892 | client->monitor = findmonbycoord(client->x, client->y); 893 | if (NULL == client->monitor && NULL != monlist) 894 | /* Window coordinates are outside all physical monitors. 895 | * Choose the first screen.*/ 896 | client->monitor = monlist->data; 897 | } 898 | 899 | fitonscreen(client); 900 | 901 | /* Show window on screen. */ 902 | xcb_map_window(conn, client->id); 903 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->id, 904 | ewmh->_NET_WM_STATE, ewmh->_NET_WM_STATE, 32, 2, data); 905 | 906 | centerpointer(e->window,client); 907 | updateclientlist(); 908 | 909 | if (!client->maxed) 910 | setborders(client,true); 911 | // always focus new window 912 | setfocus(client); 913 | } 914 | 915 | /* Set border colour, width and event mask for window. */ 916 | struct client * 917 | setupwin(xcb_window_t win) 918 | { 919 | unsigned int i; 920 | uint8_t result; 921 | uint32_t values[2],ws; 922 | xcb_atom_t a; 923 | xcb_size_hints_t hints; 924 | xcb_ewmh_get_atoms_reply_t win_type; 925 | xcb_window_t prop; 926 | struct item *item; 927 | struct client *client; 928 | xcb_get_property_cookie_t cookie; 929 | 930 | 931 | if (xcb_ewmh_get_wm_window_type_reply(ewmh, 932 | xcb_ewmh_get_wm_window_type(ewmh, win), &win_type, NULL) == 1) { 933 | for (i = 0; i < win_type.atoms_len; i++) { 934 | a = win_type.atoms[i]; 935 | if (a == ewmh->_NET_WM_WINDOW_TYPE_TOOLBAR || a 936 | == ewmh->_NET_WM_WINDOW_TYPE_DOCK || a 937 | == ewmh->_NET_WM_WINDOW_TYPE_DESKTOP ) { 938 | xcb_map_window(conn,win); 939 | dock_win = win; 940 | return NULL; 941 | } 942 | } 943 | xcb_ewmh_get_atoms_reply_wipe(&win_type); 944 | } 945 | values[0] = XCB_EVENT_MASK_ENTER_WINDOW; 946 | xcb_change_window_attributes(conn, win, XCB_CW_BACK_PIXEL, 947 | &conf.empty_col); 948 | xcb_change_window_attributes_checked(conn, win, XCB_CW_EVENT_MASK, 949 | values); 950 | 951 | /* Add this window to the X Save Set. */ 952 | xcb_change_save_set(conn, XCB_SET_MODE_INSERT, win); 953 | 954 | /* Remember window and store a few things about it. */ 955 | item = additem(&winlist); 956 | 957 | if (NULL == item) 958 | return NULL; 959 | 960 | client = malloc(sizeof(struct client)); 961 | 962 | if (NULL == client) 963 | return NULL; 964 | 965 | item->data = client; 966 | client->id = win; 967 | client->x = client->y = client->width = client->height 968 | = client->min_width = client->min_height = client->base_width 969 | = client->base_height = 0; 970 | 971 | client->max_width = screen->width_in_pixels; 972 | client->max_height = screen->height_in_pixels; 973 | client->width_inc = client->height_inc = 1; 974 | client->usercoord = client->vertmaxed = client->hormaxed 975 | = client->maxed = client->unkillable= client->fixed 976 | = client->ignore_borders= client->iconic= false; 977 | 978 | client->monitor = NULL; 979 | client->winitem = item; 980 | 981 | /* Initialize workspace pointers. */ 982 | client->wsitem = NULL; 983 | client->ws = -1; 984 | 985 | /* Get window geometry. */ 986 | getgeom(&client->id, &client->x, &client->y, &client->width, 987 | &client->height, &client->depth); 988 | 989 | /* Get the window's incremental size step, if any.*/ 990 | xcb_icccm_get_wm_normal_hints_reply(conn, 991 | xcb_icccm_get_wm_normal_hints_unchecked(conn, win), 992 | &hints, NULL 993 | ); 994 | 995 | /* The user specified the position coordinates. 996 | * Remember that so we can use geometry later. */ 997 | if (hints.flags &XCB_ICCCM_SIZE_HINT_US_POSITION) 998 | client->usercoord = true; 999 | 1000 | if (hints.flags &XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { 1001 | client->min_width = hints.min_width; 1002 | client->min_height = hints.min_height; 1003 | } 1004 | 1005 | if (hints.flags &XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) { 1006 | client->max_width = hints.max_width; 1007 | client->max_height = hints.max_height; 1008 | } 1009 | 1010 | if (hints.flags &XCB_ICCCM_SIZE_HINT_P_RESIZE_INC) { 1011 | client->width_inc = hints.width_inc; 1012 | client->height_inc = hints.height_inc; 1013 | } 1014 | 1015 | if (hints.flags &XCB_ICCCM_SIZE_HINT_BASE_SIZE) { 1016 | client->base_width = hints.base_width; 1017 | client->base_height = hints.base_height; 1018 | } 1019 | cookie = xcb_icccm_get_wm_transient_for_unchecked(conn, win); 1020 | if (cookie.sequence > 0) { 1021 | result = xcb_icccm_get_wm_transient_for_reply(conn, cookie, &prop, NULL); 1022 | if (result) { 1023 | xcb_get_geometry_reply_t *parent = xcb_get_geometry_reply(conn, 1024 | xcb_get_geometry(conn, prop), NULL); 1025 | 1026 | if (parent) { 1027 | client->usercoord = true; 1028 | client->x = parent->x+(parent->width/2.0) - (client->width/2.0); 1029 | client->y = parent->y+(parent->height/2.0) - (client->height/2.0); 1030 | moveresize(client->id, client->x, client->y, 1031 | client->width, client->height); 1032 | free(parent); 1033 | xcb_flush(conn); 1034 | } 1035 | } 1036 | } 1037 | 1038 | check_name(client); 1039 | return client; 1040 | } 1041 | 1042 | /* wrapper to get xcb keycodes from keysymbol */ 1043 | xcb_keycode_t * 1044 | xcb_get_keycodes(xcb_keysym_t keysym) 1045 | { 1046 | xcb_key_symbols_t *keysyms; 1047 | xcb_keycode_t *keycode; 1048 | 1049 | if (!(keysyms = xcb_key_symbols_alloc(conn))) 1050 | return NULL; 1051 | 1052 | keycode = xcb_key_symbols_get_keycode(keysyms, keysym); 1053 | xcb_key_symbols_free(keysyms); 1054 | 1055 | return keycode; 1056 | } 1057 | 1058 | /* the wm should listen to key presses */ 1059 | void 1060 | grabkeys(void) 1061 | { 1062 | xcb_keycode_t *keycode; 1063 | int i,k,m; 1064 | unsigned int modifiers[] = { 1065 | 0, 1066 | XCB_MOD_MASK_LOCK, 1067 | numlockmask, 1068 | numlockmask | XCB_MOD_MASK_LOCK 1069 | }; 1070 | 1071 | xcb_ungrab_key(conn, XCB_GRAB_ANY, screen->root, XCB_MOD_MASK_ANY); 1072 | 1073 | for (i=0; iroot, keys[i].mod 1079 | | modifiers[m], keycode[k], 1080 | XCB_GRAB_MODE_ASYNC,//pointer mode 1081 | XCB_GRAB_MODE_ASYNC //keyboard mode 1082 | ); 1083 | free(keycode); // allocated in xcb_get_keycodes() 1084 | } 1085 | } 1086 | 1087 | bool 1088 | setup_keyboard(void) 1089 | { 1090 | xcb_get_modifier_mapping_reply_t *reply; 1091 | xcb_keycode_t *modmap, *numlock; 1092 | unsigned int i,j,n; 1093 | 1094 | reply = xcb_get_modifier_mapping_reply(conn, 1095 | xcb_get_modifier_mapping_unchecked(conn), NULL); 1096 | 1097 | if (!reply) 1098 | return false; 1099 | 1100 | modmap = xcb_get_modifier_mapping_keycodes(reply); 1101 | 1102 | if (!modmap) 1103 | return false; 1104 | 1105 | numlock = xcb_get_keycodes(XK_Num_Lock); 1106 | 1107 | for (i=4; i<8; i++) { 1108 | for (j=0; jkeycodes_per_modifier; j++) { 1109 | xcb_keycode_t keycode = modmap[i 1110 | * reply->keycodes_per_modifier + j]; 1111 | 1112 | if (keycode == XCB_NO_SYMBOL) 1113 | continue; 1114 | 1115 | if(numlock != NULL) 1116 | for (n=0; numlock[n] != XCB_NO_SYMBOL; n++) 1117 | if (numlock[n] == keycode) { 1118 | numlockmask = 1 << i; 1119 | break; 1120 | } 1121 | } 1122 | } 1123 | 1124 | free(reply); 1125 | free(numlock); 1126 | 1127 | return true; 1128 | } 1129 | 1130 | /* Walk through all existing windows and set them up. returns true on success */ 1131 | bool 1132 | setupscreen(void) 1133 | { 1134 | xcb_get_window_attributes_reply_t *attr; 1135 | struct client *client; 1136 | uint32_t ws; 1137 | uint32_t len; 1138 | xcb_window_t *children; 1139 | uint32_t i; 1140 | 1141 | /* Get all children. */ 1142 | xcb_query_tree_reply_t *reply = xcb_query_tree_reply(conn, 1143 | xcb_query_tree(conn, screen->root), 0); 1144 | 1145 | if (NULL == reply) 1146 | return false; 1147 | 1148 | len = xcb_query_tree_children_length(reply); 1149 | children = xcb_query_tree_children(reply); 1150 | 1151 | /* Set up all windows on this root. */ 1152 | for (i=0; i < len; i ++) { 1153 | attr = xcb_get_window_attributes_reply(conn, 1154 | xcb_get_window_attributes(conn, children[i]), 1155 | NULL 1156 | ); 1157 | 1158 | if (!attr) 1159 | continue; 1160 | 1161 | /* Don't set up or even bother windows in override redirect mode. 1162 | * This mode means they wouldn't have been reported to us with a 1163 | * MapRequest if we had been running, so in the normal case we wouldn't 1164 | * have seen them. Only handle visible windows. */ 1165 | if (!attr->override_redirect && attr->map_state 1166 | == XCB_MAP_STATE_VIEWABLE) { 1167 | client = setupwin(children[i]); 1168 | 1169 | if (NULL != client) { 1170 | /* Find the physical output this window will be on if 1171 | * RANDR is active. */ 1172 | if (-1 != randrbase) 1173 | client->monitor = findmonbycoord(client->x, 1174 | client->y); 1175 | /* Fit window on physical screen. */ 1176 | fitonscreen(client); 1177 | setborders(client, false); 1178 | 1179 | /* Check if this window has a workspace set already 1180 | * as a WM hint. */ 1181 | ws = getwmdesktop(children[i]); 1182 | 1183 | if (get_unkil_state(children[i])) 1184 | unkillablewindow(client); 1185 | 1186 | if (ws == NET_WM_FIXED) { 1187 | /* Add to current workspace. */ 1188 | addtoworkspace(client, curws); 1189 | /* Add to all other workspaces. */ 1190 | fixwindow(client); 1191 | } else { 1192 | if (TWOBWM_NOWS != ws && ws < WORKSPACES) { 1193 | addtoworkspace(client, ws); 1194 | if (ws != curws) 1195 | /* If it's not our current works 1196 | * pace, hide it. */ 1197 | xcb_unmap_window(conn, 1198 | client->id); 1199 | } else { 1200 | addtoworkspace(client, curws); 1201 | addtoclientlist(children[i]); 1202 | } 1203 | } 1204 | } 1205 | } 1206 | 1207 | if(NULL != attr) 1208 | free(attr); 1209 | 1210 | } 1211 | changeworkspace_helper(0); 1212 | 1213 | if(NULL!=reply) 1214 | free(reply); 1215 | 1216 | return true; 1217 | } 1218 | 1219 | /* Set up RANDR extension. Get the extension base and subscribe to events */ 1220 | int 1221 | setuprandr(void) 1222 | { 1223 | int base; 1224 | const xcb_query_extension_reply_t *extension 1225 | = xcb_get_extension_data(conn, &xcb_randr_id); 1226 | 1227 | if (!extension->present) 1228 | return -1; 1229 | else 1230 | getrandr(); 1231 | 1232 | base = extension->first_event; 1233 | xcb_randr_select_input(conn, screen->root, 1234 | XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE 1235 | | XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE 1236 | | XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE 1237 | | XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY 1238 | ); 1239 | 1240 | return base; 1241 | } 1242 | 1243 | /* Get RANDR resources and figure out how many outputs there are. */ 1244 | void 1245 | getrandr(void) 1246 | { 1247 | int len; 1248 | xcb_randr_get_screen_resources_current_cookie_t rcookie 1249 | = xcb_randr_get_screen_resources_current(conn, screen->root); 1250 | xcb_randr_get_screen_resources_current_reply_t *res 1251 | = xcb_randr_get_screen_resources_current_reply(conn, rcookie, 1252 | NULL); 1253 | 1254 | if (NULL == res) 1255 | return; 1256 | 1257 | xcb_timestamp_t timestamp = res->config_timestamp; 1258 | len= xcb_randr_get_screen_resources_current_outputs_length(res); 1259 | xcb_randr_output_t *outputs 1260 | = xcb_randr_get_screen_resources_current_outputs(res); 1261 | 1262 | /* Request information for all outputs. */ 1263 | getoutputs(outputs, len, timestamp); 1264 | free(res); 1265 | } 1266 | 1267 | /* Walk through all the RANDR outputs (number of outputs == len) there */ 1268 | void 1269 | getoutputs(xcb_randr_output_t *outputs, const int len, 1270 | xcb_timestamp_t timestamp) 1271 | { 1272 | int i; 1273 | int name_len; 1274 | char *name; 1275 | 1276 | /* was at time timestamp. */ 1277 | xcb_randr_get_crtc_info_cookie_t icookie; 1278 | xcb_randr_get_crtc_info_reply_t *crtc = NULL; 1279 | xcb_randr_get_output_info_reply_t *output; 1280 | struct monitor *mon, *clonemon; 1281 | struct item *item; 1282 | xcb_randr_get_output_info_cookie_t ocookie[len]; 1283 | 1284 | for (i = 0; i < len; i++) 1285 | ocookie[i] = xcb_randr_get_output_info(conn, outputs[i], 1286 | timestamp); 1287 | 1288 | /* Loop through all outputs. */ 1289 | for (i = 0; i < len; i ++) { 1290 | if ((output = xcb_randr_get_output_info_reply(conn, ocookie[i], 1291 | NULL)) == NULL) 1292 | continue; 1293 | 1294 | //name_len = MIN(16, xcb_randr_get_output_info_name_length(output)); 1295 | //name = malloc(name_len+1); 1296 | //snprintf(name, name_len+1, "%.*s", name_len, 1297 | // xcb_randr_get_output_info_name(output)); 1298 | 1299 | if (XCB_NONE != output->crtc) { 1300 | icookie = xcb_randr_get_crtc_info(conn, output->crtc, 1301 | timestamp); 1302 | crtc = xcb_randr_get_crtc_info_reply(conn, icookie, NULL); 1303 | 1304 | if (NULL == crtc) 1305 | return; 1306 | 1307 | /* Check if it's a clone. */ 1308 | // TODO maybe they are not cloned, one might be bigger 1309 | // than the other after closing the lid 1310 | clonemon = findclones(outputs[i], crtc->x, crtc->y); 1311 | 1312 | if (NULL != clonemon) 1313 | continue; 1314 | 1315 | /* Do we know this monitor already? */ 1316 | if (NULL == (mon = findmonitor(outputs[i]))) 1317 | addmonitor(outputs[i], crtc->x, crtc->y, 1318 | crtc->width,crtc->height); 1319 | else 1320 | /* We know this monitor. Update information. 1321 | * If it's smaller than before, rearrange windows. */ 1322 | if ( crtc->x != mon->x||crtc->y != mon->y||crtc->width 1323 | != mon->width||crtc->height 1324 | != mon->height) { 1325 | if (crtc->x != mon->x) 1326 | mon->x = crtc->x; 1327 | if (crtc->y != mon->y) 1328 | mon->y = crtc->y; 1329 | if (crtc->width != mon->width) 1330 | mon->width = crtc->width; 1331 | if (crtc->height != mon->height) 1332 | mon->height = crtc->height; 1333 | 1334 | // TODO when lid closed, one screen 1335 | arrbymon(mon); 1336 | } 1337 | free(crtc); 1338 | } else { 1339 | /* Check if it was used before. If it was, do something. */ 1340 | if ((mon = findmonitor(outputs[i]))) { 1341 | struct client *client; 1342 | for (item = winlist; item != NULL; item = item->next) { 1343 | /* Check all windows on this monitor 1344 | * and move them to the next or to the 1345 | * first monitor if there is no next. */ 1346 | client = item->data; 1347 | 1348 | if (client->monitor == mon) { 1349 | if (NULL == client->monitor->item->next) 1350 | if (NULL == monlist) 1351 | client->monitor = NULL; 1352 | else 1353 | client->monitor = monlist->data; 1354 | else 1355 | client->monitor = client->monitor->item->next->data; 1356 | fitonscreen(client); 1357 | } 1358 | } 1359 | 1360 | /* It's not active anymore. Forget about it. */ 1361 | delmonitor(mon); 1362 | } 1363 | } 1364 | if (NULL != output) 1365 | free(output); 1366 | 1367 | free(name); 1368 | } /* for */ 1369 | } 1370 | 1371 | void 1372 | arrbymon(struct monitor *monitor) 1373 | { 1374 | struct client *client; 1375 | struct item *item; 1376 | 1377 | for (item = winlist; item != NULL; item = item->next) { 1378 | client = item->data; 1379 | 1380 | if (client->monitor == monitor) 1381 | fitonscreen(client); 1382 | } 1383 | } 1384 | 1385 | struct monitor * 1386 | findmonitor(xcb_randr_output_t id) 1387 | { 1388 | struct monitor *mon; 1389 | struct item *item; 1390 | 1391 | for (item = monlist; item != NULL; item = item->next) { 1392 | mon = item->data; 1393 | 1394 | if (id == mon->id) 1395 | return mon; 1396 | } 1397 | 1398 | return NULL; 1399 | } 1400 | 1401 | struct monitor * 1402 | findclones(xcb_randr_output_t id, const int16_t x, const int16_t y) 1403 | { 1404 | struct monitor *clonemon; 1405 | struct item *item; 1406 | 1407 | for (item = monlist; item != NULL; item = item->next) { 1408 | clonemon = item->data; 1409 | 1410 | /* Check for same position. */ 1411 | if (id != clonemon->id && clonemon->x == x && clonemon->y == y) 1412 | return clonemon; 1413 | } 1414 | 1415 | return NULL; 1416 | } 1417 | 1418 | struct monitor * 1419 | findmonbycoord(const int16_t x, const int16_t y) 1420 | { 1421 | struct monitor *mon; 1422 | struct item *item; 1423 | 1424 | for (item = monlist; item != NULL; item = item->next) { 1425 | mon = item->data; 1426 | 1427 | if (x>=mon->x && x <= mon->x + mon->width && y >= mon->y && y 1428 | <= mon->y+mon->height) 1429 | return mon; 1430 | } 1431 | 1432 | return NULL; 1433 | } 1434 | 1435 | struct monitor * 1436 | addmonitor(xcb_randr_output_t id, const int16_t x, const int16_t y, 1437 | const uint16_t width,const uint16_t height) 1438 | { 1439 | struct item *item; 1440 | struct monitor *mon = malloc(sizeof(struct monitor)); 1441 | 1442 | if (NULL == (item = additem(&monlist))) 1443 | return NULL; 1444 | 1445 | if (NULL == mon) 1446 | return NULL; 1447 | 1448 | item->data = mon; 1449 | mon->id = id; 1450 | mon->item = item; 1451 | mon->x = x; 1452 | mon->y = y; 1453 | mon->width = width; 1454 | mon->height = height; 1455 | 1456 | return mon; 1457 | } 1458 | 1459 | /* Raise window win to top of stack. */ 1460 | void 1461 | raisewindow(xcb_drawable_t win) 1462 | { 1463 | uint32_t values[] = { XCB_STACK_MODE_ABOVE }; 1464 | 1465 | if (screen->root == win || 0 == win) 1466 | return; 1467 | 1468 | xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_STACK_MODE, values); 1469 | xcb_flush(conn); 1470 | } 1471 | 1472 | /* Set window client to either top or bottom of stack depending on 1473 | * where it is now. */ 1474 | void 1475 | raiseorlower() 1476 | { 1477 | uint32_t values[] = { XCB_STACK_MODE_OPPOSITE }; 1478 | 1479 | if (NULL == focuswin) 1480 | return; 1481 | 1482 | xcb_configure_window(conn, focuswin->id,XCB_CONFIG_WINDOW_STACK_MODE, 1483 | values); 1484 | 1485 | xcb_flush(conn); 1486 | } 1487 | 1488 | /* Keep the window inside the screen */ 1489 | void 1490 | movelim(struct client *client) 1491 | { 1492 | int16_t mon_y, mon_x,temp=0; 1493 | uint16_t mon_height, mon_width; 1494 | 1495 | getmonsize(1, &mon_x, &mon_y, &mon_width, &mon_height, client); 1496 | noborder(&temp, client, true); 1497 | 1498 | /* Is it outside the physical monitor or close to the side? */ 1499 | if (client->y-conf.borderwidth < mon_y 1500 | || client->y < borders[2] + mon_y) 1501 | client->y = mon_y; 1502 | else if (client->y + client->height + (conf.borderwidth * 2) > mon_y 1503 | + mon_height - borders[2]) 1504 | client->y = mon_y + mon_height - client->height 1505 | - conf.borderwidth * 2; 1506 | 1507 | if (client->x < borders[2] + mon_x) 1508 | client->x = mon_x; 1509 | else if (client->x + client->width + (conf.borderwidth * 2) 1510 | > mon_x + mon_width - borders[2]) 1511 | client->x = mon_x + mon_width - client->width 1512 | - conf.borderwidth * 2; 1513 | 1514 | movewindow(client->id, client->x, client->y); 1515 | noborder(&temp, client, false); 1516 | } 1517 | 1518 | void 1519 | movewindow(xcb_drawable_t win, const int16_t x, const int16_t y) 1520 | { // Move window win to root coordinates x,y. 1521 | uint32_t values[2] = {x, y}; 1522 | 1523 | if (screen->root == win || 0 == win) 1524 | return; 1525 | 1526 | xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_X 1527 | | XCB_CONFIG_WINDOW_Y, values); 1528 | 1529 | xcb_flush(conn); 1530 | } 1531 | void 1532 | focusnext_helper(bool arg) 1533 | { 1534 | struct client *cl = NULL; 1535 | struct item *head = wslist[curws]; 1536 | struct item *tail,*item = NULL; 1537 | // no windows on current workspace 1538 | if (NULL == head) 1539 | return; 1540 | // if no focus on current workspace, find first valid item on list. 1541 | if (NULL == focuswin || focuswin->ws != curws) { 1542 | for(item = head;item != NULL;item = item->next){ 1543 | cl = item->data; 1544 | if(!cl->iconic) 1545 | break; 1546 | } 1547 | }else{ 1548 | // find tail of list and make list circular. 1549 | for(tail = head = item = wslist[curws]; item != NULL; 1550 | tail = item,item = item->next); 1551 | head->prev = tail; 1552 | tail->next = head; 1553 | if (arg == TWOBWM_FOCUS_NEXT) { 1554 | // start from focus next and find first valid item on circular list. 1555 | head = item = focuswin->wsitem->next; 1556 | do{ 1557 | cl = item->data; 1558 | if(!cl->iconic) 1559 | break; 1560 | item = item->next; 1561 | }while(item != head); 1562 | }else{ 1563 | // start from focus previous and find first valid on circular list. 1564 | tail = item = focuswin->wsitem->prev; 1565 | do{ 1566 | cl = item->data; 1567 | if(!cl->iconic) 1568 | break; 1569 | item = item->prev; 1570 | }while(item != tail); 1571 | } 1572 | // restore list. 1573 | wslist[curws]->prev->next = NULL; 1574 | wslist[curws]->prev = NULL; 1575 | } 1576 | if(!item || !(cl = item->data) || cl->iconic) 1577 | return; 1578 | raisewindow(cl->id); 1579 | centerpointer(cl->id,cl); 1580 | setfocus(cl); 1581 | } 1582 | /* Mark window win as unfocused. */ 1583 | void setunfocus(void) 1584 | { 1585 | // xcb_set_input_focus(conn, XCB_NONE, XCB_INPUT_FOCUS_NONE,XCB_CURRENT_TIME); 1586 | if (NULL == focuswin||focuswin->id == screen->root) 1587 | return; 1588 | 1589 | setborders(focuswin,false); 1590 | } 1591 | 1592 | /* Find client with client->id win in global window list or NULL. */ 1593 | struct client * 1594 | findclient(const xcb_drawable_t *win) 1595 | { 1596 | struct client *client; 1597 | struct item *item; 1598 | 1599 | for (item = winlist; item != NULL; item = item->next) { 1600 | client = item->data; 1601 | 1602 | if (*win == client->id){ 1603 | return client; 1604 | } 1605 | } 1606 | 1607 | return NULL; 1608 | } 1609 | 1610 | void 1611 | setfocus(struct client *client)// Set focus on window client. 1612 | { 1613 | long data[] = { XCB_ICCCM_WM_STATE_NORMAL, XCB_NONE }; 1614 | 1615 | /* If client is NULL, we focus on whatever the pointer is on. 1616 | * This is a pathological case, but it will make the poor user able 1617 | * to focus on windows anyway, even though this windowmanager might 1618 | * be buggy. */ 1619 | if (NULL == client) { 1620 | focuswin = NULL; 1621 | xcb_set_input_focus(conn, XCB_NONE, 1622 | XCB_INPUT_FOCUS_POINTER_ROOT, XCB_CURRENT_TIME); 1623 | xcb_window_t not_win = 0; 1624 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, screen->root, 1625 | ewmh->_NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 32, 1, 1626 | ¬_win); 1627 | 1628 | xcb_flush(conn); 1629 | return; 1630 | } 1631 | 1632 | /* Don't bother focusing on the root window or on the same window 1633 | * that already has focus. */ 1634 | if (client->id == screen->root) 1635 | return; 1636 | 1637 | if (NULL != focuswin) 1638 | setunfocus(); /* Unset last focus. */ 1639 | 1640 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->id, 1641 | ewmh->_NET_WM_STATE, ewmh->_NET_WM_STATE, 32, 2, data); 1642 | xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->id, 1643 | XCB_CURRENT_TIME); /* Set new input focus. */ 1644 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, screen->root, 1645 | ewmh->_NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 32, 1,&client->id); 1646 | 1647 | /* Remember the new window as the current focused window. */ 1648 | lastwin[curws] = focuswin; 1649 | focuswin = client; 1650 | 1651 | grabbuttons(client); 1652 | setborders(client,true); 1653 | } 1654 | 1655 | void 1656 | start(const Arg *arg) 1657 | { 1658 | if (fork()) 1659 | return; 1660 | 1661 | // if (conn) 1662 | // close(screen->root); 1663 | 1664 | setsid(); 1665 | execvp((char*)arg->com[0], (char**)arg->com); 1666 | } 1667 | 1668 | /* Resize with limit. */ 1669 | void 1670 | resizelim(struct client *client) 1671 | { 1672 | int16_t mon_x, mon_y,temp=0; 1673 | uint16_t mon_width, mon_height; 1674 | 1675 | getmonsize(1, &mon_x, &mon_y, &mon_width, &mon_height, client); 1676 | noborder(&temp, client, true); 1677 | 1678 | /* Is it smaller than it wants to be? */ 1679 | if (0 != client->min_height && client->height < client->min_height) 1680 | client->height = client->min_height; 1681 | if (0 != client->min_width && client->width < client->min_width) 1682 | client->width = client->min_width; 1683 | if (client->x + client->width + conf.borderwidth > mon_x + mon_width) 1684 | client->width = mon_width - ((client->x - mon_x) 1685 | + conf.borderwidth * 2); 1686 | if (client->y + client->height + conf.borderwidth > mon_y + mon_height) 1687 | client->height = mon_height - ((client->y - mon_y) 1688 | + conf.borderwidth * 2); 1689 | 1690 | resize(client->id, client->width, client->height); 1691 | noborder(&temp, client, false); 1692 | } 1693 | 1694 | void 1695 | moveresize(xcb_drawable_t win, const uint16_t x, const uint16_t y, 1696 | const uint16_t width, const uint16_t height) 1697 | { 1698 | uint32_t values[4] = { x, y, width, height }; 1699 | 1700 | if (screen->root == win || 0 == win) 1701 | return; 1702 | 1703 | xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_X 1704 | | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH 1705 | | XCB_CONFIG_WINDOW_HEIGHT, values); 1706 | 1707 | xcb_flush(conn); 1708 | } 1709 | 1710 | /* Resize window win to width,height. */ 1711 | void 1712 | resize(xcb_drawable_t win, const uint16_t width, const uint16_t height) 1713 | { 1714 | uint32_t values[2] = { width , height }; 1715 | 1716 | if (screen->root == win || 0 == win) 1717 | return; 1718 | 1719 | xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_WIDTH 1720 | | XCB_CONFIG_WINDOW_HEIGHT, values); 1721 | 1722 | xcb_flush(conn); 1723 | } 1724 | 1725 | /* Resize window client in direction. */ 1726 | void 1727 | resizestep(const Arg *arg) 1728 | { 1729 | uint8_t stepx,stepy,cases = arg->i % 4; 1730 | 1731 | if (NULL == focuswin || focuswin->maxed) 1732 | return; 1733 | 1734 | arg->i < 4 ? (stepx = stepy = movements[1]) 1735 | : (stepx = stepy = movements[0]); 1736 | 1737 | if (focuswin->width_inc > 7 && focuswin->height_inc > 7) { 1738 | /* we were given a resize hint by the window so use it */ 1739 | stepx = focuswin->width_inc; 1740 | stepy = focuswin->height_inc; 1741 | } 1742 | 1743 | if (cases == TWOBWM_RESIZE_LEFT) 1744 | focuswin->width = focuswin->width - stepx; 1745 | else if (cases == TWOBWM_RESIZE_DOWN) 1746 | focuswin->height = focuswin->height + stepy; 1747 | else if (cases == TWOBWM_RESIZE_UP) 1748 | focuswin->height = focuswin->height - stepy; 1749 | else if (cases == TWOBWM_RESIZE_RIGHT) 1750 | focuswin->width = focuswin->width + stepx; 1751 | 1752 | if (focuswin->vertmaxed) 1753 | focuswin->vertmaxed = false; 1754 | if (focuswin->hormaxed) 1755 | focuswin->hormaxed = false; 1756 | 1757 | resizelim(focuswin); 1758 | centerpointer(focuswin->id,focuswin); 1759 | raise_current_window(); 1760 | setborders(focuswin,true); 1761 | } 1762 | 1763 | /* Resize window and keep it's aspect ratio (exponentially grow), 1764 | * and round the result (+0.5) */ 1765 | void 1766 | resizestep_aspect(const Arg *arg) 1767 | { 1768 | if (NULL == focuswin || focuswin->maxed) 1769 | return; 1770 | 1771 | if (arg->i == TWOBWM_RESIZE_KEEP_ASPECT_SHRINK) { 1772 | focuswin->width = (focuswin->width / resize_keep_aspect_ratio) 1773 | +0.5; 1774 | focuswin->height = (focuswin->height / resize_keep_aspect_ratio) 1775 | +0.5; 1776 | } else { 1777 | focuswin->height = (focuswin->height * resize_keep_aspect_ratio) 1778 | +0.5; 1779 | focuswin->width = (focuswin->width * resize_keep_aspect_ratio) 1780 | +0.5; 1781 | } 1782 | 1783 | if (focuswin->vertmaxed) 1784 | focuswin->vertmaxed = false; 1785 | if (focuswin->hormaxed) 1786 | focuswin->hormaxed = false; 1787 | 1788 | resizelim(focuswin); 1789 | centerpointer(focuswin->id,focuswin); 1790 | raise_current_window(); 1791 | setborders(focuswin,true); 1792 | } 1793 | 1794 | /* Try to snap to other windows and monitor border */ 1795 | static void 1796 | snapwindow(struct client *client) 1797 | { 1798 | struct item *item; 1799 | struct client *win; 1800 | int16_t mon_x, mon_y; 1801 | uint16_t mon_width, mon_height; 1802 | 1803 | getmonsize(1, &mon_x,&mon_y,&mon_width,&mon_height,focuswin); 1804 | 1805 | for (item = wslist[curws]; item != NULL; item = item->next) { 1806 | win = item->data; 1807 | 1808 | if (client != win) { 1809 | if (abs((win->x +win->width) - client->x 1810 | + conf.borderwidth) < borders[2]) 1811 | if (client->y + client->height > win->y 1812 | && client->y < win->y 1813 | + win->height) 1814 | client->x = (win->x + win->width) 1815 | + (2 * conf.borderwidth); 1816 | 1817 | if (abs((win->y + win->height) - client->y 1818 | + conf.borderwidth) 1819 | < borders[2]) 1820 | if (client->x + client->width >win->x 1821 | && client->x < win->x 1822 | + win->width) 1823 | client->y = (win->y + win->height) 1824 | + (2 * conf.borderwidth); 1825 | 1826 | if (abs((client->x + client->width) - win->x 1827 | + conf.borderwidth) 1828 | < borders[2]) 1829 | if (client->y + client->height > win->y 1830 | && client->y < win->y 1831 | + win->height) 1832 | client->x = (win->x - client->width) 1833 | - (2 * conf.borderwidth); 1834 | 1835 | if (abs((client->y + client->height) - win->y 1836 | + conf.borderwidth) 1837 | < borders[2]) 1838 | if (client->x + client->width >win->x 1839 | && client->x < win->x 1840 | + win->width) 1841 | client->y = (win->y - client->height) 1842 | - (2 * conf.borderwidth); 1843 | } 1844 | } 1845 | } 1846 | 1847 | /* Move window win as a result of pointer motion to coordinates rel_x,rel_y. */ 1848 | void 1849 | mousemove(const int16_t rel_x, const int16_t rel_y) 1850 | { 1851 | if (focuswin == NULL || focuswin->ws != curws) 1852 | return; 1853 | 1854 | focuswin->x = rel_x; 1855 | focuswin->y = rel_y; 1856 | 1857 | if (borders[2] > 0) 1858 | snapwindow(focuswin); 1859 | 1860 | movelim(focuswin); 1861 | } 1862 | 1863 | void 1864 | mouseresize(struct client *client, const int16_t rel_x, const int16_t rel_y) 1865 | { 1866 | if(focuswin->id == screen->root || focuswin->maxed) 1867 | return; 1868 | 1869 | client->width = abs(rel_x); 1870 | client->height = abs(rel_y); 1871 | 1872 | if (resize_by_line) { 1873 | client->width -= (client->width - client->base_width) 1874 | % client->width_inc; 1875 | client->height -= (client->height - client->base_height) 1876 | % client->height_inc; 1877 | } 1878 | 1879 | resizelim(client); 1880 | client->vertmaxed = false; 1881 | client->hormaxed = false; 1882 | } 1883 | 1884 | void 1885 | movestep(const Arg *arg) 1886 | { 1887 | int16_t start_x, start_y; 1888 | uint8_t step, cases=arg->i; 1889 | 1890 | if (NULL == focuswin||focuswin->maxed) 1891 | return; 1892 | 1893 | /* Save pointer position so we can warp pointer here later. */ 1894 | if (!getpointer(&focuswin->id, &start_x, &start_y)) 1895 | return; 1896 | 1897 | cases = cases%4; 1898 | arg->i < 4 ? (step = movements[1]) : (step = movements[0]); 1899 | 1900 | if (cases == TWOBWM_MOVE_LEFT) 1901 | focuswin->x = focuswin->x - step; 1902 | else if (cases == TWOBWM_MOVE_DOWN) 1903 | focuswin->y = focuswin->y + step; 1904 | else if (cases == TWOBWM_MOVE_UP) 1905 | focuswin->y = focuswin->y - step; 1906 | else if (cases == TWOBWM_MOVE_RIGHT) 1907 | focuswin->x = focuswin->x + step; 1908 | 1909 | raise_current_window(); 1910 | movelim(focuswin); 1911 | movepointerback(start_x,start_y,focuswin); 1912 | xcb_flush(conn); 1913 | } 1914 | 1915 | void 1916 | setborders(struct client *client,const bool isitfocused) 1917 | { 1918 | uint32_t values[1]; /* this is the color maintainer */ 1919 | uint16_t half = 0; 1920 | bool inv = conf.inverted_colors; 1921 | 1922 | // something weird happened, fix client 1923 | if (client->width == 0 || client->height == 0) { 1924 | // restore from geometry 1925 | getgeom(&client->id, &client->x, &client->y, &client->width, 1926 | &client->height, &client->depth); 1927 | resize(client->id, client->width, client->height); 1928 | xcb_flush(conn); 1929 | } 1930 | 1931 | if (client->maxed || client->ignore_borders) 1932 | return; 1933 | 1934 | /* Set border width. */ 1935 | values[0] = conf.borderwidth; 1936 | xcb_configure_window(conn, client->id, 1937 | XCB_CONFIG_WINDOW_BORDER_WIDTH, values); 1938 | 1939 | if (top_win!=0 &&client->id ==top_win) 1940 | inv = !inv; 1941 | 1942 | half = conf.outer_border; 1943 | 1944 | xcb_rectangle_t rect_inner[] = { 1945 | { 1946 | client->width, 1947 | 0, 1948 | conf.borderwidth - half,client->height 1949 | + conf.borderwidth - half 1950 | }, 1951 | { 1952 | client->width + conf.borderwidth + half, 1953 | 0, 1954 | conf.borderwidth - half, 1955 | client->height + conf.borderwidth - half 1956 | }, 1957 | { 1958 | 0, 1959 | client->height, 1960 | client->width + conf.borderwidth 1961 | - half,conf.borderwidth - half 1962 | }, 1963 | { 1964 | 0, 1965 | client->height + conf.borderwidth + half,client->width 1966 | + conf.borderwidth - half,conf.borderwidth 1967 | - half 1968 | }, 1969 | { 1970 | client->width + conf.borderwidth 1971 | + half,conf.borderwidth + client->height 1972 | + half,conf.borderwidth, 1973 | conf.borderwidth 1974 | } 1975 | }; 1976 | 1977 | xcb_rectangle_t rect_outer[] = { 1978 | { 1979 | client->width + conf.borderwidth - half, 1980 | 0, 1981 | half, 1982 | client->height + conf.borderwidth * 2 1983 | }, 1984 | { 1985 | client->width + conf.borderwidth, 1986 | 0, 1987 | half, 1988 | client->height + conf.borderwidth * 2 1989 | }, 1990 | { 1991 | 0, 1992 | client->height + conf.borderwidth - half,client->width 1993 | + conf.borderwidth * 2, 1994 | half 1995 | }, 1996 | { 1997 | 0, 1998 | client->height + conf.borderwidth, 1999 | client->width + conf.borderwidth * 2, 2000 | half 2001 | }, 2002 | { 2003 | 1,1,1,1 2004 | } 2005 | }; 2006 | 2007 | xcb_pixmap_t pmap = xcb_generate_id(conn); 2008 | xcb_create_pixmap(conn, client->depth, pmap, client->id, 2009 | client->width + (conf.borderwidth * 2), 2010 | client->height + (conf.borderwidth * 2) 2011 | ); 2012 | 2013 | xcb_gcontext_t gc = xcb_generate_id(conn); 2014 | xcb_create_gc(conn, gc, pmap, 0, NULL); 2015 | 2016 | if (inv) { 2017 | xcb_rectangle_t fake_rect[5]; 2018 | 2019 | for (uint8_t i=0;i<5;i++) { 2020 | fake_rect[i] = rect_outer[i]; 2021 | rect_outer[i] = rect_inner[i]; 2022 | rect_inner[i] = fake_rect[i]; 2023 | } 2024 | } 2025 | 2026 | values[0] = conf.outer_border_col; 2027 | 2028 | if (client->unkillable || client->fixed) { 2029 | if (client->unkillable && client->fixed) 2030 | values[0] = conf.fixed_unkil_col; 2031 | else 2032 | if (client->fixed) 2033 | values[0] = conf.fixedcol; 2034 | else 2035 | values[0] = conf.unkillcol; 2036 | } 2037 | 2038 | xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, &values[0]); 2039 | xcb_poly_fill_rectangle(conn, pmap, gc, 5, rect_outer); 2040 | 2041 | values[0] = conf.focuscol; 2042 | 2043 | if (!isitfocused) 2044 | values[0] = conf.unfocuscol; 2045 | 2046 | xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, &values[0]); 2047 | xcb_poly_fill_rectangle(conn, pmap, gc, 5, rect_inner); 2048 | values[0] = pmap; 2049 | xcb_change_window_attributes(conn,client->id, XCB_CW_BORDER_PIXMAP, 2050 | &values[0]); 2051 | 2052 | /* free the memory we allocated for the pixmap */ 2053 | xcb_free_pixmap(conn,pmap); 2054 | xcb_free_gc(conn,gc); 2055 | xcb_flush(conn); 2056 | } 2057 | 2058 | void 2059 | unmax(struct client *client) 2060 | { 2061 | uint32_t values[5], mask = 0; 2062 | 2063 | if (NULL == client) 2064 | return; 2065 | 2066 | client->x = client->origsize.x; 2067 | client->y = client->origsize.y; 2068 | client->width = client->origsize.width; 2069 | client->height = client->origsize.height; 2070 | 2071 | /* Restore geometry. */ 2072 | values[0] = client->x; 2073 | values[1] = client->y; 2074 | values[2] = client->width; 2075 | values[3] = client->height; 2076 | 2077 | client->maxed = client->hormaxed = 0; 2078 | moveresize(client->id, client->x, client->y, 2079 | client->width, client->height); 2080 | 2081 | centerpointer(client->id,client); 2082 | setborders(client,true); 2083 | } 2084 | 2085 | void 2086 | maximize(const Arg *arg) 2087 | { 2088 | maxwin(focuswin, 1); 2089 | } 2090 | 2091 | void 2092 | fullscreen(const Arg *arg) 2093 | { 2094 | maxwin(focuswin, 0); 2095 | } 2096 | 2097 | 2098 | void 2099 | unmaxwin(struct client *client){ 2100 | unmax(client); 2101 | client->maxed = false; 2102 | setborders(client,true); 2103 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->id, 2104 | ewmh->_NET_WM_STATE, XCB_ATOM_ATOM, 32, 0, NULL); 2105 | } 2106 | 2107 | void 2108 | maxwin(struct client *client, uint8_t with_offsets){ 2109 | uint32_t values[4]; 2110 | int16_t mon_x, mon_y; 2111 | int16_t mon_width, mon_height; 2112 | 2113 | if (NULL == focuswin) 2114 | return; 2115 | 2116 | /* Check if maximized already. If so, revert to stored geometry. */ 2117 | if (focuswin->maxed) { 2118 | unmaxwin(focuswin); 2119 | return; 2120 | } 2121 | 2122 | getmonsize(with_offsets, &mon_x, &mon_y, &mon_width, &mon_height, client); 2123 | maximize_helper(client, mon_x, mon_y, mon_width, mon_height); 2124 | raise_current_window(); 2125 | if (!with_offsets) { 2126 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->id, 2127 | ewmh->_NET_WM_STATE, XCB_ATOM_ATOM, 32, 1, &ewmh->_NET_WM_STATE_FULLSCREEN); 2128 | } 2129 | xcb_flush(conn); 2130 | } 2131 | 2132 | void 2133 | maxvert_hor(const Arg *arg) 2134 | { 2135 | uint32_t values[2]; 2136 | int16_t mon_y, mon_x, temp = 0; 2137 | uint16_t mon_height, mon_width; 2138 | 2139 | if (NULL == focuswin) 2140 | return; 2141 | 2142 | if (focuswin->vertmaxed || focuswin->hormaxed) { 2143 | unmax(focuswin); 2144 | focuswin->vertmaxed = focuswin->hormaxed = false; 2145 | fitonscreen(focuswin); 2146 | setborders(focuswin, true); 2147 | return; 2148 | } 2149 | 2150 | getmonsize(1, &mon_x,&mon_y,&mon_width,&mon_height,focuswin); 2151 | saveorigsize(focuswin); 2152 | noborder(&temp, focuswin,true); 2153 | 2154 | if (arg->i==TWOBWM_MAXIMIZE_VERTICALLY) { 2155 | focuswin->y = mon_y; 2156 | /* Compute new height considering height increments 2157 | * and screen height. */ 2158 | focuswin->height = mon_height - (conf.borderwidth * 2); 2159 | 2160 | /* Move to top of screen and resize. */ 2161 | values[0] = focuswin->y; 2162 | values[1] = focuswin->height; 2163 | 2164 | xcb_configure_window(conn, focuswin->id, XCB_CONFIG_WINDOW_Y 2165 | | XCB_CONFIG_WINDOW_HEIGHT, values); 2166 | 2167 | focuswin->vertmaxed = true; 2168 | } else if (arg->i==TWOBWM_MAXIMIZE_HORIZONTALLY) { 2169 | focuswin->x = mon_x; 2170 | focuswin->width = mon_width - (conf.borderwidth * 2); 2171 | values[0] = focuswin->x; 2172 | values[1] = focuswin->width; 2173 | 2174 | xcb_configure_window(conn, focuswin->id, XCB_CONFIG_WINDOW_X 2175 | | XCB_CONFIG_WINDOW_WIDTH, values); 2176 | 2177 | focuswin->hormaxed = true; 2178 | } 2179 | 2180 | noborder(&temp, focuswin,false); 2181 | raise_current_window(); 2182 | centerpointer(focuswin->id,focuswin); 2183 | setborders(focuswin,true); 2184 | } 2185 | 2186 | void 2187 | maxhalf(const Arg *arg) 2188 | { 2189 | uint32_t values[4]; 2190 | int16_t mon_x, mon_y, temp=0; 2191 | uint16_t mon_width, mon_height; 2192 | 2193 | if (NULL == focuswin||focuswin->maxed) 2194 | return; 2195 | 2196 | getmonsize(1, &mon_x,&mon_y,&mon_width,&mon_height,focuswin); 2197 | noborder(&temp, focuswin, true); 2198 | 2199 | if (arg->i>4) { 2200 | if (arg->i>6) { 2201 | /* in folding mode */ 2202 | if (arg->i == TWOBWM_MAXHALF_FOLD_VERTICAL) 2203 | focuswin->height = focuswin->height / 2 2204 | - (conf.borderwidth); 2205 | else 2206 | focuswin->height = focuswin->height * 2 2207 | + (2*conf.borderwidth); 2208 | } else { 2209 | focuswin->y = mon_y; 2210 | focuswin->height = mon_height - (conf.borderwidth * 2); 2211 | focuswin->width = ((float)(mon_width) / 2) 2212 | - (conf.borderwidth * 2); 2213 | 2214 | if (arg->i== TWOBWM_MAXHALF_VERTICAL_LEFT) 2215 | focuswin->x = mon_x; 2216 | else 2217 | focuswin->x = mon_x + mon_width 2218 | - (focuswin->width 2219 | + conf.borderwidth * 2); 2220 | } 2221 | } else { 2222 | if (arg->i < 2) { 2223 | /* in folding mode */ 2224 | if (arg->i == TWOBWM_MAXHALF_FOLD_HORIZONTAL) 2225 | focuswin->width = focuswin->width / 2 2226 | - conf.borderwidth; 2227 | else 2228 | focuswin->width = focuswin->width * 2 2229 | + (2 * conf.borderwidth); //unfold 2230 | } else { 2231 | focuswin->x = mon_x; 2232 | focuswin->width = mon_width - (conf.borderwidth * 2); 2233 | focuswin->height = ((float)(mon_height) / 2) 2234 | - (conf.borderwidth * 2); 2235 | 2236 | if (arg->i == TWOBWM_MAXHALF_HORIZONTAL_TOP) 2237 | focuswin->y = mon_y; 2238 | else 2239 | focuswin->y = mon_y + mon_height 2240 | - (focuswin->height 2241 | + conf.borderwidth * 2); 2242 | } 2243 | } 2244 | 2245 | moveresize(focuswin->id, focuswin->x, focuswin->y, 2246 | focuswin->width, focuswin->height); 2247 | 2248 | focuswin->verthor = true; 2249 | noborder(&temp, focuswin, false); 2250 | raise_current_window(); 2251 | fitonscreen(focuswin); 2252 | centerpointer(focuswin->id, focuswin); 2253 | setborders(focuswin, true); 2254 | } 2255 | 2256 | void 2257 | hide(void) 2258 | { 2259 | if (focuswin==NULL) 2260 | return; 2261 | 2262 | long data[] = { 2263 | XCB_ICCCM_WM_STATE_ICONIC, 2264 | ewmh->_NET_WM_STATE_HIDDEN, 2265 | XCB_NONE 2266 | }; 2267 | 2268 | /* Unmap window and declare iconic. Unmapping will generate an 2269 | * UnmapNotify event so we can forget about the window later. */ 2270 | focuswin->iconic = true; 2271 | 2272 | xcb_unmap_window(conn, focuswin->id); 2273 | xcb_change_property(conn, XCB_PROP_MODE_REPLACE, focuswin->id, 2274 | ewmh->_NET_WM_STATE, ewmh->_NET_WM_STATE, 32, 3, data); 2275 | 2276 | xcb_flush(conn); 2277 | } 2278 | 2279 | bool 2280 | getpointer(const xcb_drawable_t *win, int16_t *x, int16_t *y) 2281 | { 2282 | xcb_query_pointer_reply_t *pointer; 2283 | 2284 | pointer = xcb_query_pointer_reply(conn, 2285 | xcb_query_pointer(conn, *win), 0); 2286 | if (NULL == pointer) 2287 | return false; 2288 | *x = pointer->win_x; 2289 | *y = pointer->win_y; 2290 | 2291 | free(pointer); 2292 | return true; 2293 | } 2294 | 2295 | bool 2296 | getgeom(const xcb_drawable_t *win, int16_t *x, int16_t *y, uint16_t *width, 2297 | uint16_t *height, uint8_t *depth) 2298 | { 2299 | xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(conn, 2300 | xcb_get_geometry(conn, *win), NULL); 2301 | 2302 | if (NULL == geom) 2303 | return false; 2304 | 2305 | *x = geom->x; 2306 | *y = geom->y; 2307 | *width = geom->width; 2308 | *height = geom->height; 2309 | *depth = geom->depth; 2310 | 2311 | free(geom); 2312 | return true; 2313 | } 2314 | 2315 | void 2316 | teleport(const Arg *arg) 2317 | { 2318 | int16_t pointx, pointy, mon_x, mon_y, temp = 0; 2319 | uint16_t mon_width, mon_height; 2320 | 2321 | if (NULL == focuswin|| NULL == wslist[curws]|| focuswin->maxed) 2322 | return; 2323 | 2324 | if (!getpointer(&focuswin->id, &pointx, &pointy)) 2325 | return; 2326 | uint16_t tmp_x = focuswin->x; 2327 | uint16_t tmp_y = focuswin->y; 2328 | 2329 | getmonsize(1, &mon_x, &mon_y, &mon_width, &mon_height,focuswin); 2330 | noborder(&temp, focuswin,true); 2331 | focuswin->x = mon_x; focuswin->y = mon_y; 2332 | 2333 | if (arg->i==TWOBWM_TELEPORT_CENTER) { /* center */ 2334 | focuswin->x += mon_width - (focuswin->width 2335 | + conf.borderwidth * 2) +mon_x; 2336 | focuswin->y += mon_height - (focuswin->height 2337 | + conf.borderwidth* 2)+ mon_y; 2338 | focuswin->y = focuswin->y /2; 2339 | focuswin->x = focuswin->x /2; 2340 | } else { 2341 | /* top-left */ 2342 | if (arg->i>3) { 2343 | /* bottom-left */ 2344 | if (arg->i == TWOBWM_TELEPORT_BOTTOM_LEFT) 2345 | focuswin->y += mon_height - (focuswin->height 2346 | + conf.borderwidth* 2); 2347 | /* center y */ 2348 | else if (arg->i == TWOBWM_TELEPORT_CENTER_Y) { 2349 | focuswin->x = tmp_x; 2350 | focuswin->y += mon_height - (focuswin->height 2351 | + conf.borderwidth* 2)+ mon_y; 2352 | focuswin->y = focuswin->y /2; 2353 | } 2354 | } else { 2355 | /* top-right */ 2356 | if (arg->i<2) 2357 | /* center x */ 2358 | if (arg->i==TWOBWM_TELEPORT_CENTER_X) { 2359 | focuswin->y = tmp_y; 2360 | focuswin->x += mon_width 2361 | - (focuswin->width 2362 | + conf.borderwidth * 2) 2363 | + mon_x; 2364 | focuswin->x = focuswin->x /2; 2365 | } else 2366 | focuswin->x += mon_width 2367 | - (focuswin->width 2368 | + conf.borderwidth * 2); 2369 | else { 2370 | /* bottom-right */ 2371 | focuswin->x += mon_width 2372 | - (focuswin->width 2373 | + conf.borderwidth * 2); 2374 | focuswin->y += mon_height 2375 | - (focuswin->height 2376 | + conf.borderwidth * 2); 2377 | } 2378 | } 2379 | } 2380 | 2381 | movewindow(focuswin->id, focuswin->x, focuswin->y); 2382 | movepointerback(pointx,pointy, focuswin); 2383 | noborder(&temp, focuswin, false); 2384 | raise_current_window(); 2385 | xcb_flush(conn); 2386 | } 2387 | 2388 | void 2389 | deletewin() 2390 | { 2391 | bool use_delete = false; 2392 | xcb_icccm_get_wm_protocols_reply_t protocols; 2393 | xcb_get_property_cookie_t cookie; 2394 | 2395 | if (NULL == focuswin || focuswin->unkillable==true) 2396 | return; 2397 | 2398 | /* Check if WM_DELETE is supported. */ 2399 | cookie = xcb_icccm_get_wm_protocols_unchecked(conn, focuswin->id, 2400 | ewmh->WM_PROTOCOLS); 2401 | 2402 | if (focuswin->id == top_win) 2403 | top_win = 0; 2404 | 2405 | if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &protocols, NULL) 2406 | == 1) { 2407 | for (uint32_t i = 0; i < protocols.atoms_len; i++) 2408 | if (protocols.atoms[i] == ATOM[wm_delete_window]) { 2409 | xcb_client_message_event_t ev = { 2410 | .response_type = XCB_CLIENT_MESSAGE, 2411 | .format = 32, 2412 | .sequence = 0, 2413 | .window = focuswin->id, 2414 | .type = ewmh->WM_PROTOCOLS, 2415 | .data.data32 = { 2416 | ATOM[wm_delete_window], 2417 | XCB_CURRENT_TIME 2418 | } 2419 | }; 2420 | 2421 | xcb_send_event(conn, false, focuswin->id, 2422 | XCB_EVENT_MASK_NO_EVENT, 2423 | (char *)&ev 2424 | ); 2425 | 2426 | use_delete = true; 2427 | break; 2428 | } 2429 | 2430 | xcb_icccm_get_wm_protocols_reply_wipe(&protocols); 2431 | } 2432 | if (!use_delete) xcb_kill_client(conn, focuswin->id); 2433 | } 2434 | 2435 | void 2436 | changescreen(const Arg *arg) 2437 | { 2438 | struct item *item; 2439 | float xpercentage, ypercentage; 2440 | 2441 | if (NULL == focuswin || NULL == focuswin->monitor) 2442 | return; 2443 | 2444 | if (arg->i == TWOBWM_NEXT_SCREEN) 2445 | item = focuswin->monitor->item->next; 2446 | else 2447 | item = focuswin->monitor->item->prev; 2448 | 2449 | if (NULL == item) 2450 | return; 2451 | 2452 | xpercentage = (float)((focuswin->x - focuswin->monitor->x) 2453 | /(focuswin->monitor->width)); 2454 | ypercentage = (float)((focuswin->y-focuswin->monitor->y) 2455 | /(focuswin->monitor->height)); 2456 | 2457 | focuswin->monitor = item->data; 2458 | 2459 | focuswin->x = focuswin->monitor->width * xpercentage 2460 | + focuswin->monitor->x + 0.5; 2461 | focuswin->y = focuswin->monitor->height * ypercentage 2462 | + focuswin->monitor->y+0.5; 2463 | 2464 | raise_current_window(); 2465 | fitonscreen(focuswin); 2466 | movelim(focuswin); 2467 | setborders(focuswin, true); 2468 | centerpointer(focuswin->id, focuswin); 2469 | } 2470 | 2471 | /* Function to make the cursor move with the keyboard */ 2472 | void 2473 | cursor_move(const Arg *arg) 2474 | { 2475 | uint16_t speed; uint8_t cases=arg->i%4; 2476 | arg->i < 4 ? (speed = movements[3]) : (speed = movements[2]); 2477 | 2478 | if (cases == TWOBWM_CURSOR_UP) 2479 | xcb_warp_pointer(conn, XCB_NONE, XCB_NONE, 2480 | 0, 0, 0, 0, 0, -speed); 2481 | else if (cases == TWOBWM_CURSOR_DOWN) 2482 | xcb_warp_pointer(conn, XCB_NONE, XCB_NONE, 2483 | 0, 0, 0, 0, 0, speed); 2484 | else if (cases == TWOBWM_CURSOR_RIGHT) 2485 | xcb_warp_pointer(conn, XCB_NONE, XCB_NONE, 2486 | 0, 0, 0, 0, speed, 0); 2487 | else if (cases == TWOBWM_CURSOR_LEFT) 2488 | xcb_warp_pointer(conn, XCB_NONE, XCB_NONE, 2489 | 0, 0, 0, 0, -speed, 0); 2490 | 2491 | xcb_flush(conn); 2492 | } 2493 | 2494 | /* wrapper to get xcb keysymbol from keycode */ 2495 | static xcb_keysym_t 2496 | xcb_get_keysym(xcb_keycode_t keycode) 2497 | { 2498 | xcb_key_symbols_t *keysyms; 2499 | 2500 | if (!(keysyms = xcb_key_symbols_alloc(conn))) 2501 | return 0; 2502 | 2503 | xcb_keysym_t keysym = xcb_key_symbols_get_keysym(keysyms, keycode, 0); 2504 | xcb_key_symbols_free(keysyms); 2505 | 2506 | return keysym; 2507 | } 2508 | 2509 | void 2510 | circulaterequest(xcb_generic_event_t *ev) 2511 | { 2512 | xcb_circulate_request_event_t *e = (xcb_circulate_request_event_t *)ev; 2513 | 2514 | /* 2515 | * Subwindow e->window to parent e->event is about to be restacked. 2516 | * Just do what was requested, e->place is either 2517 | * XCB_PLACE_ON_TOP or _ON_BOTTOM. 2518 | */ 2519 | xcb_circulate_window(conn, e->window, e->place); 2520 | } 2521 | 2522 | void 2523 | handle_keypress(xcb_generic_event_t *e) 2524 | { 2525 | xcb_key_press_event_t *ev = (xcb_key_press_event_t *)e; 2526 | xcb_keysym_t keysym = xcb_get_keysym(ev->detail); 2527 | 2528 | for (unsigned int i=0; istate) && keys[i].func) { 2531 | keys[i].func(&keys[i].arg); 2532 | break; 2533 | } 2534 | } 2535 | } 2536 | 2537 | /* Helper function to configure a window. */ 2538 | void 2539 | configwin(xcb_window_t win, uint16_t mask, const struct winconf *wc) 2540 | { 2541 | uint32_t values[7]; 2542 | int8_t i = -1; 2543 | 2544 | if (mask & XCB_CONFIG_WINDOW_X) { 2545 | mask |= XCB_CONFIG_WINDOW_X; 2546 | i++; 2547 | values[i] = wc->x; 2548 | } 2549 | 2550 | if (mask & XCB_CONFIG_WINDOW_Y) { 2551 | mask |= XCB_CONFIG_WINDOW_Y; 2552 | i++; 2553 | values[i] = wc->y; 2554 | } 2555 | 2556 | if (mask & XCB_CONFIG_WINDOW_WIDTH) { 2557 | mask |= XCB_CONFIG_WINDOW_WIDTH; 2558 | if (wc->width != 0) { 2559 | i++; 2560 | values[i] = wc->width; 2561 | } 2562 | } 2563 | 2564 | if (mask & XCB_CONFIG_WINDOW_HEIGHT) { 2565 | mask |= XCB_CONFIG_WINDOW_HEIGHT; 2566 | if (wc->height != 0) { 2567 | i++; 2568 | values[i] = wc->height; 2569 | } 2570 | } 2571 | 2572 | if (mask & XCB_CONFIG_WINDOW_SIBLING) { 2573 | mask |= XCB_CONFIG_WINDOW_SIBLING; 2574 | i++; 2575 | values[i] = wc->sibling; 2576 | } 2577 | 2578 | if (mask & XCB_CONFIG_WINDOW_STACK_MODE) { 2579 | mask |= XCB_CONFIG_WINDOW_STACK_MODE; 2580 | i++; 2581 | values[i] = wc->stackmode; 2582 | } 2583 | 2584 | if (i == -1) 2585 | return; 2586 | 2587 | xcb_configure_window(conn, win, mask, values); 2588 | xcb_flush(conn); 2589 | } 2590 | 2591 | void 2592 | configurerequest(xcb_generic_event_t *ev) 2593 | { 2594 | xcb_configure_request_event_t *e = (xcb_configure_request_event_t *)ev; 2595 | struct client *client; 2596 | struct winconf wc; 2597 | int16_t mon_x, mon_y; 2598 | uint16_t mon_width, mon_height; 2599 | uint32_t values[1]; 2600 | 2601 | if ((client = findclient(&e->window))) { /* Find the client. */ 2602 | getmonsize(1, &mon_x, &mon_y, &mon_width, &mon_height, client); 2603 | 2604 | if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) 2605 | if (!client->maxed && !client->hormaxed) 2606 | client->width = e->width; 2607 | 2608 | if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) 2609 | if (!client->maxed && !client->vertmaxed) 2610 | client->height = e->height; 2611 | 2612 | 2613 | if (e->value_mask & XCB_CONFIG_WINDOW_X) 2614 | if (!client->maxed && !client->hormaxed) 2615 | client->x = e->x; 2616 | 2617 | if (e->value_mask & XCB_CONFIG_WINDOW_Y) 2618 | if (!client->maxed && !client->vertmaxed) 2619 | client->y = e->y; 2620 | 2621 | /* XXX Do we really need to pass on sibling and stack mode 2622 | * configuration? Do we want to? */ 2623 | if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) { 2624 | values[0] = e->sibling; 2625 | xcb_configure_window(conn, e->window, 2626 | XCB_CONFIG_WINDOW_SIBLING,values); 2627 | } 2628 | 2629 | if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) { 2630 | values[0] = e->stack_mode; 2631 | xcb_configure_window(conn, e->window, 2632 | XCB_CONFIG_WINDOW_STACK_MODE,values); 2633 | } 2634 | 2635 | /* Check if window fits on screen after resizing. */ 2636 | if (!client->maxed) { 2637 | resizelim(client); 2638 | movelim(client); 2639 | fitonscreen(client); 2640 | } 2641 | 2642 | setborders(client,true); 2643 | } else { 2644 | /* Unmapped window, pass all options except border width. */ 2645 | wc.x = e->x; 2646 | wc.y = e->y; 2647 | wc.width = e->width; 2648 | wc.height = e->height; 2649 | wc.sibling = e->sibling; 2650 | wc.stackmode = e->stack_mode; 2651 | 2652 | configwin(e->window, e->value_mask, &wc); 2653 | } 2654 | } 2655 | 2656 | xcb_cursor_t 2657 | Create_Font_Cursor(xcb_connection_t *conn, uint16_t glyph) 2658 | { 2659 | static xcb_font_t cursor_font; 2660 | 2661 | cursor_font = xcb_generate_id (conn); 2662 | xcb_open_font(conn, cursor_font, strlen("cursor"), "cursor"); 2663 | xcb_cursor_t cursor = xcb_generate_id (conn); 2664 | xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font, glyph, 2665 | glyph + 1,0x3232, 0x3232, 0x3232, 0xeeee, 0xeeee, 0xeeec 2666 | ); 2667 | 2668 | return cursor; 2669 | } 2670 | 2671 | struct client 2672 | create_back_win(void) 2673 | { 2674 | struct client temp_win; 2675 | uint32_t values[1] = { conf.focuscol }; 2676 | 2677 | temp_win.id = xcb_generate_id(conn); 2678 | xcb_create_window(conn, 2679 | /* depth */ 2680 | XCB_COPY_FROM_PARENT, 2681 | /* window Id */ 2682 | temp_win.id, 2683 | /* parent window */ 2684 | screen->root, 2685 | /* x, y */ 2686 | focuswin->x, 2687 | focuswin->y, 2688 | /* width, height */ 2689 | focuswin->width, 2690 | focuswin->height, 2691 | /* border width */ 2692 | borders[3], 2693 | /* class */ 2694 | XCB_WINDOW_CLASS_INPUT_OUTPUT, 2695 | /* visual */ 2696 | screen->root_visual, 2697 | XCB_CW_BORDER_PIXEL, 2698 | values 2699 | ); 2700 | 2701 | if (conf.enable_compton) 2702 | { 2703 | values[0] = 1; 2704 | xcb_change_window_attributes(conn, temp_win.id, 2705 | XCB_BACK_PIXMAP_PARENT_RELATIVE, values); 2706 | } 2707 | else 2708 | { 2709 | values[0] = conf.unfocuscol; 2710 | xcb_change_window_attributes(conn, temp_win.id, 2711 | XCB_CW_BACK_PIXEL, values); 2712 | } 2713 | 2714 | temp_win.x = focuswin->x; 2715 | temp_win.y = focuswin->y; 2716 | temp_win.width = focuswin->width; 2717 | temp_win.unkillable = focuswin->unkillable; 2718 | temp_win.fixed = focuswin->fixed; 2719 | temp_win.height = focuswin->height; 2720 | temp_win.width_inc = focuswin->width_inc; 2721 | temp_win.height_inc = focuswin->height_inc; 2722 | temp_win.base_width = focuswin->base_width; 2723 | temp_win.base_height = focuswin->base_height; 2724 | temp_win.monitor = focuswin->monitor; 2725 | temp_win.min_height = focuswin->min_height; 2726 | temp_win.min_width = focuswin->min_height; 2727 | temp_win.ignore_borders = focuswin->ignore_borders; 2728 | 2729 | return temp_win; 2730 | } 2731 | 2732 | static void 2733 | mousemotion(const Arg *arg) 2734 | { 2735 | int16_t mx, my, winx, winy, winw, winh; 2736 | xcb_query_pointer_reply_t *pointer; 2737 | xcb_grab_pointer_reply_t *grab_reply; 2738 | xcb_motion_notify_event_t *ev = NULL; 2739 | xcb_generic_event_t *e = NULL; 2740 | bool ungrab; 2741 | 2742 | pointer = xcb_query_pointer_reply(conn, 2743 | xcb_query_pointer(conn, screen->root), 0 2744 | ); 2745 | 2746 | if (!pointer || focuswin->maxed) { 2747 | free(pointer); 2748 | return; 2749 | } 2750 | 2751 | mx = pointer->root_x; 2752 | my = pointer->root_y; 2753 | winx = focuswin->x; 2754 | winy = focuswin->y; 2755 | winw = focuswin->width; 2756 | winh = focuswin->height; 2757 | 2758 | xcb_cursor_t cursor; 2759 | struct client example; 2760 | raise_current_window(); 2761 | 2762 | if(arg->i == TWOBWM_MOVE) 2763 | cursor = Create_Font_Cursor (conn, 52 ); /* fleur */ 2764 | else { 2765 | cursor = Create_Font_Cursor (conn, 120); /* sizing */ 2766 | example = create_back_win(); 2767 | xcb_map_window(conn,example.id); 2768 | } 2769 | 2770 | grab_reply = xcb_grab_pointer_reply(conn, xcb_grab_pointer(conn, 0, 2771 | screen->root, BUTTONMASK | XCB_EVENT_MASK_BUTTON_MOTION 2772 | | XCB_EVENT_MASK_POINTER_MOTION, XCB_GRAB_MODE_ASYNC, 2773 | XCB_GRAB_MODE_ASYNC, XCB_NONE, cursor, XCB_CURRENT_TIME) 2774 | , NULL 2775 | ); 2776 | 2777 | if (grab_reply->status != XCB_GRAB_STATUS_SUCCESS) { 2778 | free(grab_reply); 2779 | 2780 | if (arg->i == TWOBWM_RESIZE) 2781 | xcb_unmap_window(conn,example.id); 2782 | 2783 | return; 2784 | } 2785 | 2786 | free(grab_reply); 2787 | ungrab = false; 2788 | 2789 | do { 2790 | if (NULL!=e) 2791 | free(e); 2792 | 2793 | while(!(e = xcb_wait_for_event(conn))) 2794 | xcb_flush(conn); 2795 | 2796 | switch (e->response_type & ~0x80) { 2797 | case XCB_CONFIGURE_REQUEST: 2798 | case XCB_MAP_REQUEST: 2799 | events[e->response_type & ~0x80](e); 2800 | break; 2801 | case XCB_MOTION_NOTIFY: 2802 | ev = (xcb_motion_notify_event_t*)e; 2803 | if (arg->i == TWOBWM_MOVE) 2804 | mousemove(winx + ev->root_x - mx, 2805 | winy + ev->root_y-my); 2806 | else 2807 | mouseresize(&example, winw + ev->root_x - mx, 2808 | winh + ev->root_y - my); 2809 | 2810 | xcb_flush(conn); 2811 | break; 2812 | case XCB_KEY_PRESS: 2813 | case XCB_KEY_RELEASE: 2814 | case XCB_BUTTON_PRESS: 2815 | case XCB_BUTTON_RELEASE: 2816 | if (arg->i==TWOBWM_RESIZE) { 2817 | ev = (xcb_motion_notify_event_t*)e; 2818 | 2819 | mouseresize(focuswin, winw + ev->root_x - mx, 2820 | winh + ev->root_y - my); 2821 | 2822 | setborders(focuswin,true); 2823 | } 2824 | 2825 | ungrab = true; 2826 | break; 2827 | } 2828 | } while (!ungrab && focuswin != NULL); 2829 | 2830 | free(pointer); 2831 | free(e); 2832 | xcb_free_cursor(conn,cursor); 2833 | xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); 2834 | 2835 | if (arg->i == TWOBWM_RESIZE) 2836 | xcb_unmap_window(conn,example.id); 2837 | 2838 | xcb_flush(conn); 2839 | } 2840 | 2841 | void 2842 | buttonpress(xcb_generic_event_t *ev) 2843 | { 2844 | xcb_button_press_event_t *e = (xcb_button_press_event_t *)ev; 2845 | struct client *client; 2846 | unsigned int i; 2847 | 2848 | 2849 | if (!is_sloppy && e->detail == XCB_BUTTON_INDEX_1 2850 | && CLEANMASK(e->state) == 0) { 2851 | // skip if already focused 2852 | if (NULL != focuswin && e->event == focuswin->id) { 2853 | return; 2854 | } 2855 | client = findclient(&e->event); 2856 | if (NULL != client) { 2857 | setfocus(client); 2858 | raisewindow(client->id); 2859 | setborders(client,true); 2860 | } 2861 | return; 2862 | } 2863 | 2864 | for (i=0; idetail 2866 | && CLEANMASK(buttons[i].mask) 2867 | == CLEANMASK(e->state)){ 2868 | if ((focuswin==NULL) && buttons[i].func == mousemotion) 2869 | return; 2870 | if (buttons[i].root_only) { 2871 | if (e->event == e->root && e->child == 0) 2872 | buttons[i].func(&(buttons[i].arg)); 2873 | } 2874 | else { 2875 | buttons[i].func(&(buttons[i].arg)); 2876 | } 2877 | } 2878 | } 2879 | 2880 | void 2881 | clientmessage(xcb_generic_event_t *ev) 2882 | { 2883 | xcb_client_message_event_t *e= (xcb_client_message_event_t *)ev; 2884 | struct client *cl; 2885 | 2886 | if ((e->type == ATOM[wm_change_state] && e->format==32 2887 | && e->data.data32[0]==XCB_ICCCM_WM_STATE_ICONIC) 2888 | || e->type == ewmh->_NET_ACTIVE_WINDOW) { 2889 | cl = findclient( &e->window); 2890 | 2891 | if (NULL == cl) 2892 | return; 2893 | 2894 | if ( false == cl->iconic ) { 2895 | if (e->type == ewmh->_NET_ACTIVE_WINDOW) { 2896 | setfocus(cl); 2897 | raisewindow(cl->id); 2898 | } else { 2899 | hide(); 2900 | } 2901 | 2902 | return; 2903 | } 2904 | 2905 | cl->iconic = false; 2906 | xcb_map_window(conn, cl->id); 2907 | setfocus(cl); 2908 | } 2909 | else if (e->type == ewmh->_NET_CURRENT_DESKTOP) { 2910 | if (e->data.data32[0] > 0 && e->data.data32[0] < WORKSPACES) { 2911 | changeworkspace_helper(e->data.data32[0]); 2912 | } 2913 | } else if (e->type == ewmh->_NET_WM_STATE && e->format == 32) { 2914 | cl = findclient(&e->window); 2915 | if (NULL == cl) 2916 | return; 2917 | if(e->data.data32[1] == ewmh->_NET_WM_STATE_FULLSCREEN 2918 | || e->data.data32[2] == ewmh->_NET_WM_STATE_FULLSCREEN) { 2919 | switch (e->data.data32[0]) { 2920 | case XCB_EWMH_WM_STATE_REMOVE: 2921 | unmaxwin(cl); 2922 | break; 2923 | case XCB_EWMH_WM_STATE_ADD: 2924 | maxwin(cl, false); 2925 | break; 2926 | case XCB_EWMH_WM_STATE_TOGGLE: 2927 | if(cl->maxed) 2928 | unmaxwin(cl); 2929 | else 2930 | maxwin(cl, false); 2931 | break; 2932 | 2933 | default: 2934 | break; 2935 | } 2936 | } 2937 | } else if (e->type == ewmh->_NET_WM_DESKTOP && e->format == 32) { 2938 | cl = findclient(&e->window); 2939 | if (NULL == cl) 2940 | return; 2941 | /* 2942 | * e->data.data32[1] Source indication 2943 | * 0: backward compat 2944 | * 1: normal 2945 | * 2: pager/bars 2946 | * 2947 | * e->data.data32[0] new workspace 2948 | */ 2949 | uint32_t new_ws = e->data.data32[0]; 2950 | if (new_ws >= 0 && new_ws < WORKSPACES) { 2951 | delfromworkspace(cl); 2952 | addtoworkspace(cl, e->data.data32[0]); 2953 | xcb_unmap_window(conn, cl->id); 2954 | xcb_flush(conn); 2955 | } else { 2956 | // specific case, treat it as new window 2957 | xcb_map_window(conn, cl->id); 2958 | raisewindow(cl->id); 2959 | } 2960 | } 2961 | } 2962 | 2963 | void 2964 | destroynotify(xcb_generic_event_t *ev) 2965 | { 2966 | struct client *cl; 2967 | 2968 | xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *) ev; 2969 | if (NULL != focuswin && focuswin->id == e->window) 2970 | focuswin = NULL; 2971 | 2972 | if (NULL != lastwin[curws] && lastwin[curws]->id == e->window) 2973 | lastwin[curws] = NULL; 2974 | 2975 | cl = findclient( & e->window); 2976 | 2977 | /* Find this window in list of clients and forget about it. */ 2978 | if (NULL != cl) 2979 | forgetwin(cl->id); 2980 | 2981 | updateclientlist(); 2982 | } 2983 | 2984 | void 2985 | enternotify(xcb_generic_event_t *ev) 2986 | { 2987 | xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *)ev; 2988 | struct client *client; 2989 | unsigned int modifiers[] = { 2990 | 0, 2991 | XCB_MOD_MASK_LOCK, 2992 | numlockmask, 2993 | numlockmask | XCB_MOD_MASK_LOCK 2994 | }; 2995 | 2996 | 2997 | /* 2998 | * If this isn't a normal enter notify, don't bother. We also need 2999 | * ungrab events, since these will be generated on button and key 3000 | * grabs and if the user for some reason presses a button on the 3001 | * root and then moves the pointer to our window and releases the 3002 | * button, we get an Ungrab EnterNotify. The other cases means the 3003 | * pointer is grabbed and that either means someone is using it for 3004 | * menu selections or that we're moving or resizing. We don't want 3005 | * to change focus in those cases. 3006 | */ 3007 | 3008 | 3009 | if (e->mode == XCB_NOTIFY_MODE_NORMAL 3010 | || e->mode == XCB_NOTIFY_MODE_UNGRAB) { 3011 | /* If we're entering the same window we focus now, 3012 | * then don't bother focusing. */ 3013 | 3014 | if (NULL != focuswin && e->event == focuswin->id) 3015 | return; 3016 | 3017 | 3018 | /* Otherwise, set focus to the window we just entered if we 3019 | * can find it among the windows we know about. 3020 | * If not, just keep focus in the old window. */ 3021 | 3022 | client = findclient(&e->event); 3023 | if (NULL == client) 3024 | return; 3025 | 3026 | /* skip this if not is_sloppy 3027 | * we'll focus on click instead (see buttonpress function) 3028 | * thus we have to grab left click button on that window 3029 | * the grab is removed at the end of the setfocus function, 3030 | * in the grabbuttons when not in sloppy mode 3031 | */ 3032 | if (!is_sloppy) { 3033 | for (unsigned int m=0; m 0 means 3036 | // the grab_window won't 3037 | // receive this event 3038 | client->id, 3039 | XCB_EVENT_MASK_BUTTON_PRESS, 3040 | XCB_GRAB_MODE_ASYNC, 3041 | XCB_GRAB_MODE_ASYNC, 3042 | screen->root, XCB_NONE, 3043 | XCB_BUTTON_INDEX_1, 3044 | modifiers[m] 3045 | ); 3046 | } 3047 | return; 3048 | } 3049 | 3050 | setfocus(client); 3051 | setborders(client,true); 3052 | } 3053 | } 3054 | 3055 | void 3056 | unmapnotify(xcb_generic_event_t *ev) 3057 | { 3058 | xcb_unmap_notify_event_t *e = (xcb_unmap_notify_event_t *)ev; 3059 | struct client *client = NULL; 3060 | /* 3061 | * Find the window in our current workspace list, then forget about it. 3062 | * Note that we might not know about the window we got the UnmapNotify 3063 | * event for. 3064 | * It might be a window we just unmapped on *another* workspace when 3065 | * changing workspaces, for instance, or it might be a window with 3066 | * override redirect set. 3067 | * This is not an error. 3068 | * XXX We might need to look in the global window list, after all. 3069 | * Consider if a window is unmapped on our last workspace while 3070 | * changing workspaces. 3071 | * If we do this, we need to keep track of our own windows and 3072 | * ignore UnmapNotify on them. 3073 | */ 3074 | client = findclient( & e->window); 3075 | if (NULL == client || client->ws != curws) 3076 | return; 3077 | if (focuswin!=NULL && client->id == focuswin->id) 3078 | focuswin = NULL; 3079 | if (lastwin[curws]!=NULL && client->id == lastwin[curws]->id) 3080 | lastwin[curws] = NULL; 3081 | 3082 | if (client->iconic == false) 3083 | forgetclient(client); 3084 | 3085 | updateclientlist(); 3086 | if (focuswin == NULL) // try to focus another window 3087 | focusnext_helper(true); 3088 | } 3089 | 3090 | void 3091 | mapnotify(xcb_generic_event_t *ev) 3092 | { 3093 | xcb_mapping_notify_event_t *e = (xcb_mapping_notify_event_t *)ev; 3094 | xcb_key_symbols_t *keysyms; 3095 | if (!(keysyms = xcb_key_symbols_alloc(conn))) 3096 | return; 3097 | xcb_refresh_keyboard_mapping(keysyms, e); 3098 | xcb_key_symbols_free(keysyms); 3099 | 3100 | setup_keyboard(); 3101 | grabkeys(); 3102 | } 3103 | 3104 | void 3105 | confignotify(xcb_generic_event_t *ev) 3106 | { 3107 | xcb_configure_notify_event_t *e= (xcb_configure_notify_event_t *)ev; 3108 | 3109 | if (e->window == screen->root) { 3110 | /* 3111 | * When using RANDR or Xinerama, the root can change geometry 3112 | * when the user adds a new screen, tilts their screen 90 3113 | * degrees or whatnot. We might need to rearrange windows to 3114 | * be visible. 3115 | * We might get notified for several reasons, not just if the 3116 | * geometry changed. 3117 | * If the geometry is unchanged we do nothing. 3118 | */ 3119 | 3120 | if (e->width!=screen->width_in_pixels 3121 | || e->height != screen->height_in_pixels) { 3122 | screen->width_in_pixels = e->width; 3123 | screen->height_in_pixels = e->height; 3124 | 3125 | if (-1 == randrbase) 3126 | arrangewindows(); 3127 | } 3128 | } 3129 | } 3130 | 3131 | void 3132 | run(void) 3133 | { 3134 | sigcode = 0; 3135 | 3136 | while (0 == sigcode) { 3137 | /* the WM is running */ 3138 | xcb_flush(conn); 3139 | 3140 | if (xcb_connection_has_error(conn)){ 3141 | cleanup(); 3142 | abort(); 3143 | } 3144 | if ((ev = xcb_wait_for_event(conn))) { 3145 | if(ev->response_type==randrbase + 3146 | XCB_RANDR_SCREEN_CHANGE_NOTIFY) 3147 | getrandr(); 3148 | 3149 | if (events[ev->response_type & ~0x80]) 3150 | events[ev->response_type & ~0x80](ev); 3151 | 3152 | if(top_win!=0) 3153 | raisewindow(top_win); 3154 | if (dock_win != 0) 3155 | raisewindow(dock_win); 3156 | 3157 | free(ev); 3158 | } 3159 | } 3160 | if (sigcode == SIGHUP) { 3161 | sigcode = 0; 3162 | twobwm_restart(); 3163 | } 3164 | } 3165 | 3166 | /* Get a defined atom from the X server. */ 3167 | xcb_atom_t 3168 | getatom(const char *atom_name) 3169 | { 3170 | xcb_intern_atom_cookie_t atom_cookie = xcb_intern_atom(conn, 0, 3171 | strlen(atom_name), atom_name); 3172 | 3173 | xcb_intern_atom_reply_t *rep = xcb_intern_atom_reply(conn, atom_cookie, 3174 | NULL); 3175 | 3176 | /* XXX Note that we return 0 as an atom if anything goes wrong. 3177 | * Might become interesting.*/ 3178 | 3179 | if (NULL == rep) 3180 | return 0; 3181 | 3182 | xcb_atom_t atom = rep->atom; 3183 | 3184 | free(rep); 3185 | return atom; 3186 | } 3187 | 3188 | /* set the given client to listen to button events (presses / releases) */ 3189 | void 3190 | grabbuttons(struct client *c) 3191 | { 3192 | unsigned int modifiers[] = { 3193 | 0, 3194 | XCB_MOD_MASK_LOCK, 3195 | numlockmask, 3196 | numlockmask | XCB_MOD_MASK_LOCK 3197 | }; 3198 | 3199 | for (unsigned int b=0; bid, 3203 | XCB_EVENT_MASK_BUTTON_PRESS, 3204 | XCB_GRAB_MODE_ASYNC, 3205 | XCB_GRAB_MODE_ASYNC, 3206 | screen->root, XCB_NONE, 3207 | buttons[b].button, 3208 | buttons[b].mask|modifiers[m] 3209 | ); 3210 | } 3211 | 3212 | /* ungrab the left click, otherwise we can't use it 3213 | * we've previously grabbed the left click in the enternotify function 3214 | * when not in sloppy mode 3215 | * though the name is counter-intuitive to the method 3216 | */ 3217 | for (unsigned int m=0; mid, 3221 | modifiers[m] 3222 | ); 3223 | } 3224 | } 3225 | 3226 | void 3227 | ewmh_init(void) 3228 | { 3229 | if (!(ewmh = calloc(1, sizeof(xcb_ewmh_connection_t)))) 3230 | printf("Fail\n"); 3231 | 3232 | xcb_intern_atom_cookie_t *cookie = xcb_ewmh_init_atoms(conn, ewmh); 3233 | if(!xcb_ewmh_init_atoms_replies(ewmh, cookie, (void *)0)){ 3234 | fprintf(stderr,"%s\n","xcb_ewmh_init_atoms_replies:faild."); 3235 | exit(1); 3236 | } 3237 | } 3238 | 3239 | bool 3240 | setup(int scrno) 3241 | { 3242 | unsigned int i; 3243 | uint32_t event_mask_pointer[] = { XCB_EVENT_MASK_POINTER_MOTION }; 3244 | 3245 | unsigned int values[1] = { 3246 | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT 3247 | | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY 3248 | | XCB_EVENT_MASK_PROPERTY_CHANGE 3249 | | XCB_EVENT_MASK_BUTTON_PRESS 3250 | }; 3251 | 3252 | screen = xcb_screen_of_display(conn, scrno); 3253 | 3254 | if (!screen) 3255 | return false; 3256 | 3257 | ewmh_init(); 3258 | xcb_ewmh_set_wm_pid(ewmh, screen->root, getpid()); 3259 | xcb_ewmh_set_wm_name(ewmh, screen->root, 4, "2bwm"); 3260 | 3261 | xcb_atom_t net_atoms[] = { 3262 | ewmh->_NET_SUPPORTED, ewmh->_NET_WM_DESKTOP, 3263 | ewmh->_NET_NUMBER_OF_DESKTOPS, ewmh->_NET_CURRENT_DESKTOP, 3264 | ewmh->_NET_ACTIVE_WINDOW, ewmh->_NET_WM_ICON, 3265 | ewmh->_NET_WM_STATE, ewmh->_NET_WM_NAME, 3266 | ewmh->_NET_SUPPORTING_WM_CHECK , ewmh->_NET_WM_STATE_HIDDEN, 3267 | ewmh->_NET_WM_ICON_NAME, ewmh->_NET_WM_WINDOW_TYPE, 3268 | ewmh->_NET_WM_WINDOW_TYPE_DOCK, ewmh->_NET_WM_WINDOW_TYPE_DESKTOP, 3269 | ewmh->_NET_WM_WINDOW_TYPE_TOOLBAR, ewmh->_NET_WM_PID, 3270 | ewmh->_NET_CLIENT_LIST, ewmh->_NET_CLIENT_LIST_STACKING, 3271 | ewmh->WM_PROTOCOLS, ewmh->_NET_WM_STATE, 3272 | ewmh->_NET_WM_STATE_DEMANDS_ATTENTION, 3273 | ewmh->_NET_WM_STATE_FULLSCREEN 3274 | }; 3275 | 3276 | xcb_ewmh_set_supported(ewmh, scrno, LENGTH(net_atoms), net_atoms); 3277 | 3278 | xcb_xrm_database_t* db = xcb_xrm_database_from_default(conn); 3279 | 3280 | // Load the default config anyway. 3281 | conf.borderwidth = borders[1]; 3282 | conf.outer_border = borders[0]; 3283 | conf.focuscol = getcolor(colors[0]); 3284 | conf.unfocuscol = getcolor(colors[1]); 3285 | conf.fixedcol = getcolor(colors[2]); 3286 | conf.unkillcol = getcolor(colors[3]); 3287 | conf.outer_border_col = getcolor(colors[5]); 3288 | conf.fixed_unkil_col = getcolor(colors[4]); 3289 | conf.empty_col = getcolor(colors[6]); 3290 | conf.inverted_colors = inverted_colors; 3291 | conf.enable_compton = false; 3292 | 3293 | if (db != NULL) 3294 | { 3295 | char* value; 3296 | 3297 | if (xcb_xrm_resource_get_string(db, "twobwm.border_width", NULL, &value) >= 0) 3298 | conf.borderwidth = atoi(value); 3299 | 3300 | if (xcb_xrm_resource_get_string(db, "twobwm.outer_border", NULL, &value) >= 0) 3301 | conf.outer_border = atoi(value); 3302 | 3303 | if (xcb_xrm_resource_get_string(db, "twobwm.focus_color", NULL, &value) >= 0) 3304 | conf.focuscol = getcolor(value); 3305 | 3306 | if (xcb_xrm_resource_get_string(db, "twobwm.unfocus_color", NULL, &value) >= 0) 3307 | conf.unfocuscol = getcolor(value); 3308 | 3309 | if (xcb_xrm_resource_get_string(db, "twobwm.fixed_color", NULL, &value) >= 0) 3310 | conf.fixedcol = getcolor(value); 3311 | 3312 | if (xcb_xrm_resource_get_string(db, "twobwm.unkill_color", NULL, &value) >= 0) 3313 | conf.unkillcol = getcolor(value); 3314 | 3315 | if (xcb_xrm_resource_get_string(db, "twobwm.outer_border_color", NULL, &value) >= 0) 3316 | conf.outer_border_col = getcolor(value); 3317 | 3318 | if (xcb_xrm_resource_get_string(db, "twobwm.fixed_unkill_color", NULL, &value) >= 0) 3319 | conf.fixed_unkil_col = getcolor(value); 3320 | 3321 | if (xcb_xrm_resource_get_string(db, "twobwm.inverted_colors", NULL, &value) >= 0) 3322 | conf.inverted_colors = strcmp(value, "true") == 0; 3323 | 3324 | if (xcb_xrm_resource_get_string(db, "twobwm.enable_compton", NULL, &value) >= 0) 3325 | conf.enable_compton = strcmp(value, "true") == 0; 3326 | } 3327 | 3328 | xcb_xrm_database_free(db); 3329 | 3330 | for (i=0; iroot, 3343 | XCB_CW_EVENT_MASK, values)); 3344 | xcb_flush(conn); 3345 | 3346 | if (error){ 3347 | fprintf(stderr,"%s\n","xcb_request_check:faild."); 3348 | free(error); 3349 | return false; 3350 | } 3351 | xcb_ewmh_set_current_desktop(ewmh, scrno, curws); 3352 | xcb_ewmh_set_number_of_desktops(ewmh, scrno, WORKSPACES); 3353 | 3354 | grabkeys(); 3355 | /* set events */ 3356 | for (i=0; i