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