aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--src/Makefile.am1
-rw-r--r--src/MinOverlapPlacement.cc182
-rw-r--r--src/MinOverlapPlacement.hh83
-rw-r--r--src/ScreenPlacement.cc13
-rw-r--r--src/ScreenPlacement.hh6
6 files changed, 288 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 0dc4dde..8d9f984 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
1 (Format: Year/Month/Day) 1 (Format: Year/Month/Day)
2Changes for 1.1: 2Changes for 1.1:
3*07/05/13:
4 * Added new placement policies {Row,Col}MinOverlapPlacement. They behave the
5 same as {Row,Col}SmartPlacement when the window fits but fall back on
6 minimizing overlap with other windows instead of CascadePlacement (Mark)
7 MinOverlapPlacement.cc/hh ScreenPlacement.cc/hh
3*07/05/12: 8*07/05/12:
4 * Changed interpretation of Horizontal/Vertical maximization of a window that 9 * Changed interpretation of Horizontal/Vertical maximization of a window that
5 is already maximized (Mark) 10 is already maximized (Mark)
diff --git a/src/Makefile.am b/src/Makefile.am
index df18b97..0f3395e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -131,6 +131,7 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.cc \
131 PlacementStrategy.hh \ 131 PlacementStrategy.hh \
132 CascadePlacement.hh CascadePlacement.cc \ 132 CascadePlacement.hh CascadePlacement.cc \
133 ColSmartPlacement.hh ColSmartPlacement.cc \ 133 ColSmartPlacement.hh ColSmartPlacement.cc \
134 MinOverlapPlacement.hh MinOverlapPlacement.cc \
134 RowSmartPlacement.hh RowSmartPlacement.cc \ 135 RowSmartPlacement.hh RowSmartPlacement.cc \
135 ScreenPlacement.hh ScreenPlacement.cc \ 136 ScreenPlacement.hh ScreenPlacement.cc \
136 UnderMousePlacement.hh UnderMousePlacement.cc \ 137 UnderMousePlacement.hh UnderMousePlacement.cc \
diff --git a/src/MinOverlapPlacement.cc b/src/MinOverlapPlacement.cc
new file mode 100644
index 0000000..121109f
--- /dev/null
+++ b/src/MinOverlapPlacement.cc
@@ -0,0 +1,182 @@
1// MinOverlapPlacement.cc
2// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR (*it)
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR (*it)WISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR (*it)
20// DEALINGS IN THE SOFTWARE.
21
22// $Id$
23
24#include "MinOverlapPlacement.hh"
25
26#include "Window.hh"
27#include "Screen.hh"
28
29ScreenPlacement::PlacementPolicy MinOverlapPlacement::s_policy = ScreenPlacement::ROWMINOVERLAPPLACEMENT;
30ScreenPlacement::RowDirection MinOverlapPlacement::s_row_dir = ScreenPlacement::LEFTRIGHT;
31ScreenPlacement::ColumnDirection MinOverlapPlacement::s_col_dir = ScreenPlacement::TOPBOTTOM;
32
33MinOverlapPlacement::MinOverlapPlacement(ScreenPlacement::PlacementPolicy policy) {
34 s_policy = policy;
35}
36
37bool MinOverlapPlacement::placeWindow(
38 const std::list<FluxboxWindow *> &windowlist,
39 const FluxboxWindow &win, int &place_x, int &place_y) {
40
41 // view (screen + head) constraints
42 int head = (signed) win.screen().getCurrHead();
43 int head_left = (signed) win.screen().maxLeft(head);
44 int head_right = (signed) win.screen().maxRight(head);
45 int head_top = (signed) win.screen().maxTop(head);
46 int head_bot = (signed) win.screen().maxBottom(head);
47
48 const ScreenPlacement &screen_placement =
49 dynamic_cast<const ScreenPlacement &>(win.screen().placementStrategy());
50 s_row_dir = screen_placement.rowDirection();
51 s_col_dir = screen_placement.colDirection();
52
53 int win_w = win.width() + win.fbWindow().borderWidth()*2 + win.widthOffset();
54 int win_h = win.height() + win.fbWindow().borderWidth()*2 + win.heightOffset();
55
56 // we keep a set of open spaces on the desktop, sorted by size/location
57 std::set<Region> region_set;
58
59 // initialize the set of regions to contain the entire head
60 region_set.insert(Region(Region::TOPLEFT, head_left, head_top));
61 region_set.insert(Region(Region::TOPRIGHT, head_right - win_w, head_top));
62 region_set.insert(Region(Region::BOTTOMLEFT, head_left, head_bot - win_h));
63 region_set.insert(Region(Region::BOTTOMRIGHT, head_right - win_w,
64 head_bot - win_h));
65
66 // go through the list of windows, creating other reasonable placements
67 // at the end, we'll find the one with minimum overlap
68 // the size of this set is at most 2(n+2)(n+1) (n = number of windows)
69 // finding overlaps is therefore O(n^3), but it can probably be improved
70 std::list<FluxboxWindow *>::const_reverse_iterator it = windowlist.rbegin(),
71 it_end = windowlist.rend();
72 for (; it != it_end; ++it) {
73
74 // get the dimensions of the window
75 int bottom = (*it)->y() + (*it)->height() +
76 2*(*it)->frame().window().borderWidth();
77 int top = (*it)->y();
78 int right = (*it)->x() + (*it)->width() +
79 2*(*it)->frame().window().borderWidth();
80 int left = (*it)->x();
81
82 // go through the list of regions
83 // if this window overlaps that region and the new window still fits,
84 // it will create new regions to test
85 std::set<Region>::iterator reg_it = region_set.begin();
86 for (; reg_it != region_set.end(); ++reg_it) {
87
88 switch (reg_it->corner) {
89 case Region::TOPLEFT:
90 if (right > reg_it->x && bottom > reg_it->y) {
91 if (bottom + win_h <= head_bot)
92 region_set.insert(Region(Region::TOPLEFT,
93 reg_it->x, bottom));
94 if (right + win_w <= head_right)
95 region_set.insert(Region(Region::TOPLEFT,
96 right, reg_it->y));
97 }
98 break;
99 case Region::TOPRIGHT:
100 if (left < reg_it->x + win_w && bottom > reg_it->y) {
101 if (bottom + win_h <= head_bot)
102 region_set.insert(Region(Region::TOPRIGHT,
103 reg_it->x, bottom));
104 if (left - win_w >= head_left)
105 region_set.insert(Region(Region::TOPRIGHT,
106 left - win_w, reg_it->y));
107 }
108 break;
109 case Region::BOTTOMRIGHT:
110 if (left < reg_it->x + win_w && top < reg_it->y + win_h) {
111 if (top - win_h >= head_top)
112 region_set.insert(Region(Region::BOTTOMRIGHT,
113 reg_it->x, top - win_h));
114 if (left - win_w >= head_left)
115 region_set.insert(Region(Region::BOTTOMRIGHT,
116 left - win_w, reg_it->y));
117 }
118 break;
119 case Region::BOTTOMLEFT:
120 if (right > reg_it->x && top < reg_it->y + win_h) {
121 if (top - win_h >= head_top)
122 region_set.insert(Region(Region::BOTTOMLEFT,
123 reg_it->x, top - win_h));
124 if (right + win_w <= head_right)
125 region_set.insert(Region(Region::BOTTOMLEFT,
126 right, reg_it->y));
127 }
128 break;
129 }
130
131 }
132 }
133
134 // choose the region with minimum overlap
135 int min_so_far = win_w * win_h * windowlist.size() + 1;
136 std::set<Region>::iterator min_reg = region_set.end();
137
138 std::set<Region>::iterator reg_it = region_set.begin();
139 for (; reg_it != region_set.end(); ++reg_it) {
140
141 int overlap = 0;
142 it = windowlist.rbegin();
143 for (; it != windowlist.rend(); ++it) {
144
145 // get the dimensions of the window
146 int bottom = (*it)->y() + (*it)->height() +
147 2*(*it)->frame().window().borderWidth();
148 int top = (*it)->y();
149 int right = (*it)->x() + (*it)->width() +
150 2*(*it)->frame().window().borderWidth();
151 int left = (*it)->x();
152
153 // get the coordinates of the overlap region
154 int min_right = (right > reg_it->x + win_w) ?
155 reg_it->x + win_w : right;
156 int min_bottom = (bottom > reg_it->y + win_h) ?
157 reg_it->y + win_h : bottom;
158 int max_left = (left > reg_it->x) ? left : reg_it->x;
159 int max_top = (top > reg_it->y) ? top : reg_it->y;
160
161 // now compute the overlap and add to running total
162 if (min_right > max_left && min_bottom > max_top)
163 overlap += (min_right - max_left) * (min_bottom - max_top);
164
165 }
166
167 // if this placement is better, use it
168 if (overlap < min_so_far) {
169 min_reg = reg_it;
170 min_so_far = overlap;
171 if (overlap == 0) // can't do better than this
172 break;
173 }
174
175 }
176
177 // place window
178 place_x = min_reg->x;
179 place_y = min_reg->y;
180
181 return true;
182}
diff --git a/src/MinOverlapPlacement.hh b/src/MinOverlapPlacement.hh
new file mode 100644
index 0000000..20b5c95
--- /dev/null
+++ b/src/MinOverlapPlacement.hh
@@ -0,0 +1,83 @@
1// MinOverlapPlacement.hh
2// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22// $Id$
23
24#ifndef MINOVERLAPPLACEMENT_HH
25#define MINOVERLAPPLACEMENT_HH
26
27#include "ScreenPlacement.hh"
28
29class MinOverlapPlacement: public PlacementStrategy {
30public:
31 MinOverlapPlacement(ScreenPlacement::PlacementPolicy policy);
32
33 bool placeWindow(const std::list<FluxboxWindow *> &windowlist,
34 const FluxboxWindow &win,
35 int &place_x, int &place_y);
36
37private:
38 class Region {
39 public:
40
41 enum Corner {
42 TOPLEFT,
43 TOPRIGHT,
44 BOTTOMLEFT,
45 BOTTOMRIGHT
46 } corner; // indicates the corner of the window that will be placed
47
48 Region(Corner _corner, int _x, int _y):
49 corner(_corner), x(_x), y(_y) { };
50
51 // do all STL set implementations use this for sorting?
52 bool operator <(const Region &o) const {
53 // for now, I'm assuming RowSmartPlacement, so y is more important
54 switch (MinOverlapPlacement::s_policy) {
55 case ScreenPlacement::ROWMINOVERLAPPLACEMENT:
56 // if we're making rows, y-value is most important
57 if (y != o.y)
58 return ((y < o.y) ^ (s_col_dir == ScreenPlacement::BOTTOMTOP));
59 if (x != o.x)
60 return ((x < o.x) ^ (s_row_dir == ScreenPlacement::RIGHTLEFT));
61 return (corner < o.corner);
62 case ScreenPlacement::COLMINOVERLAPPLACEMENT:
63 // if we're making columns, x-value is most important
64 if (x != o.x)
65 return ((x < o.x) ^ (s_row_dir == ScreenPlacement::RIGHTLEFT));
66 if (y != o.y)
67 return ((y < o.y) ^ (s_col_dir == ScreenPlacement::BOTTOMTOP));
68 return (corner < o.corner);
69 default:
70 return false;
71 }
72 }
73
74 // position where the top left corner of the window will be placed
75 int x, y;
76 };
77
78 static ScreenPlacement::PlacementPolicy s_policy;
79 static ScreenPlacement::RowDirection s_row_dir;
80 static ScreenPlacement::ColumnDirection s_col_dir;
81};
82
83#endif // MINOVERLAPPLACEMENT_HH
diff --git a/src/ScreenPlacement.cc b/src/ScreenPlacement.cc
index 6ba4b6f..fb79d88 100644
--- a/src/ScreenPlacement.cc
+++ b/src/ScreenPlacement.cc
@@ -25,6 +25,7 @@
25 25
26 26
27#include "RowSmartPlacement.hh" 27#include "RowSmartPlacement.hh"
28#include "MinOverlapPlacement.hh"
28#include "UnderMousePlacement.hh" 29#include "UnderMousePlacement.hh"
29#include "ColSmartPlacement.hh" 30#include "ColSmartPlacement.hh"
30#include "CascadePlacement.hh" 31#include "CascadePlacement.hh"
@@ -68,6 +69,10 @@ bool ScreenPlacement::placeWindow(const std::list<FluxboxWindow *> &windowlist,
68 case COLSMARTPLACEMENT: 69 case COLSMARTPLACEMENT:
69 m_strategy.reset(new ColSmartPlacement()); 70 m_strategy.reset(new ColSmartPlacement());
70 break; 71 break;
72 case ROWMINOVERLAPPLACEMENT:
73 case COLMINOVERLAPPLACEMENT:
74 m_strategy.reset(new MinOverlapPlacement(*m_placement_policy));
75 break;
71 case CASCADEPLACEMENT: 76 case CASCADEPLACEMENT:
72 m_strategy.reset(new CascadePlacement(win.screen())); 77 m_strategy.reset(new CascadePlacement(win.screen()));
73 break; 78 break;
@@ -137,6 +142,10 @@ void FbTk::Resource<ScreenPlacement::PlacementPolicy>::setFromString(const char
137 *(*this) = ScreenPlacement::ROWSMARTPLACEMENT; 142 *(*this) = ScreenPlacement::ROWSMARTPLACEMENT;
138 else if (strcasecmp("ColSmartPlacement", str) == 0) 143 else if (strcasecmp("ColSmartPlacement", str) == 0)
139 *(*this) = ScreenPlacement::COLSMARTPLACEMENT; 144 *(*this) = ScreenPlacement::COLSMARTPLACEMENT;
145 else if (strcasecmp("RowMinOverlapPlacement", str) == 0)
146 *(*this) = ScreenPlacement::ROWMINOVERLAPPLACEMENT;
147 else if (strcasecmp("ColMinOverlapPlacement", str) == 0)
148 *(*this) = ScreenPlacement::COLMINOVERLAPPLACEMENT;
140 else if (strcasecmp("UnderMousePlacement", str) == 0) 149 else if (strcasecmp("UnderMousePlacement", str) == 0)
141 *(*this) = ScreenPlacement::UNDERMOUSEPLACEMENT; 150 *(*this) = ScreenPlacement::UNDERMOUSEPLACEMENT;
142 else if (strcasecmp("CascadePlacement", str) == 0) 151 else if (strcasecmp("CascadePlacement", str) == 0)
@@ -152,6 +161,10 @@ std::string FbTk::Resource<ScreenPlacement::PlacementPolicy>::getString() const
152 return "RowSmartPlacement"; 161 return "RowSmartPlacement";
153 case ScreenPlacement::COLSMARTPLACEMENT: 162 case ScreenPlacement::COLSMARTPLACEMENT:
154 return "ColSmartPlacement"; 163 return "ColSmartPlacement";
164 case ScreenPlacement::ROWMINOVERLAPPLACEMENT:
165 return "RowMinOverlapPlacement";
166 case ScreenPlacement::COLMINOVERLAPPLACEMENT:
167 return "ColMinOverlapPlacement";
155 case ScreenPlacement::UNDERMOUSEPLACEMENT: 168 case ScreenPlacement::UNDERMOUSEPLACEMENT:
156 return "UnderMousePlacement"; 169 return "UnderMousePlacement";
157 case ScreenPlacement::CASCADEPLACEMENT: 170 case ScreenPlacement::CASCADEPLACEMENT:
diff --git a/src/ScreenPlacement.hh b/src/ScreenPlacement.hh
index 4326c91..79d6c21 100644
--- a/src/ScreenPlacement.hh
+++ b/src/ScreenPlacement.hh
@@ -43,8 +43,10 @@ class ScreenPlacement: public PlacementStrategy {
43public: 43public:
44 enum PlacementPolicy { 44 enum PlacementPolicy {
45 ROWSMARTPLACEMENT, 45 ROWSMARTPLACEMENT,
46 COLSMARTPLACEMENT, 46 COLSMARTPLACEMENT,
47 CASCADEPLACEMENT, 47 COLMINOVERLAPPLACEMENT,
48 ROWMINOVERLAPPLACEMENT,
49 CASCADEPLACEMENT,
48 UNDERMOUSEPLACEMENT 50 UNDERMOUSEPLACEMENT
49 }; 51 };
50 52