~ubuntu-branches/ubuntu/trusty/fluxbox/trusty-proposed

« back to all changes in this revision

Viewing changes to src/Container.cc

  • Committer: Bazaar Package Importer
  • Author(s): Dmitry E. Oboukhov
  • Date: 2008-07-01 10:38:14 UTC
  • mfrom: (2.1.12 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080701103814-khx2b6il152x9p93
Tags: 1.0.0+deb1-8
* x-dev has been removed from build-depends (out-of-date package).
* Standards-Version bumped to 3.8.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Container.cc
2
 
// Copyright (c) 2003 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
3
 
//                and Simon Bowden    (rathnor at users.sourceforge.net)
4
 
//
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:
11
 
//
12
 
// The above copyright notice and this permission notice shall be included in
13
 
// all copies or substantial portions of the Software.
14
 
//
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.
22
 
 
23
 
// $Id: Container.cc 4085 2005-07-25 23:17:41Z mathias $
24
 
 
25
 
#include "Container.hh"
26
 
 
27
 
#include "FbTk/Button.hh"
28
 
#include "FbTk/EventManager.hh"
29
 
#include "CompareWindow.hh"
30
 
 
31
 
#include <algorithm>
32
 
 
33
 
Container::Container(const FbTk::FbWindow &parent):
34
 
    FbTk::FbWindow(parent, 0, 0, 1, 1, ExposureMask), 
35
 
    m_align(RELATIVE),
36
 
    m_max_size_per_client(60),
37
 
    m_selected(0),
38
 
    m_update_lock(false) {
39
 
    FbTk::EventManager::instance()->add(*this, *this);
40
 
}
41
 
 
42
 
Container::~Container() {
43
 
    // ~FbWindow cleans event manager
44
 
}
45
 
 
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)
50
 
        return;
51
 
 
52
 
    FbTk::FbWindow::resize(width, height);
53
 
    repositionItems();
54
 
}
55
 
 
56
 
void Container::moveResize(int x, int y,
57
 
                           unsigned int width, unsigned int height) {
58
 
    FbTk::FbWindow::moveResize(x, y, width, height);
59
 
    repositionItems();
60
 
}
61
 
 
62
 
void Container::insertItems(ItemList &item_list, int pos) {
63
 
 
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)
69
 
            return;
70
 
    }
71
 
 
72
 
    if (pos > size() || pos < 0) {
73
 
        // insert last
74
 
        m_item_list.splice(m_item_list.end(), item_list);
75
 
    } else if (pos == 0) {
76
 
        // insert first
77
 
        m_item_list.splice(m_item_list.begin(), item_list);
78
 
    } else {
79
 
        // find insert point
80
 
        for (it = m_item_list.begin(); pos != 0; ++it, --pos)
81
 
            continue;
82
 
        m_item_list.splice(it, item_list);
83
 
    }
84
 
 
85
 
    m_item_list.unique();
86
 
 
87
 
    // update position
88
 
    repositionItems();
89
 
}
90
 
 
91
 
void Container::insertItem(Item item, int pos) {
92
 
    if (find(item) != -1)
93
 
        return;
94
 
 
95
 
    // it must be a child of this window
96
 
    if (item->parent() != this)
97
 
        return;
98
 
 
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);
103
 
    } else {
104
 
        ItemList::iterator it = m_item_list.begin();
105
 
        for (; pos != 0; ++it, --pos)
106
 
            continue;
107
 
 
108
 
        m_item_list.insert(it, item);
109
 
    }
110
 
 
111
 
    // make sure we dont have duplicate items
112
 
    m_item_list.unique();
113
 
 
114
 
    repositionItems();
115
 
}
116
 
 
117
 
void Container::moveItem(Item item, int movement) {
118
 
 
119
 
    int index = find(item);
120
 
    const int size = m_item_list.size();
121
 
 
122
 
    if (index < 0 || (movement % size) == 0) {
123
 
        return;
124
 
    }
125
 
 
126
 
    int newindex = (index + movement) % size;
127
 
    if (newindex < 0) // neg wrap
128
 
        newindex += size;
129
 
 
130
 
    ItemList::iterator it = std::find(m_item_list.begin(), 
131
 
                                      m_item_list.end(), 
132
 
                                      item);
133
 
    m_item_list.erase(it);
134
 
    
135
 
    for (it = m_item_list.begin(); newindex >= 0; ++it, --newindex) {
136
 
        if (newindex == 0) {
137
 
            break;
138
 
        }
139
 
    }
140
 
 
141
 
    m_item_list.insert(it, item);
142
 
    repositionItems();
143
 
}
144
 
 
145
 
// returns true if something was done
146
 
bool Container::moveItemTo(Item item, int x, int y) {
147
 
    Window parent_return=0,
148
 
        root_return=0,
149
 
        *children_return = NULL;
150
 
 
151
 
    unsigned int nchildren_return;
152
 
 
153
 
    // get the root window
154
 
    if (!XQueryTree(display(), window(),
155
 
                    &root_return, &parent_return, &children_return, &nchildren_return))
156
 
        parent_return = parent_return;
157
 
 
158
 
    if (children_return != NULL)
159
 
        XFree(children_return);
160
 
 
161
 
    int dest_x = 0, dest_y = 0;
162
 
    Window itemwin = 0;
163
 
    if (!XTranslateCoordinates(display(),
164
 
                               root_return, window(),
165
 
                               x, y, &dest_x, &dest_y,
166
 
                               &itemwin))
167
 
        return false;
168
 
 
169
 
    ItemList::iterator it = find_if(m_item_list.begin(),
170
 
                                    m_item_list.end(),
171
 
                                    CompareWindow(&FbTk::FbWindow::window,
172
 
                                                  itemwin));
173
 
    // not found :(
174
 
    if (it == m_item_list.end())
175
 
        return false;
176
 
 
177
 
    Window child_return = 0;
178
 
    //make x and y relative to our item
179
 
    if (!XTranslateCoordinates(display(),
180
 
                               window(), itemwin,
181
 
                               dest_x, dest_y, &x, &y,
182
 
                               &child_return))
183
 
        return false;
184
 
    return true;
185
 
}
186
 
 
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);
191
 
 
192
 
    if (it == it_end)
193
 
        return false;
194
 
 
195
 
    m_item_list.erase(it);
196
 
    repositionItems();
197
 
    return true;
198
 
}
199
 
 
200
 
bool Container::removeItem(int index) {
201
 
    if (index < 0 || index > size())
202
 
        return false;
203
 
 
204
 
    ItemList::iterator it = m_item_list.begin();
205
 
    for (; index != 0; ++it, --index)
206
 
        continue;
207
 
 
208
 
    if (*it == selected())
209
 
        m_selected = 0;
210
 
 
211
 
    m_item_list.erase(it);
212
 
 
213
 
    repositionItems();
214
 
    return true;
215
 
}
216
 
 
217
 
void Container::removeAll() {
218
 
    m_selected = 0;
219
 
    m_item_list.clear();
220
 
    if (!m_update_lock) {
221
 
        clear();
222
 
    }
223
 
 
224
 
}
225
 
 
226
 
int Container::find(ConstItem item) {
227
 
    ItemList::iterator it = m_item_list.begin();
228
 
    ItemList::iterator it_end = m_item_list.end();
229
 
    int index = 0;
230
 
    for (; it != it_end; ++it, ++index) {
231
 
        if ((*it) == item)
232
 
            break;
233
 
    }
234
 
 
235
 
    if (it == it_end)
236
 
        return -1;
237
 
 
238
 
    return index;
239
 
}
240
 
 
241
 
void Container::setSelected(int pos) {
242
 
    if (pos < 0 || pos >= size())
243
 
        m_selected = 0;
244
 
    else {
245
 
        ItemList::iterator it = m_item_list.begin();
246
 
        for (; pos != 0; --pos, ++it)
247
 
            continue;
248
 
        m_selected = *it;
249
 
        // caller does any graphics stuff if appropriate
250
 
    }
251
 
        
252
 
}
253
 
 
254
 
void Container::setMaxSizePerClient(unsigned int size) {
255
 
    m_max_size_per_client = size;
256
 
}
257
 
 
258
 
void Container::setAlignment(Container::Alignment a) {
259
 
    m_align = a;
260
 
}
261
 
 
262
 
void Container::exposeEvent(XExposeEvent &event) {
263
 
    if (!m_update_lock) {
264
 
        clearArea(event.x, event.y, event.width, event.height);
265
 
    }
266
 
}
267
 
 
268
 
bool Container::tryExposeEvent(XExposeEvent &event) {
269
 
    if (event.window == window()) {
270
 
        exposeEvent(event);
271
 
        return true;
272
 
    }
273
 
 
274
 
    ItemList::iterator it = find_if(m_item_list.begin(),
275
 
                                    m_item_list.end(),
276
 
                                    CompareWindow(&FbTk::FbWindow::window,
277
 
                                                  event.window));
278
 
    // not found :(
279
 
    if (it == m_item_list.end())
280
 
        return false;
281
 
 
282
 
    (*it)->exposeEvent(event);
283
 
    return true;
284
 
}
285
 
 
286
 
bool Container::tryButtonPressEvent(XButtonEvent &event) {
287
 
    if (event.window == window()) {
288
 
        // we don't have a buttonrelease event atm
289
 
        return true;
290
 
    }
291
 
 
292
 
    ItemList::iterator it = find_if(m_item_list.begin(),
293
 
                                    m_item_list.end(),
294
 
                                    CompareWindow(&FbTk::FbWindow::window,
295
 
                                                  event.window));
296
 
    // not found :(
297
 
    if (it == m_item_list.end())
298
 
        return false;
299
 
 
300
 
    (*it)->buttonPressEvent(event);
301
 
    return true;
302
 
}
303
 
 
304
 
bool Container::tryButtonReleaseEvent(XButtonEvent &event) {
305
 
    if (event.window == window()) {
306
 
        // we don't have a buttonrelease event atm
307
 
        return true;
308
 
    }
309
 
 
310
 
    ItemList::iterator it = find_if(m_item_list.begin(),
311
 
                                    m_item_list.end(),
312
 
                                    CompareWindow(&FbTk::FbWindow::window,
313
 
                                                  event.window));
314
 
    // not found :(
315
 
    if (it == m_item_list.end())
316
 
        return false;
317
 
 
318
 
    (*it)->buttonReleaseEvent(event);
319
 
    return true;
320
 
}
321
 
 
322
 
void Container::repositionItems() {
323
 
    if (empty() || m_update_lock)
324
 
        return;
325
 
 
326
 
    //!! TODO vertical position
327
 
 
328
 
    const int max_width_per_client = maxWidthPerClient();
329
 
 
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();
333
 
 
334
 
    int rounding_error = width() - ((maxWidthPerClient() + borderW)* m_item_list.size() - borderW);
335
 
 
336
 
    int next_x = -borderW; // zero so the border of the first shows
337
 
    int extra = 0;
338
 
    int direction = 1;
339
 
    if (alignment() == RIGHT) {
340
 
        direction = -1;
341
 
        next_x = width() - max_width_per_client + borderW;
342
 
    }
343
 
 
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) {
347
 
            --rounding_error;
348
 
            extra = 1;
349
 
        } else {
350
 
            extra = 0;
351
 
        }
352
 
        // resize each clients including border in size
353
 
        (*it)->moveResize(next_x,
354
 
                          -borderW,
355
 
                          max_width_per_client + extra,
356
 
                          height());
357
 
        // moveresize does a clear
358
 
    }
359
 
 
360
 
}
361
 
 
362
 
 
363
 
unsigned int Container::maxWidthPerClient() const {
364
 
    switch (alignment()) {
365
 
    case RIGHT:
366
 
    case LEFT:
367
 
        return m_max_size_per_client;
368
 
        break;
369
 
    case RELATIVE:
370
 
        int count = size();
371
 
        if (count == 0)
372
 
            return width();
373
 
        else {
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;
378
 
        }
379
 
        break;
380
 
    }
381
 
 
382
 
    // this will never happen anyway
383
 
    return 1;
384
 
}
385
 
 
386
 
void Container::for_each(std::mem_fun_t<void, FbTk::FbWindow> function) {
387
 
    std::for_each(m_item_list.begin(),
388
 
             m_item_list.end(),
389
 
             function);
390
 
}
391
 
 
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);
397
 
}
398
 
 
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)
403
 
        (*it)->clear();
404
 
 
405
 
}