diff options
-rw-r--r-- | src/MinOverlapPlacement.cc | 176 | ||||
-rw-r--r-- | src/MinOverlapPlacement.hh | 44 | ||||
-rw-r--r-- | src/ScreenPlacement.cc | 2 | ||||
-rw-r--r-- | src/ScreenPlacement.hh | 1 |
4 files changed, 108 insertions, 115 deletions
diff --git a/src/MinOverlapPlacement.cc b/src/MinOverlapPlacement.cc index 559ff11..78cadb4 100644 --- a/src/MinOverlapPlacement.cc +++ b/src/MinOverlapPlacement.cc | |||
@@ -25,17 +25,75 @@ | |||
25 | #include "Window.hh" | 25 | #include "Window.hh" |
26 | #include "Screen.hh" | 26 | #include "Screen.hh" |
27 | 27 | ||
28 | ScreenPlacement::PlacementPolicy MinOverlapPlacement::s_policy = ScreenPlacement::ROWMINOVERLAPPLACEMENT; | 28 | namespace { |
29 | ScreenPlacement::RowDirection MinOverlapPlacement::s_row_dir = ScreenPlacement::LEFTRIGHT; | ||
30 | ScreenPlacement::ColumnDirection MinOverlapPlacement::s_col_dir = ScreenPlacement::TOPBOTTOM; | ||
31 | 29 | ||
32 | MinOverlapPlacement::MinOverlapPlacement(ScreenPlacement::PlacementPolicy policy) { | 30 | inline void getWindowDimensions(const FluxboxWindow& win, int& left, int& top, int& right, int& bottom) { |
33 | s_policy = policy; | 31 | |
32 | const int bw = 2 * win.frame().window().borderWidth(); | ||
33 | left = win.x() - win.xOffset(); | ||
34 | top = win.y() - win.yOffset(); | ||
35 | right = left + win.width() + bw + win.widthOffset(); | ||
36 | bottom = top + win.height() + bw + win.heightOffset(); | ||
34 | } | 37 | } |
35 | 38 | ||
39 | class Area { | ||
40 | public: | ||
41 | |||
42 | enum Corner { | ||
43 | TOPLEFT, | ||
44 | TOPRIGHT, | ||
45 | BOTTOMLEFT, | ||
46 | BOTTOMRIGHT | ||
47 | } corner; // indicates the corner of the window that will be placed | ||
48 | |||
49 | Area(Corner _corner, int _x, int _y): | ||
50 | corner(_corner), x(_x), y(_y) { }; | ||
51 | |||
52 | // do all STL set implementations use this for sorting? | ||
53 | bool operator <(const Area &o) const { | ||
54 | switch (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 | static ScreenPlacement::RowDirection s_row_dir; | ||
78 | static ScreenPlacement::ColumnDirection s_col_dir; | ||
79 | static ScreenPlacement::PlacementPolicy s_policy; | ||
80 | }; | ||
81 | |||
82 | ScreenPlacement::RowDirection Area::s_row_dir = ScreenPlacement::LEFTRIGHT; | ||
83 | ScreenPlacement::ColumnDirection Area::s_col_dir = ScreenPlacement::TOPBOTTOM; | ||
84 | ScreenPlacement::PlacementPolicy Area::s_policy = ScreenPlacement::ROWMINOVERLAPPLACEMENT; | ||
85 | |||
86 | } // end of anonymous namespace | ||
87 | |||
88 | |||
36 | bool MinOverlapPlacement::placeWindow(const FluxboxWindow &win, int head, | 89 | bool MinOverlapPlacement::placeWindow(const FluxboxWindow &win, int head, |
37 | int &place_x, int &place_y) { | 90 | int &place_x, int &place_y) { |
38 | 91 | ||
92 | int left; | ||
93 | int top; | ||
94 | int right; | ||
95 | int bottom; | ||
96 | |||
39 | std::list<FluxboxWindow *> windowlist; | 97 | std::list<FluxboxWindow *> windowlist; |
40 | const std::list<Focusable *> focusables = | 98 | const std::list<Focusable *> focusables = |
41 | win.screen().focusControl().focusedOrderWinList().clientList(); | 99 | win.screen().focusControl().focusedOrderWinList().clientList(); |
@@ -56,24 +114,26 @@ bool MinOverlapPlacement::placeWindow(const FluxboxWindow &win, int head, | |||
56 | int head_top = (signed) win.screen().maxTop(head); | 114 | int head_top = (signed) win.screen().maxTop(head); |
57 | int head_bot = (signed) win.screen().maxBottom(head); | 115 | int head_bot = (signed) win.screen().maxBottom(head); |
58 | 116 | ||
59 | const ScreenPlacement &screen_placement = win.screen().placementStrategy(); | ||
60 | s_row_dir = screen_placement.rowDirection(); | ||
61 | s_col_dir = screen_placement.colDirection(); | ||
62 | |||
63 | int win_w = win.normalWidth() + win.fbWindow().borderWidth()*2 + | 117 | int win_w = win.normalWidth() + win.fbWindow().borderWidth()*2 + |
64 | win.widthOffset(); | 118 | win.widthOffset(); |
65 | int win_h = win.normalHeight() + win.fbWindow().borderWidth()*2 + | 119 | int win_h = win.normalHeight() + win.fbWindow().borderWidth()*2 + |
66 | win.heightOffset(); | 120 | win.heightOffset(); |
67 | 121 | ||
68 | // we keep a set of open spaces on the desktop, sorted by size/location | 122 | // we keep a set of open spaces on the desktop, sorted by size/location |
69 | std::set<Region> region_set; | 123 | std::set<Area> areas; |
124 | |||
125 | // setup stuff in order to make Area::operator< work | ||
126 | const ScreenPlacement& p = win.screen().placementStrategy(); | ||
127 | Area::s_policy = p.placementPolicy(); | ||
128 | Area::s_row_dir = p.rowDirection(); | ||
129 | Area::s_col_dir = p.colDirection(); | ||
130 | |||
70 | 131 | ||
71 | // initialize the set of regions to contain the entire head | 132 | // initialize the set of areas to contain the entire head |
72 | region_set.insert(Region(Region::TOPLEFT, head_left, head_top)); | 133 | areas.insert(Area(Area::TOPLEFT, head_left, head_top)); |
73 | region_set.insert(Region(Region::TOPRIGHT, head_right - win_w, head_top)); | 134 | areas.insert(Area(Area::TOPRIGHT, head_right - win_w, head_top)); |
74 | region_set.insert(Region(Region::BOTTOMLEFT, head_left, head_bot - win_h)); | 135 | areas.insert(Area(Area::BOTTOMLEFT, head_left, head_bot - win_h)); |
75 | region_set.insert(Region(Region::BOTTOMRIGHT, head_right - win_w, | 136 | areas.insert(Area(Area::BOTTOMRIGHT, head_right - win_w, head_bot - win_h)); |
76 | head_bot - win_h)); | ||
77 | 137 | ||
78 | // go through the list of windows, creating other reasonable placements | 138 | // go through the list of windows, creating other reasonable placements |
79 | // at the end, we'll find the one with minimum overlap | 139 | // at the end, we'll find the one with minimum overlap |
@@ -85,61 +145,45 @@ bool MinOverlapPlacement::placeWindow(const FluxboxWindow &win, int head, | |||
85 | for (; it != it_end; ++it) { | 145 | for (; it != it_end; ++it) { |
86 | if (*it == &win) continue; | 146 | if (*it == &win) continue; |
87 | 147 | ||
88 | // get the dimensions of the window | 148 | getWindowDimensions(*(*it), left, top, right, bottom); |
89 | int left = (*it)->x() - (*it)->xOffset(); | ||
90 | int top = (*it)->y() - (*it)->yOffset(); | ||
91 | int right = left + (*it)->width() + | ||
92 | 2*(*it)->frame().window().borderWidth() + | ||
93 | (*it)->widthOffset(); | ||
94 | int bottom = top + (*it)->height() + | ||
95 | 2*(*it)->frame().window().borderWidth() + | ||
96 | (*it)->heightOffset(); | ||
97 | 149 | ||
98 | // go through the list of regions | 150 | // go through the list of regions |
99 | // if this window overlaps that region and the new window still fits, | 151 | // if this window overlaps that region and the new window still fits, |
100 | // it will create new regions to test | 152 | // it will create new regions to test |
101 | std::set<Region>::iterator reg_it = region_set.begin(); | 153 | std::set<Area>::iterator ar_it = areas.begin(); |
102 | for (; reg_it != region_set.end(); ++reg_it) { | 154 | for (; ar_it != areas.end(); ++ar_it) { |
103 | 155 | ||
104 | switch (reg_it->corner) { | 156 | switch (ar_it->corner) { |
105 | case Region::TOPLEFT: | 157 | case Area::TOPLEFT: |
106 | if (right > reg_it->x && bottom > reg_it->y) { | 158 | if (right > ar_it->x && bottom > ar_it->y) { |
107 | if (bottom + win_h <= head_bot) | 159 | if (bottom + win_h <= head_bot) |
108 | region_set.insert(Region(Region::TOPLEFT, | 160 | areas.insert(Area(Area::TOPLEFT, ar_it->x, bottom)); |
109 | reg_it->x, bottom)); | ||
110 | if (right + win_w <= head_right) | 161 | if (right + win_w <= head_right) |
111 | region_set.insert(Region(Region::TOPLEFT, | 162 | areas.insert(Area(Area::TOPLEFT, right, ar_it->y)); |
112 | right, reg_it->y)); | ||
113 | } | 163 | } |
114 | break; | 164 | break; |
115 | case Region::TOPRIGHT: | 165 | case Area::TOPRIGHT: |
116 | if (left < reg_it->x + win_w && bottom > reg_it->y) { | 166 | if (left < ar_it->x + win_w && bottom > ar_it->y) { |
117 | if (bottom + win_h <= head_bot) | 167 | if (bottom + win_h <= head_bot) |
118 | region_set.insert(Region(Region::TOPRIGHT, | 168 | areas.insert(Area(Area::TOPRIGHT, ar_it->x, bottom)); |
119 | reg_it->x, bottom)); | ||
120 | if (left - win_w >= head_left) | 169 | if (left - win_w >= head_left) |
121 | region_set.insert(Region(Region::TOPRIGHT, | 170 | areas.insert(Area(Area::TOPRIGHT, left - win_w, ar_it->y)); |
122 | left - win_w, reg_it->y)); | ||
123 | } | 171 | } |
124 | break; | 172 | break; |
125 | case Region::BOTTOMRIGHT: | 173 | case Area::BOTTOMRIGHT: |
126 | if (left < reg_it->x + win_w && top < reg_it->y + win_h) { | 174 | if (left < ar_it->x + win_w && top < ar_it->y + win_h) { |
127 | if (top - win_h >= head_top) | 175 | if (top - win_h >= head_top) |
128 | region_set.insert(Region(Region::BOTTOMRIGHT, | 176 | areas.insert(Area(Area::BOTTOMRIGHT, ar_it->x, top - win_h)); |
129 | reg_it->x, top - win_h)); | ||
130 | if (left - win_w >= head_left) | 177 | if (left - win_w >= head_left) |
131 | region_set.insert(Region(Region::BOTTOMRIGHT, | 178 | areas.insert(Area(Area::BOTTOMRIGHT, left - win_w, ar_it->y)); |
132 | left - win_w, reg_it->y)); | ||
133 | } | 179 | } |
134 | break; | 180 | break; |
135 | case Region::BOTTOMLEFT: | 181 | case Area::BOTTOMLEFT: |
136 | if (right > reg_it->x && top < reg_it->y + win_h) { | 182 | if (right > ar_it->x && top < ar_it->y + win_h) { |
137 | if (top - win_h >= head_top) | 183 | if (top - win_h >= head_top) |
138 | region_set.insert(Region(Region::BOTTOMLEFT, | 184 | areas.insert(Area(Area::BOTTOMLEFT, ar_it->x, top - win_h)); |
139 | reg_it->x, top - win_h)); | ||
140 | if (right + win_w <= head_right) | 185 | if (right + win_w <= head_right) |
141 | region_set.insert(Region(Region::BOTTOMLEFT, | 186 | areas.insert(Area(Area::BOTTOMLEFT, right, ar_it->y)); |
142 | right, reg_it->y)); | ||
143 | } | 187 | } |
144 | break; | 188 | break; |
145 | } | 189 | } |
@@ -149,32 +193,22 @@ bool MinOverlapPlacement::placeWindow(const FluxboxWindow &win, int head, | |||
149 | 193 | ||
150 | // choose the region with minimum overlap | 194 | // choose the region with minimum overlap |
151 | int min_so_far = win_w * win_h * windowlist.size() + 1; | 195 | int min_so_far = win_w * win_h * windowlist.size() + 1; |
152 | std::set<Region>::iterator min_reg = region_set.end(); | 196 | std::set<Area>::iterator min_reg = areas.end(); |
153 | 197 | ||
154 | std::set<Region>::iterator reg_it = region_set.begin(); | 198 | std::set<Area>::iterator ar_it = areas.begin(); |
155 | for (; reg_it != region_set.end(); ++reg_it) { | 199 | for (; ar_it != areas.end(); ++ar_it) { |
156 | 200 | ||
157 | int overlap = 0; | 201 | int overlap = 0; |
158 | it = const_windowlist.rbegin(); | 202 | it = const_windowlist.rbegin(); |
159 | for (; it != it_end; ++it) { | 203 | for (; it != it_end; ++it) { |
160 | 204 | ||
161 | // get the dimensions of the window | 205 | getWindowDimensions(*(*it), left, top, right, bottom); |
162 | int left = (*it)->x() - (*it)->xOffset(); | ||
163 | int top = (*it)->y() - (*it)->yOffset(); | ||
164 | int right = left + (*it)->width() + | ||
165 | 2*(*it)->frame().window().borderWidth() + | ||
166 | (*it)->widthOffset(); | ||
167 | int bottom = top + (*it)->height() + | ||
168 | 2*(*it)->frame().window().borderWidth() + | ||
169 | (*it)->heightOffset(); | ||
170 | 206 | ||
171 | // get the coordinates of the overlap region | 207 | // get the coordinates of the overlap region |
172 | int min_right = (right > reg_it->x + win_w) ? | 208 | int min_right = std::min(right, ar_it->x + win_w); |
173 | reg_it->x + win_w : right; | 209 | int min_bottom = std::min(bottom, ar_it->y + win_h); |
174 | int min_bottom = (bottom > reg_it->y + win_h) ? | 210 | int max_left = std::max(left, ar_it->x); |
175 | reg_it->y + win_h : bottom; | 211 | int max_top = std::max(top, ar_it->y); |
176 | int max_left = (left > reg_it->x) ? left : reg_it->x; | ||
177 | int max_top = (top > reg_it->y) ? top : reg_it->y; | ||
178 | 212 | ||
179 | // now compute the overlap and add to running total | 213 | // now compute the overlap and add to running total |
180 | if (min_right > max_left && min_bottom > max_top) | 214 | if (min_right > max_left && min_bottom > max_top) |
@@ -184,7 +218,7 @@ bool MinOverlapPlacement::placeWindow(const FluxboxWindow &win, int head, | |||
184 | 218 | ||
185 | // if this placement is better, use it | 219 | // if this placement is better, use it |
186 | if (overlap < min_so_far) { | 220 | if (overlap < min_so_far) { |
187 | min_reg = reg_it; | 221 | min_reg = ar_it; |
188 | min_so_far = overlap; | 222 | min_so_far = overlap; |
189 | if (overlap == 0) // can't do better than this | 223 | if (overlap == 0) // can't do better than this |
190 | break; | 224 | break; |
diff --git a/src/MinOverlapPlacement.hh b/src/MinOverlapPlacement.hh index daf49f2..1c741ca 100644 --- a/src/MinOverlapPlacement.hh +++ b/src/MinOverlapPlacement.hh | |||
@@ -26,54 +26,12 @@ | |||
26 | 26 | ||
27 | class MinOverlapPlacement: public PlacementStrategy { | 27 | class MinOverlapPlacement: public PlacementStrategy { |
28 | public: | 28 | public: |
29 | MinOverlapPlacement(ScreenPlacement::PlacementPolicy policy); | 29 | MinOverlapPlacement() { }; |
30 | 30 | ||
31 | bool placeWindow(const FluxboxWindow &win, int head, | 31 | bool placeWindow(const FluxboxWindow &win, int head, |
32 | int &place_x, int &place_y); | 32 | int &place_x, int &place_y); |
33 | 33 | ||
34 | private: | 34 | private: |
35 | class Region { | ||
36 | public: | ||
37 | |||
38 | enum Corner { | ||
39 | TOPLEFT, | ||
40 | TOPRIGHT, | ||
41 | BOTTOMLEFT, | ||
42 | BOTTOMRIGHT | ||
43 | } corner; // indicates the corner of the window that will be placed | ||
44 | |||
45 | Region(Corner _corner, int _x, int _y): | ||
46 | corner(_corner), x(_x), y(_y) { }; | ||
47 | |||
48 | // do all STL set implementations use this for sorting? | ||
49 | bool operator <(const Region &o) const { | ||
50 | switch (MinOverlapPlacement::s_policy) { | ||
51 | case ScreenPlacement::ROWMINOVERLAPPLACEMENT: | ||
52 | // if we're making rows, y-value is most important | ||
53 | if (y != o.y) | ||
54 | return ((y < o.y) ^ (s_col_dir == ScreenPlacement::BOTTOMTOP)); | ||
55 | if (x != o.x) | ||
56 | return ((x < o.x) ^ (s_row_dir == ScreenPlacement::RIGHTLEFT)); | ||
57 | return (corner < o.corner); | ||
58 | case ScreenPlacement::COLMINOVERLAPPLACEMENT: | ||
59 | // if we're making columns, x-value is most important | ||
60 | if (x != o.x) | ||
61 | return ((x < o.x) ^ (s_row_dir == ScreenPlacement::RIGHTLEFT)); | ||
62 | if (y != o.y) | ||
63 | return ((y < o.y) ^ (s_col_dir == ScreenPlacement::BOTTOMTOP)); | ||
64 | return (corner < o.corner); | ||
65 | default: | ||
66 | return false; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // position where the top left corner of the window will be placed | ||
71 | int x, y; | ||
72 | }; | ||
73 | |||
74 | static ScreenPlacement::PlacementPolicy s_policy; | ||
75 | static ScreenPlacement::RowDirection s_row_dir; | ||
76 | static ScreenPlacement::ColumnDirection s_col_dir; | ||
77 | }; | 35 | }; |
78 | 36 | ||
79 | #endif // MINOVERLAPPLACEMENT_HH | 37 | #endif // MINOVERLAPPLACEMENT_HH |
diff --git a/src/ScreenPlacement.cc b/src/ScreenPlacement.cc index 1da1700..73ddfa2 100644 --- a/src/ScreenPlacement.cc +++ b/src/ScreenPlacement.cc | |||
@@ -75,7 +75,7 @@ bool ScreenPlacement::placeWindow(const FluxboxWindow &win, int head, | |||
75 | break; | 75 | break; |
76 | case ROWMINOVERLAPPLACEMENT: | 76 | case ROWMINOVERLAPPLACEMENT: |
77 | case COLMINOVERLAPPLACEMENT: | 77 | case COLMINOVERLAPPLACEMENT: |
78 | m_strategy.reset(new MinOverlapPlacement(*m_placement_policy)); | 78 | m_strategy.reset(new MinOverlapPlacement()); |
79 | break; | 79 | break; |
80 | case CASCADEPLACEMENT: | 80 | case CASCADEPLACEMENT: |
81 | m_strategy.reset(new CascadePlacement(win.screen())); | 81 | m_strategy.reset(new CascadePlacement(win.screen())); |
diff --git a/src/ScreenPlacement.hh b/src/ScreenPlacement.hh index 0e749d4..05db90d 100644 --- a/src/ScreenPlacement.hh +++ b/src/ScreenPlacement.hh | |||
@@ -71,6 +71,7 @@ public: | |||
71 | // places and show 'menu' at 'x','y' | 71 | // places and show 'menu' at 'x','y' |
72 | void placeAndShowMenu(FbTk::Menu& menu, int x, int y, bool respect_struts); | 72 | void placeAndShowMenu(FbTk::Menu& menu, int x, int y, bool respect_struts); |
73 | 73 | ||
74 | PlacementPolicy placementPolicy() const { return *m_placement_policy; } | ||
74 | RowDirection rowDirection() const { return *m_row_direction; } | 75 | RowDirection rowDirection() const { return *m_row_direction; } |
75 | ColumnDirection colDirection() const { return *m_col_direction; } | 76 | ColumnDirection colDirection() const { return *m_col_direction; } |
76 | 77 | ||