A tiling window manager
at master 1018 lines 24 kB view raw
1/* 2 * Manage windows, such as Mapping them and making sure the proper key Grabs 3 * have been put in place. 4 * 5 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along with 18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 19 * Place, Suite 330, Boston, MA 02111-1307 USA. 20 */ 21 22#include <stdio.h> 23#include <stdlib.h> 24#include <string.h> 25#include <err.h> 26 27#include <X11/X.h> 28#include <X11/Xlib.h> 29#include <X11/Xutil.h> 30#include <X11/Xatom.h> 31#include <X11/keysymdef.h> 32 33#include "sdorfehs.h" 34 35static char **unmanaged_window_list = NULL; 36static int num_unmanaged_windows = 0; 37 38void 39clear_unmanaged_list(void) 40{ 41 if (unmanaged_window_list) { 42 int i; 43 44 for (i = 0; i < num_unmanaged_windows; i++) 45 free(unmanaged_window_list[i]); 46 47 free(unmanaged_window_list); 48 49 unmanaged_window_list = NULL; 50 } 51 num_unmanaged_windows = 0; 52} 53 54char * 55list_unmanaged_windows(void) 56{ 57 char *tmp = NULL; 58 59 if (unmanaged_window_list) { 60 struct sbuf *buf; 61 int i; 62 63 buf = sbuf_new(0); 64 65 for (i = 0; i < num_unmanaged_windows; i++) { 66 sbuf_concat(buf, unmanaged_window_list[i]); 67 sbuf_concat(buf, "\n"); 68 } 69 sbuf_chop(buf); 70 tmp = sbuf_free_struct(buf); 71 } 72 return tmp; 73} 74 75void 76add_unmanaged_window(char *name) 77{ 78 char **tmp; 79 80 if (!name) 81 return; 82 83 tmp = xmalloc((num_unmanaged_windows + 1) * sizeof(char *)); 84 85 if (unmanaged_window_list) { 86 memcpy(tmp, unmanaged_window_list, 87 num_unmanaged_windows * sizeof(char *)); 88 free(unmanaged_window_list); 89 } 90 tmp[num_unmanaged_windows] = xstrdup(name); 91 num_unmanaged_windows++; 92 93 unmanaged_window_list = tmp; 94} 95 96void 97grab_top_level_keys(Window w) 98{ 99 rp_keymap *map = find_keymap(defaults.top_kmap); 100 int i; 101 102 if (map == NULL) { 103 warnx("unable to find %s level keymap", defaults.top_kmap); 104 return; 105 } 106 PRINT_INPUT_DEBUG(("grabbing top level key\n")); 107 for (i = 0; i < map->actions_last; i++) { 108 PRINT_INPUT_DEBUG(("%d\n", i)); 109 grab_key(map->actions[i].key, map->actions[i].state, w); 110 } 111} 112 113void 114ungrab_top_level_keys(Window w) 115{ 116 XUngrabKey(dpy, AnyKey, AnyModifier, w); 117} 118 119void 120ungrab_keys_all_wins(void) 121{ 122 rp_window *cur; 123 124 /* Remove the grab on the current prefix key */ 125 list_for_each_entry(cur, &rp_mapped_window, node) { 126 ungrab_top_level_keys(cur->w); 127 } 128} 129 130void 131grab_keys_all_wins(void) 132{ 133 rp_window *cur; 134 135 /* Remove the grab on the current prefix key */ 136 list_for_each_entry(cur, &rp_mapped_window, node) { 137 grab_top_level_keys(cur->w); 138 } 139} 140 141void 142update_normal_hints(rp_window *win) 143{ 144 long supplied; 145 146 XGetWMNormalHints(dpy, win->w, win->hints, &supplied); 147 148 /* Discard bogus hints */ 149 if ((win->hints->flags & PAspect) && (win->hints->min_aspect.x < 1 || 150 win->hints->min_aspect.y < 1 || win->hints->max_aspect.x < 1 || 151 win->hints->max_aspect.y < 1)) 152 win->hints->flags &= ~PAspect; 153 if ((win->hints->flags & PMaxSize) && win->hints->max_width < 1) 154 win->hints->flags &= ~PMaxSize; 155 if ((win->hints->flags & PMinSize) && win->hints->min_width < 1) 156 win->hints->flags &= ~PMinSize; 157 if ((win->hints->flags & PResizeInc) && (win->hints->width_inc < 1 || 158 win->hints->height_inc < 1)) 159 win->hints->flags &= ~PResizeInc; 160 161 /* Print debugging output for window hints. */ 162#ifdef DEBUG 163 if (win->hints->flags & PMinSize) 164 PRINT_DEBUG(("minx: %d miny: %d\n", win->hints->min_width, 165 win->hints->min_height)); 166 167 if (win->hints->flags & PMaxSize) 168 PRINT_DEBUG(("maxx: %d maxy: %d\n", win->hints->max_width, 169 win->hints->max_height)); 170 171 if (win->hints->flags & PResizeInc) 172 PRINT_DEBUG(("incx: %d incy: %d\n", win->hints->width_inc, 173 win->hints->height_inc)); 174#endif 175} 176 177 178static char * 179get_wmname(Window w) 180{ 181 char *name = NULL; 182 XTextProperty text_prop; 183 Atom type = None; 184 int ret = None, n; 185 unsigned long nitems, bytes_after; 186 int format; 187 char **cl; 188 unsigned char *val = NULL; 189 190 /* 191 * Try to use the window's _NET_WM_NAME ewmh property 192 */ 193 ret = XGetWindowProperty(dpy, w, _net_wm_name, 0, 40, False, 194 xa_utf8_string, &type, &format, &nitems, 195 &bytes_after, &val); 196 /* We have a valid UTF-8 string */ 197 if (ret == Success && type == xa_utf8_string && format == 8 && 198 nitems > 0) { 199 name = xstrdup((char *) val); 200 XFree(val); 201 PRINT_DEBUG(("Fetching window name using " 202 "_NET_WM_NAME succeeded\n")); 203 PRINT_DEBUG(("WM_NAME: %s\n", name)); 204 return name; 205 } 206 /* Something went wrong for whatever reason */ 207 if (ret == Success && val) 208 XFree(val); 209 PRINT_DEBUG(("Could not fetch window name using _NET_WM_NAME\n")); 210 211 if (XGetWMName(dpy, w, &text_prop) == 0) { 212 PRINT_DEBUG(("XGetWMName failed\n")); 213 return NULL; 214 } 215 PRINT_DEBUG(("WM_NAME encoding: ")); 216 if (text_prop.encoding == xa_string) 217 PRINT_DEBUG(("STRING\n")); 218 else if (text_prop.encoding == xa_compound_text) 219 PRINT_DEBUG(("COMPOUND_TEXT\n")); 220 else if (text_prop.encoding == xa_utf8_string) 221 PRINT_DEBUG(("UTF8_STRING\n")); 222 else 223 PRINT_DEBUG(("unknown (%d)\n", (int) text_prop.encoding)); 224 225 /* 226 * It seems that most applications supporting UTF8_STRING and 227 * _NET_WM_NAME don't bother making their WM_NAME available as 228 * UTF8_STRING (but only as either STRING or COMPOUND_TEXT). Let's try 229 * anyway. 230 */ 231 if (text_prop.encoding == xa_utf8_string) { 232 ret = Xutf8TextPropertyToTextList(dpy, &text_prop, &cl, &n); 233 PRINT_DEBUG(("Xutf8TextPropertyToTextList: %s\n", 234 ret == Success ? "success" : "error")); 235 } else { 236 /* 237 * XmbTextPropertyToTextList should be fine for all cases, even 238 * UTF8_STRING encoded WM_NAME 239 */ 240 ret = XmbTextPropertyToTextList(dpy, &text_prop, &cl, &n); 241 PRINT_DEBUG(("XmbTextPropertyToTextList: %s\n", 242 ret == Success ? "success" : "error")); 243 } 244 245 if (ret == Success && cl && n > 0) { 246 name = xstrdup(cl[0]); 247 XFreeStringList(cl); 248 } else if (text_prop.value) { 249 /* Convertion failed, try to get the raw string */ 250 name = xstrdup((char *) text_prop.value); 251 XFree(text_prop.value); 252 } 253 if (name == NULL) { 254 PRINT_DEBUG(("I can't get the WMName.\n")); 255 } else { 256 PRINT_DEBUG(("WM_NAME: '%s'\n", name)); 257 } 258 259 return name; 260} 261 262static XClassHint * 263get_class_hints(Window w) 264{ 265 XClassHint *class; 266 267 class = XAllocClassHint(); 268 269 if (class == NULL) 270 errx(1, "not enough memory for WM_CLASS structure"); 271 272 XGetClassHint(dpy, w, class); 273 274 return class; 275} 276 277/* 278 * Reget the WM_NAME property for the window and update its name. Return 1 if 279 * the name changed. 280 */ 281int 282update_window_name(rp_window *win) 283{ 284 char *newstr; 285 int changed = 0; 286 XClassHint *class; 287 288 newstr = get_wmname(win->w); 289 if (newstr != NULL) { 290 changed = changed || win->wm_name == NULL || 291 strcmp(newstr, win->wm_name); 292 free(win->wm_name); 293 win->wm_name = newstr; 294 } 295 class = get_class_hints(win->w); 296 297 if (class->res_class != NULL 298 && (win->res_class == NULL || strcmp(class->res_class, win->res_class))) { 299 changed = 1; 300 free(win->res_class); 301 win->res_class = xstrdup(class->res_class); 302 } 303 if (class->res_name != NULL 304 && (win->res_name == NULL || strcmp(class->res_name, win->res_name))) { 305 changed = 1; 306 free(win->res_name); 307 win->res_name = xstrdup(class->res_name); 308 } 309 XFree(class->res_name); 310 XFree(class->res_class); 311 XFree(class); 312 return changed; 313} 314 315/* 316 * This function is used to determine if the window should be treated as a 317 * transient. 318 */ 319int 320window_is_transient(rp_window *win) 321{ 322 return win->transient 323#ifdef ASPECT_WINDOWS_ARE_TRANSIENTS 324 || win->hints->flags & PAspect 325#endif 326#ifdef MAXSIZE_WINDOWS_ARE_TRANSIENTS 327 || (win->hints->flags & PMaxSize 328 && (win->hints->max_width < win->vscreen->screen->width 329 || win->hints->max_height < win->vscreen->screen->height)) 330#endif 331 ; 332} 333 334Atom 335get_net_wm_window_type(rp_window *win) 336{ 337 Atom type, window_type = None; 338 int format; 339 unsigned long nitems; 340 unsigned long bytes_left; 341 unsigned char *data; 342 343 if (win == NULL) 344 return None; 345 346 if (XGetWindowProperty(dpy, win->w, _net_wm_window_type, 0, 1L, 347 False, XA_ATOM, &type, &format, &nitems, &bytes_left, 348 &data) == Success && nitems > 0) { 349 window_type = *(Atom *)data; 350 XFree(data); 351 } 352 return window_type; 353} 354 355int 356is_unmanaged_window_type(Window win) 357{ 358 Atom win_type; 359 rp_window tmp; 360 361 tmp.w = win; 362 win_type = get_net_wm_window_type(&tmp); 363 if (win_type == _net_wm_window_type_dock || 364 win_type == _net_wm_window_type_splash || 365 win_type == _net_wm_window_type_tooltip || 366 win_type == _net_wm_window_type_utility) 367 return 1; 368 369 return 0; 370} 371 372void 373update_window_information(rp_window *win) 374{ 375 XWindowAttributes attr; 376 377 update_window_name(win); 378 379 /* Get the WM Hints */ 380 update_normal_hints(win); 381 382 /* Get the colormap */ 383 XGetWindowAttributes(dpy, win->w, &attr); 384 win->colormap = attr.colormap; 385 win->x = attr.x; 386 win->y = attr.y; 387 win->width = attr.width; 388 win->height = attr.height; 389 win->border = attr.border_width; 390 391 /* Transient status */ 392 win->transient = XGetTransientForHint(dpy, win->w, &win->transient_for); 393 394 if (get_net_wm_window_type(win) == _net_wm_window_type_dialog) 395 win->transient = 1; 396 397 PRINT_DEBUG(("update_window_information: x:%d y:%d width:%d height:%d " 398 "transient:%d\n", win->x, win->y, win->width, win->height, 399 win->transient)); 400 401 update_window_gravity(win); 402} 403 404void 405unmanage(rp_window *w) 406{ 407 list_del(&w->node); 408 vscreen_del_window(w->vscreen, w); 409 410 remove_atom(rp_glob_screen.root, _net_client_list, XA_WINDOW, w->w); 411 remove_atom(rp_glob_screen.root, _net_client_list_stacking, XA_WINDOW, 412 w->w); 413 414 free_window(w); 415} 416 417/* When starting up scan existing windows and start managing them. */ 418void 419scanwins(void) 420{ 421 rp_window *win; 422 XWindowAttributes attr; 423 unsigned int i, nwins; 424 Window dw1, dw2, *wins; 425 426 XQueryTree(dpy, rp_glob_screen.root, &dw1, &dw2, &wins, &nwins); 427 PRINT_DEBUG(("windows: %d\n", nwins)); 428 429 for (i = 0; i < nwins; i++) { 430 rp_screen *screen; 431 432 XGetWindowAttributes(dpy, wins[i], &attr); 433 if (is_rp_window(wins[i]) 434 || attr.override_redirect == True 435 || unmanaged_window(wins[i])) 436 continue; 437 438 screen = find_screen_by_attr(attr); 439 if (!screen) 440 list_first(screen, &rp_screens, node); 441 442 win = add_to_window_list(screen, wins[i]); 443 444 PRINT_DEBUG(("map_state: %s\n", 445 attr.map_state == IsViewable ? "IsViewable" : 446 attr.map_state == IsUnviewable ? "IsUnviewable" : 447 "IsUnmapped")); 448 PRINT_DEBUG(("state: %s\n", 449 get_state(win) == IconicState ? "Iconic" : 450 get_state(win) == NormalState ? "Normal" : "Other")); 451 452 /* Collect mapped and iconized windows. */ 453 if (attr.map_state == IsViewable 454 || (attr.map_state == IsUnmapped 455 && get_state(win) == IconicState)) 456 map_window(win); 457 } 458 459 XFree(wins); 460} 461 462int 463unmanaged_window(Window w) 464{ 465 char *wname; 466 int i; 467 468 if (!unmanaged_window_list) 469 return 0; 470 471 wname = get_wmname(w); 472 if (!wname) 473 return 0; 474 475 for (i = 0; i < num_unmanaged_windows; i++) { 476 if (!strcmp(unmanaged_window_list[i], wname)) { 477 free(wname); 478 return 1; 479 } 480 } 481 482 free(wname); 483 484 if (is_unmanaged_window_type(w)) 485 return 1; 486 487 return 0; 488} 489 490/* Set the state of the window. */ 491void 492set_state(rp_window *win, int state) 493{ 494 unsigned long data[2]; 495 496 win->state = state; 497 498 data[0] = (long) win->state; 499 data[1] = (long) None; 500 501 set_atom(win->w, wm_state, wm_state, data, 2); 502} 503 504/* Get the WM state of the window. */ 505long 506get_state(rp_window *win) 507{ 508 long state = WithdrawnState; 509 Atom type; 510 int format; 511 unsigned long nitems; 512 unsigned long bytes_left; 513 unsigned char *data; 514 515 if (win == NULL) 516 return state; 517 518 if (XGetWindowProperty(dpy, win->w, wm_state, 0L, 2L, False, wm_state, 519 &type, &format, &nitems, &bytes_left, &data) == Success && 520 nitems > 0) { 521 state = *(long *)data; 522 XFree(data); 523 } 524 return state; 525} 526 527void 528check_state(rp_window *win) 529{ 530 Atom state; 531 unsigned long read, left; 532 int i, fs = 0; 533 534 for (i = 0, left = 1; left; i += read) { 535 read = get_atom(win->w, _net_wm_state, XA_ATOM, i, &state, 1, 536 &left); 537 if (!read) 538 break; 539 540 if (state == _net_wm_state_fullscreen) { 541 fs = 1; 542 window_full_screen(win); 543 } else { 544 PRINT_DEBUG(("unhandled window state %ld (%s)\n", 545 state, XGetAtomName(dpy, state))); 546 } 547 } 548 549 if (win->full_screen && !fs) 550 window_full_screen(NULL); 551} 552 553static void 554move_window(rp_window *win) 555{ 556 rp_frame *frame; 557 int t, t2, gap; 558 559 if (win->frame_number == EMPTY) { 560 PRINT_DEBUG(("%s: window has no frame\n", __func__)); 561 return; 562 } 563 564 frame = win_get_frame(win); 565 566 if (win->full_screen) { 567 win->x = win->vscreen->screen->left; 568 win->y = win->vscreen->screen->top; 569 return; 570 } 571 572 if (defaults.only_border == 0 && num_frames(win->vscreen) <= 1) 573 gap = 0; 574 else 575 gap = defaults.gap; 576 577 /* X coord. */ 578 switch (win->gravity) { 579 case NorthWestGravity: 580 case WestGravity: 581 case SouthWestGravity: 582 win->x = frame->x + 583 (frame_left_screen_edge(frame) ? 0 : gap); 584 break; 585 case NorthGravity: 586 case CenterGravity: 587 case SouthGravity: 588 t = (frame_left_screen_edge(frame) ? 0 : gap); 589 t2 = (frame_right_screen_edge(frame) ? 0 : gap); 590 win->x = frame->x + t + 591 ((frame->width - t - t2 - 592 (win->width + win->border * 2)) / 2); 593 break; 594 case NorthEastGravity: 595 case EastGravity: 596 case SouthEastGravity: 597 win->x = frame->x + frame->width - 598 (win->width + win->border * 2) - 599 (frame_right_screen_edge(frame) ? 0 : gap); 600 break; 601 } 602 603 /* Y coord. */ 604 switch (win->gravity) { 605 case NorthEastGravity: 606 case NorthGravity: 607 case NorthWestGravity: 608 win->y = frame->y + 609 (frame_top_screen_edge(frame) ? 0 : gap); 610 break; 611 case EastGravity: 612 case CenterGravity: 613 case WestGravity: 614 t = (frame_top_screen_edge(frame) ? 0 : gap); 615 t2 = (frame_bottom_screen_edge(frame) ? 0 : gap); 616 win->y = frame->y + t + 617 ((frame->height - t - t2 - 618 (win->height + win->border * 2)) / 2); 619 break; 620 case SouthEastGravity: 621 case SouthGravity: 622 case SouthWestGravity: 623 win->y = frame->y + frame->height - 624 (win->height + win->border * 2) - 625 (frame_bottom_screen_edge(frame) ? 0 : gap); 626 break; 627 } 628 629 if (win->x < frame->x) 630 win->x = frame->x; 631 if (win->y < frame->y) 632 win->y = frame->y; 633} 634 635/* 636 * set a good standard window's x,y,width,height fields to maximize the window. 637 */ 638static void 639maximize_window(rp_window *win, int transient) 640{ 641 rp_frame *frame; 642 int maxw, maxh; 643 float gap; 644 645 frame = win_get_frame(win); 646 647 /* We can't maximize a window if it has no frame. */ 648 if (frame == NULL) { 649 PRINT_DEBUG(("%s: no frame\n", __func__)); 650 return; 651 } 652 653 /* Set the window's border */ 654 if ((defaults.only_border == 0 && num_frames(win->vscreen) <= 1) || 655 win->full_screen) 656 win->border = 0; 657 else 658 win->border = defaults.window_border_width; 659 660 if (win->full_screen) { 661 maxw = win->vscreen->screen->width; 662 maxh = win->vscreen->screen->height; 663 } else { 664 if (transient) { 665 maxw = win->width; 666 maxh = win->height; 667 } else { 668 maxw = frame->width; 669 maxh = frame->height; 670 } 671 672 if (win->hints->flags & PMaxSize) { 673 if (maxw > win->hints->max_width) 674 maxw = win->hints->max_width; 675 676 if (maxh > win->hints->max_height) 677 maxh = win->hints->max_height; 678 } 679 680 if (maxw > frame->width) 681 maxw = frame->width; 682 if (maxh > frame->height) 683 maxh = frame->height; 684 685 PRINT_DEBUG(("adjusted to frame, maxsize %d %d\n", maxw, maxh)); 686 687 if (!transient && !(defaults.only_border == 0 && 688 num_frames(win->vscreen) <= 1)) { 689 int fw, fh; 690 691 gap = (frame_right_screen_edge(frame) ? 0 : 1); 692 gap += (frame_left_screen_edge(frame) ? 0 : 1); 693 fw = frame->width - (gap * defaults.gap) - 694 (win->border * 2); 695 if (maxw > fw) 696 maxw = fw; 697 698 gap = (frame_top_screen_edge(frame) ? 0 : 1); 699 gap += (frame_bottom_screen_edge(frame) ? 0 : 1); 700 fh = frame->height - (gap * defaults.gap) - 701 (win->border * 2); 702 if (maxh > fh) 703 maxh = fh; 704 } 705 } 706 707 /* Honour the window's aspect ratio. */ 708 PRINT_DEBUG(("aspect: %ld\n", win->hints->flags & PAspect)); 709 if (!win->full_screen && (win->hints->flags & PAspect)) { 710 float ratio = (float) maxw / maxh; 711 float min_ratio = (float) win->hints->min_aspect.x / 712 win->hints->min_aspect.y; 713 float max_ratio = (float) win->hints->max_aspect.x / 714 win->hints->max_aspect.y; 715 PRINT_DEBUG(("ratio=%f min_ratio=%f max_ratio=%f\n", 716 ratio, min_ratio, max_ratio)); 717 if (ratio < min_ratio) { 718 maxh = (int) (maxw / min_ratio); 719 } else if (ratio > max_ratio) { 720 maxw = (int) (maxh * max_ratio); 721 } 722 723 PRINT_DEBUG(("honored ratio, maxsize %d %d\n", maxw, maxh)); 724 } 725 /* 726 * Make sure we maximize to the nearest Resize Increment specified by 727 * the window 728 */ 729 if (!defaults.ignore_resize_hints && !win->full_screen && 730 (win->hints->flags & PResizeInc)) { 731 int amount; 732 int delta; 733 734 if (win->hints->width_inc) { 735 amount = maxw - win->width; 736 delta = amount % win->hints->width_inc; 737 if (amount < 0 && delta) 738 amount -= win->hints->width_inc; 739 amount -= delta; 740 maxw = amount + win->width; 741 } 742 if (win->hints->height_inc) { 743 amount = maxh - win->height; 744 delta = amount % win->hints->height_inc; 745 if (amount < 0 && delta) 746 amount -= win->hints->height_inc; 747 amount -= delta; 748 maxh = amount + win->height; 749 } 750 751 PRINT_DEBUG(("applied width_inc/height_inc, maxsize %d %d\n", 752 maxw, maxh)); 753 } 754 PRINT_DEBUG(("final maxsize: %d %d\n", maxw, maxh)); 755 756 win->width = maxw; 757 win->height = maxh; 758} 759 760/* 761 * Maximize the current window if data = 0, otherwise assume it is a pointer to 762 * a window that should be maximized 763 */ 764void 765maximize(rp_window *win) 766{ 767 if (!win) 768 win = current_window(); 769 if (!win) 770 return; 771 772 /* Handle maximizing transient windows differently. */ 773 maximize_window(win, win->transient); 774 775 /* Reposition the window. */ 776 move_window(win); 777 778 PRINT_DEBUG(("Resizing %s window '%s' to x:%d y:%d w:%d h:%d\n", 779 win->transient ? "transient" : "normal", 780 window_name(win), win->x, win->y, win->width, win->height)); 781 782 /* Actually do the maximizing. */ 783 XMoveResizeWindow(dpy, win->w, win->x, win->y, win->width, win->height); 784 XSetWindowBorderWidth(dpy, win->w, win->border); 785 786 XSync(dpy, False); 787} 788 789/* 790 * Maximize the current window but don't treat transient windows differently. 791 */ 792void 793force_maximize(rp_window *win) 794{ 795 if (!win) 796 win = current_window(); 797 if (!win) 798 return; 799 800 maximize_window(win, 0); 801 802 /* Reposition the window. */ 803 move_window(win); 804 805 /* 806 * This little dance is to force a maximize event. If the window is 807 * already "maximized" X11 will optimize away the event since to 808 * geometry changes were made. This initial resize solves the problem. 809 */ 810 if (!defaults.ignore_resize_hints && (win->hints->flags & PResizeInc)) { 811 XMoveResizeWindow(dpy, win->w, 812 win->vscreen->screen->left + win->x, 813 win->vscreen->screen->top + win->y, 814 win->width + win->hints->width_inc, 815 win->height + win->hints->height_inc); 816 } else { 817 XResizeWindow(dpy, win->w, win->width + 1, win->height + 1); 818 } 819 820 XSync(dpy, False); 821 822 /* Resize the window to its proper maximum size. */ 823 XMoveResizeWindow(dpy, win->w, win->vscreen->screen->left + win->x, 824 win->vscreen->screen->top + win->y, win->width, win->height); 825 XSetWindowBorderWidth(dpy, win->w, win->border); 826 827 XSync(dpy, False); 828} 829 830/* map the unmapped window win */ 831void 832map_window(rp_window *win) 833{ 834 rp_window *transfor; 835 836 PRINT_DEBUG(("Mapping the unmapped window %s\n", window_name(win))); 837 838 /* Fill in the necessary data about the window */ 839 update_window_information(win); 840 841 if (win->transient_for && 842 (transfor = find_window(win->transient_for))) { 843 PRINT_DEBUG(("map_window: transient_for %lu\n", 844 win->transient_for)); 845 win->vscreen = transfor->vscreen; 846 win->intended_frame_number = transfor->frame_number; 847 } 848 849 win->number = numset_request(rp_window_numset); 850 grab_top_level_keys(win->w); 851 852 /* Put win in the mapped window list */ 853 list_del(&win->node); 854 insert_into_list(win, &rp_mapped_window); 855 856 vscreen_map_window(win->vscreen, win); 857 858 /* 859 * The window has never been accessed since it was brought back from the 860 * Withdrawn state. 861 */ 862 win->last_access = 0; 863 864 /* It is now considered iconic and set_active_window can handle the 865 * rest. */ 866 set_state(win, IconicState); 867 868 /* Depending on the rudeness level, actually map the window. */ 869 if ((rp_honour_transient_map && win->transient) 870 || (rp_honour_normal_map && !win->transient)) 871 set_active_window(win); 872 else 873 show_rudeness_msg(win, 0); 874 875 append_atom(rp_glob_screen.root, _net_client_list, XA_WINDOW, &win->w, 876 1); 877 append_atom(rp_glob_screen.root, _net_client_list_stacking, XA_WINDOW, 878 &win->w, 1); 879 880 hook_run(&rp_new_window_hook); 881} 882 883void 884hide_window(rp_window *win) 885{ 886 if (win == NULL) 887 return; 888 889 /* An unmapped window is not inside a frame. */ 890 win->frame_number = EMPTY; 891 892 /* Ignore the unmap_notify event. */ 893 XSelectInput(dpy, win->w, WIN_EVENTS & ~(StructureNotifyMask)); 894 XUnmapWindow(dpy, win->w); 895 XSelectInput(dpy, win->w, WIN_EVENTS); 896 /* 897 * Ensure that the window doesn't have the focused border color. This 898 * is needed by remove_frame and possibly others. 899 */ 900 XSetWindowBorder(dpy, win->w, rp_glob_screen.bwcolor); 901 set_state(win, IconicState); 902} 903 904void 905unhide_window(rp_window * win) 906{ 907 if (win == NULL) 908 return; 909 910 /* Always raise the window. */ 911 XRaiseWindow(dpy, win->w); 912 913 if (win->state != IconicState) 914 return; 915 916 XMapWindow(dpy, win->w); 917 set_state(win, NormalState); 918} 919 920void 921unhide_all_windows(void) 922{ 923 struct list_head *tmp, *iter; 924 rp_window *win; 925 926 list_for_each_safe_entry(win, iter, tmp, &rp_mapped_window, node) 927 unhide_window(win); 928} 929 930void 931withdraw_window(rp_window *win) 932{ 933 if (win == NULL) 934 return; 935 936 PRINT_DEBUG(("withdraw_window on '%s'\n", window_name(win))); 937 938 if (win->full_screen) 939 window_full_screen(NULL); 940 941 /* 942 * Give back the window number. the window will get another one, if it is 943 * remapped. 944 */ 945 if (win->number == -1) 946 warnx("attempting to withdraw '%s' with number -1!", 947 window_name(win)); 948 949 numset_release(rp_window_numset, win->number); 950 win->number = -1; 951 952 list_move_tail(&win->node, &rp_unmapped_window); 953 954 /* Update the vscreens. */ 955 vscreen_unmap_window(win->vscreen, win); 956 957 ignore_badwindow++; 958 959 XRemoveFromSaveSet(dpy, win->w); 960 set_state(win, WithdrawnState); 961 XSync(dpy, False); 962 963 ignore_badwindow--; 964 965 /* Call our hook */ 966 hook_run(&rp_delete_window_hook); 967} 968 969/* Hide all other mapped windows except for win in win's frame. */ 970void 971hide_others(rp_window *win) 972{ 973 rp_frame *frame; 974 rp_window *cur; 975 976 if (win == NULL) 977 return; 978 frame = find_windows_frame(win); 979 if (frame == NULL) 980 return; 981 982 list_for_each_entry(cur, &rp_mapped_window, node) { 983 if (find_windows_frame(cur) 984 || cur->state != NormalState 985 || cur->frame_number != frame->number) 986 continue; 987 988 hide_window(cur); 989 } 990} 991 992/* Hide any window displayed on the given screen */ 993void 994hide_vscreen_windows(rp_vscreen *v) 995{ 996 rp_window *cur; 997 998 list_for_each_entry(cur, &rp_mapped_window, node) 999 if (cur->vscreen == v) 1000 hide_window(cur); 1001} 1002 1003void 1004raise_utility_windows(void) 1005{ 1006 unsigned int i, nwins; 1007 Window dw1, dw2, *wins; 1008 1009 XQueryTree(dpy, rp_glob_screen.root, &dw1, &dw2, &wins, &nwins); 1010 1011 for (i = 0; i < nwins; i++) { 1012 if (!is_rp_window(wins[i]) && 1013 is_unmanaged_window_type(wins[i])) 1014 XRaiseWindow(dpy, wins[i]); 1015 } 1016 1017 XFree(wins); 1018}