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