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