2
// Copyright (c) 2003 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
3
// and Simon Bowden (rathnor at users.sourceforge.net)
5
// Permission is hereby granted, free of charge, to any person obtaining a
6
// copy of this software and associated documentation files (the "Software"),
7
// to deal in the Software without restriction, including without limitation
8
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
// and/or sell copies of the Software, and to permit persons to whom the
10
// Software is furnished to do so, subject to the following conditions:
12
// The above copyright notice and this permission notice shall be included in
13
// all copies or substantial portions of the Software.
15
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
// DEALINGS IN THE SOFTWARE.
23
// $Id: Container.cc 4085 2005-07-25 23:17:41Z mathias $
25
#include "Container.hh"
27
#include "FbTk/Button.hh"
28
#include "FbTk/EventManager.hh"
29
#include "CompareWindow.hh"
33
Container::Container(const FbTk::FbWindow &parent):
34
FbTk::FbWindow(parent, 0, 0, 1, 1, ExposureMask),
36
m_max_size_per_client(60),
38
m_update_lock(false) {
39
FbTk::EventManager::instance()->add(*this, *this);
42
Container::~Container() {
43
// ~FbWindow cleans event manager
46
void Container::resize(unsigned int width, unsigned int height) {
47
// do we need to resize?
48
if (FbTk::FbWindow::width() == width &&
49
FbTk::FbWindow::height() == height)
52
FbTk::FbWindow::resize(width, height);
56
void Container::moveResize(int x, int y,
57
unsigned int width, unsigned int height) {
58
FbTk::FbWindow::moveResize(x, y, width, height);
62
void Container::insertItems(ItemList &item_list, int pos) {
64
// make sure all items have parent == this
65
ItemList::iterator it = m_item_list.begin();
66
ItemList::iterator it_end = m_item_list.end();
67
for (; it != it_end; ++it) {
68
if ((*it)->parent() != this)
72
if (pos > size() || pos < 0) {
74
m_item_list.splice(m_item_list.end(), item_list);
75
} else if (pos == 0) {
77
m_item_list.splice(m_item_list.begin(), item_list);
80
for (it = m_item_list.begin(); pos != 0; ++it, --pos)
82
m_item_list.splice(it, item_list);
91
void Container::insertItem(Item item, int pos) {
95
// it must be a child of this window
96
if (item->parent() != this)
99
if (pos >= size() || pos < 0) {
100
m_item_list.push_back(item);
101
} else if (pos == 0) {
102
m_item_list.push_front(item);
104
ItemList::iterator it = m_item_list.begin();
105
for (; pos != 0; ++it, --pos)
108
m_item_list.insert(it, item);
111
// make sure we dont have duplicate items
112
m_item_list.unique();
117
void Container::moveItem(Item item, int movement) {
119
int index = find(item);
120
const int size = m_item_list.size();
122
if (index < 0 || (movement % size) == 0) {
126
int newindex = (index + movement) % size;
127
if (newindex < 0) // neg wrap
130
ItemList::iterator it = std::find(m_item_list.begin(),
133
m_item_list.erase(it);
135
for (it = m_item_list.begin(); newindex >= 0; ++it, --newindex) {
141
m_item_list.insert(it, item);
145
// returns true if something was done
146
bool Container::moveItemTo(Item item, int x, int y) {
147
Window parent_return=0,
149
*children_return = NULL;
151
unsigned int nchildren_return;
153
// get the root window
154
if (!XQueryTree(display(), window(),
155
&root_return, &parent_return, &children_return, &nchildren_return))
156
parent_return = parent_return;
158
if (children_return != NULL)
159
XFree(children_return);
161
int dest_x = 0, dest_y = 0;
163
if (!XTranslateCoordinates(display(),
164
root_return, window(),
165
x, y, &dest_x, &dest_y,
169
ItemList::iterator it = find_if(m_item_list.begin(),
171
CompareWindow(&FbTk::FbWindow::window,
174
if (it == m_item_list.end())
177
Window child_return = 0;
178
//make x and y relative to our item
179
if (!XTranslateCoordinates(display(),
181
dest_x, dest_y, &x, &y,
187
bool Container::removeItem(Item item) {
188
ItemList::iterator it = m_item_list.begin();
189
ItemList::iterator it_end = m_item_list.end();
190
for (; it != it_end && (*it) != item; ++it);
195
m_item_list.erase(it);
200
bool Container::removeItem(int index) {
201
if (index < 0 || index > size())
204
ItemList::iterator it = m_item_list.begin();
205
for (; index != 0; ++it, --index)
208
if (*it == selected())
211
m_item_list.erase(it);
217
void Container::removeAll() {
220
if (!m_update_lock) {
226
int Container::find(ConstItem item) {
227
ItemList::iterator it = m_item_list.begin();
228
ItemList::iterator it_end = m_item_list.end();
230
for (; it != it_end; ++it, ++index) {
241
void Container::setSelected(int pos) {
242
if (pos < 0 || pos >= size())
245
ItemList::iterator it = m_item_list.begin();
246
for (; pos != 0; --pos, ++it)
249
// caller does any graphics stuff if appropriate
254
void Container::setMaxSizePerClient(unsigned int size) {
255
m_max_size_per_client = size;
258
void Container::setAlignment(Container::Alignment a) {
262
void Container::exposeEvent(XExposeEvent &event) {
263
if (!m_update_lock) {
264
clearArea(event.x, event.y, event.width, event.height);
268
bool Container::tryExposeEvent(XExposeEvent &event) {
269
if (event.window == window()) {
274
ItemList::iterator it = find_if(m_item_list.begin(),
276
CompareWindow(&FbTk::FbWindow::window,
279
if (it == m_item_list.end())
282
(*it)->exposeEvent(event);
286
bool Container::tryButtonPressEvent(XButtonEvent &event) {
287
if (event.window == window()) {
288
// we don't have a buttonrelease event atm
292
ItemList::iterator it = find_if(m_item_list.begin(),
294
CompareWindow(&FbTk::FbWindow::window,
297
if (it == m_item_list.end())
300
(*it)->buttonPressEvent(event);
304
bool Container::tryButtonReleaseEvent(XButtonEvent &event) {
305
if (event.window == window()) {
306
// we don't have a buttonrelease event atm
310
ItemList::iterator it = find_if(m_item_list.begin(),
312
CompareWindow(&FbTk::FbWindow::window,
315
if (it == m_item_list.end())
318
(*it)->buttonReleaseEvent(event);
322
void Container::repositionItems() {
323
if (empty() || m_update_lock)
326
//!! TODO vertical position
328
const int max_width_per_client = maxWidthPerClient();
330
ItemList::iterator it = m_item_list.begin();
331
const ItemList::iterator it_end = m_item_list.end();
332
int borderW = m_item_list.front()->borderWidth();
334
int rounding_error = width() - ((maxWidthPerClient() + borderW)* m_item_list.size() - borderW);
336
int next_x = -borderW; // zero so the border of the first shows
339
if (alignment() == RIGHT) {
341
next_x = width() - max_width_per_client + borderW;
344
for (; it != it_end; ++it, next_x += direction*(max_width_per_client + borderW + extra)) {
345
// we only need to do error stuff with alignment RELATIVE
346
if (rounding_error != 0 && alignment() == RELATIVE) {
352
// resize each clients including border in size
353
(*it)->moveResize(next_x,
355
max_width_per_client + extra,
357
// moveresize does a clear
363
unsigned int Container::maxWidthPerClient() const {
364
switch (alignment()) {
367
return m_max_size_per_client;
374
int borderW = m_item_list.front()->borderWidth();
375
// there're count-1 borders to fit in with the windows
376
// -> 1 per window plus end
377
return (width() - (count - 1) * borderW) / count;
382
// this will never happen anyway
386
void Container::for_each(std::mem_fun_t<void, FbTk::FbWindow> function) {
387
std::for_each(m_item_list.begin(),
392
void Container::setAlpha(unsigned char alpha) {
393
ItemList::iterator it = m_item_list.begin();
394
ItemList::iterator it_end = m_item_list.end();
395
for (; it != it_end; ++it)
396
(*it)->setAlpha(alpha);
399
void Container::clear() {
400
ItemList::iterator it = m_item_list.begin();
401
ItemList::iterator it_end = m_item_list.end();
402
for (; it != it_end; ++it)