summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorjjacky2013-04-08 11:04:25 +0200
committerOlivier Brunel2015-06-08 19:22:24 +0200
commit54888078ff79d77e7161a7c74985d62729c58844 (patch)
treedb1ba45eeb3116ce619504f077ab9ce78360f2a7
downloadaur-54888078ff79d77e7161a7c74985d62729c58844.tar.gz
Add xfwm4-better-smartplacement
Patch for xfwm4 for better smartPlacement of new windows. Fore more see: http://jjacky.com/2013-04-04-where-does-your-window-manager-place-new-windows/ Signed-off-by: Olivier Brunel <jjk@jjacky.com>
-rw-r--r--.SRCINFO27
-rw-r--r--0001-Rewrote-smartPlacement.patch401
-rw-r--r--PKGBUILD48
-rw-r--r--xfwm4-4.10.0-implement-NET_WM_MOVERESIZE_CANCEL.patch84
-rw-r--r--xfwm4-better-smartplacement.install11
5 files changed, 571 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..5abf968f1ff2
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,27 @@
+pkgbase = xfwm4-better-smartplacement
+ pkgdesc = Xfce window manager w/ better smart placement of new windows
+ pkgver = 4.10.0
+ pkgrel = 1
+ url = http://www.xfce.org/
+ install = xfwm4-better-smartplacement.install
+ arch = i686
+ arch = x86_64
+ groups = xfce4
+ license = GPL2
+ makedepends = pkgconfig
+ makedepends = intltool
+ depends = libxfce4ui
+ depends = libwnck
+ depends = hicolor-icon-theme
+ provides = xfwm4=4.10.0
+ conflicts = xfwm4
+ options = !libtool
+ source = http://archive.xfce.org/src/xfce/xfwm4/4.10/xfwm4-4.10.0.tar.bz2
+ source = 0001-Rewrote-smartPlacement.patch
+ source = xfwm4-4.10.0-implement-NET_WM_MOVERESIZE_CANCEL.patch
+ sha1sums = 1549954949b5e1f38a2279a39a477b52bb5339f2
+ sha1sums = a7894fd9fb0edc7b4c0149e5c6c3eb085483cff3
+ sha1sums = 32dd678f8477a5b30d17641a0d75c5a54c4dca52
+
+pkgname = xfwm4-better-smartplacement
+
diff --git a/0001-Rewrote-smartPlacement.patch b/0001-Rewrote-smartPlacement.patch
new file mode 100644
index 000000000000..7538abd5d2b9
--- /dev/null
+++ b/0001-Rewrote-smartPlacement.patch
@@ -0,0 +1,401 @@
+From 451fee0896ec21ccaaeb02f88f39becc5d06db0f Mon Sep 17 00:00:00 2001
+From: jjacky <i.am.jack.mail@gmail.com>
+Date: Fri, 5 Apr 2013 15:33:00 +0200
+Subject: [PATCH] Rewrote smartPlacement()
+
+Instead of trying to find the position with the least overlaps, including all
+stacked windows with the same weight, we now try to determine the place where
+the lowest window on stack is visible, to put the new window there.
+
+In effect, this means all windows hidden by another one are ignored, only
+windows visible to the user should matter. We put the new window on top of the
+window the lowest on stack, i.e. the last one to be activated/(fully) visible.
+
+By default we will snap to top/left if possible, since we use that corner as
+position for the window. If option snap_to_border is activated, and we're not
+snapper to the top/left borders, if we can we'll snap to the bottom/right ones.
+
+Signed-off-by: jjacky <i.am.jack.mail@gmail.com>
+---
+ src/placement.c | 341 +++++++++++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 288 insertions(+), 53 deletions(-)
+
+diff --git a/src/placement.c b/src/placement.c
+index 248d339..b4423cc 100644
+--- a/src/placement.c
++++ b/src/placement.c
+@@ -532,15 +532,139 @@ clientAutoMaximize (Client * c, int full_w, int full_h)
+ }
+
+ static void
++expand_horizontal (cairo_region_t *region,
++ cairo_rectangle_int_t *rect,
++ gint full_x,
++ gint full_y,
++ gint full_w,
++ gint full_h)
++{
++ cairo_rectangle_int_t r;
++ cairo_region_overlap_t overlap;
++
++ /* a chance to expand on the left? */
++ if (rect->x > full_x)
++ {
++ /* try the full expansion first */
++ r.x = full_x;
++ r.y = rect->y;
++ r.width = rect->x;
++ r.height = rect->height;
++ overlap = cairo_region_contains_rectangle (region, &r);
++ if (overlap == CAIRO_REGION_OVERLAP_IN)
++ rect->x = r.x;
++ else if (overlap == CAIRO_REGION_OVERLAP_PART)
++ {
++ /* there might be some expansion possible */
++ r.x = rect->x;
++ r.width = 0;
++ do
++ {
++ --r.x;
++ ++r.width;
++ overlap = cairo_region_contains_rectangle (region, &r);
++ } while (overlap == CAIRO_REGION_OVERLAP_IN);
++ if (r.width - 1 > 0)
++ rect->x = r.x + 1;
++ }
++ }
++ /* a chance to expand on the right? */
++ if (rect->x + rect->width < full_x + full_w)
++ {
++ /* try the full expansion first */
++ r.x = rect->x + rect->width;
++ r.y = rect->y;
++ r.width = full_x + full_w - r.x;
++ r.height = rect->height;
++ overlap = cairo_region_contains_rectangle (region, &r);
++ if (overlap == CAIRO_REGION_OVERLAP_IN)
++ rect->width += r.width;
++ else if (overlap == CAIRO_REGION_OVERLAP_PART)
++ {
++ /* there might be some expansion possible */
++ r.width = 0;
++ do
++ {
++ ++r.width;
++ overlap = cairo_region_contains_rectangle (region, &r);
++ } while (overlap == CAIRO_REGION_OVERLAP_IN);
++ if (--r.width > 0)
++ rect->width += r.width;
++ }
++ }
++}
++
++static void
++expand_vertical (cairo_region_t *region,
++ cairo_rectangle_int_t *rect,
++ gint full_x,
++ gint full_y,
++ gint full_w,
++ gint full_h)
++{
++ cairo_rectangle_int_t r;
++ cairo_region_overlap_t overlap;
++
++ /* a chance to expand on top? */
++ if (rect->y > full_y)
++ {
++ /* try the full expansion first */
++ r.x = rect->x;
++ r.y = full_y;
++ r.width = rect->width;
++ r.height = rect->y - r.y;
++ overlap = cairo_region_contains_rectangle (region, &r);
++ if (overlap == CAIRO_REGION_OVERLAP_IN)
++ rect->y = r.y;
++ else if (overlap == CAIRO_REGION_OVERLAP_PART)
++ {
++ /* there might be some expansion possible */
++ r.height = 0;
++ r.y = rect->y;
++ do
++ {
++ --r.y;
++ ++r.height;
++ overlap = cairo_region_contains_rectangle (region, &r);
++ } while (overlap == CAIRO_REGION_OVERLAP_IN);
++ if (r.height - 1 > 0)
++ rect->y = r.y + 1;
++ }
++ }
++ /* a chance to expand on bottom? */
++ if (rect->y + rect->height < full_y + full_h)
++ {
++ /* try the full expansion first */
++ r.x = rect->x;
++ r.y = rect->y + rect->height;
++ r.width = rect->width;
++ r.height = full_y + full_h - r.y;
++ overlap = cairo_region_contains_rectangle (region, &r);
++ if (overlap == CAIRO_REGION_OVERLAP_IN)
++ rect->height += r.height;
++ else if (overlap == CAIRO_REGION_OVERLAP_PART)
++ {
++ /* there might be some expansion possible */
++ r.height = 0;
++ do
++ {
++ ++r.height;
++ overlap = cairo_region_contains_rectangle (region, &r);
++ } while (overlap == CAIRO_REGION_OVERLAP_IN);
++ if (--r.height > 0)
++ rect->height += r.height;
++ }
++ }
++}
++
++static void
+ smartPlacement (Client * c, int full_x, int full_y, int full_w, int full_h)
+ {
+- Client *c2;
+ ScreenInfo *screen_info;
+- gfloat best_overlaps;
+- guint i;
+- gint test_x, test_y, xmax, ymax, best_x, best_y;
+ gint frame_height, frame_width, frame_left, frame_top;
+- gboolean first;
++ cairo_region_t *region_monitor, *region_used, *region_hole, *region_tmp;
++ cairo_rectangle_int_t rect;
++ GList *list;
+
+ g_return_if_fail (c != NULL);
+ TRACE ("entering smartPlacement");
+@@ -550,67 +674,178 @@ smartPlacement (Client * c, int full_x, int full_y, int full_w, int full_h)
+ frame_width = frameWidth (c);
+ frame_left = frameLeft(c);
+ frame_top = frameTop (c);
+- test_x = 0;
+- test_y = 0;
+- best_overlaps = 0.0;
+- first = TRUE;
+-
+- xmax = full_x + full_w - c->width - frameRight (c);
+- ymax = full_y + full_h - c->height - frameBottom (c);
+- best_x = full_x + frameLeft (c);
+- best_y = full_y + frameTop (c);
+
+- test_y = full_y + frameTop (c);
+- do
++ /* region of the monitor (i.e. where we can/want to put the window) */
++ rect.x = full_x;
++ rect.y = full_y;
++ rect.width = full_w;
++ rect.height = full_h;
++ region_monitor = cairo_region_create_rectangle (&rect);
++ /* region where we'll add visible windows (i.e. used space) */
++ region_used = cairo_region_create ();
++ /* region of monitor we can use, i.e. monitor - used */
++ region_hole = NULL;
++
++ for (list = g_list_last (screen_info->windows_stack); list; list = g_list_previous (list))
+ {
+- test_x = full_x + frameLeft (c);
+- do
++ Client *c2 = list->data;
++ gint i, n;
++ gboolean done;
++ cairo_rectangle_int_t best;
++ gdouble best_surface = 0;
++ gboolean can_window_fit = FALSE;
++
++ if (!clientSelectMask (c2, NULL, SEARCH_INCLUDE_SKIP_PAGER | SEARCH_INCLUDE_SKIP_TASKBAR, WINDOW_REGULAR_FOCUSABLE))
++ continue;
++
++ /* rectangle for the window */
++ rect.x = frameX (c2);
++ rect.y = frameY (c2);
++ rect.width = frameWidth (c2);
++ rect.height = frameHeight (c2);
++
++ switch (cairo_region_contains_rectangle (region_monitor, &rect))
+ {
+- gfloat count_overlaps = 0.0;
+- TRACE ("analyzing %i clients", screen_info->client_count);
+- for (c2 = screen_info->clients, i = 0; i < screen_info->client_count; c2 = c2->next, i++)
+- {
+- if ((c2 != c) && (c2->type != WINDOW_DESKTOP)
+- && (c->win_workspace == c2->win_workspace)
+- && FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE))
++ case CAIRO_REGION_OVERLAP_OUT:
++ /* another monitor, ignore it */
++ continue;
++ case CAIRO_REGION_OVERLAP_IN:
++ /* add the window's rect to region_used */
++ cairo_region_union_rectangle (region_used, &rect);
++ break;
++ case CAIRO_REGION_OVERLAP_PART:
+ {
+- count_overlaps += overlap (test_x - frame_left,
+- test_y - frame_top,
+- test_x - frame_left + frame_width,
+- test_y - frame_top + frame_height,
+- frameX (c2),
+- frameY (c2),
+- frameX (c2) + frameWidth (c2),
+- frameY (c2) + frameHeight (c2));
++ /* get only the part of the window on our monitor */
++ region_tmp = cairo_region_copy (region_monitor);
++ cairo_region_intersect_rectangle (region_tmp, &rect);
++ /* and add it to region_used */
++ cairo_region_union (region_used, region_tmp);
++ cairo_region_destroy (region_tmp);
+ }
+- }
+- if (count_overlaps < 0.1)
+- {
+- TRACE ("overlaps is 0 so it's the best we can get");
+- c->x = test_x;
+- c->y = test_y;
++ }
+
+- return;
+- }
+- else if ((count_overlaps < best_overlaps) || (first))
++ /* get a region of the monitor - visible window, i.e. leaving space
++ * where we can put out window. The goal is to reach a place where there
++ * isn't such space, and then go back one iteration, so we use the space
++ * of the visible (to the user) window the lowest on the stack */
++ region_tmp = cairo_region_copy (region_monitor);
++ cairo_region_subtract (region_tmp, region_used);
++
++ /* is there still free space left? */
++ n = cairo_region_num_rectangles (region_tmp);
++ done = TRUE;
++ for (i = 0; i < n; ++i)
++ {
++ cairo_region_get_rectangle (region_tmp, i, &rect);
++ /* ignore little areas between windows */
++ if (rect.width <= 15 || rect.height <= 15)
++ continue;
++ done = FALSE;
++ break;
++ }
++ if (!done)
++ {
++ if (region_hole)
++ cairo_region_destroy (region_hole);
++ region_hole = region_tmp;
++ continue;
++ }
++ cairo_region_destroy (region_tmp);
++
++ /* got nothing, use defaults */
++ if (!region_hole)
++ break;
++
++ cairo_region_destroy (region_monitor);
++ cairo_region_destroy (region_used);
++
++ n = cairo_region_num_rectangles (region_hole);
++ for (i = 0; i < n; ++i)
++ {
++ cairo_rectangle_int_t r;
++ cairo_rectangle_int_t exp;
++ gdouble exp_surface;
++ gboolean exp_can_window_fit;
++ gdouble surface;
++ gboolean can_fit;
++
++ cairo_region_get_rectangle (region_hole, i, &rect);
++
++ /* expand horizontally, then vertically */
++ expand_horizontal (region_hole, &rect, full_x, full_y, full_w, full_h);
++ expand_vertical (region_hole, &rect, full_x, full_y, full_w, full_h);
++ exp = rect;
++ exp_surface = exp.width * exp.height;
++ exp_can_window_fit = frame_width <= exp.width && frame_height <= exp.height;
++
++ /* expand vertically, then horizontally */
++ expand_vertical (region_hole, &rect, full_x, full_y, full_w, full_h);
++ expand_horizontal (region_hole, &rect, full_x, full_y, full_w, full_h);
++ /* keep the best one */
++ surface = rect.width * rect.height;
++ can_fit = frame_width <= rect.width && frame_height <= rect.height;
++ /* if we can now fit the window, or still can't but in a larger
++ * rect; or still can but in a smaller rect */
++ if ((!exp_can_window_fit && (can_fit || surface > exp_surface))
++ || (exp_can_window_fit && can_fit && surface < exp_surface))
+ {
+- best_x = test_x;
+- best_y = test_y;
+- best_overlaps = count_overlaps;
++ exp_can_window_fit = can_fit;
++ exp = rect;
++ exp_surface = surface;
+ }
+- if (first)
++
++ /* is this the new best result ? (same criteria) */
++ if (best_surface == 0 /* our first result */
++ || (!can_window_fit && (exp_can_window_fit || exp_surface > best_surface))
++ || (can_window_fit && exp_can_window_fit && exp_surface < best_surface))
+ {
+- first = FALSE;
++ can_window_fit = exp_can_window_fit;
++ best = exp;
++ best_surface = exp_surface;
+ }
+- test_x += 8;
+ }
+- while (test_x <= xmax);
+- test_y += 8;
++ cairo_region_destroy (region_hole);
++
++ c->x = best.x;
++ c->y = best.y;
++
++ /* unless it could fit, make sure it's fully within monitor */
++ if (!can_window_fit)
++ {
++ /* move to the left if needed */
++ n = c->x + frame_width - full_x - full_w;
++ if (n > 0)
++ c->x -= n;
++ /* move to the top if needed */
++ n = c->y + frame_height - full_y - full_h;
++ if (n > 0)
++ c->y -= n;
++ }
++
++ /* w/ option snap_to_border, we'll try to do just that on the right
++ * & bottom borders if we can & are not on the top/left ones already */
++ if (screen_info->params->snap_to_border)
++ {
++ /* snap right */
++ if (c->x > full_x && best.x + best.width == full_x + full_w)
++ c->x = full_x + full_w - frame_width;
++ /* snap bottom */
++ if (c->y > full_y && best.y + best.height == full_y + full_h)
++ c->y = full_y + full_h - frame_height;
++ }
++
++ /* add frames */
++ c->x += frame_left;
++ c->y += frame_top;
++
++ return;
+ }
+- while (test_y <= ymax);
+
+- c->x = best_x;
+- c->y = best_y;
++ cairo_region_destroy (region_monitor);
++ cairo_region_destroy (region_used);
++
++ c->x = full_x + frame_left;
++ c->y = full_y + frame_top;
+ }
+
+ static void
+--
+1.8.2
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..342b62cd515b
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,48 @@
+# Maintainer: jjacky
+# Contributor: AndyRTR <andyrtr@archlinux.org>
+# Contributor: tobias <tobias funnychar archlinux.org>
+
+_pkgname=xfwm4
+pkgname=$_pkgname-better-smartplacement
+pkgver=4.10.0
+pkgrel=1
+pkgdesc="Xfce window manager w/ better smart placement of new windows"
+arch=('i686' 'x86_64')
+license=('GPL2')
+url="http://www.xfce.org/"
+groups=('xfce4')
+depends=("libxfce4ui" 'libwnck' 'hicolor-icon-theme')
+makedepends=('pkgconfig' 'intltool')
+options=('!libtool')
+provides=('xfwm4=4.10.0')
+conflicts=('xfwm4')
+install=${pkgname}.install
+source=(http://archive.xfce.org/src/xfce/${_pkgname}/4.10/${_pkgname}-${pkgver}.tar.bz2
+ 0001-Rewrote-smartPlacement.patch
+ xfwm4-4.10.0-implement-NET_WM_MOVERESIZE_CANCEL.patch)
+sha1sums=('1549954949b5e1f38a2279a39a477b52bb5339f2'
+ 'a7894fd9fb0edc7b4c0149e5c6c3eb085483cff3'
+ '32dd678f8477a5b30d17641a0d75c5a54c4dca52')
+
+build() {
+ cd ${srcdir}/${_pkgname}-${pkgver}
+ patch -p1 -i ../0001-Rewrote-smartPlacement.patch
+ # fixes https://bugzilla.xfce.org/show_bug.cgi?id=8949
+ patch -Np1 -i ../xfwm4-4.10.0-implement-NET_WM_MOVERESIZE_CANCEL.patch
+ ./configure --prefix=/usr \
+ --sysconfdir=/etc \
+ --libexecdir=/usr/lib \
+ --localstatedir=/var \
+ --disable-static \
+ --enable-startup-notification \
+ --enable-randr \
+ --enable-compositor \
+ --enable-xsync \
+ --disable-debug
+ make
+}
+
+package() {
+ cd ${srcdir}/${_pkgname}-${pkgver}
+ make DESTDIR=${pkgdir} install
+}
diff --git a/xfwm4-4.10.0-implement-NET_WM_MOVERESIZE_CANCEL.patch b/xfwm4-4.10.0-implement-NET_WM_MOVERESIZE_CANCEL.patch
new file mode 100644
index 000000000000..f141ed646ac4
--- /dev/null
+++ b/xfwm4-4.10.0-implement-NET_WM_MOVERESIZE_CANCEL.patch
@@ -0,0 +1,84 @@
+From 099614e3f045e06db7ab509e174510ea74857adb Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <fourdan@xfce.org>
+Date: Wed, 18 Jul 2012 20:12:07 +0000
+Subject: Implement NET_WM_MOVERESIZE_CANCEL message (bug #8949)
+
+as gtk+-3.4 now uses it.
+---
+diff --git a/src/display.h b/src/display.h
+index 1ad2ef8..8797237 100644
+--- a/src/display.h
++++ b/src/display.h
+@@ -163,7 +163,8 @@ enum
+ NET_WM_MOVERESIZE_SIZE_LEFT,
+ NET_WM_MOVERESIZE_MOVE,
+ NET_WM_MOVERESIZE_SIZE_KEYBOARD,
+- NET_WM_MOVERESIZE_MOVE_KEYBOARD
++ NET_WM_MOVERESIZE_MOVE_KEYBOARD,
++ NET_WM_MOVERESIZE_CANCEL
+ };
+
+ enum
+diff --git a/src/moveresize.c b/src/moveresize.c
+index 9893c30..a98bdf7 100644
+--- a/src/moveresize.c
++++ b/src/moveresize.c
+@@ -827,7 +827,7 @@ clientMoveEventFilter (XEvent * xevent, gpointer data)
+ eventFilterStatus status = EVENT_FILTER_STOP;
+ MoveResizeData *passdata = (MoveResizeData *) data;
+ Client *c = NULL;
+- gboolean moving = TRUE;
++ gboolean moving;
+ XWindowChanges wc;
+ int prev_x, prev_y;
+
+@@ -840,6 +840,12 @@ clientMoveEventFilter (XEvent * xevent, gpointer data)
+ display_info = screen_info->display_info;
+ configure_flags = NO_CFG_FLAG;
+
++ /*
++ * Clients may choose to end the move operation,
++ * we use XFWM_FLAG_MOVING_RESIZING for that.
++ */
++ moving = FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING);
++
+ /* Update the display time */
+ myDisplayUpdateCurrentTime (display_info, xevent);
+
+@@ -1294,7 +1300,12 @@ clientResizeEventFilter (XEvent * xevent, gpointer data)
+ screen_info = c->screen_info;
+ display_info = screen_info->display_info;
+ status = EVENT_FILTER_STOP;
+- resizing = TRUE;
++
++ /*
++ * Clients may choose to end the resize operation,
++ * we use XFWM_FLAG_MOVING_RESIZING for that.
++ */
++ resizing = FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING);
+
+ frame_x = frameX (c);
+ frame_y = frameY (c);
+diff --git a/src/netwm.c b/src/netwm.c
+index 545e64a..1352f08 100644
+--- a/src/netwm.c
++++ b/src/netwm.c
+@@ -695,10 +695,15 @@ clientNetMoveResize (Client * c, XClientMessageEvent * ev)
+ resize = TRUE; /* Resize */
+ break;
+ case NET_WM_MOVERESIZE_MOVE:
+- default:
+ event->type = ButtonPress;
+ resize = FALSE; /* Move */
+ break;
++ case NET_WM_MOVERESIZE_CANCEL:
++ FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING);
++ /* Walk through */
++ default: /* Do nothing */
++ return;
++ break;
+ }
+
+ if (!FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
+--
+cgit v0.9.0.3
diff --git a/xfwm4-better-smartplacement.install b/xfwm4-better-smartplacement.install
new file mode 100644
index 000000000000..21b79d2d44de
--- /dev/null
+++ b/xfwm4-better-smartplacement.install
@@ -0,0 +1,11 @@
+post_install() {
+ gtk-update-icon-cache -q -t -f usr/share/icons/hicolor
+}
+
+post_upgrade() {
+ post_install $1
+}
+
+post_remove() {
+ gtk-update-icon-cache -q -t -f usr/share/icons/hicolor
+}