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 = 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, ¤t_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}