diff options
author | sabetts <sabetts> | 2001-04-01 01:17:53 +0000 |
---|---|---|
committer | sabetts <sabetts> | 2001-04-01 01:17:53 +0000 |
commit | 299d16aa6ae37bd73ae92ee8a5d1c6715682ee35 (patch) | |
tree | 2361849e3956311464ab696132f35ed931946fd1 | |
parent | f04f2c8483f144d20caa9ee7103a0eca8493545f (diff) | |
download | ratpoison-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
-rw-r--r-- | ChangeLog | 75 | ||||
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/actions.c | 130 | ||||
-rw-r--r-- | src/actions.h | 6 | ||||
-rw-r--r-- | src/conf.h | 2 | ||||
-rw-r--r-- | src/data.h | 10 | ||||
-rw-r--r-- | src/events.c | 86 | ||||
-rw-r--r-- | src/list.c | 123 | ||||
-rw-r--r-- | src/list.h | 11 | ||||
-rw-r--r-- | src/manage.c | 124 | ||||
-rw-r--r-- | src/ratpoison.h | 1 | ||||
-rw-r--r-- | src/split.c | 377 | ||||
-rw-r--r-- | src/split.h | 31 |
14 files changed, 863 insertions, 125 deletions
@@ -1,3 +1,78 @@ +2001-03-31 shawn <sabetts@diggin.lamenet.tmp> + + * 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 + 2001-03-31 Ryan Yeske <rcyeske@cut.hotdog.tmp> * doc/ipaq.ratpoisonrc: Use keysym names. @@ -1,6 +1,12 @@ ratpoison NEWS --- history of user-visible changes. -*- outline -*- * Changes since 0.1.0 +** Split windows + +Well, the day is finally here. You can now split windows in +ratpoison. Although it is currently sub-optimal it is present. Hit +C-t S to split horizontally and C-t C-S to split vertically. Have fun! + ** new command-line option --command You can now send ratpoison commands (colon-commands) to ratpoison via diff --git a/src/Makefile.am b/src/Makefile.am index 01c8dbb..6f907dd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,7 +17,7 @@ ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## -## $Id: Makefile.am,v 1.10 2001/02/25 22:01:41 rcyeske Exp $ +## $Id: Makefile.am,v 1.11 2001/04/01 01:17:53 sabetts Exp $ bin_PROGRAMS = ratpoison @@ -46,5 +46,7 @@ ratpoison_SOURCES = actions.c \ number.h \ ratpoison.h \ sbuf.c \ - sbuf.h + sbuf.h \ + split.c \ + split.h diff --git a/src/actions.c b/src/actions.c index 44017fd..f7f3163 100644 --- a/src/actions.c +++ b/src/actions.c @@ -125,29 +125,40 @@ initialize_default_keybindings (void) add_keybinding (XK_v, ControlMask, "version"); add_keybinding (XK_w, 0, "windows"); add_keybinding (XK_w, ControlMask, "windows"); + add_keybinding (XK_S, 0, "split"); + add_keybinding (XK_S, ControlMask, "vsplit"); + add_keybinding (XK_Tab, 0, "focus"); + add_keybinding (XK_Q, 0, "only"); + add_keybinding (XK_R, 0, "remove"); } user_command user_commands[] = - { {"abort", cmd_abort, arg_VOID}, - {"next", cmd_next, arg_VOID}, - {"prev", cmd_prev, arg_VOID}, - {"exec", cmd_exec, arg_STRING}, - {"select", cmd_select, arg_STRING}, - {"colon", cmd_colon, arg_STRING}, - {"kill", cmd_kill, arg_VOID}, - {"delete", cmd_delete, arg_VOID}, - {"other", cmd_other, arg_VOID}, - {"windows", cmd_windows, arg_VOID}, - {"title", cmd_rename, arg_STRING}, - {"clock", cmd_clock, arg_VOID}, - {"maximize", cmd_maximize, arg_VOID}, - {"newwm", cmd_newwm, arg_STRING}, - {"generate", cmd_generate, arg_STRING}, /* rename to stuff */ - {"version", cmd_version, arg_VOID}, - {"bind", cmd_bind, arg_VOID}, - {"source", cmd_source, arg_STRING}, - {"escape", cmd_escape, arg_STRING}, - {"echo", cmd_echo, arg_STRING}, + { {"abort", cmd_abort, arg_VOID}, + {"next", cmd_next, arg_VOID}, + {"prev", cmd_prev, arg_VOID}, + {"exec", cmd_exec, arg_STRING}, + {"select", cmd_select, arg_STRING}, + {"colon", cmd_colon, arg_STRING}, + {"kill", cmd_kill, arg_VOID}, + {"delete", cmd_delete, arg_VOID}, + {"other", cmd_other, arg_VOID}, + {"windows", cmd_windows, arg_VOID}, + {"title", cmd_rename, arg_STRING}, + {"clock", cmd_clock, arg_VOID}, + {"maximize", cmd_maximize, arg_VOID}, + {"newwm", cmd_newwm, arg_STRING}, + {"generate", cmd_generate, arg_STRING}, /* rename to stuff */ + {"version", cmd_version, arg_VOID}, + {"bind", cmd_bind, arg_VOID}, + {"source", cmd_source, arg_STRING}, + {"escape", cmd_escape, arg_STRING}, + {"echo", cmd_echo, arg_STRING}, + {"split", cmd_h_split, arg_VOID}, + {"hsplit", cmd_h_split, arg_VOID}, + {"vsplit", cmd_v_split, arg_VOID}, + {"focus", cmd_next_frame, arg_VOID}, + {"only", cmd_only, arg_VOID}, + {"remove", cmd_remove, arg_VOID}, /* the following screen commands may or may not be able to be implemented. See the screen documentation for what should be @@ -172,8 +183,6 @@ user_command user_commands[] = {"shelltitle", cmd_unimplemented, arg_VOID}, {"sleep", cmd_unimplemented, arg_VOID}, {"sorendition", cmd_unimplemented, arg_VOID}, - {"split", cmd_unimplemented, arg_VOID}, - {"focus", cmd_unimplemented, arg_VOID}, {"startup_message", cmd_unimplemented, arg_VOID}, {0, 0, 0} }; @@ -351,6 +360,24 @@ cmd_prev (void *data) } void +cmd_prev_frame (void *data) +{ + rp_window *w; + + if (!rp_current_window) + message (MESSAGE_NO_MANAGED_WINDOWS); + else + { + w = find_window_prev_with_frame (rp_current_window); + + if (!w) + message (MESSAGE_NO_OTHER_WINDOW); + else + set_active_window (w); + } +} + +void cmd_next (void *data) { rp_window *w; @@ -368,6 +395,24 @@ cmd_next (void *data) } } +void +cmd_next_frame (void *data) +{ + rp_window *w; + + if (!rp_current_window) + message (MESSAGE_NO_MANAGED_WINDOWS); + else + { + w = find_window_next_with_frame (rp_current_window); + + if (!w) + message (MESSAGE_NO_OTHER_WINDOW); + else + set_active_window (w); + } +} + void cmd_other (void *data) { @@ -761,3 +806,44 @@ cmd_echo (void *data) { if (data) message ((char *)data); } + +void +cmd_h_split (void *data) +{ + h_split_window (rp_current_window); +} + +void +cmd_v_split (void *data) +{ + v_split_window (rp_current_window); +} + +void +cmd_only (void *data) +{ + if (!rp_current_window) return; + + remove_all_frames(); + maximize (rp_current_window); +} + +void +cmd_remove (void *data) +{ + rp_window *win; + + if (!rp_current_window) return; + + remove_frame (rp_current_window); + + win = find_window_next_with_frame (rp_current_window); + if (win) + { + set_active_window (win); + } + else + { + set_active_window (find_window_other()); + } +} diff --git a/src/actions.h b/src/actions.h index 7d0633e..3438685 100644 --- a/src/actions.h +++ b/src/actions.h @@ -52,7 +52,9 @@ void cmd_rename (void *data); void cmd_select (void *data); void cmd_last (void *data); void cmd_next (void *data); +void cmd_next_frame (void *data); void cmd_prev (void *data); +void cmd_prev_frame (void *data); void cmd_windows (void *data); void cmd_other (void *data); void cmd_clock (void *data); @@ -63,6 +65,10 @@ void cmd_source (void* data); void cmd_maximize (void *data); void cmd_escape (void *data); void cmd_echo (void *data); +void cmd_h_split (void *data); +void cmd_v_split (void *data); +void cmd_only (void *data); +void cmd_remove (void *data); /* void cmd_xterm (void *data); */ @@ -40,7 +40,7 @@ /* The border width ratpoison configures all windows with */ -#define WINDOW_BORDER_WIDTH 0 +#define WINDOW_BORDER_WIDTH 1 /* Pressing a key sends the mouse to the bottom right corner. This doesn't work very well yet. */ @@ -35,6 +35,13 @@ typedef struct rp_window rp_window; typedef struct screen_info screen_info; typedef struct rp_action rp_action; +typedef struct rp_window_frame rp_window_frame; + +struct rp_window_frame +{ + int x, y, width, height; +}; + struct rp_window { @@ -62,6 +69,9 @@ struct rp_window /* Saved mouse position */ int mouse_x, mouse_y; + /* Frame for split screen */ + rp_window_frame *frame; + rp_window *next, *prev; }; diff --git a/src/events.c b/src/events.c index 9d8f140..cbf6cd7 100644 --- a/src/events.c +++ b/src/events.c @@ -76,11 +76,59 @@ unmap_notify (XEvent *ev) win->number = -1; win->state = STATE_UNMAPPED; + ignore_badwindow++; + + if (win->frame) + { + rp_window *new_window; + + PRINT_DEBUG ("unmapping framed window.\n"); + + new_window = find_window_for_frame (win->frame); + if (new_window) + { + PRINT_DEBUG ("Found a window to fit the frame.\n"); + + new_window->frame = xmalloc (sizeof (rp_window_frame)); + memcpy (new_window->frame, win->frame, sizeof (rp_window_frame)); + maximize (new_window); + XRaiseWindow (dpy, new_window->w); + + if (win == rp_current_window) + { + set_active_window (new_window); + } + } + else + { + PRINT_DEBUG ("No window to fit the frame.\n"); + + /* We coudn't find a window to occupy the frame, so get + rid of it. */ + remove_frame (win); + new_window = find_window_next_with_frame (rp_current_window); + if (new_window) + { + set_active_window (new_window); + } + else + { + set_active_window (find_window_other()); + } + } + + free (win->frame); + win->frame = NULL; + } + else if (rp_current_window == win) + { + cmd_other (NULL); + } + remove_from_list (win); append_to_list (win, rp_unmapped_window_sentinel); /* Update the state of the actual window */ - ignore_badwindow = 1; XRemoveFromSaveSet (dpy, win->w); XChangeProperty(dpy, win->w, wm_state, wm_state, 32, @@ -88,12 +136,7 @@ unmap_notify (XEvent *ev) XSync(dpy, False); - ignore_badwindow = 0; - - if (rp_current_window == win) - { - cmd_other (NULL); - } + ignore_badwindow--; update_window_names (s); } @@ -164,34 +207,29 @@ destroy_window (XDestroyWindowEvent *ev) { rp_window *win; + ignore_badwindow++; + win = find_window (ev->window); if (win) { - /* Goto the last accessed window. */ - if (win == rp_current_window) + if (win == rp_current_window) { - PRINT_DEBUG ("Destroying current window.\n"); - - unmanage (win); + PRINT_DEBUG ("Destroying the current window.\n"); - if (rp_mapped_window_sentinel->next == rp_mapped_window_sentinel - && rp_mapped_window_sentinel->prev == rp_mapped_window_sentinel) - { - rp_current_window = NULL; - } - else - { - /* Switch to last viewed window */ - set_current_window( find_window_other() ); - } + rp_current_window = NULL; + set_active_window (find_window_other ()); + unmanage (win); } else { PRINT_DEBUG ("Destroying some other window.\n"); + unmanage (win); } } + + ignore_badwindow--; } void @@ -373,11 +411,11 @@ key_press (XEvent *ev) { if (rp_current_window) { - ignore_badwindow = 1; + ignore_badwindow++; ev->xkey.window = rp_current_window->w; XSendEvent (dpy, rp_current_window->w, False, KeyPressMask, ev); XSync (dpy, False); - ignore_badwindow = 0; + ignore_badwindow--; } } } @@ -41,6 +41,19 @@ get_mouse_root_position (rp_window *win, int *mouse_x, int *mouse_y) XQueryPointer (dpy, win->scr->root, &root_win, &child_win, &win_x, &win_y, mouse_x, mouse_y, &mask); } +void +free_window (rp_window *w) +{ + if (w == NULL) return; + + if (w->frame) free (w->frame); + free (w->name); + XFree (w->hints); + + free (w); +} + + /* Allocate a new window and add it to the list of managed windows */ rp_window * add_to_window_list (screen_info *s, Window w) @@ -60,6 +73,7 @@ add_to_window_list (screen_info *s, Window w) new_window->colormap = DefaultColormap (dpy, s->screen_num); new_window->transient = XGetTransientForHint (dpy, new_window->w, &new_window->transient_for); PRINT_DEBUG ("transient %d\n", new_window->transient); + new_window->frame = NULL; get_mouse_root_position (new_window, &new_window->mouse_x, &new_window->mouse_y); @@ -179,52 +193,103 @@ find_window_name (char *name) return NULL; } -/* return the previous window in the list. Assumes window is in the +/* Return the previous window in the list. Assumes window is in the mapped window list. */ rp_window* find_window_prev (rp_window *w) { - rp_window *prev; + rp_window *cur; if (!w) return NULL; - prev = w->prev; - - if (prev == rp_mapped_window_sentinel) + for (cur = w->prev; + cur != w; + cur = cur->prev) { - prev = rp_mapped_window_sentinel->prev; - if (prev == w) + if (cur == rp_mapped_window_sentinel) continue; + + if (!cur->frame) { - return NULL; + return cur; } } - return prev; + return NULL; } -/* return the next window in the list. Assumes window is in the mapped +/* Return the next window that is contained in a frame. Assumes window + is in the mapped window list. */ +rp_window* +find_window_prev_with_frame (rp_window *w) +{ + rp_window *cur; + + if (!w) return NULL; + + for (cur = w->prev; + cur != w; + cur = cur->prev) + { + if (cur == rp_mapped_window_sentinel) continue; + + if (cur->frame) + { + return cur; + } + } + + return NULL; +} + +/* Return the next window in the list. Assumes window is in the mapped window list. */ rp_window* find_window_next (rp_window *w) { - rp_window *next; + rp_window *cur; + + if (!w) return NULL; + + for (cur = w->next; + cur != w; + cur = cur->next) + { + if (cur == rp_mapped_window_sentinel) continue; + + if (!cur->frame) + { + return cur; + } + } + + return NULL; +} + +/* Return the next window that is contained in a frame. Assumes window + is in the mapped window list. */ +rp_window* +find_window_next_with_frame (rp_window *w) +{ + rp_window *cur; if (!w) return NULL; - next = w->next; - - if (next == rp_mapped_window_sentinel) + for (cur = w->next; + cur != w; + cur = cur->next) { - next = rp_mapped_window_sentinel->next; - if (next == w) + if (cur == rp_mapped_window_sentinel) continue; + + if (cur->frame) { - return NULL; + return cur; } } - return next; + return NULL; } + rp_window * find_window_other () { @@ -237,7 +302,8 @@ find_window_other () cur = cur->next) { if (cur->last_access >= last_access - && cur != rp_current_window) + && cur != rp_current_window + && !cur->frame) { most_recent = cur; last_access = cur->last_access; @@ -352,12 +418,12 @@ save_mouse_position (rp_window *win) what we store in mouse_x and mouse_y since they will never be used again. */ - ignore_badwindow = 1; + ignore_badwindow++; XQueryPointer (dpy, win->w, &root_win, &child_win, &win->mouse_x, &win->mouse_y, &win_x, &win_y, &mask); - ignore_badwindow = 0; + ignore_badwindow--; } void @@ -368,6 +434,7 @@ set_active_window (rp_window *rp_w) which window was last accessed. */ if (rp_w == NULL) return; + if (rp_w == rp_current_window) return; counter++; rp_w->last_access = counter; @@ -385,7 +452,6 @@ set_active_window (rp_window *rp_w) XSetInputFocus (dpy, rp_w->w, RevertToPointerRoot, CurrentTime); - XRaiseWindow (dpy, rp_w->w); /* Swap colormaps */ if (rp_current_window != NULL) @@ -394,9 +460,20 @@ set_active_window (rp_window *rp_w) } XInstallColormap (dpy, rp_w->colormap); + /* If the new window doesn't have a frame then it inherits the frame + of the current window */ + if (!rp_w->frame && rp_current_window) + { + rp_w->frame = rp_current_window->frame; + rp_current_window->frame = NULL; + } + rp_current_window = rp_w; - + /* Make sure the window comes up full screen */ + maximize (rp_current_window); + XRaiseWindow (dpy, rp_w->w); + /* Make sure the program bar is always on the top */ update_window_names (rp_w->scr); } @@ -22,6 +22,7 @@ #ifndef _RATPOISON_LIST_H #define _RATPOISON_LIST_H 1 +void free_window (rp_window *w); rp_window *add_to_window_list (screen_info *s, Window w); void init_window_list (); /* void next_window (); */ @@ -35,10 +36,12 @@ void set_current_window (rp_window *win); /* int goto_window_name (char *name); */ rp_window *find_window_other (); rp_window *find_window_by_number (int n); -rp_window* find_window_name (char *name); -rp_window* find_window_prev (rp_window *w); -rp_window* find_window_next (rp_window *w); -rp_window* find_window_number (int n); +rp_window *find_window_name (char *name); +rp_window *find_window_prev (rp_window *w); +rp_window *find_window_prev_with_frame (rp_window *w); +rp_window *find_window_next (rp_window *w); +rp_window *find_window_next_with_frame (rp_window *w); +rp_window *find_window_number (int n); void sort_window_list_by_number (); void append_to_list (rp_window *win, rp_window *sentinel); diff --git a/src/manage.c b/src/manage.c index 9980f93..e8b1b06 100644 --- a/src/manage.c +++ b/src/manage.c @@ -195,16 +195,15 @@ unmanage (rp_window *w) { return_window_number (w->number); remove_from_list (w); - XFree (w->hints); - free (w); + free_window (w); #ifdef AUTO_CLOSE if (rp_mapped_window_sentinel->next == rp_mapped_window_sentinel && rp_mapped_window_sentinel->prev == rp_mapped_window_sentinel) { /* If the mapped window list is empty then we have run out of - managed windows, So kill ratpoison. */ + managed windows, so kill ratpoison. */ /* FIXME: The unmapped window list may also have to be checked in the case that the only mapped window in unmapped and @@ -306,33 +305,45 @@ maximize_transient (rp_window *win) { maxx = win->width; maxy = win->height; + } - /* Make sure we maximize to the nearest Resize Increment specified - by the window */ - if (win->hints->flags & PResizeInc) - { - int amount; - - amount = maxx - win->width; - amount -= amount % win->hints->width_inc; - if (amount < 0) amount -= win->hints->width_inc; - PRINT_DEBUG ("amount x: %d\n", amount); - maxx = amount + win->width; - - amount = maxy - win->height; - amount -= amount % win->hints->height_inc; - if (amount < 0) amount -= win->hints->height_inc; - PRINT_DEBUG ("amount y: %d\n", amount); - maxy = amount + win->height; - } + /* Make sure we maximize to the nearest Resize Increment specified + by the window */ + if (win->hints->flags & PResizeInc) + { + int amount; + + amount = maxx - win->width; + amount -= amount % win->hints->width_inc; + if (amount < 0) amount -= win->hints->width_inc; + PRINT_DEBUG ("amount x: %d\n", amount); + maxx = amount + win->width; + + amount = maxy - win->height; + amount -= amount % win->hints->height_inc; + if (amount < 0) amount -= win->hints->height_inc; + PRINT_DEBUG ("amount y: %d\n", amount); + maxy = amount + win->height; } PRINT_DEBUG ("maxsize: %d %d\n", maxx, maxy); - win->x = PADDING_LEFT - win->width / 2 - + (win->scr->root_attr.width - PADDING_LEFT - PADDING_RIGHT - win->border * 2) / 2; - win->y = PADDING_TOP - win->height / 2 - + (win->scr->root_attr.height - PADDING_TOP - PADDING_BOTTOM - win->border * 2) / 2; + /* Fit the window inside its frame (if it has one) */ + if (win->frame) + { + win->x = win->frame->x - win->width / 2 + + (win->frame->width - win->border * 2) / 2; + win->y = win->frame->y - win->height / 2 + + (win->frame->height - win->border * 2) / 2; + } + else + { + win->x = PADDING_LEFT - win->width / 2 + + (win->scr->root_attr.width - PADDING_LEFT - PADDING_RIGHT - win->border * 2) / 2; + win->y = PADDING_TOP - win->height / 2 + + (win->scr->root_attr.height - PADDING_TOP - PADDING_BOTTOM - win->border * 2) / 2; + } + win->width = maxx; win->height = maxy; } @@ -355,10 +366,6 @@ maximize_normal (rp_window *win) { maxx = win->hints->max_width; maxy = win->hints->max_height; - - /* centre the non-maximized window */ -/* off_x = ((win->scr->root_attr.width - PADDING_LEFT - PADDING_RIGHT) - win->hints->max_width) / 2; */ -/* off_y = ((win->scr->root_attr.height - PADDING_TOP - PADDING_BOTTOM) - win->hints->max_height) / 2; */ } else { @@ -366,31 +373,50 @@ maximize_normal (rp_window *win) - PADDING_LEFT - PADDING_RIGHT - win->border * 2; maxy = win->scr->root_attr.height - PADDING_TOP - PADDING_BOTTOM - win->border * 2; + } - /* Make sure we maximize to the nearest Resize Increment specified - by the window */ - if (win->hints->flags & PResizeInc) - { - int amount; - - amount = maxx - win->width; - amount -= amount % win->hints->width_inc; - if (amount < 0) amount -= win->hints->width_inc; - PRINT_DEBUG ("amount x: %d\n", amount); - maxx = amount + win->width; - - amount = maxy - win->height; - amount -= amount % win->hints->height_inc; - if (amount < 0) amount -= win->hints->height_inc; - PRINT_DEBUG ("amount y: %d\n", amount); - maxy = amount + win->height; - } + /* Fit the window inside its frame (if it has one) */ + if (win->frame) + { + if (maxx > win->frame->width) maxx = win->frame->width + - win->border * 2; + if (maxy > win->frame->height) maxy = win->frame->height + - win->border * 2; + } + + /* Make sure we maximize to the nearest Resize Increment specified + by the window */ + if (win->hints->flags & PResizeInc) + { + int amount; + + amount = maxx - win->width; + amount -= amount % win->hints->width_inc; + if (amount < 0) amount -= win->hints->width_inc; + PRINT_DEBUG ("amount x: %d\n", amount); + maxx = amount + win->width; + + amount = maxy - win->height; + amount -= amount % win->hints->height_inc; + if (amount < 0) amount -= win->hints->height_inc; + PRINT_DEBUG ("amount y: %d\n", amount); + maxy = amount + win->height; } PRINT_DEBUG ("maxsize: %d %d\n", maxx, maxy); - win->x = PADDING_LEFT + off_x; - win->y = PADDING_TOP + off_y; + /* Fit the window inside its frame (if it has one) */ + if (win->frame) + { + win->x = win->frame->x; + win->y = win->frame->y; + } + else + { + win->x = PADDING_LEFT + off_x; + win->y = PADDING_TOP + off_y; + } + win->width = maxx; win->height = maxy; } diff --git a/src/ratpoison.h b/src/ratpoison.h index bb8ef41..4defe46 100644 --- a/src/ratpoison.h +++ b/src/ratpoison.h @@ -57,6 +57,7 @@ extern XGCValues gv; #include "messages.h" #include "communications.h" #include "sbuf.h" +#include "split.h" void clean_up (); screen_info *find_screen (Window w); 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); +} diff --git a/src/split.h b/src/split.h new file mode 100644 index 0000000..4e70e24 --- /dev/null +++ b/src/split.h @@ -0,0 +1,31 @@ +/* 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 + * + */ + +#ifndef SPLIT_H +#define SPLIT_H + +int h_split_window (rp_window *w); +int v_split_window (rp_window *w); +void remove_all_frames (); +void remove_frame (rp_window *w); +rp_window *find_window_for_frame (rp_window_frame *frame); + +#endif |