From 71d001e943851a845bdf8debec1ba87b1a84308b Mon Sep 17 00:00:00 2001 From: Denis G Date: Fri, 5 Nov 2010 23:10:00 +0100 Subject: [PATCH] Add tiling support ala Windows 7 to Xfwm4. Windows are tiled verticaly when moved near the right or left side of the screen and tiled horizontaly when moved near the top or bottom side. --- src/client.c | 15 +++++-- src/client.h | 6 +++ src/moveresize.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/moveresize.h | 3 + src/placement.c | 4 ++ 5 files changed, 141 insertions(+), 4 deletions(-) diff --git a/src/client.c b/src/client.c index 6fe0715..489c0e1 100644 --- a/src/client.c +++ b/src/client.c @@ -107,8 +107,6 @@ struct _ButtonPressData /* Forward decl */ static void clientUpdateIconPix (Client * c); -static void -clientNewMaxSize (Client * c, XWindowChanges *wc); Display * clientGetXDisplay (Client * c) @@ -2151,6 +2149,14 @@ clientFrameAll (ScreenInfo *screen_info) if ((attr.map_state == IsViewable) && (attr.root == screen_info->xroot)) { Client *c = clientFrame (display_info, wins[i], TRUE); + + /* initial values for existing windows */ + if (c) + { + c->pretiling_height = -1; + c->pretiling_width = -1; + } + if ((c) && ((screen_info->params->raise_on_click) || (screen_info->params->click_to_focus))) { clientGrabMouseButton (c); @@ -3201,7 +3207,7 @@ clientNewMaxState (Client * c, XWindowChanges *wc, int mode) wc->height = c->old_height; } -static void +void clientNewMaxSize (Client * c, XWindowChanges *wc) { ScreenInfo *screen_info; @@ -3228,7 +3234,8 @@ clientNewMaxSize (Client * c, XWindowChanges *wc) full_h = MIN (screen_info->height - screen_info->params->xfwm_margins[STRUTS_BOTTOM], rect.y + rect.height) - full_y; - if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)) + if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED) + || FLAG_TEST (c->flags, CLIENT_FLAG_TILED)) { /* Adjust size to the largest size available, not covering struts */ clientMaxSpace (screen_info, &full_x, &full_y, &full_w, &full_h); diff --git a/src/client.h b/src/client.h index 10137f7..20fe028 100644 --- a/src/client.h +++ b/src/client.h @@ -161,6 +161,7 @@ #define CLIENT_FLAG_DEMANDS_ATTENTION (1L<<17) #define CLIENT_FLAG_HAS_SHAPE (1L<<18) #define CLIENT_FLAG_FULLSCREN_MONITORS (1L<<19) +#define CLIENT_FLAG_TILED (1L<<20) #define WM_FLAG_DELETE (1L<<0) #define WM_FLAG_INPUT (1L<<1) @@ -283,6 +284,8 @@ struct _Client gint old_y; gint old_width; gint old_height; + int pretiling_width; + int pretiling_height; gint fullscreen_old_x; gint fullscreen_old_y; gint fullscreen_old_width; @@ -338,6 +341,9 @@ struct _Client extern Client *clients; extern unsigned int client_count; +void clientNewMaxSize (Client * c, + XWindowChanges *wc); + Display *clientGetXDisplay (Client *); void clientClearLastOpTime (Client *); void clientUpdateWinState (Client *, diff --git a/src/moveresize.c b/src/moveresize.c index 8b58544..52692c0 100644 --- a/src/moveresize.c +++ b/src/moveresize.c @@ -916,6 +916,116 @@ clientMoveEventFilter (XEvent * xevent, gpointer data) c->x = passdata->ox + (xevent->xmotion.x_root - passdata->mx); c->y = passdata->oy + (xevent->xmotion.y_root - passdata->my); + /* if window is not maximized */ + if (!FLAG_TEST_ALL(c->flags, CLIENT_FLAG_MAXIMIZED)) + { + /* if user moved cursor to the edge of the screen */ + if (xevent->xmotion.x_root < TILING_EDGE + || xevent->xmotion.x_root > screen_info->width - TILING_EDGE + || xevent->xmotion.y_root < TILING_EDGE + || xevent->xmotion.y_root > screen_info->height - TILING_EDGE) + { + /* save pretiling sizes for future restore + + initial values for pretiling_width and pretiling_height + are set in functions: + placement.c => clientInitPosition - for new windows + client.c => clientFrameAll - for existing windows + P.S. maybe it's a dirty hack :-) */ + + if (c->pretiling_width == -1) + c->pretiling_width = c->width; + if (c->pretiling_height == -1) + c->pretiling_height = c->height; + + /* get information about maximum available space */ + FLAG_SET (c->flags, CLIENT_FLAG_TILED); + clientNewMaxSize(c, &wc); + + if (xevent->xmotion.x_root < TILING_EDGE) + { + /* wc.x = avialable screen x + 1 x left frame's width + wc.width = available screen width - 1 x left frame's width - 1 x right frame's width */ + + c->x = wc.x; + c->y = wc.y; + + /* we need to substract another two (left, right) frames' width + because of two windows we have */ + + c->width = (wc.width - frameRight(c) - frameLeft(c))/2; + c->height = wc.height; + } + else if (xevent->xmotion.x_root > screen_info->width - TILING_EDGE) + { + /* see upper */ + c->width = (wc.width - frameRight(c) - frameLeft(c))/2; + c->height = wc.height; + + /* c->width has to be first (left) window's width + but two windows we have are equal, + consequently we can use second windows's width + + frameRight(c) + frameLeft(c) = width of frames between windows */ + + c->x = wc.x + c->width + frameRight(c) + frameLeft(c); + c->y = wc.y; + } + else if (xevent->xmotion.y_root < TILING_EDGE) + { + /* see previous tilings' comments */ + c->x = wc.x; + c->y = wc.y; + c->width = wc.width; + c->height = (wc.height - frameBottom(c) - frameTop(c))/2; + } + else + { + /* see previous tilings' comments */ + c->width = wc.width; + c->height = (wc.height - frameBottom(c) - frameTop(c))/2; + c->x = wc.x; + c->y = wc.y + c->height + frameBottom(c) + frameTop(c); + } + } + else + { + if (c->pretiling_width != -1) + { + /* calculate x-resize ratio */ + double ratio_x = ((double) c->pretiling_width) / ((double) c->width); + + /* restore pretiling size (by x) */ + c->width = c->pretiling_width; + c->pretiling_width = -1; + + /* fix cursor position (by x) */ + passdata->mx *= ratio_x; + passdata->ox *= ratio_x; + } + + if (c->pretiling_height != -1) + { + /* calculate y-resize ratio */ + double ratio_y = ((double) c->pretiling_height) / ((double) c->height); + + /* restore pretiling size (by y) */ + c->height = c->pretiling_height; + c->pretiling_height = -1; + + /* fix cursor position (by y) */ + passdata->my *= ratio_y; + passdata->oy *= ratio_y; + } + + FLAG_UNSET (c->flags, CLIENT_FLAG_TILED); + + } + + /* we need it for our window to be not only moved, but resized too */ + passdata->move_resized = 1; + } + clientSnapPosition (c, prev_x, prev_y); if (screen_info->params->restore_on_move) { @@ -1228,6 +1338,13 @@ clientResizeEventFilter (XEvent * xevent, gpointer data) status = EVENT_FILTER_STOP; resizing = TRUE; + /* + if (xevent->xmotion.x_root > TILING_EDGE || xevent->xmotion.x_root < screen_info->width - TILING_EDGE) + { + c->pretiling_width = c->pretiling_height = -1; + } + */ + frame_x = frameX (c); frame_y = frameY (c); frame_height = frameHeight (c); diff --git a/src/moveresize.h b/src/moveresize.h index cd5c770..69e1c32 100644 --- a/src/moveresize.h +++ b/src/moveresize.h @@ -33,6 +33,9 @@ #ifndef INC_MOVERESIZE_H #define INC_MOVERESIZE_H + +#define TILING_EDGE 10 + void clientSetWidth (Client *, int); void clientSetHeight (Client *, diff --git a/src/placement.c b/src/placement.c index 0881f7d..0b4efb5 100644 --- a/src/placement.c +++ b/src/placement.c @@ -739,6 +739,10 @@ clientInitPosition (Client * c) { clientAutoMaximize (c, full_w, full_h); } + + /* initial values for new windows */ + c->pretiling_width = -1; + c->pretiling_height = -1; } -- 1.7.5.4