jcs ratpoison hax
at oldjcs 1093 lines 26 kB view raw
1/* Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca> 2 * 3 * This file is part of ratpoison. 4 * 5 * ratpoison is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2, or (at your option) 8 * any later version. 9 * 10 * ratpoison is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this software; see the file COPYING. If not, write to 17 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 18 * Boston, MA 02111-1307 USA 19 * 20 * 21 * Functions for handling window splitting and tiling. 22 */ 23 24#include <unistd.h> 25#include <string.h> 26 27#include "ratpoison.h" 28 29#define VERTICALLY 0 30#define HORIZONTALLY 1 31 32static void 33update_last_access (rp_frame *frame) 34{ 35 static int counter = 0; 36 37 frame->last_access = counter; 38 counter++; 39} 40 41rp_frame * 42current_frame (void) 43{ 44 rp_screen *s = current_screen(); 45 return screen_get_frame (s, s->current_frame); 46} 47 48int 49num_frames (rp_screen *s) 50{ 51 int count = 0; 52 rp_frame *cur; 53 54 list_for_each_entry (cur, &s->frames, node) 55 { 56 count++; 57 } 58 59 return count; 60} 61 62void 63cleanup_frame (rp_frame *frame) 64{ 65 rp_window *win; 66 rp_screen *screen; 67 screen = frames_screen(frame); 68 69 win = find_window_other (screen); 70 if (win == NULL) 71 { 72 set_frames_window (frame, NULL); 73 return; 74 } 75 76 set_frames_window (frame, win); 77 78 maximize (win); 79 unhide_window (win); 80 81 82 if (!window_is_transient (win)) 83 hide_others (win); 84} 85 86rp_window * 87set_frames_window (rp_frame *frame, rp_window *win) 88{ 89 int last_win; 90 91 last_win = frame->win_number; 92 if (win) 93 { 94 frame->win_number = win->number; 95 win->frame_number = frame->number; 96 97 /* We need to make sure that win and frame are on the same screen, 98 * since with Xinerama, windows can move from one screen to another. 99 */ 100 win->scr = frames_screen(frame); 101 } 102 else 103 { 104 frame->win_number = EMPTY; 105 } 106 107 return find_window_number (last_win); 108} 109 110rp_screen * 111frames_screen (rp_frame *frame) 112{ 113 int i; 114 rp_frame *cur; 115 116 for (i=0; i<num_screens; i++) 117 list_for_each_entry (cur, &screens[i].frames, node) 118 { 119 if (frame == cur) 120 return &screens[i]; 121 } 122 123 /* This SHOULD be impossible to get to. FIXME: It'll crash higher up if we 124 return NULL. */ 125 return NULL; 126} 127 128void 129maximize_all_windows_in_frame (rp_frame *frame) 130{ 131 rp_window *win; 132 133 list_for_each_entry (win, &rp_mapped_window, node) 134 { 135 if (win->frame_number == frame->number) 136 { 137 maximize (win); 138 } 139 } 140} 141 142/* Make the frame occupy the entire screen */ 143static void 144maximize_frame (rp_frame *frame) 145{ 146 rp_screen *s = frames_screen (frame); 147 148 frame->x = defaults.padding_left; 149 frame->y = defaults.padding_top; 150 151 frame->width = screen_width (s); 152 frame->height = screen_height (s); 153} 154 155/* Create a full screen frame */ 156static void 157create_initial_frame (rp_screen *screen) 158{ 159 rp_frame *frame; 160 161 frame = frame_new (screen); 162 screen->current_frame = frame->number; 163 list_add_tail (&frame->node, &screen->frames); 164 165 update_last_access (frame); 166 167 maximize_frame (frame); 168 set_frames_window (frame, NULL); 169} 170 171void 172init_frame_lists (void) 173{ 174 int i; 175 176 for (i=0; i<num_screens; i++) 177 init_frame_list (&screens[i]); 178} 179 180void 181init_frame_list (rp_screen *screen) 182{ 183 INIT_LIST_HEAD (&screen->frames); 184 185 create_initial_frame(screen); 186} 187 188rp_frame * 189find_last_frame (void) 190{ 191 rp_frame *cur, *last = NULL; 192 int last_access = -1; 193 int i; 194 195 for (i=0; i<num_screens; i++) 196 { 197 rp_screen *s = &screens[i]; 198 199 list_for_each_entry (cur, &s->frames, node) 200 { 201 if (cur->number != current_screen()->current_frame 202 && cur->last_access > last_access) 203 { 204 last_access = cur->last_access; 205 last = cur; 206 } 207 } 208 } 209 210 return last; 211} 212 213/* Return the frame that contains the window. */ 214rp_frame * 215find_windows_frame (rp_window *win) 216{ 217 rp_screen *s; 218 rp_frame *cur; 219 220 s = win->scr; 221 222 list_for_each_entry (cur, &s->frames, node) 223 { 224 if (cur->win_number == win->number) return cur; 225 } 226 227 return NULL; 228} 229 230rp_frame * 231find_frame_next (rp_frame *frame) 232{ 233 if (frame == NULL) return NULL; 234 return list_next_entry (frame, &frames_screen (frame)->frames, node); 235} 236 237rp_frame * 238find_frame_prev (rp_frame *frame) 239{ 240 if (frame == NULL) return NULL; 241 return list_prev_entry (frame, &frames_screen (frame)->frames, node); 242} 243 244rp_window * 245current_window (void) 246{ 247 if (current_frame()) 248 return find_window_number (current_frame()->win_number); 249 else 250 return NULL; 251} 252 253static int 254window_fits_in_frame (rp_window *win, rp_frame *frame) 255{ 256 /* If the window has minimum size hints, make sure they are smaller 257 than the frame. */ 258 if (win->hints->flags & PMinSize) 259 { 260 if (win->hints->min_width > frame->width 261 || 262 win->hints->min_height > frame->height) 263 { 264 return 0; 265 } 266 } 267 268 return 1; 269} 270 271/* Search the list of mapped windows for a window that will fit in the 272 specified frame. */ 273rp_window * 274find_window_for_frame (rp_frame *frame) 275{ 276 rp_screen *s = frames_screen (frame); 277 int last_access = 0; 278 rp_window_elem *most_recent = NULL; 279 rp_window_elem *cur; 280 281 list_for_each_entry (cur, &rp_current_group->mapped_windows, node) 282 { 283 if ((cur->win->scr == s || rp_have_xinerama) 284 && cur->win != current_window() 285 && !find_windows_frame (cur->win) 286 && cur->win->last_access >= last_access 287 && window_fits_in_frame (cur->win, frame) 288 && cur->win->frame_number == EMPTY) 289 { 290 most_recent = cur; 291 last_access = cur->win->last_access; 292 } 293 } 294 295 if (most_recent) 296 return most_recent->win; 297 298 return NULL; 299} 300 301/* Splits the frame in 2. if way is 0 then split vertically otherwise 302 split it horizontally. */ 303static void 304split_frame (rp_frame *frame, int way, int pixels) 305{ 306 rp_screen *s; 307 rp_window *win; 308 rp_frame *new_frame; 309 310 s = frames_screen (frame); 311 312 /* Make our new frame. */ 313 new_frame = frame_new (s); 314 315 /* Add the frame to the frameset. */ 316 list_add (&new_frame->node, &current_frame()->node); 317 318 set_frames_window (new_frame, NULL); 319 320 if (way == HORIZONTALLY) 321 { 322 new_frame->x = frame->x; 323 new_frame->y = frame->y + pixels; 324 new_frame->width = frame->width; 325 new_frame->height = frame->height - pixels; 326 327 frame->height = pixels; 328 } 329 else 330 { 331 new_frame->x = frame->x + pixels; 332 new_frame->y = frame->y; 333 new_frame->width = frame->width - pixels; 334 new_frame->height = frame->height; 335 336 frame->width = pixels; 337 } 338 339 win = find_window_for_frame (new_frame); 340 if (win) 341 { 342 PRINT_DEBUG (("Found a window for the frame!\n")); 343 344 set_frames_window (new_frame, win); 345 346 maximize (win); 347 unhide_window (win); 348 XRaiseWindow (dpy, win->w); 349 } 350 else 351 { 352 PRINT_DEBUG (("No window fits the frame.\n")); 353 354 set_frames_window (new_frame, NULL); 355 } 356 357 /* resize the existing frame */ 358 if (frame->win_number != EMPTY) 359 { 360 maximize_all_windows_in_frame (frame); 361 XRaiseWindow (dpy, find_window_number (frame->win_number)->w); 362 } 363 364 update_bar (s); 365 show_frame_indicator(0); 366} 367 368/* Splits the window vertically leaving the original with 'pixels' 369 pixels . */ 370void 371v_split_frame (rp_frame *frame, int pixels) 372{ 373 split_frame (frame, VERTICALLY, pixels); 374} 375 376/* Splits the frame horizontally leaving the original with 'pixels' 377 pixels . */ 378void 379h_split_frame (rp_frame *frame, int pixels) 380{ 381 split_frame (frame, HORIZONTALLY, pixels); 382} 383 384void 385remove_all_splits (void) 386{ 387 struct list_head *tmp, *iter; 388 rp_screen *s = current_screen(); 389 rp_frame *frame; 390 rp_window *win; 391 392 /* Hide all the windows not in the current frame. */ 393 list_for_each_entry (win, &rp_mapped_window, node) 394 { 395 if (win->frame_number != s->current_frame && win->scr == s) 396 hide_window (win); 397 } 398 399 /* Delete all the frames except the current one. */ 400 list_for_each_safe_entry (frame, iter, tmp, &s->frames, node) 401 { 402 if (frame->number != s->current_frame) 403 { 404 list_del (&frame->node); 405 frame_free (s, frame); 406 } 407 } 408 409 /* Maximize the frame and the windows in the frame. */ 410 maximize_frame (current_frame()); 411 maximize_all_windows_in_frame (current_frame()); 412} 413 414/* Shrink the size of the frame to fit it's current window. */ 415void 416resize_shrink_to_window (rp_frame *frame) 417{ 418 rp_window *win; 419 420 if (frame->win_number == EMPTY) return; 421 422 win = find_window_number (frame->win_number); 423 424 resize_frame_horizontally (frame, win->width + win->border*2 + defaults.gap*2 - frame->width); 425 resize_frame_vertically (frame, win->height + win->border*2 + defaults.gap*2 - frame->height); 426} 427 428/* resize_frame is a generic frame resizer that can resize vertically, 429 horizontally, to the right, to the left, etc. It all depends on the 430 functions passed to it. Returns -1 if the resize failed, 0 for 431 success. */ 432static int 433resize_frame (rp_frame *frame, rp_frame *pusher, int diff, 434 int (*c1)(rp_frame *), int (c2)(rp_frame *), 435 int (*c3)(rp_frame *), int (c4)(rp_frame *), 436 void (*resize1)(rp_frame *, int), 437 void (*resize2)(rp_frame *, int), 438 int (*resize3)(rp_frame *, rp_frame *, int)) 439{ 440 rp_screen *s = frames_screen (frame); 441 rp_frame *cur; 442 443 /* Loop through the frames and determine which ones are affected by 444 resizing frame. */ 445 list_for_each_entry (cur, &s->frames, node) 446 { 447 if (cur == frame || cur == pusher) continue; 448 /* If cur is touching frame along the axis that is being 449 moved then this frame is affected by the resize. */ 450 if ((*c1)(cur) == (*c3)(frame)) 451 { 452 /* If the frame can't get any smaller, then fail. */ 453 if (diff > 0 454 && abs ((*c3)(cur) - (*c1)(cur)) - diff <= defaults.gap * 2 + defaults.window_border_width * 2) 455 return -1; 456 /* Test for this circumstance: 457 --+ 458 | |+-+ 459 |f||c| 460 | |+-+ 461 --+ 462 463 In this case, resizing cur will not affect any other 464 frames, so just do the resize. 465 */ 466 if (((*c2)(cur) >= (*c2)(frame)) 467 && (*c4)(cur) <= (*c4)(frame)) 468 { 469 (*resize2)(cur, -diff); 470 maximize_all_windows_in_frame (cur); 471 } 472 /* Otherwise, cur's corners are either strictly outside 473 frame's corners, or one of them is inside and the other 474 isn't. In either of these cases, resizing cur will affect 475 other adjacent frames, so find them and resize them first 476 (recursive step) and then resize cur. */ 477 else if (((*c2)(cur) < (*c2)(frame) 478 && (*c4)(cur) > (*c4)(frame)) 479 || ((*c2)(cur) >= (*c2)(frame) 480 && (*c2)(cur) < (*c4)(frame)) 481 || ((*c4)(cur) > (*c2)(frame) 482 && (*c4)(cur) <= (*c4)(frame))) 483 { 484 /* Attempt to resize cur. */ 485 if (resize3 (cur, frame, -diff) == -1) 486 return -1; 487 } 488 } 489 } 490 491 /* Finally, resize the frame and the windows inside. */ 492 (*resize1) (frame, diff); 493 maximize_all_windows_in_frame (frame); 494 495 return 0; 496} 497 498static int resize_frame_bottom (rp_frame *frame, rp_frame *pusher, int diff); 499static int resize_frame_top (rp_frame *frame, rp_frame *pusher, int diff); 500static int resize_frame_left (rp_frame *frame, rp_frame *pusher, int diff); 501static int resize_frame_right (rp_frame *frame, rp_frame *pusher, int diff); 502 503/* Resize frame by moving it's right side. */ 504static int 505resize_frame_right (rp_frame *frame, rp_frame *pusher, int diff) 506{ 507 return resize_frame (frame, pusher, diff, 508 frame_left, frame_top, frame_right, frame_bottom, 509 frame_resize_right, frame_resize_left, resize_frame_left); 510} 511 512/* Resize frame by moving it's left side. */ 513static int 514resize_frame_left (rp_frame *frame, rp_frame *pusher, int diff) 515{ 516 return resize_frame (frame, pusher, diff, 517 frame_right, frame_top, frame_left, frame_bottom, 518 frame_resize_left, frame_resize_right, resize_frame_right); 519} 520 521/* Resize frame by moving it's top side. */ 522static int 523resize_frame_top (rp_frame *frame, rp_frame *pusher, int diff) 524{ 525 return resize_frame (frame, pusher, diff, 526 frame_bottom, frame_left, frame_top, frame_right, 527 frame_resize_up, frame_resize_down, resize_frame_bottom); 528} 529 530/* Resize frame by moving it's bottom side. */ 531static int 532resize_frame_bottom (rp_frame *frame, rp_frame *pusher, int diff) 533{ 534 return resize_frame (frame, pusher, diff, 535 frame_top, frame_left, frame_bottom, frame_right, 536 frame_resize_down, frame_resize_up, resize_frame_top); 537} 538 539/* Resize frame diff pixels by expanding it to the right. If the frame 540 is against the right side of the screen, expand it to the left. */ 541void 542resize_frame_horizontally (rp_frame *frame, int diff) 543{ 544 int (*resize_fn)(rp_frame *, rp_frame*, int); 545 struct list_head *l; 546 rp_screen *s = frames_screen (frame); 547 548 if (num_frames (s) < 2 || diff == 0) 549 return; 550 551 if (frame_width (frame) + diff <= defaults.gap * 2 + defaults.window_border_width * 2) 552 return; 553 554 /* Find out which resize function to use. */ 555 if (frame_right (frame) < screen_right (s)) 556 { 557 resize_fn = resize_frame_right; 558 } 559 else if (frame_left (frame) > screen_left (s)) 560 { 561 resize_fn = resize_frame_left; 562 } 563 else 564 { 565 return; 566 } 567 568 /* Copy the frameset. If the resize fails, then we restore the 569 original one. */ 570 l = screen_copy_frameset (s); 571 572 if ((*resize_fn) (frame, NULL, diff) == -1) 573 { 574 screen_restore_frameset (s, l); 575 } 576 else 577 { 578 frameset_free (l); 579 } 580 581 /* It's our responsibility to free this. */ 582 free (l); 583} 584 585/* Resize frame diff pixels by expanding it down. If the frame is 586 against the bottom of the screen, expand it up. */ 587void 588resize_frame_vertically (rp_frame *frame, int diff) 589{ 590 int (*resize_fn)(rp_frame *, rp_frame*, int); 591 struct list_head *l; 592 rp_screen *s = frames_screen (frame); 593 594 if (num_frames (s) < 2 || diff == 0) 595 return; 596 597 if (frame_height (frame) + diff <= defaults.gap * 2 + defaults.window_border_width * 2) 598 return; 599 600 /* Find out which resize function to use. */ 601 if (frame_bottom (frame) < screen_bottom (s)) 602 { 603 resize_fn = resize_frame_bottom; 604 } 605 else if (frame_top (frame) > screen_top (s)) 606 { 607 resize_fn = resize_frame_top; 608 } 609 else 610 { 611 return; 612 } 613 614 /* Copy the frameset. If the resize fails, then we restore the 615 original one. */ 616 l = screen_copy_frameset (s); 617 618 if ((*resize_fn) (frame, NULL, diff) == -1) 619 { 620 screen_restore_frameset (s, l); 621 } 622 else 623 { 624 frameset_free (l); 625 } 626 627 /* It's our responsibility to free this. */ 628 free (l); 629} 630 631static int 632frame_is_below (rp_frame *src, rp_frame *frame) 633{ 634 if (frame->y > src->y) return 1; 635 return 0; 636} 637 638static int 639frame_is_above (rp_frame *src, rp_frame *frame) 640{ 641 if (frame->y < src->y) return 1; 642 return 0; 643} 644 645static int 646frame_is_left (rp_frame *src, rp_frame *frame) 647{ 648 if (frame->x < src->x) return 1; 649 return 0; 650} 651 652static int 653frame_is_right (rp_frame *src, rp_frame *frame) 654{ 655 if (frame->x > src->x) return 1; 656 return 0; 657} 658 659static int 660total_frame_area (rp_screen *s) 661{ 662 int area = 0; 663 rp_frame *cur; 664 665 list_for_each_entry (cur, &s->frames, node) 666 { 667 area += cur->width * cur->height; 668 } 669 670 return area; 671} 672 673/* Return 1 if frames f1 and f2 overlap */ 674static int 675frames_overlap (rp_frame *f1, rp_frame *f2) 676{ 677 if (f1->x >= f2->x + f2->width 678 || f1->y >= f2->y + f2->height 679 || f2->x >= f1->x + f1->width 680 || f2->y >= f1->y + f1->height) 681 { 682 return 0; 683 } 684 return 1; 685} 686 687/* Return 1 if w's frame overlaps any other window's frame */ 688static int 689frame_overlaps (rp_frame *frame) 690{ 691 rp_screen *s; 692 rp_frame *cur; 693 694 s = frames_screen (frame); 695 696 list_for_each_entry (cur, &s->frames, node) 697 { 698 if (cur != frame && frames_overlap (cur, frame)) 699 { 700 return 1; 701 } 702 } 703 return 0; 704} 705 706void 707remove_frame (rp_frame *frame) 708{ 709 rp_screen *s; 710 int area; 711 rp_frame *cur; 712 rp_window *win; 713 714 if (frame == NULL) return; 715 716 s = frames_screen (frame); 717 718 area = total_frame_area(s); 719 PRINT_DEBUG (("Total Area: %d\n", area)); 720 721 list_del (&frame->node); 722 win = find_window_number (frame->win_number); 723 hide_window (win); 724 hide_others (win); 725 726 list_for_each_entry (cur, &s->frames, node) 727 { 728 rp_frame tmp_frame; 729 int fits = 0; 730 731/* if (cur->win_number != EMPTY) */ 732/* { */ 733/* PRINT_DEBUG (("Trying frame containing window '%s'\n", window_name (cur->win))); */ 734/* } */ 735/* else */ 736/* { */ 737/* PRINT_DEBUG (("Trying some empty frame\n")); */ 738/* } */ 739 740 /* Backup the frame */ 741 memcpy (&tmp_frame, cur, sizeof (rp_frame)); 742 743 if (frame_is_below (frame, cur) 744 || frame_is_above (frame, cur)) 745 { 746 if (frame_is_below (frame, cur)) 747 cur->y = frame->y; 748 cur->height += frame->height; 749 } 750 751 PRINT_DEBUG (("Attempting vertical Frame y=%d height=%d\n", cur->y, cur->height)); 752 PRINT_DEBUG (("New Total Area: %d\n", total_frame_area(s))); 753 754 /* If the area is bigger than before, the frame takes up too 755 much space. If the current frame and the deleted frame DON'T 756 overlap then the current window took up just the right amount 757 of space but didn't take up the space left behind by the 758 deleted window. If any active frames overlap, it could have 759 taken up the right amount of space, overlaps with the deleted 760 frame but obviously didn't fit. */ 761 if (total_frame_area(s) > area || !frames_overlap (cur, frame) || frame_overlaps (cur)) 762 { 763 PRINT_DEBUG (("Didn't fit vertically\n")); 764 765 /* Restore the current window's frame */ 766 memcpy (cur, &tmp_frame, sizeof (rp_frame)); 767 } 768 else 769 { 770 PRINT_DEBUG (("It fit vertically!!\n")); 771 772 /* update the frame backup */ 773 memcpy (&tmp_frame, cur, sizeof (rp_frame)); 774 fits = 1; 775 } 776 777 if (frame_is_left (frame, cur) 778 || frame_is_right (frame, cur)) 779 { 780 if (frame_is_right (frame, cur)) 781 cur->x = frame->x; 782 cur->width += frame->width; 783 } 784 785 PRINT_DEBUG (("Attempting horizontal Frame x=%d width=%d\n", cur->x, cur->width)); 786 PRINT_DEBUG (("New Total Area: %d\n", total_frame_area(s))); 787 788 /* Same test as the vertical test, above. */ 789 if (total_frame_area(s) > area || !frames_overlap (cur, frame) || frame_overlaps (cur)) 790 { 791 PRINT_DEBUG (("Didn't fit horizontally\n")); 792 793 /* Restore the current window's frame */ 794 memcpy (cur, &tmp_frame, sizeof (rp_frame)); 795 } 796 else 797 { 798 PRINT_DEBUG (("It fit horizontally!!\n")); 799 fits = 1; 800 } 801 802 if (fits) 803 { 804 /* The current frame fits into the new space so keep its 805 new frame parameters and maximize the window to fit 806 the new frame size. */ 807 if (cur->win_number != EMPTY) 808 { 809 rp_window *new = find_window_number (cur->win_number); 810 maximize_all_windows_in_frame (cur); 811 XRaiseWindow (dpy, new->w); 812 } 813 } 814 else 815 { 816 memcpy (cur, &tmp_frame, sizeof (rp_frame)); 817 } 818 } 819 820 frame_free (s, frame); 821} 822 823/* Switch the input focus to another frame, and therefore a different 824 window. */ 825void 826set_active_frame (rp_frame *frame, int force_indicator) 827{ 828 rp_screen *old_s = current_screen(); 829 rp_screen *s = frames_screen (frame); 830 int old = current_screen()->current_frame; 831 rp_window *win, *old_win; 832 rp_frame *old_frame; 833 834 win = find_window_number (frame->win_number); 835 old_frame = current_frame(); 836 if (old_frame) 837 { 838 old_win = find_window_number (old_frame->win_number); 839 } 840 else 841 { 842 old_win = NULL; 843 } 844 845 /* Make the switch */ 846 give_window_focus (win, old_win); 847 update_last_access (frame); 848 s->current_frame = frame->number; 849 850 /* If frame->win == NULL, then rp_current_screen is not updated. */ 851 rp_current_screen = s->xine_screen_num; 852 853 update_bar (s); 854 855 /* Possibly show the frame indicator. */ 856 if ((old != s->current_frame && num_frames(s) > 1) 857 || s != old_s) 858 { 859 show_frame_indicator(force_indicator); 860 861 /* run the frame switch hook. We call it in here because this is 862 when a frame switch ACTUALLY (for sure) happens. */ 863 hook_run (&rp_switch_frame_hook); 864 } 865 866 /* If the frame has no window to give focus to, give the key window 867 focus. */ 868 if(frame->win_number == EMPTY) 869 { 870 set_window_focus (s->key_window); 871 } 872 873 /* Call the switchscreen hook, when appropriate. */ 874 if (s != old_s) 875 hook_run (&rp_switch_screen_hook); 876} 877 878void 879exchange_with_frame (rp_frame *cur, rp_frame *frame) 880{ 881 rp_window *win,*last_win; 882 883 if (frame == NULL || frame == cur) return; 884 885 /* Exchange the windows in the frames */ 886 win = find_window_number (cur->win_number); 887 last_win = set_frames_window (frame, win); 888 set_frames_window (cur, last_win); 889 890 /* Make sure the windows comes up full screen */ 891 if (last_win) 892 maximize (last_win); 893 if (win) 894 { 895 maximize (win); 896 /* Make sure the program bar is always on the top */ 897 update_window_names (win->scr, defaults.window_fmt); 898 } 899 900 /* Make the switch */ 901 update_last_access (frame); 902 903 set_active_frame(frame, 0); 904} 905 906 907void 908blank_frame (rp_frame *frame) 909{ 910 rp_screen *s; 911 rp_window *win; 912 913 if (frame->win_number == EMPTY) return; 914 915 s = frames_screen (frame); 916 917 win = find_window_number (frame->win_number); 918 hide_window (win); 919 hide_others (win); 920 921 set_frames_window (frame, NULL); 922 923 update_bar (s); 924 925 /* Give the key window focus. */ 926 set_window_focus (frames_screen(frame)->key_window); 927} 928 929void 930hide_frame_indicator (void) 931{ 932 int i; 933 for (i=0; i<num_screens; i++) 934 XUnmapWindow (dpy, screens[i].frame_window); 935} 936 937void 938show_frame_indicator (int force) 939{ 940 if (num_frames (current_screen()) > 1 || force) 941 { 942 hide_frame_indicator (); 943 show_frame_message (defaults.frame_fmt); 944 alarm (defaults.frame_indicator_timeout); 945 } 946} 947 948void 949show_frame_message (char *msg) 950{ 951 rp_screen *s = current_screen (); 952 int width, height; 953 rp_frame *frame; 954 rp_window *win; 955 rp_window_elem *elem = NULL; 956 struct sbuf *msgbuf; 957 958 frame = current_frame(); 959 win = current_window (); 960 if (win) 961 { 962 rp_group *g; 963 964 g = groups_find_group_by_window (win); 965 elem = group_find_window (&g->mapped_windows, win); 966 } 967 968 /* A frame doesn't always contain a window. */ 969 msgbuf = sbuf_new (0); 970 if (elem) 971 format_string (msg, elem, msgbuf); 972 else 973 { 974 sbuf_concat (msgbuf, EMPTY_FRAME_MESSAGE); 975 } 976 977 width = defaults.bar_x_padding * 2 978 + rp_text_width (s, msgbuf->data, msgbuf->len); 979 height = (FONT_HEIGHT (s) + defaults.bar_y_padding * 2); 980 981 /* We don't want another frame indicator to be displayed on another 982 * screen at the same time, so we hide it before bringing it back again. 983 */ 984 hide_frame_indicator (); 985 986 XMoveResizeWindow (dpy, s->frame_window, 987 s->left + frame->x + frame->width / 2 - width / 2, 988 s->top + frame->y + frame->height / 2 - height / 2, 989 width, height); 990 991 XMapRaised (dpy, s->frame_window); 992 XClearWindow (dpy, s->frame_window); 993 XSync (dpy, False); 994 995 rp_draw_string (s, s->frame_window, STYLE_NORMAL, 996 defaults.bar_x_padding, 997 defaults.bar_y_padding + FONT_ASCENT(s), 998 msgbuf->data, msgbuf->len); 999 1000 sbuf_free (msgbuf); 1001} 1002 1003rp_frame * 1004find_frame_up (rp_frame *frame) 1005{ 1006 rp_screen *s = frames_screen (frame); 1007 rp_frame *cur; 1008 1009 list_for_each_entry (cur, &s->frames, node) 1010 { 1011 if (frame->y == cur->y + cur->height) 1012 { 1013 if (frame->x >= cur->x && frame->x < cur->x + cur->width) 1014 return cur; 1015 } 1016 } 1017 1018 return NULL; 1019} 1020 1021rp_frame * 1022find_frame_down (rp_frame *frame) 1023{ 1024 rp_screen *s = frames_screen (frame); 1025 rp_frame *cur; 1026 1027 list_for_each_entry (cur, &s->frames, node) 1028 { 1029 if (frame->y + frame->height == cur->y) 1030 { 1031 if (frame->x >= cur->x && frame->x < cur->x + cur->width) 1032 return cur; 1033 } 1034 } 1035 1036 return NULL; 1037} 1038 1039rp_frame * 1040find_frame_left (rp_frame *frame) 1041{ 1042 rp_screen *s = frames_screen (frame); 1043 rp_frame *cur; 1044 1045 list_for_each_entry (cur, &s->frames, node) 1046 { 1047 if (frame->x == cur->x + cur->width) 1048 { 1049 if (frame->y >= cur->y && frame->y < cur->y + cur->height) 1050 return cur; 1051 } 1052 } 1053 1054 return NULL; 1055} 1056 1057rp_frame * 1058find_frame_right (rp_frame *frame) 1059{ 1060 rp_screen *s = frames_screen (frame); 1061 rp_frame *cur; 1062 1063 list_for_each_entry (cur, &s->frames, node) 1064 { 1065 if (frame->x + frame->width == cur->x) 1066 { 1067 if (frame->y >= cur->y && frame->y < cur->y + cur->height) 1068 return cur; 1069 } 1070 } 1071 1072 return NULL; 1073} 1074 1075rp_frame * 1076find_frame_number (int num) 1077{ 1078 int i; 1079 rp_frame *cur; 1080 1081 for (i=0; i<num_screens; i++) 1082 { 1083 rp_screen *s = &screens[i]; 1084 1085 list_for_each_entry (cur, &s->frames, node) 1086 { 1087 if (cur->number == num) 1088 return cur; 1089 } 1090 } 1091 1092 return NULL; 1093}