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

« back to all changes in this revision

Viewing changes to src/Toolbar.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
 
// Toolbar.cc for Fluxbox
2
 
// Copyright (c) 2002 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
3
 
//
4
 
// Toolbar.cc for Blackbox - an X11 Window manager
5
 
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
6
 
//
7
 
// Permission is hereby granted, free of charge, to any person obtaining a
8
 
// copy of this software and associated documentation files (the "Software"),
9
 
// to deal in the Software without restriction, including without limitation
10
 
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 
// and/or sell copies of the Software, and to permit persons to whom the
12
 
// Software is furnished to do so, subject to the following conditions:
13
 
//
14
 
// The above copyright notice and this permission notice shall be included in
15
 
// all copies or substantial portions of the Software.
16
 
//
17
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
 
// DEALINGS IN THE SOFTWARE.
24
 
 
25
 
// $Id: Toolbar.cc 4068 2005-06-28 10:16:59Z mathias $
26
 
 
27
 
#include "Toolbar.hh"
28
 
 
29
 
// tool
30
 
#include "ToolbarItem.hh"
31
 
 
32
 
// themes
33
 
#include "ToolbarTheme.hh"
34
 
 
35
 
#include "FbTk/I18n.hh"
36
 
#include "fluxbox.hh"
37
 
#include "Screen.hh"
38
 
#include "IntResMenuItem.hh"
39
 
#include "BoolMenuItem.hh"
40
 
#include "Xinerama.hh"
41
 
#include "Strut.hh"
42
 
#include "CommandParser.hh"
43
 
 
44
 
#include "FbTk/ImageControl.hh"
45
 
#include "FbTk/MacroCommand.hh"
46
 
#include "FbTk/EventManager.hh"
47
 
#include "FbTk/SimpleCommand.hh"
48
 
#include "FbTk/StringUtil.hh"
49
 
#include "FbTk/Transparent.hh"
50
 
 
51
 
 
52
 
// use GNU extensions
53
 
#ifndef  _GNU_SOURCE
54
 
#define  _GNU_SOURCE
55
 
#endif // _GNU_SOURCE
56
 
 
57
 
#ifdef HAVE_CONFIG_H
58
 
#include "config.h"
59
 
#endif // HAVE_CONFIG_H
60
 
 
61
 
#include "Shape.hh"
62
 
 
63
 
#include <X11/Xutil.h>
64
 
#include <X11/keysym.h>
65
 
 
66
 
#ifdef HAVE_CSTRING
67
 
  #include <cstring>
68
 
#else
69
 
  #include <string.h>
70
 
#endif
71
 
#include <iterator>
72
 
#include <typeinfo>
73
 
 
74
 
using namespace std;
75
 
 
76
 
namespace FbTk {
77
 
 
78
 
template<>
79
 
void FbTk::Resource<Toolbar::Placement>::
80
 
setFromString(const char *strval) {
81
 
    if (strcasecmp(strval, "TopLeft")==0)
82
 
        m_value = Toolbar::TOPLEFT;
83
 
    else if (strcasecmp(strval, "BottomLeft")==0)
84
 
        m_value = Toolbar::BOTTOMLEFT;
85
 
    else if (strcasecmp(strval, "TopCenter")==0)
86
 
        m_value = Toolbar::TOPCENTER;
87
 
    else if (strcasecmp(strval, "BottomCenter")==0)
88
 
        m_value = Toolbar::BOTTOMCENTER;
89
 
    else if (strcasecmp(strval, "TopRight")==0)
90
 
        m_value = Toolbar::TOPRIGHT;
91
 
    else if (strcasecmp(strval, "BottomRight")==0)
92
 
        m_value = Toolbar::BOTTOMRIGHT;
93
 
    else if (strcasecmp(strval, "LeftTop") == 0)
94
 
        m_value = Toolbar::LEFTTOP;
95
 
    else if (strcasecmp(strval, "LeftCenter") == 0)
96
 
        m_value = Toolbar::LEFTCENTER;
97
 
    else if (strcasecmp(strval, "LeftBottom") == 0)
98
 
        m_value = Toolbar::LEFTBOTTOM;
99
 
    else if (strcasecmp(strval, "RightTop") == 0)
100
 
        m_value = Toolbar::RIGHTTOP;
101
 
    else if (strcasecmp(strval, "RightCenter") == 0)
102
 
        m_value = Toolbar::RIGHTCENTER;
103
 
    else if (strcasecmp(strval, "RightBottom") == 0)
104
 
        m_value = Toolbar::RIGHTBOTTOM;
105
 
    else
106
 
        setDefaultValue();
107
 
}
108
 
 
109
 
template<>
110
 
string FbTk::Resource<Toolbar::Placement>::
111
 
getString() {
112
 
    switch (m_value) {
113
 
    case Toolbar::TOPLEFT:
114
 
        return string("TopLeft");
115
 
        break;
116
 
    case Toolbar::BOTTOMLEFT:
117
 
        return string("BottomLeft");
118
 
        break;
119
 
    case Toolbar::TOPCENTER:
120
 
        return string("TopCenter");
121
 
        break;
122
 
    case Toolbar::BOTTOMCENTER:
123
 
        return string("BottomCenter");
124
 
        break;
125
 
    case Toolbar::TOPRIGHT:
126
 
        return string("TopRight");
127
 
        break;
128
 
    case Toolbar::BOTTOMRIGHT:
129
 
        return string("BottomRight");
130
 
        break;
131
 
    case Toolbar::LEFTTOP:
132
 
        return string("LeftTop");
133
 
        break;
134
 
    case Toolbar::LEFTCENTER:
135
 
        return string("LeftCenter");
136
 
        break;
137
 
    case Toolbar::LEFTBOTTOM:
138
 
        return string("LeftBottom");
139
 
        break;
140
 
    case Toolbar::RIGHTTOP:
141
 
        return string("RightTop");
142
 
        break;
143
 
    case Toolbar::RIGHTCENTER:
144
 
        return string("RightCenter");
145
 
        break;
146
 
    case Toolbar::RIGHTBOTTOM:
147
 
        return string("RightBottom");
148
 
        break;
149
 
    }
150
 
    //default string
151
 
    return string("BottomCenter");
152
 
}
153
 
 
154
 
}
155
 
 
156
 
namespace {
157
 
class SetToolbarPlacementCmd: public FbTk::Command {
158
 
public:
159
 
    SetToolbarPlacementCmd(Toolbar &tbar, Toolbar::Placement place):m_tbar(tbar), m_place(place) { }
160
 
    void execute() {
161
 
        m_tbar.setPlacement(m_place);
162
 
        m_tbar.reconfigure();
163
 
        Fluxbox::instance()->save_rc();
164
 
    }
165
 
private:
166
 
    Toolbar &m_tbar;
167
 
    Toolbar::Placement m_place;
168
 
};
169
 
 
170
 
}; // end anonymous
171
 
 
172
 
// toolbar frame
173
 
Toolbar::Frame::Frame(FbTk::EventHandler &evh, int screen_num):
174
 
    window(screen_num, // screen (parent)
175
 
           0, 0, // pos
176
 
           10, 10, // size
177
 
           // event mask
178
 
           ButtonPressMask | ButtonReleaseMask | ExposureMask |
179
 
           EnterWindowMask | LeaveWindowMask | SubstructureNotifyMask,
180
 
 
181
 
           true) // override redirect
182
 
{
183
 
 
184
 
    FbTk::EventManager &evm = *FbTk::EventManager::instance();
185
 
    // add windows to eventmanager
186
 
    evm.add(evh, window);
187
 
 
188
 
}
189
 
 
190
 
Toolbar::Frame::~Frame() {
191
 
    FbTk::EventManager &evm = *FbTk::EventManager::instance();
192
 
    // remove windows from eventmanager
193
 
    evm.remove(window);
194
 
}
195
 
 
196
 
Toolbar::Toolbar(BScreen &scrn, FbTk::XLayer &layer, size_t width):
197
 
    m_hidden(false),
198
 
    frame(*this, scrn.screenNumber()),
199
 
    m_window_pm(0),
200
 
    m_screen(scrn),
201
 
    m_layeritem(frame.window, layer),
202
 
    m_layermenu(scrn.menuTheme(),
203
 
                scrn.imageControl(),
204
 
                *scrn.layerManager().getLayer(Fluxbox::instance()->getMenuLayer()),
205
 
                this,
206
 
                true),
207
 
    m_placementmenu(scrn.menuTheme(),
208
 
                    scrn.imageControl(),
209
 
                    *scrn.layerManager().getLayer(Fluxbox::instance()->getMenuLayer())),
210
 
    m_toolbarmenu(scrn.menuTheme(),
211
 
                  scrn.imageControl(),
212
 
                  *scrn.layerManager().getLayer(Fluxbox::instance()->getMenuLayer())),
213
 
    m_theme(scrn.screenNumber()),
214
 
    m_tool_factory(scrn),
215
 
    m_strut(0),
216
 
    // lock rcmanager here
217
 
    m_rc_auto_hide(scrn.resourceManager().lock(), false,
218
 
                   scrn.name() + ".toolbar.autoHide", scrn.altName() + ".Toolbar.AutoHide"),
219
 
    m_rc_maximize_over(scrn.resourceManager(), false,
220
 
                       scrn.name() + ".toolbar.maxOver", scrn.altName() + ".Toolbar.MaxOver"),
221
 
    m_rc_visible(scrn.resourceManager(), true, scrn.name() + ".toolbar.visible", scrn.altName() + ".Toolbar.Visible"),
222
 
    m_rc_width_percent(scrn.resourceManager(), 65,
223
 
                       scrn.name() + ".toolbar.widthPercent", scrn.altName() + ".Toolbar.WidthPercent"),
224
 
    m_rc_alpha(scrn.resourceManager(), 255,
225
 
                       scrn.name() + ".toolbar.alpha", scrn.altName() + ".Toolbar.Alpha"),
226
 
    m_rc_layernum(scrn.resourceManager(), Fluxbox::Layer(Fluxbox::instance()->getDesktopLayer()),
227
 
                  scrn.name() + ".toolbar.layer", scrn.altName() + ".Toolbar.Layer"),
228
 
    m_rc_on_head(scrn.resourceManager(), 0,
229
 
                 scrn.name() + ".toolbar.onhead", scrn.altName() + ".Toolbar.onHead"),
230
 
    m_rc_placement(scrn.resourceManager(), Toolbar::BOTTOMCENTER,
231
 
                   scrn.name() + ".toolbar.placement", scrn.altName() + ".Toolbar.Placement"),
232
 
    m_rc_height(scrn.resourceManager(), 0, scrn.name() + ".toolbar.height", scrn.altName() + ".Toolbar.Height"),
233
 
    m_rc_tools(scrn.resourceManager(), "workspacename, prevworkspace, nextworkspace, iconbar, systemtray, prevwindow, nextwindow, clock",
234
 
               scrn.name() + ".toolbar.tools", scrn.altName() + ".Toolbar.Tools"),
235
 
    m_shape(new Shape(frame.window, 0)),
236
 
    m_resize_lock(false) {
237
 
    _FB_USES_NLS;
238
 
    // we need to get notified when the theme is reloaded
239
 
    m_theme.reconfigSig().attach(this);
240
 
    // listen to screen size changes
241
 
    screen().resizeSig().attach(this);
242
 
    screen().reconfigureSig().attach(this); // get this on antialias change
243
 
 
244
 
    moveToLayer((*m_rc_layernum).getNum());
245
 
 
246
 
    m_layermenu.setLabel(_FBTEXT(Toolbar, Layer, "Toolbar Layer", "Title of toolbar layer menu"));
247
 
    m_placementmenu.setLabel(_FBTEXT(Toolbar, Placement, "Toolbar Placement", "Title of toolbar placement menu"));
248
 
 
249
 
    m_layermenu.setInternalMenu();
250
 
    m_placementmenu.setInternalMenu();
251
 
    setupMenus();
252
 
    // add menu to screen
253
 
    screen().addConfigMenu(_FBTEXT(Toolbar, Toolbar, "Toolbar", "title of toolbar menu item"), menu());
254
 
 
255
 
    // geometry settings
256
 
    frame.width = width;
257
 
    frame.height = 10;
258
 
    frame.bevel_w = 1;
259
 
    frame.grab_x = frame.grab_y = 0;
260
 
 
261
 
    // setup hide timer
262
 
    m_hide_timer.setTimeout(Fluxbox::instance()->getAutoRaiseDelay());
263
 
    FbTk::RefCount<FbTk::Command> toggle_hidden(new FbTk::SimpleCommand<Toolbar>(*this, &Toolbar::toggleHidden));
264
 
    m_hide_timer.setCommand(toggle_hidden);
265
 
    m_hide_timer.fireOnce(true);
266
 
 
267
 
 
268
 
    // show all windows
269
 
    frame.window.showSubwindows();
270
 
    //    frame.window.show();
271
 
 
272
 
    scrn.resourceManager().unlock();
273
 
    // setup to listen to child events
274
 
    FbTk::EventManager::instance()->addParent(*this, window());
275
 
    // get everything together
276
 
    reconfigure();
277
 
    // this gets done by the screen later as it loads
278
 
 
279
 
}
280
 
 
281
 
Toolbar::~Toolbar() {
282
 
    FbTk::EventManager::instance()->remove(window());
283
 
    // remove menu items before we delete tools so we dont end up
284
 
    // with dangling pointers to old submenu items (internal menus)
285
 
    // from the tools
286
 
    menu().removeAll();
287
 
 
288
 
    deleteItems();
289
 
    clearStrut();
290
 
 
291
 
    if (m_window_pm)
292
 
        screen().imageControl().removeImage(m_window_pm);
293
 
}
294
 
 
295
 
void Toolbar::clearStrut() {
296
 
    if (m_strut) {
297
 
        screen().clearStrut(m_strut);
298
 
        m_strut = 0;
299
 
    }
300
 
}
301
 
 
302
 
void Toolbar::updateStrut() {
303
 
 
304
 
    bool had_strut = m_strut ? true : false;
305
 
    clearStrut();
306
 
    // we should request space if we're in autohide mode or
307
 
    // if the user dont want to request space for toolbar.
308
 
    if (doAutoHide() || *m_rc_maximize_over || ! *m_rc_visible) {
309
 
        if (had_strut)
310
 
            screen().updateAvailableWorkspaceArea();
311
 
        return;
312
 
    }
313
 
 
314
 
    // request area on screen
315
 
    int top = 0, bottom = 0, left = 0, right = 0;
316
 
    switch (placement()) {
317
 
    case TOPLEFT:
318
 
    case TOPCENTER:
319
 
    case TOPRIGHT:
320
 
        top = height() + 2 * theme().border().width();
321
 
        break;
322
 
    case BOTTOMLEFT:
323
 
    case BOTTOMCENTER:
324
 
    case BOTTOMRIGHT:
325
 
        bottom = height() + 2 * theme().border().width();
326
 
        break;
327
 
    case RIGHTTOP:
328
 
    case RIGHTCENTER:
329
 
    case RIGHTBOTTOM:
330
 
        right = width() + 2 * theme().border().width();
331
 
        break;
332
 
    case LEFTTOP:
333
 
    case LEFTCENTER:
334
 
    case LEFTBOTTOM:
335
 
        left = width() + 2 * theme().border().width();
336
 
        break;
337
 
    };
338
 
    m_strut = screen().requestStrut(getOnHead(), left, right, top, bottom);
339
 
    screen().updateAvailableWorkspaceArea();
340
 
}
341
 
 
342
 
bool Toolbar::isVertical() const {
343
 
    return (placement() == RIGHTCENTER ||
344
 
            placement() == RIGHTTOP ||
345
 
            placement() == RIGHTBOTTOM ||
346
 
            placement() == LEFTCENTER ||
347
 
            placement() == LEFTTOP ||
348
 
            placement() == LEFTBOTTOM);
349
 
}
350
 
 
351
 
 
352
 
void Toolbar::raise() {
353
 
    m_layeritem.raise();
354
 
}
355
 
 
356
 
void Toolbar::lower() {
357
 
    m_layeritem.lower();
358
 
}
359
 
 
360
 
void Toolbar::reconfigure() {
361
 
    //    updateVisibleState();
362
 
 
363
 
    if (!doAutoHide() && isHidden())
364
 
        toggleHidden();
365
 
 
366
 
    m_tool_factory.updateThemes();
367
 
 
368
 
    // parse resource tools and determine if we need to rebuild toolbar
369
 
 
370
 
    bool need_update = false;
371
 
    // parse and transform to lower case
372
 
    std::list<std::string> tools;
373
 
    FbTk::StringUtil::stringtok(tools, *m_rc_tools, ", ");
374
 
    transform(tools.begin(),
375
 
              tools.end(),
376
 
              tools.begin(),
377
 
              FbTk::StringUtil::toLower);
378
 
 
379
 
    if (!tools.empty() && tools.size() == m_tools.size()) {
380
 
        StringList::const_iterator tool_it = tools.begin();
381
 
        StringList::const_iterator current_tool_it = m_tools.begin();
382
 
        StringList::const_iterator tool_it_end = tools.end();
383
 
        for (; tool_it != tool_it_end; ++tool_it, ++current_tool_it) {
384
 
            if (*current_tool_it != *tool_it)
385
 
                break;
386
 
        }
387
 
        // did we find anything that wasn't in the right place or new item?
388
 
        if (tool_it != tool_it_end)
389
 
            need_update = true;
390
 
    } else // sizes does not match so we update
391
 
        need_update = true;
392
 
 
393
 
    if (need_update) {
394
 
 
395
 
        // destroy tools and rebuild them
396
 
        deleteItems();
397
 
 
398
 
        m_tools = tools; // copy values
399
 
 
400
 
        if (m_tools.size()) {
401
 
            // make lower case
402
 
            transform(m_tools.begin(), m_tools.end(),
403
 
                      m_tools.begin(),
404
 
                      FbTk::StringUtil::toLower);
405
 
 
406
 
            // create items
407
 
            StringList::const_iterator item_it = m_tools.begin();
408
 
            StringList::const_iterator item_it_end = m_tools.end();
409
 
            for (; item_it != item_it_end; ++item_it) {
410
 
                ToolbarItem *item = m_tool_factory.create(*item_it, frame.window, *this);
411
 
                if (item == 0)
412
 
                    continue;
413
 
                m_item_list.push_back(item);
414
 
                item->resizeSig().attach(this);
415
 
 
416
 
            }
417
 
            // show all items
418
 
            frame.window.showSubwindows();
419
 
        }
420
 
    }
421
 
 
422
 
    if (doAutoHide())
423
 
        m_hide_timer.start();
424
 
 
425
 
    frame.bevel_w = theme().bevelWidth();
426
 
    // destroy shape if the theme wasn't specified with one,
427
 
    // or create one
428
 
    if (theme().shape() == false && m_shape.get())
429
 
        m_shape.reset(0);
430
 
    else if (theme().shape() && m_shape.get() == 0) {
431
 
        m_shape.reset(new Shape(frame.window, 0));
432
 
    }
433
 
 
434
 
    // recalibrate size
435
 
    setPlacement(placement());
436
 
 
437
 
    if (isHidden()) {
438
 
        frame.window.moveResize(frame.x_hidden, frame.y_hidden,
439
 
                                frame.width, frame.height);
440
 
    } else {
441
 
        frame.window.moveResize(frame.x, frame.y,
442
 
                                frame.width, frame.height);
443
 
    }
444
 
 
445
 
    // render frame window
446
 
    Pixmap tmp = m_window_pm;
447
 
    if (!theme().toolbar().usePixmap()) {
448
 
        m_window_pm = 0;
449
 
        frame.window.setBackgroundColor(theme().toolbar().color());
450
 
    } else {
451
 
        m_window_pm = screen().imageControl().renderImage(frame.window.width(), frame.window.height(),
452
 
                                                          theme().toolbar());
453
 
        frame.window.setBackgroundPixmap(m_window_pm);
454
 
    }
455
 
    if (tmp)
456
 
        screen().imageControl().removeImage(tmp);
457
 
 
458
 
    frame.window.setBorderColor(theme().border().color());
459
 
    frame.window.setBorderWidth(theme().border().width());
460
 
 
461
 
    bool have_composite = FbTk::Transparent::haveComposite();
462
 
    if (have_composite) {
463
 
        frame.window.setOpaque(alpha());
464
 
    } else {
465
 
        frame.window.setAlpha(alpha());
466
 
    }
467
 
    frame.window.clear();
468
 
 
469
 
    if (theme().shape() && m_shape.get())
470
 
        m_shape->update();
471
 
 
472
 
    ItemList::iterator item_it = m_item_list.begin();
473
 
    ItemList::iterator item_it_end = m_item_list.end();
474
 
    for (; item_it != item_it_end; ++item_it) {
475
 
        (*item_it)->updateSizing();
476
 
    }
477
 
 
478
 
    rearrangeItems();
479
 
 
480
 
    for (item_it = m_item_list.begin(); item_it != item_it_end; ++item_it) {
481
 
        (*item_it)->renderTheme(alpha());
482
 
    }
483
 
 
484
 
    menu().reconfigure();
485
 
    // we're done with all resizing and stuff now we can request a new
486
 
    // area to be reserved on screen
487
 
    updateStrut();
488
 
 
489
 
}
490
 
 
491
 
 
492
 
 
493
 
void Toolbar::buttonPressEvent(XButtonEvent &be) {
494
 
    if (be.button != 3)
495
 
        return;
496
 
 
497
 
    screen().hideMenus();
498
 
 
499
 
    if (! menu().isVisible()) {
500
 
 
501
 
        int head = screen().getHead(be.x_root, be.y_root);
502
 
        int borderw = menu().fbwindow().borderWidth();
503
 
        pair<int, int> m = screen().clampToHead(head,
504
 
                                                be.x_root - (menu().width() / 2),
505
 
                                                be.y_root - (menu().titleWindow().height() / 2),
506
 
                                                menu().width() + 2*borderw,
507
 
                                                menu().height() + 2*borderw);
508
 
 
509
 
        menu().setScreen(screen().getHeadX(head),
510
 
                         screen().getHeadY(head),
511
 
                         screen().getHeadWidth(head),
512
 
                         screen().getHeadHeight(head));
513
 
        menu().move(m.first, m.second);
514
 
        menu().show();
515
 
        menu().grabInputFocus();
516
 
    } else
517
 
        menu().hide();
518
 
 
519
 
}
520
 
 
521
 
 
522
 
void Toolbar::buttonReleaseEvent(XButtonEvent &re) {
523
 
    if (re.button == 1)
524
 
        raise();
525
 
    else if (re.button == 4) //mousewheel scroll up
526
 
        screen().nextWorkspace(1);
527
 
    else if (re.button == 5)    //mousewheel scroll down
528
 
        screen().prevWorkspace(1);
529
 
}
530
 
 
531
 
void Toolbar::enterNotifyEvent(XCrossingEvent &not_used) {
532
 
    if (! doAutoHide()) {
533
 
        if (isHidden())
534
 
            toggleHidden();
535
 
        return;
536
 
    }
537
 
 
538
 
    if (isHidden()) {
539
 
        if (! m_hide_timer.isTiming())
540
 
            m_hide_timer.start();
541
 
    } else {
542
 
        if (m_hide_timer.isTiming())
543
 
            m_hide_timer.stop();
544
 
    }
545
 
}
546
 
 
547
 
void Toolbar::leaveNotifyEvent(XCrossingEvent &event) {
548
 
    if (! doAutoHide())
549
 
        return;
550
 
    // still inside?
551
 
    if (event.x_root > x() && event.x_root <= (int)(x() + width()) &&
552
 
        event.y_root > y() && event.y_root <= (int)(y() + height()))
553
 
        return;
554
 
 
555
 
    if (isHidden()) {
556
 
        if (m_hide_timer.isTiming())
557
 
            m_hide_timer.stop();
558
 
    } else if (! menu().isVisible() && ! m_hide_timer.isTiming())
559
 
        m_hide_timer.start();
560
 
 
561
 
}
562
 
 
563
 
 
564
 
void Toolbar::exposeEvent(XExposeEvent &ee) {
565
 
    if (ee.window == frame.window) {
566
 
        frame.window.clearArea(ee.x, ee.y,
567
 
                               ee.width, ee.height);
568
 
    }
569
 
}
570
 
 
571
 
 
572
 
void Toolbar::handleEvent(XEvent &event) {
573
 
    /* Commented out by Simon 16jun04, since it causes LOTS of rearrangeItems
574
 
       particularly on startup. This was needed to resize when tool changes its own
575
 
       size, but it has too many side effects. Use the resizeSig in ToolbarItem instead.
576
 
 
577
 
    if (event.type == ConfigureNotify &&
578
 
        event.xconfigure.window != window().window()) {
579
 
        rearrangeItems();
580
 
    }
581
 
*/
582
 
}
583
 
 
584
 
void Toolbar::update(FbTk::Subject *subj) {
585
 
 
586
 
    // either screen reconfigured, theme was reloaded
587
 
    // or a tool resized itself
588
 
 
589
 
    if (typeid(*subj) == typeid(ToolbarItem::ToolbarItemSubject))
590
 
        rearrangeItems();
591
 
    else
592
 
        reconfigure();
593
 
 
594
 
}
595
 
 
596
 
void Toolbar::setPlacement(Toolbar::Placement where) {
597
 
    // disable vertical toolbar
598
 
    switch (where) {
599
 
    case LEFTTOP:
600
 
    case LEFTCENTER:
601
 
    case LEFTBOTTOM:
602
 
    case RIGHTTOP:
603
 
    case RIGHTCENTER:
604
 
    case RIGHTBOTTOM:
605
 
        where = BOTTOMCENTER;
606
 
        break;
607
 
    default:
608
 
        break;
609
 
    }
610
 
 
611
 
    *m_rc_placement = where;
612
 
    int head_x = 0,
613
 
        head_y = 0,
614
 
        head_w = screen().width(),
615
 
        head_h = screen().height();
616
 
 
617
 
    if (screen().hasXinerama()) {
618
 
        int head = *m_rc_on_head;
619
 
        head_x = screen().getHeadX(head);
620
 
        head_y = screen().getHeadY(head);
621
 
        head_w = screen().getHeadWidth(head);
622
 
        head_h = screen().getHeadHeight(head);
623
 
    }
624
 
 
625
 
    int bevel_width = theme().bevelWidth();
626
 
    int border_width = theme().border().width();
627
 
 
628
 
    frame.width = (head_w - 2*border_width) * (*m_rc_width_percent) / 100;
629
 
    //!! TODO: change this
630
 
    // max height of each toolbar items font...
631
 
    unsigned int max_height = m_tool_factory.maxFontHeight();
632
 
 
633
 
    if (theme().height() > 0)
634
 
        max_height = theme().height();
635
 
 
636
 
    if (*m_rc_height > 0 && *m_rc_height < 100)
637
 
        max_height = *m_rc_height;
638
 
 
639
 
    frame.height = max_height;
640
 
 
641
 
    frame.height += 2;
642
 
    frame.height += (frame.bevel_w * 2);
643
 
 
644
 
    // should we flipp sizes?
645
 
    if (isVertical()) {
646
 
        frame.width = frame.height;
647
 
        frame.height = head_h * (*m_rc_width_percent) / 100;
648
 
 
649
 
    } // else horizontal toolbar
650
 
 
651
 
 
652
 
    // So we get at least one pixel visible in hidden mode
653
 
    if (bevel_width <= border_width)
654
 
        bevel_width = border_width + 1;
655
 
 
656
 
    switch (where) {
657
 
    case TOPLEFT:
658
 
        frame.x = head_x;
659
 
        frame.y = head_y;
660
 
        frame.x_hidden = head_x;
661
 
        frame.y_hidden = head_y + bevel_width - border_width - frame.height;
662
 
        if (m_shape.get())
663
 
            m_shape->setPlaces(Shape::BOTTOMRIGHT | Shape::BOTTOMLEFT);
664
 
        break;
665
 
 
666
 
    case BOTTOMLEFT:
667
 
        frame.x = head_x;
668
 
        frame.y = head_y + head_h - frame.height - border_width*2;
669
 
        frame.x_hidden = head_x;
670
 
        frame.y_hidden = head_y + head_h - bevel_width - border_width;
671
 
        if (m_shape.get())
672
 
            m_shape->setPlaces(Shape::TOPRIGHT | Shape::TOPLEFT);
673
 
        break;
674
 
 
675
 
    case TOPCENTER:
676
 
        frame.x = head_x + (head_w - frame.width) / 2 - border_width;
677
 
        frame.y = head_y;
678
 
        frame.x_hidden = frame.x;
679
 
        frame.y_hidden = head_y + bevel_width - border_width - frame.height;
680
 
        if (m_shape.get())
681
 
            m_shape->setPlaces(Shape::BOTTOMRIGHT | Shape::BOTTOMLEFT);
682
 
        break;
683
 
    case TOPRIGHT:
684
 
        frame.x = head_x + head_w - frame.width - border_width*2;
685
 
        frame.y = head_y;
686
 
        frame.x_hidden = frame.x;
687
 
        frame.y_hidden = head_y + bevel_width - border_width - frame.height;
688
 
        if (m_shape.get())
689
 
            m_shape->setPlaces(Shape::BOTTOMRIGHT | Shape::BOTTOMLEFT);
690
 
        break;
691
 
 
692
 
    case BOTTOMRIGHT:
693
 
        frame.x = head_x + head_w - frame.width - border_width*2;
694
 
        frame.y = head_y + head_h - frame.height - border_width*2;
695
 
        frame.x_hidden = frame.x;
696
 
        frame.y_hidden = head_y + head_h - bevel_width - border_width;
697
 
        if (m_shape.get())
698
 
            m_shape->setPlaces(Shape::TOPRIGHT | Shape::TOPLEFT);
699
 
        break;
700
 
 
701
 
    case BOTTOMCENTER: // default is BOTTOMCENTER
702
 
    default:
703
 
        frame.x = head_x + (head_w - frame.width) / 2 - border_width;
704
 
        frame.y = head_y + head_h - frame.height - border_width*2;
705
 
        frame.x_hidden = frame.x;
706
 
        frame.y_hidden = head_y + head_h - bevel_width - border_width;
707
 
        if (m_shape.get())
708
 
            m_shape->setPlaces(Shape::TOPRIGHT | Shape::TOPLEFT);
709
 
        break;
710
 
    case LEFTCENTER:
711
 
        frame.x = head_x;
712
 
        frame.y = head_y + (head_h - frame.height)/2 - border_width;
713
 
        frame.x_hidden = frame.x - frame.width + bevel_width + border_width;
714
 
        frame.y_hidden = frame.y;
715
 
        if (m_shape.get())
716
 
            m_shape->setPlaces(Shape::TOPRIGHT | Shape::BOTTOMRIGHT);
717
 
        break;
718
 
    case LEFTTOP:
719
 
        frame.x = head_x;
720
 
        frame.y = head_y;
721
 
        frame.x_hidden = frame.x - frame.width + bevel_width + border_width;
722
 
        frame.y_hidden = frame.y;
723
 
        if (m_shape.get())
724
 
            m_shape->setPlaces(Shape::TOPRIGHT | Shape::BOTTOMRIGHT);
725
 
        break;
726
 
    case LEFTBOTTOM:
727
 
        frame.x = head_x;
728
 
        frame.y = head_y + head_h - frame.height - border_width*2;
729
 
        frame.x_hidden = frame.x - frame.width + bevel_width + border_width;
730
 
        frame.y_hidden = frame.y;
731
 
        if (m_shape.get())
732
 
            m_shape->setPlaces(Shape::TOPRIGHT | Shape::BOTTOMRIGHT);
733
 
        break;
734
 
    case RIGHTCENTER:
735
 
        frame.x = head_x + head_w - frame.width - border_width*2;
736
 
        frame.y = head_y + (head_h - frame.height)/2 - border_width;
737
 
        frame.x_hidden = frame.x + frame.width - bevel_width - border_width;
738
 
        frame.y_hidden = frame.y;
739
 
        if (m_shape.get())
740
 
            m_shape->setPlaces(Shape::TOPLEFT | Shape::BOTTOMLEFT);
741
 
        break;
742
 
    case RIGHTTOP:
743
 
        frame.x = head_x + head_w - frame.width - border_width*2;
744
 
        frame.y = head_y;
745
 
        frame.x_hidden = frame.x + frame.width - bevel_width - border_width;
746
 
        frame.y_hidden = frame.y;
747
 
        if (m_shape.get())
748
 
            m_shape->setPlaces(Shape::TOPLEFT | Shape::BOTTOMLEFT);
749
 
        break;
750
 
    case RIGHTBOTTOM:
751
 
        frame.x = head_x + head_w - frame.width - border_width*2;
752
 
        frame.y = head_y + head_h - frame.height - border_width*2;
753
 
        frame.x_hidden = frame.x + frame.width - bevel_width - border_width;
754
 
        frame.y_hidden = frame.y;
755
 
        if (m_shape.get())
756
 
            m_shape->setPlaces(Shape::TOPLEFT | Shape::BOTTOMLEFT);
757
 
        break;
758
 
    }
759
 
}
760
 
 
761
 
void Toolbar::updateVisibleState() {
762
 
    *m_rc_visible ? frame.window.show() : frame.window.hide();
763
 
}
764
 
 
765
 
void Toolbar::toggleHidden() {
766
 
 
767
 
 
768
 
    // toggle hidden
769
 
    m_hidden = ! m_hidden;
770
 
    if (isHidden())
771
 
        frame.window.move(frame.x_hidden, frame.y_hidden);
772
 
    else
773
 
        frame.window.move(frame.x, frame.y);
774
 
 
775
 
}
776
 
 
777
 
void Toolbar::moveToLayer(int layernum) {
778
 
    m_layeritem.moveToLayer(layernum);
779
 
    *m_rc_layernum = layernum;
780
 
}
781
 
 
782
 
void Toolbar::setupMenus() {
783
 
    _FB_USES_NLS;
784
 
    using namespace FbTk;
785
 
 
786
 
    typedef RefCount<Command> RefCommand;
787
 
    typedef SimpleCommand<Toolbar> ToolbarCommand;
788
 
 
789
 
    menu().setLabel(_FBTEXT(Toolbar, Toolbar,
790
 
                            "Toolbar", "Title of Toolbar menu"));
791
 
 
792
 
    RefCommand reconfig_toolbar(new ToolbarCommand(*this, &Toolbar::reconfigure));
793
 
    RefCommand save_resources(CommandParser::instance().parseLine("saverc"));
794
 
    MacroCommand *toolbar_menuitem_macro = new MacroCommand();
795
 
    toolbar_menuitem_macro->add(reconfig_toolbar);
796
 
    toolbar_menuitem_macro->add(save_resources);
797
 
    RefCommand reconfig_toolbar_and_save_resource(toolbar_menuitem_macro);
798
 
 
799
 
    MacroCommand *visible_macro = new MacroCommand();
800
 
    RefCommand toggle_visible(new ToolbarCommand(*this, &Toolbar::updateVisibleState));
801
 
    visible_macro->add(toggle_visible);
802
 
    visible_macro->add(reconfig_toolbar);
803
 
    visible_macro->add(save_resources);
804
 
    RefCommand toggle_visible_cmd(visible_macro);
805
 
    menu().insert(new BoolMenuItem(_FBTEXT(Common, Visible, "Visible", "Whether this item is visible"),
806
 
                                   *m_rc_visible, toggle_visible_cmd));
807
 
 
808
 
    menu().insert(new BoolMenuItem(_FBTEXT(Common, AutoHide,
809
 
                                           "Auto hide", "Toggle auto hide of toolbar"),
810
 
                                   *m_rc_auto_hide,
811
 
                                   reconfig_toolbar_and_save_resource));
812
 
 
813
 
    MenuItem *toolbar_menuitem = new IntResMenuItem(_FBTEXT(Toolbar, WidthPercent, "Toolbar width percent", "Percentage of screen width taken by toolbar"),
814
 
                                                    m_rc_width_percent,
815
 
                                                    0, 100, menu()); // min/max value
816
 
 
817
 
    
818
 
    toolbar_menuitem->setCommand(reconfig_toolbar_and_save_resource);
819
 
    menu().insert(toolbar_menuitem);
820
 
    
821
 
    menu().insert(new BoolMenuItem(_FBTEXT(Common, MaximizeOver,"Maximize Over", "Maximize over this thing when maximizing"),
822
 
                                   *m_rc_maximize_over,
823
 
                                   reconfig_toolbar_and_save_resource));
824
 
    menu().insert(_FBTEXT(Menu, Layer, "Layer...", "Title of Layer menu"), &layerMenu());
825
 
 
826
 
    if (screen().hasXinerama()) {
827
 
        menu().insert(_FBTEXT(Menu, OnHead, "On Head...", "Title of On Head menu"),
828
 
                      new XineramaHeadMenu<Toolbar>(screen().menuTheme(),
829
 
                                                    screen(),
830
 
                                                    screen().imageControl(),
831
 
                                                    *screen().layerManager().getLayer(Fluxbox::instance()->getMenuLayer()),
832
 
                                                    *this,
833
 
                                                    _FBTEXT(Toolbar, OnHead, "Toolbar on Head", "Title of toolbar on head menu")));
834
 
    }
835
 
 
836
 
    typedef pair<const char*, Toolbar::Placement> PlacementP;
837
 
    typedef list<PlacementP> Placements;
838
 
    Placements place_menu;
839
 
 
840
 
    // menu is 3 wide, 5 down
841
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, TopLeft, "Top Left", "Top Left"), Toolbar::TOPLEFT));
842
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, LeftTop, "Left Top", "Left Top"), Toolbar::LEFTTOP));
843
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, LeftCenter, "Left Center", "Left Center"), Toolbar::LEFTCENTER));
844
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, LeftBottom, "Left Bottom", "Left Bottom"), Toolbar::LEFTBOTTOM));
845
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, BottomLeft, "Bottom Left", "Bottom Left"), Toolbar::BOTTOMLEFT));
846
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, TopCenter, "Top Center", "Top Center"), Toolbar::TOPCENTER));
847
 
    place_menu.push_back(PlacementP((const char *)0, Toolbar::TOPLEFT));
848
 
    place_menu.push_back(PlacementP((const char *)0, Toolbar::TOPLEFT));
849
 
    place_menu.push_back(PlacementP((const char *)0, Toolbar::TOPLEFT));
850
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, BottomCenter, "Bottom Center", "Bottom Center"), Toolbar::BOTTOMCENTER));
851
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, TopRight, "Top Right", "Top Right"), Toolbar::TOPRIGHT));
852
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, RightTop, "Right Top", "Right Top"), Toolbar::RIGHTTOP));
853
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, RightCenter, "Right Center", "Right Center"), Toolbar::RIGHTCENTER));
854
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, RightBottom, "Right Bottom", "Right Bottom"), Toolbar::RIGHTBOTTOM));
855
 
    place_menu.push_back(PlacementP(_FBTEXT(Align, BottomRight, "Bottom Right", "Bottom Right"), Toolbar::BOTTOMRIGHT));
856
 
 
857
 
 
858
 
    placementMenu().setMinimumSublevels(3);
859
 
    // create items in sub menu
860
 
    for (size_t i=0; i<15; ++i) {
861
 
        const char *str = place_menu.front().first;
862
 
        Toolbar::Placement placement = place_menu.front().second;
863
 
 
864
 
        if (str == 0) {
865
 
            placementMenu().insert("");
866
 
            placementMenu().setItemEnabled(i, false);
867
 
        } else {
868
 
            RefCommand setplace(new SetToolbarPlacementCmd(*this, placement));
869
 
            placementMenu().insert(str, setplace);
870
 
 
871
 
        }
872
 
        place_menu.pop_front();
873
 
    }
874
 
    menu().insert(_FBTEXT(Menu, Placement, "Placement", "Title of Placement menu"), &placementMenu());
875
 
    placementMenu().updateMenu();
876
 
 
877
 
 
878
 
    // this saves resources and clears the slit window to update alpha value
879
 
    FbTk::MenuItem *alpha_menuitem =
880
 
        new IntResMenuItem(_FBTEXT(Common, Alpha, "Alpha", "Transparency level"),
881
 
                           m_rc_alpha,
882
 
                           0, 255, menu());
883
 
    // setup command for alpha value
884
 
    MacroCommand *alpha_macrocmd = new MacroCommand();
885
 
    RefCount<Command> alpha_cmd(new SimpleCommand<Toolbar>(*this, &Toolbar::updateAlpha));
886
 
    alpha_macrocmd->add(save_resources);
887
 
    alpha_macrocmd->add(alpha_cmd);
888
 
    RefCount<Command> set_alpha_cmd(alpha_macrocmd);
889
 
    alpha_menuitem->setCommand(set_alpha_cmd);
890
 
 
891
 
    menu().insert(alpha_menuitem);
892
 
    menu().updateMenu();
893
 
}
894
 
 
895
 
void Toolbar::saveOnHead(int head) {
896
 
    m_rc_on_head = head;
897
 
    reconfigure();
898
 
}
899
 
 
900
 
/*
901
 
 * Place items next to each other, with a bevel width between,
902
 
 * above and below each item. BUT, if there is no bevel width, then
903
 
 * borders should be merged for evenness.
904
 
 */
905
 
 
906
 
void Toolbar::rearrangeItems() {
907
 
    if (m_resize_lock || screen().isShuttingdown() ||
908
 
        m_item_list.empty())
909
 
        return;
910
 
 
911
 
    // lock this
912
 
    m_resize_lock = true;
913
 
    // calculate size for fixed items
914
 
    ItemList::iterator item_it = m_item_list.begin();
915
 
    ItemList::iterator item_it_end = m_item_list.end();
916
 
    int bevel_width = theme().bevelWidth();
917
 
    int fixed_width = bevel_width; // combined size of all fixed items
918
 
    int fixed_items = 0; // number of fixed items
919
 
    int relative_items = 0;
920
 
    int last_bw = 0; // we show the largest border of adjoining items
921
 
    bool first = true;
922
 
    for (; item_it != item_it_end; ++item_it) {
923
 
        if (!(*item_it)->active())
924
 
            continue;
925
 
 
926
 
        int borderW = (*item_it)->borderWidth();
927
 
 
928
 
        if (bevel_width > 0) {
929
 
            // the bevel and border are fixed whether relative or not
930
 
            fixed_width += bevel_width + 2*borderW;
931
 
        } else {
932
 
            if (!first) {
933
 
                if (borderW > last_bw)
934
 
                    fixed_width += borderW;
935
 
                else
936
 
                    fixed_width += last_bw;
937
 
            } else {
938
 
                first = false;
939
 
            }
940
 
        }
941
 
 
942
 
        last_bw = borderW;
943
 
 
944
 
        if ((*item_it)->type() == ToolbarItem::FIXED) {
945
 
            fixed_width += (*item_it)->width();
946
 
            fixed_items++;
947
 
        } else if ((*item_it)->type() == ToolbarItem::SQUARE) {
948
 
            fixed_width += height() - 2*bevel_width;
949
 
            if (bevel_width != 0) fixed_width -= 2*borderW;
950
 
            fixed_items++;
951
 
        } else {
952
 
            relative_items++;
953
 
        }
954
 
    }
955
 
 
956
 
    // calculate what's going to be le ft over to the relative sized items
957
 
    int relative_width = 0;
958
 
    int rounding_error = 0;
959
 
    if (fixed_items == 0) // no fixed items, then the rest is the entire width
960
 
        relative_width = width();
961
 
    else {
962
 
        if (relative_items == 0)
963
 
            relative_width = 0;
964
 
        else { // size left after fixed items / number of relative items
965
 
            relative_width = (width() - fixed_width)/relative_items;
966
 
            rounding_error = width() - fixed_width - relative_items*(relative_width);
967
 
        }
968
 
    }
969
 
 
970
 
    // now move and resize the items
971
 
    // borderWidth added back on straight away
972
 
    int next_x = -m_item_list.front()->borderWidth(); // list isn't empty
973
 
    if (bevel_width != 0)
974
 
        next_x = 0;
975
 
 
976
 
    last_bw = 0;
977
 
    for (item_it = m_item_list.begin(); item_it != item_it_end; ++item_it) {
978
 
        int borderW = (*item_it)->borderWidth();
979
 
        if (!(*item_it)->active()) {
980
 
            (*item_it)->hide();
981
 
            // make sure it still gets told the toolbar height
982
 
            (*item_it)->resize(1, height()-2*(bevel_width+borderW));  // width of 0 changes to 1 anyway
983
 
            continue;
984
 
        }
985
 
        int offset = bevel_width;
986
 
        int size_offset = 2*(borderW + bevel_width);
987
 
 
988
 
        if (bevel_width == 0) {
989
 
            offset = -borderW;
990
 
            size_offset = 0;
991
 
            if (borderW > last_bw)
992
 
                next_x += borderW;
993
 
            else
994
 
                next_x += last_bw;
995
 
        }
996
 
        last_bw = borderW;
997
 
 
998
 
        if ((*item_it)->type() == ToolbarItem::RELATIVE) {
999
 
            int extra = 0;
1000
 
            if (rounding_error != 0) { // distribute rounding error over all relatives
1001
 
                extra = 1;
1002
 
                --rounding_error;
1003
 
            }
1004
 
            (*item_it)->moveResize(next_x + offset, offset, extra + relative_width, height() - size_offset);
1005
 
        } else if ((*item_it)->type() == ToolbarItem::SQUARE) {
1006
 
            (*item_it)->moveResize(next_x + offset, offset,
1007
 
                                   height() - size_offset, height() - size_offset);
1008
 
        } else { // fixed size
1009
 
            (*item_it)->moveResize(next_x + offset, offset,
1010
 
                                   (*item_it)->width(), height() - size_offset);
1011
 
        }
1012
 
        (*item_it)->show();
1013
 
        next_x += (*item_it)->width() + bevel_width;
1014
 
        if (bevel_width != 0)
1015
 
            next_x += 2*borderW;
1016
 
 
1017
 
    }
1018
 
    // unlock
1019
 
    m_resize_lock = false;
1020
 
    frame.window.clear();
1021
 
}
1022
 
 
1023
 
void Toolbar::deleteItems() {
1024
 
    while (!m_item_list.empty()) {
1025
 
        delete m_item_list.back();
1026
 
        m_item_list.pop_back();
1027
 
    }
1028
 
    m_tools.clear();
1029
 
}
1030
 
 
1031
 
void Toolbar::updateAlpha() {
1032
 
    // called when the alpha resource is changed
1033
 
    if (FbTk::Transparent::haveComposite()) {
1034
 
        frame.window.setOpaque(*m_rc_alpha);
1035
 
    } else {
1036
 
        frame.window.setAlpha(*m_rc_alpha);
1037
 
        frame.window.clear();
1038
 
 
1039
 
        ItemList::iterator item_it = m_item_list.begin();
1040
 
        ItemList::iterator item_it_end = m_item_list.end();
1041
 
        for (item_it = m_item_list.begin(); item_it != item_it_end; ++item_it) {
1042
 
            (*item_it)->renderTheme(alpha());
1043
 
        }
1044
 
    }
1045
 
}