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