summaryrefslogtreecommitdiff
path: root/src/split.c
diff options
context:
space:
mode:
authorsabetts <sabetts>2001-04-01 01:17:53 +0000
committersabetts <sabetts>2001-04-01 01:17:53 +0000
commit299d16aa6ae37bd73ae92ee8a5d1c6715682ee35 (patch)
tree2361849e3956311464ab696132f35ed931946fd1 /src/split.c
parentf04f2c8483f144d20caa9ee7103a0eca8493545f (diff)
downloadratpoison-299d16aa6ae37bd73ae92ee8a5d1c6715682ee35.zip
* src/split.h (find_window_for_frame): new function prototype
(find_window_for_frame): likewise (find_window_for_frame): likewise (find_window_for_frame): likewise (find_window_for_frame): likewise * src/split.c (window_fits_in_frame): new function (find_window_for_frame): likewise (split_window): likewise (v_split_window): likewise (h_split_window): likewise (remove_all_frames): likewise (frame_is_below): likewise (frame_is_above): likewise (frame_is_left): likewise (frame_is_right): likewise (total_frame_area): likewise (num_frames): likewise (frames_overlap): likewise (frame_overlaps): likewise (remove_frame): likewise * src/ratpoison.h: includes "split.h" * src/manage.c (unmanage): calls free_window (maximize_transient): takes the window's frame into account (maximize_normal): likewise * src/list.h (find_window_prev_with_frame): new function prototype (find_window_next_with_frame): likewise (free_window): likewise * src/list.c (free_window): new function (add_to_window_list): initialize new window's frame to NULL. (find_window_prev): skips windows with frames (find_window_next): likewise (find_window_other): likewise (find_window_prev_with_frame): new function (find_window_next_with_frame): new function (set_active_window): returns if the specified window is already the current window. (set_active_window): If the new window has no frame it inherits the current window's frame. (set_active_window): maximize and raise the newly active window. * src/events.c (unmap_notify): handles window frames. (destroy_window): simplified * src/data.h (struct rp_window_frame): new struct (struct rp_window): add frame variable * src/conf.h (WINDOW_BORDER_WIDTH): set to 1 * src/actions.h (cmd_next_frame): new function prototype (cmd_prev_frame): likewise (cmd_h_split): likewise (cmd_v_split): likewise (cmd_only): likewise (cmd_remove): likewise * src/actions.c (initialize_default_keybindings): new default bindings for "split", "vsplit", "focus", "only", "remove" (user_commands): new user commands "split", "vsplit", "focus", "only", "remove" (cmd_prev_frame): new function (cmd_next_frame): likewise (cmd_h_split): likewise (cmd_v_split): likewise (cmd_only): likewise (cmd_remove): likewise * src/Makefile.am (ratpoison_SOURCES): new files split.c split.h
Diffstat (limited to 'src/split.c')
-rw-r--r--src/split.c377
1 files changed, 377 insertions, 0 deletions
diff --git a/src/split.c b/src/split.c
new file mode 100644
index 0000000..d79903b
--- /dev/null
+++ b/src/split.c
@@ -0,0 +1,377 @@
+/* Copyright (C) 2000, 2001 Shawn Betts
+ *
+ * This file is part of ratpoison.
+ *
+ * ratpoison is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * ratpoison is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ *
+ *
+ * Functions for handling window splitting and tiling.
+ */
+
+#include "ratpoison.h"
+
+static int
+window_fits_in_frame (rp_window *win, rp_window_frame *frame)
+{
+ /* If the window has minimum size hints, make sure they are smaller
+ than the frame. */
+ if (win->hints->flags & PMinSize)
+ {
+ if (win->hints->min_width > frame->width
+ ||
+ win->hints->min_height > frame->height)
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* Search the list of mapped windows for a window that will fit in the
+ specified frame. */
+rp_window *
+find_window_for_frame (rp_window_frame *frame)
+{
+ int last_access = 0;
+ rp_window *most_recent = NULL;
+ rp_window *cur;
+
+ for (cur = rp_mapped_window_sentinel->next;
+ cur != rp_mapped_window_sentinel;
+ cur = cur->next)
+ {
+ if (cur != rp_current_window
+ && !cur->frame
+ && cur->last_access >= last_access
+ && window_fits_in_frame (cur, frame))
+ {
+ most_recent = cur;
+ last_access = cur->last_access;
+ }
+ }
+
+ return most_recent;
+}
+
+/* Splits the window in 2. if way is != 0 then split it horizontally
+ otherwise split it vertically. */
+static int
+split_window (rp_window *win, int way)
+{
+ rp_window *other_window;
+ rp_window_frame *frame1, *frame2;
+
+ frame1 = xmalloc (sizeof (rp_window_frame));
+ frame2 = xmalloc (sizeof (rp_window_frame));
+
+ if (!win->frame)
+ {
+ frame1->x = PADDING_LEFT;
+ frame1->y = PADDING_TOP;
+ frame1->width = win->scr->root_attr.width
+ - PADDING_RIGHT - PADDING_LEFT;
+ frame1->height = win->scr->root_attr.height
+ - PADDING_BOTTOM - PADDING_TOP;
+ }
+ else
+ {
+ frame1->x = win->frame->x;
+ frame1->y = win->frame->y;
+ frame1->width = win->frame->width;
+ frame1->height = win->frame->height;
+ }
+
+ if (way)
+ {
+ frame2->x = frame1->x;
+ frame2->y = frame1->y + frame1->height / 2;
+ frame2->width = frame1->width;
+ frame2->height = frame1->height / 2 + frame1->height % 2;
+
+ frame1->height /= 2;
+ }
+ else
+ {
+ frame2->x = frame1->x + frame1->width / 2;
+ frame2->y = frame1->y;
+ frame2->width = frame1->width / 2 + frame1->width % 2;
+ frame2->height = frame1->height;
+
+ frame1->width /= 2;
+ }
+
+ other_window = find_window_for_frame (frame2);
+ if (other_window)
+ {
+ PRINT_DEBUG ("Split the window!\n");
+
+ if (win->frame) free (win->frame);
+ win->frame = frame1;
+ other_window->frame = frame2;
+
+ maximize (win);
+ maximize (other_window);
+ XRaiseWindow (dpy, other_window->w);
+ XRaiseWindow (dpy, win->w);
+
+ return 1;
+ }
+ else
+ {
+ PRINT_DEBUG ("Failed to split.\n");
+
+ free (frame1);
+ free (frame2);
+
+ return 0;
+ }
+}
+
+/* Splits the window vertically in 2. */
+int
+v_split_window (rp_window *win)
+{
+ return split_window (win, 0);
+}
+
+/* Splits the window horizontally in 2. */
+int
+h_split_window (rp_window *win)
+{
+ return split_window (win, 1);
+}
+
+void
+remove_all_frames ()
+{
+ rp_window *cur;
+
+ for (cur = rp_mapped_window_sentinel->next;
+ cur != rp_mapped_window_sentinel;
+ cur = cur->next)
+ {
+ if (cur->frame)
+ {
+ free (cur->frame);
+ cur->frame = NULL;
+ }
+ }
+}
+
+static int
+frame_is_below (rp_window_frame *src, rp_window_frame *frame)
+{
+ if (frame->y > src->y) return 1;
+ return 0;
+}
+
+static int
+frame_is_above (rp_window_frame *src, rp_window_frame *frame)
+{
+ if (frame->y < src->y) return 1;
+ return 0;
+}
+
+static int
+frame_is_left (rp_window_frame *src, rp_window_frame *frame)
+{
+ if (frame->x < src->x) return 1;
+ return 0;
+}
+
+static int
+frame_is_right (rp_window_frame *src, rp_window_frame *frame)
+{
+ if (frame->x > src->x) return 1;
+ return 0;
+}
+
+static int
+total_frame_area ()
+{
+ int area = 0;
+ rp_window *cur;
+
+ for (cur = rp_mapped_window_sentinel->next;
+ cur != rp_mapped_window_sentinel;
+ cur = cur->next)
+ {
+ if (cur->frame)
+ {
+ area += cur->frame->width * cur->frame->height;
+ }
+ }
+
+ return area;
+}
+
+static int
+num_frames ()
+{
+ int count = 0;
+ rp_window *cur;
+
+ for (cur = rp_mapped_window_sentinel->next;
+ cur != rp_mapped_window_sentinel;
+ cur = cur->next)
+ {
+ if (cur->frame)
+ {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+/* Return 1 if frames f1 and f2 overlap */
+static int
+frames_overlap (rp_window_frame *f1, rp_window_frame *f2)
+{
+ if (f1->x >= f2->x + f2->width
+ || f1->y >= f2->y + f2->height
+ || f2->x >= f1->x + f1->width
+ || f2->y >= f1->y + f1->height)
+ {
+ return 0;
+ }
+ return 1;
+}
+
+/* Return 1 if w's frame overlaps any other window's frame */
+static int
+frame_overlaps (rp_window *w)
+{
+ rp_window *cur;
+
+ for (cur = rp_mapped_window_sentinel->next;
+ cur != rp_mapped_window_sentinel;
+ cur = cur->next)
+ {
+ if (cur != w
+ && cur->frame
+ && frames_overlap (cur->frame, w->frame))
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+remove_frame (rp_window *w)
+{
+ int area;
+ rp_window *cur;
+ rp_window_frame *frame;
+
+ if (w->frame == NULL) return;
+
+ area = total_frame_area();
+ PRINT_DEBUG ("Total Area: %d\n", area);
+
+ frame = w->frame;
+ w->frame = NULL;
+
+ /* If there is 1 frame then we have no split screen, so get rid
+ of the remaining window frame. */
+ if (num_frames() <= 1)
+ {
+ remove_all_frames();
+ free (frame);
+ return;
+ }
+
+ for (cur = rp_mapped_window_sentinel->next;
+ cur != rp_mapped_window_sentinel;
+ cur = cur->next)
+ {
+ if (cur->frame)
+ {
+ rp_window_frame tmp_frame;
+ int fits = 0;
+
+ /* Backup the frame */
+ memcpy (&tmp_frame, cur->frame, sizeof (rp_window_frame));
+
+ if (frame_is_below (frame, cur->frame)
+ || frame_is_above (frame, cur->frame))
+ {
+ if (frame_is_below (frame, cur->frame))
+ cur->frame->y = frame->y;
+ cur->frame->height += frame->height;
+ }
+
+ PRINT_DEBUG ("New Total Area: %d\n", total_frame_area());
+
+ if (total_frame_area() > area || frame_overlaps (cur))
+ {
+ PRINT_DEBUG ("Didn't fit vertically\n");
+
+ /* Restore the current window's frame */
+ memcpy (cur->frame, &tmp_frame, sizeof (rp_window_frame));
+ }
+ else
+ {
+ PRINT_DEBUG ("It fit vertically!!\n");
+
+ /* update the frame backup */
+ memcpy (&tmp_frame, cur->frame, sizeof (rp_window_frame));
+ fits = 1;
+ }
+
+ if (frame_is_left (frame, cur->frame)
+ || frame_is_right (frame, cur->frame))
+ {
+ if (frame_is_right (frame, cur->frame))
+ cur->frame->x = frame->x;
+ cur->frame->width += frame->width;
+ }
+
+ PRINT_DEBUG ("New Total Area: %d\n", total_frame_area());
+
+ if (total_frame_area() > area || frame_overlaps (cur))
+ {
+ PRINT_DEBUG ("Didn't fit horizontally\n");
+
+ /* Restore the current window's frame */
+ memcpy (cur->frame, &tmp_frame, sizeof (rp_window_frame));
+ }
+ else
+ {
+ PRINT_DEBUG ("It fit horizontally!!\n");
+ fits = 1;
+ }
+
+ if (fits)
+ {
+ /* The current frame fits into the new space so keep its
+ new frame parameters and maximize the window to fit
+ the new frame size. */
+ maximize (cur);
+ XRaiseWindow (dpy, cur->w);
+ }
+ else
+ {
+ memcpy (cur->frame, &tmp_frame, sizeof (rp_window_frame));
+ }
+
+ }
+ }
+
+ free (frame);
+}