Initial revision
[mikachu/openbox.git] / src / Toolbar.cc
1 // Toolbar.cc for Openbox
2 // Copyright (c) 2001 Sean 'Shaleh' Perry <shaleh@debian.org>
3 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.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 // stupid macros needed to access some functions in version 2 of the GNU C
24 // library
25 #ifndef   _GNU_SOURCE
26 #define   _GNU_SOURCE
27 #endif // _GNU_SOURCE
28
29 #ifdef    HAVE_CONFIG_H
30 #  include "../config.h"
31 #endif // HAVE_CONFIG_H
32
33 #include "i18n.h"
34 #include "openbox.h"
35 #include "Clientmenu.h"
36 #include "Iconmenu.h"
37 #include "Rootmenu.h"
38 #include "Screen.h"
39 #include "Toolbar.h"
40 #include "Window.h"
41 #include "Workspace.h"
42 #include "Workspacemenu.h"
43
44 #include <X11/Xutil.h>
45 #include <X11/keysym.h>
46
47 #ifdef    STDC_HEADERS
48 #  include <string.h>
49 #endif // STDC_HEADERS
50
51 #ifdef    HAVE_STDIO_H
52 #  include <stdio.h>
53 #endif // HAVE_STDIO_H
54
55 #ifdef    TIME_WITH_SYS_TIME
56 # include <sys/time.h>
57 # include <time.h>
58 #else // !TIME_WITH_SYS_TIME
59 # ifdef    HAVE_SYS_TIME_H
60 #  include <sys/time.h>
61 # else // !HAVE_SYS_TIME_H
62 #  include <time.h>
63 # endif // HAVE_SYS_TIME_H
64 #endif // TIME_WITH_SYS_TIME
65
66
67 Toolbar::Toolbar(BScreen *scrn) {
68   screen = scrn;
69   openbox = screen->getOpenbox();
70
71   // get the clock updating every minute
72   clock_timer = new BTimer(openbox, this);
73   timeval now;
74   gettimeofday(&now, 0);
75   clock_timer->setTimeout((60 - (now.tv_sec % 60)) * 1000);
76   clock_timer->start();
77
78   hide_handler.toolbar = this;
79   hide_timer = new BTimer(openbox, &hide_handler);
80   hide_timer->setTimeout(openbox->getAutoRaiseDelay());
81   hide_timer->fireOnce(True);
82
83   image_ctrl = screen->getImageControl();
84
85   on_top = screen->isToolbarOnTop();
86   hidden = do_auto_hide = screen->doToolbarAutoHide();
87
88   editing = False;
89   new_workspace_name = (char *) 0;
90   new_name_pos = 0;
91   frame.grab_x = frame.grab_y = 0;
92
93   toolbarmenu = new Toolbarmenu(this);
94
95   display = openbox->getXDisplay();
96   XSetWindowAttributes attrib;
97   unsigned long create_mask = CWBackPixmap | CWBackPixel | CWBorderPixel |
98                               CWColormap | CWOverrideRedirect | CWEventMask;
99   attrib.background_pixmap = None;
100   attrib.background_pixel = attrib.border_pixel =
101     screen->getBorderColor()->getPixel();
102   attrib.colormap = screen->getColormap();
103   attrib.override_redirect = True;
104   attrib.event_mask = ButtonPressMask | ButtonReleaseMask |
105                       EnterWindowMask | LeaveWindowMask;
106
107   frame.window =
108     XCreateWindow(display, screen->getRootWindow(), 0, 0, 1, 1, 0,
109                   screen->getDepth(), InputOutput, screen->getVisual(),
110                   create_mask, &attrib);
111   openbox->saveToolbarSearch(frame.window, this);
112
113   attrib.event_mask = ButtonPressMask | ButtonReleaseMask | ExposureMask |
114                       KeyPressMask | EnterWindowMask;
115
116   frame.workspace_label =
117     XCreateWindow(display, frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
118                   InputOutput, screen->getVisual(), create_mask, &attrib);
119   openbox->saveToolbarSearch(frame.workspace_label, this);
120
121   frame.window_label =
122     XCreateWindow(display, frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
123                   InputOutput, screen->getVisual(), create_mask, &attrib);
124   openbox->saveToolbarSearch(frame.window_label, this);
125
126   frame.clock =
127     XCreateWindow(display, frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
128                   InputOutput, screen->getVisual(), create_mask, &attrib);
129   openbox->saveToolbarSearch(frame.clock, this);
130
131   frame.psbutton =
132     XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
133                   InputOutput, screen->getVisual(), create_mask, &attrib);
134   openbox->saveToolbarSearch(frame.psbutton, this);
135
136   frame.nsbutton =
137     XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
138                   InputOutput, screen->getVisual(), create_mask, &attrib);
139   openbox->saveToolbarSearch(frame.nsbutton, this);
140
141   frame.pwbutton =
142     XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
143                   InputOutput, screen->getVisual(), create_mask, &attrib);
144   openbox->saveToolbarSearch(frame.pwbutton, this);
145
146   frame.nwbutton =
147     XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
148                   InputOutput, screen->getVisual(), create_mask, &attrib);
149   openbox->saveToolbarSearch(frame.nwbutton, this);
150
151   frame.base = frame.label = frame.wlabel = frame.clk = frame.button =
152     frame.pbutton = None;
153
154   reconfigure();
155
156   XMapSubwindows(display, frame.window);
157   XMapWindow(display, frame.window);
158 }
159
160
161 Toolbar::~Toolbar(void) {
162   XUnmapWindow(display, frame.window);
163
164   if (frame.base) image_ctrl->removeImage(frame.base);
165   if (frame.label) image_ctrl->removeImage(frame.label);
166   if (frame.wlabel) image_ctrl->removeImage(frame.wlabel);
167   if (frame.clk) image_ctrl->removeImage(frame.clk);
168   if (frame.button) image_ctrl->removeImage(frame.button);
169   if (frame.pbutton) image_ctrl->removeImage(frame.pbutton);
170
171   openbox->removeToolbarSearch(frame.window);
172   openbox->removeToolbarSearch(frame.workspace_label);
173   openbox->removeToolbarSearch(frame.window_label);
174   openbox->removeToolbarSearch(frame.clock);
175   openbox->removeToolbarSearch(frame.psbutton);
176   openbox->removeToolbarSearch(frame.nsbutton);
177   openbox->removeToolbarSearch(frame.pwbutton);
178   openbox->removeToolbarSearch(frame.nwbutton);
179
180   XDestroyWindow(display, frame.workspace_label);
181   XDestroyWindow(display, frame.window_label);
182   XDestroyWindow(display, frame.clock);
183
184   XDestroyWindow(display, frame.window);
185
186   delete hide_timer;
187   delete clock_timer;
188   delete toolbarmenu;
189 }
190
191
192 void Toolbar::reconfigure(void) {
193   frame.bevel_w = screen->getBevelWidth();
194   frame.width = screen->getWidth() * screen->getToolbarWidthPercent() / 100;
195   
196   if (i18n->multibyte())
197     frame.height =
198       screen->getToolbarStyle()->fontset_extents->max_ink_extent.height;
199   else
200     frame.height = screen->getToolbarStyle()->font->ascent +
201                    screen->getToolbarStyle()->font->descent;
202   frame.button_w = frame.height;
203   frame.height += 2;
204   frame.label_h = frame.height;
205   frame.height += (frame.bevel_w * 2);
206   
207   switch (screen->getToolbarPlacement()) {
208   case TopLeft:
209     frame.x = 0;
210     frame.y = 0;
211     frame.x_hidden = 0;
212     frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth()
213                      - frame.height;
214     break;
215
216   case BottomLeft:
217     frame.x = 0;
218     frame.y = screen->getHeight() - frame.height
219       - (screen->getBorderWidth() * 2);
220     frame.x_hidden = 0;
221     frame.y_hidden = screen->getHeight() - screen->getBevelWidth()
222                      - screen->getBorderWidth();
223     break;
224
225   case TopCenter:
226     frame.x = (screen->getWidth() - frame.width) / 2;
227     frame.y = 0;
228     frame.x_hidden = frame.x;
229     frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth()
230                      - frame.height;
231     break;
232
233   case BottomCenter:
234   default:
235     frame.x = (screen->getWidth() - frame.width) / 2;
236     frame.y = screen->getHeight() - frame.height
237       - (screen->getBorderWidth() * 2);
238     frame.x_hidden = frame.x;
239     frame.y_hidden = screen->getHeight() - screen->getBevelWidth()
240                      - screen->getBorderWidth();
241     break;
242
243   case TopRight:
244     frame.x = screen->getWidth() - frame.width
245       - (screen->getBorderWidth() * 2);
246     frame.y = 0;
247     frame.x_hidden = frame.x;
248     frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth()
249                      - frame.height;
250     break;
251
252   case BottomRight:
253     frame.x = screen->getWidth() - frame.width
254       - (screen->getBorderWidth() * 2);
255     frame.y = screen->getHeight() - frame.height
256       - (screen->getBorderWidth() * 2);
257     frame.x_hidden = frame.x;
258     frame.y_hidden = screen->getHeight() - screen->getBevelWidth()
259                      - screen->getBorderWidth();
260     break;
261   }
262
263 #ifdef    HAVE_STRFTIME
264   time_t ttmp = time(NULL);
265   struct tm *tt = 0;
266
267   if (ttmp != -1) {
268     tt = localtime(&ttmp);
269     if (tt) {
270       char t[1024], *time_string = (char *) 0;
271       int len = strftime(t, 1024, screen->getStrftimeFormat(), tt);
272
273       if (i18n->multibyte()) {
274         XRectangle ink, logical;
275         XmbTextExtents(screen->getToolbarStyle()->fontset, t, len, &ink,
276                        &logical);
277         frame.clock_w = logical.width;
278
279         // ben's additional solution to pad some space beside the numbers
280         frame.clock_w +=
281           screen->getToolbarStyle()->fontset_extents->max_logical_extent.width *
282           4;
283
284         // brad's solution, which is currently buggy, too big
285         //frame.clock_w =
286         //  screen->getToolbarStyle()->fontset_extents->max_logical_extent.width
287         //  * len;
288       } else {
289         frame.clock_w = XTextWidth(screen->getToolbarStyle()->font, t, len);
290         // ben's additional solution to pad some space beside the numbers
291         frame.clock_w += screen->getToolbarStyle()->font->max_bounds.width * 4;
292         // brad's solution again, too big
293         //frame.clock_w = screen->getToolbarStyle()->font->max_bounds.width * len;
294       }
295       frame.clock_w += (frame.bevel_w * 4);
296       
297       delete [] time_string;
298     } else {
299       frame.clock_w = 0;
300     }
301   } else {
302     frame.clock_w = 0;
303   }
304 #else // !HAVE_STRFTIME
305   frame.clock_w =
306     XTextWidth(screen->getToolbarStyle()->font,
307                i18n->getMessage(ToolbarSet, ToolbarNoStrftimeLength,
308                                 "00:00000"),
309                strlen(i18n->getMessage(ToolbarSet, ToolbarNoStrftimeLength,
310                                        "00:00000"))) + (frame.bevel_w * 4);
311 #endif // HAVE_STRFTIME
312
313   int i;
314   unsigned int w = 0;
315   frame.workspace_label_w = 0;
316
317   for (i = 0; i < screen->getCount(); i++) {
318     if (i18n->multibyte()) {
319       XRectangle ink, logical;
320       XmbTextExtents(screen->getToolbarStyle()->fontset,
321                      screen->getWorkspace(i)->getName(),
322                      strlen(screen->getWorkspace(i)->getName()),
323                      &ink, &logical);
324       w = logical.width;
325     } else {
326       w = XTextWidth(screen->getToolbarStyle()->font,
327                      screen->getWorkspace(i)->getName(),
328                      strlen(screen->getWorkspace(i)->getName()));
329     }
330     w += (frame.bevel_w * 4);
331
332     if (w > frame.workspace_label_w) frame.workspace_label_w = w;
333   }
334
335   if (frame.workspace_label_w < frame.clock_w)
336     frame.workspace_label_w = frame.clock_w;
337   else if (frame.workspace_label_w > frame.clock_w)
338     frame.clock_w = frame.workspace_label_w;
339
340   frame.window_label_w =
341     (frame.width - (frame.clock_w + (frame.button_w * 4) +
342                     frame.workspace_label_w + (frame.bevel_w * 8) + 6));
343
344   if (hidden) {
345     XMoveResizeWindow(display, frame.window, frame.x_hidden, frame.y_hidden,
346                       frame.width, frame.height);
347   } else {
348     XMoveResizeWindow(display, frame.window, frame.x, frame.y,
349                       frame.width, frame.height);
350   }
351
352   XMoveResizeWindow(display, frame.workspace_label, frame.bevel_w,
353                     frame.bevel_w, frame.workspace_label_w,
354                     frame.label_h);
355   XMoveResizeWindow(display, frame.psbutton, (frame.bevel_w * 2) +
356                     frame.workspace_label_w + 1, frame.bevel_w + 1,
357                     frame.button_w, frame.button_w);
358   XMoveResizeWindow(display ,frame.nsbutton, (frame.bevel_w * 3) +
359                     frame.workspace_label_w + frame.button_w + 2,
360                     frame.bevel_w + 1, frame.button_w, frame.button_w);
361   XMoveResizeWindow(display, frame.window_label, (frame.bevel_w * 4) +
362                     (frame.button_w * 2) + frame.workspace_label_w + 3,
363                     frame.bevel_w, frame.window_label_w, frame.label_h);
364   XMoveResizeWindow(display, frame.pwbutton, (frame.bevel_w * 5) +
365                     (frame.button_w * 2) + frame.workspace_label_w +
366                     frame.window_label_w + 4, frame.bevel_w + 1,
367                     frame.button_w, frame.button_w);
368   XMoveResizeWindow(display, frame.nwbutton, (frame.bevel_w * 6) +
369                     (frame.button_w * 3) + frame.workspace_label_w +
370                     frame.window_label_w + 5, frame.bevel_w + 1,
371                     frame.button_w, frame.button_w);
372   XMoveResizeWindow(display, frame.clock, frame.width - frame.clock_w -
373                     frame.bevel_w, frame.bevel_w, frame.clock_w,
374                     frame.label_h);
375
376   Pixmap tmp = frame.base;
377   BTexture *texture = &(screen->getToolbarStyle()->toolbar);
378   if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
379     frame.base = None;
380     XSetWindowBackground(display, frame.window,
381                          texture->getColor()->getPixel());
382   } else {
383     frame.base =
384       image_ctrl->renderImage(frame.width, frame.height, texture);
385     XSetWindowBackgroundPixmap(display, frame.window, frame.base);
386   }
387   if (tmp) image_ctrl->removeImage(tmp);
388
389   tmp = frame.label;
390   texture = &(screen->getToolbarStyle()->window);
391   if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
392     frame.label = None;
393     XSetWindowBackground(display, frame.window_label,
394                          texture->getColor()->getPixel());
395   } else {
396     frame.label =
397       image_ctrl->renderImage(frame.window_label_w, frame.label_h, texture);
398     XSetWindowBackgroundPixmap(display, frame.window_label, frame.label);
399   }
400   if (tmp) image_ctrl->removeImage(tmp);
401
402   tmp = frame.wlabel;
403   texture = &(screen->getToolbarStyle()->label);
404   if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
405     frame.wlabel = None;
406     XSetWindowBackground(display, frame.workspace_label,
407                          texture->getColor()->getPixel());
408   } else {
409     frame.wlabel =
410       image_ctrl->renderImage(frame.workspace_label_w, frame.label_h, texture);
411     XSetWindowBackgroundPixmap(display, frame.workspace_label, frame.wlabel);
412   }
413   if (tmp) image_ctrl->removeImage(tmp);
414
415   tmp = frame.clk;
416   texture = &(screen->getToolbarStyle()->clock);
417   if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
418     frame.clk = None;
419     XSetWindowBackground(display, frame.clock,
420                          texture->getColor()->getPixel());
421   } else {
422     frame.clk =
423       image_ctrl->renderImage(frame.clock_w, frame.label_h, texture);
424     XSetWindowBackgroundPixmap(display, frame.clock, frame.clk);
425   }
426   if (tmp) image_ctrl->removeImage(tmp);
427
428   tmp = frame.button;
429   texture = &(screen->getToolbarStyle()->button);
430   if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
431     frame.button = None;
432
433     frame.button_pixel = texture->getColor()->getPixel();
434     XSetWindowBackground(display, frame.psbutton, frame.button_pixel);
435     XSetWindowBackground(display, frame.nsbutton, frame.button_pixel);
436     XSetWindowBackground(display, frame.pwbutton, frame.button_pixel);
437     XSetWindowBackground(display, frame.nwbutton, frame.button_pixel);
438   } else {
439     frame.button =
440       image_ctrl->renderImage(frame.button_w, frame.button_w, texture);
441
442     XSetWindowBackgroundPixmap(display, frame.psbutton, frame.button);
443     XSetWindowBackgroundPixmap(display, frame.nsbutton, frame.button);
444     XSetWindowBackgroundPixmap(display, frame.pwbutton, frame.button);
445     XSetWindowBackgroundPixmap(display, frame.nwbutton, frame.button);
446   }
447   if (tmp) image_ctrl->removeImage(tmp);
448
449   tmp = frame.pbutton;
450   texture = &(screen->getToolbarStyle()->pressed);
451   if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
452     frame.pbutton = None;
453     frame.pbutton_pixel = texture->getColor()->getPixel();
454   } else {
455     frame.pbutton =
456       image_ctrl->renderImage(frame.button_w, frame.button_w, texture);
457   }
458   if (tmp) image_ctrl->removeImage(tmp);
459
460   XSetWindowBorder(display, frame.window,
461                    screen->getBorderColor()->getPixel());
462   XSetWindowBorderWidth(display, frame.window, screen->getBorderWidth());
463
464   XClearWindow(display, frame.window);
465   XClearWindow(display, frame.workspace_label);
466   XClearWindow(display, frame.window_label);
467   XClearWindow(display, frame.clock);
468   XClearWindow(display, frame.psbutton);
469   XClearWindow(display, frame.nsbutton);
470   XClearWindow(display, frame.pwbutton);
471   XClearWindow(display, frame.nwbutton);
472
473   redrawWindowLabel();
474   redrawWorkspaceLabel();
475   redrawPrevWorkspaceButton();
476   redrawNextWorkspaceButton();
477   redrawPrevWindowButton();
478   redrawNextWindowButton();
479   checkClock(True);
480
481   toolbarmenu->reconfigure();
482 }
483
484
485 #ifdef    HAVE_STRFTIME
486 void Toolbar::checkClock(Bool redraw) {
487 #else // !HAVE_STRFTIME
488 void Toolbar::checkClock(Bool redraw, Bool date) {
489 #endif // HAVE_STRFTIME
490   time_t tmp = 0;
491   struct tm *tt = 0;
492
493   if ((tmp = time(NULL)) != -1) {
494     if (! (tt = localtime(&tmp))) return;
495     if (tt->tm_min != frame.minute || tt->tm_hour != frame.hour) {
496       frame.hour = tt->tm_hour;
497       frame.minute = tt->tm_min;
498       XClearWindow(display, frame.clock);
499       redraw = True;
500     }
501   }
502
503   if (redraw) {
504 #ifdef    HAVE_STRFTIME
505     char t[1024];
506     if (! strftime(t, 1024, screen->getStrftimeFormat(), tt))
507       return;
508 #else // !HAVE_STRFTIME
509     char t[9];
510     if (date) {
511       // format the date... with special consideration for y2k ;)
512       if (screen->getDateFormat() == Openbox::B_EuropeanDate)
513         sprintf(t, 18n->getMessage(ToolbarSet, ToolbarNoStrftimeDateFormatEu,
514                                    "%02d.%02d.%02d"),
515                 tt->tm_mday, tt->tm_mon + 1,
516                 (tt->tm_year >= 100) ? tt->tm_year - 100 : tt->tm_year);
517       else
518         sprintf(t, i18n->getMessage(ToolbarSet, ToolbarNoStrftimeDateFormat,
519                                     "%02d/%02d/%02d"),
520                 tt->tm_mon + 1, tt->tm_mday,
521                 (tt->tm_year >= 100) ? tt->tm_year - 100 : tt->tm_year);
522     } else {
523       if (screen->isClock24Hour())
524         sprintf(t, i18n->getMessage(ToolbarSet, ToolbarNoStrftimeTimeFormat24,
525                                     "  %02d:%02d "),
526                 frame.hour, frame.minute);
527       else
528         sprintf(t, i18n->getMessage(ToolbarSet, ToolbarNoStrftimeTimeFormat12,
529                                     "%02d:%02d %sm"),
530                 ((frame.hour > 12) ? frame.hour - 12 :
531                  ((frame.hour == 0) ? 12 : frame.hour)), frame.minute,
532                 ((frame.hour >= 12) ?
533                  i18n->getMessage(ToolbarSet,
534                                   ToolbarNoStrftimeTimeFormatP, "p") :
535                  i18n->getMessage(ToolbarSet,
536                                   ToolbarNoStrftimeTimeFormatA, "a")));
537     }
538 #endif // HAVE_STRFTIME
539
540     int dx = (frame.bevel_w * 2), dlen = strlen(t);
541     unsigned int l;
542
543     if (i18n->multibyte()) {
544       XRectangle ink, logical;
545       XmbTextExtents(screen->getToolbarStyle()->fontset,
546                      t, dlen, &ink, &logical);
547       l = logical.width;
548     } else {
549       l = XTextWidth(screen->getToolbarStyle()->font, t, dlen);
550     }
551     
552     l += (frame.bevel_w * 4);
553     
554     if (l > frame.clock_w) {
555       for (; dlen >= 0; dlen--) {
556         if (i18n->multibyte()) {
557           XRectangle ink, logical;
558           XmbTextExtents(screen->getToolbarStyle()->fontset,
559                          t, dlen, &ink, &logical);
560           l = logical.width;
561         } else {
562           l = XTextWidth(screen->getToolbarStyle()->font, t, dlen);
563         }
564         l+= (frame.bevel_w * 4);
565         
566         if (l < frame.clock_w)
567           break;
568       }
569     }
570     switch (screen->getToolbarStyle()->justify) {
571     case BScreen::RightJustify:
572       dx += frame.clock_w - l;
573       break;
574
575     case BScreen::CenterJustify:
576       dx += (frame.clock_w - l) / 2;
577       break;
578     }
579
580     ToolbarStyle *style = screen->getToolbarStyle();
581     if (i18n->multibyte())
582       XmbDrawString(display, frame.clock, style->fontset, style->c_text_gc,
583                     dx, (1 - style->fontset_extents->max_ink_extent.y),
584                     t, dlen);
585     else
586       XDrawString(display, frame.clock, style->c_text_gc, dx,
587                   (style->font->ascent + 1), t, dlen);
588   }
589 }
590
591
592 void Toolbar::redrawWindowLabel(Bool redraw) {
593   if (screen->getOpenbox()->getFocusedWindow()) {
594     if (redraw)
595       XClearWindow(display, frame.window_label);
596
597     OpenboxWindow *foc = screen->getOpenbox()->getFocusedWindow();
598     if (foc->getScreen() != screen) return;
599
600     int dx = (frame.bevel_w * 2), dlen = strlen(*foc->getTitle());
601     unsigned int l;
602
603     if (i18n->multibyte()) {
604       XRectangle ink, logical;
605       XmbTextExtents(screen->getToolbarStyle()->fontset, *foc->getTitle(),
606                      dlen, &ink, &logical);
607       l = logical.width;
608     } else {
609       l = XTextWidth(screen->getToolbarStyle()->font, *foc->getTitle(), dlen);
610     }
611     l += (frame.bevel_w * 4);
612
613     if (l > frame.window_label_w) {
614       for (; dlen >= 0; dlen--) {
615         if (i18n->multibyte()) {
616           XRectangle ink, logical;
617           XmbTextExtents(screen->getToolbarStyle()->fontset,
618                          *foc->getTitle(), dlen, &ink, &logical);
619           l = logical.width;
620         } else {
621           l = XTextWidth(screen->getToolbarStyle()->font,
622                          *foc->getTitle(), dlen);
623         }
624         l += (frame.bevel_w * 4);
625         
626         if (l < frame.window_label_w)
627           break;
628       }
629     }
630     switch (screen->getToolbarStyle()->justify) {
631     case BScreen::RightJustify:
632       dx += frame.window_label_w - l;
633       break;
634
635     case BScreen::CenterJustify:
636       dx += (frame.window_label_w - l) / 2;
637       break;
638     }
639
640     ToolbarStyle *style = screen->getToolbarStyle();
641     if (i18n->multibyte())
642       XmbDrawString(display, frame.window_label, style->fontset,
643                     style->w_text_gc, dx,
644                     (1 - style->fontset_extents->max_ink_extent.y),
645                     *foc->getTitle(), dlen);
646     else
647       XDrawString(display, frame.window_label, style->w_text_gc, dx,
648                   (style->font->ascent + 1), *foc->getTitle(), dlen);
649   } else {
650     XClearWindow(display, frame.window_label);
651   }
652 }
653  
654  
655 void Toolbar::redrawWorkspaceLabel(Bool redraw) {
656   if (screen->getCurrentWorkspace()->getName()) {
657     if (redraw)
658       XClearWindow(display, frame.workspace_label);
659     
660     int dx = (frame.bevel_w * 2), dlen =
661              strlen(screen->getCurrentWorkspace()->getName());
662     unsigned int l;
663     
664     if (i18n->multibyte()) {
665       XRectangle ink, logical;
666       XmbTextExtents(screen->getToolbarStyle()->fontset,
667                      screen->getCurrentWorkspace()->getName(), dlen,
668                      &ink, &logical);
669       l = logical.width;
670     } else {
671       l = XTextWidth(screen->getToolbarStyle()->font,
672                      screen->getCurrentWorkspace()->getName(), dlen);
673     }
674     l += (frame.bevel_w * 4);
675     
676     if (l > frame.workspace_label_w) {
677       for (; dlen >= 0; dlen--) {
678         if (i18n->multibyte()) {
679           XRectangle ink, logical;
680           XmbTextExtents(screen->getToolbarStyle()->fontset,
681                          screen->getCurrentWorkspace()->getName(), dlen,
682                          &ink, &logical);
683           l = logical.width;
684         } else {
685           l = XTextWidth(screen->getWindowStyle()->font,
686                          screen->getCurrentWorkspace()->getName(), dlen);
687         }
688         l += (frame.bevel_w * 4);
689         
690         if (l < frame.workspace_label_w)
691           break;
692       }
693     }
694     switch (screen->getToolbarStyle()->justify) {
695     case BScreen::RightJustify:
696       dx += frame.workspace_label_w - l;
697       break;
698
699     case BScreen::CenterJustify:
700       dx += (frame.workspace_label_w - l) / 2;
701       break;
702     }
703
704     ToolbarStyle *style = screen->getToolbarStyle();
705     if (i18n->multibyte())
706       XmbDrawString(display, frame.workspace_label, style->fontset,
707                     style->l_text_gc, dx,
708                     (1 - style->fontset_extents->max_ink_extent.y),
709                     (char *) screen->getCurrentWorkspace()->getName(), dlen);
710     else
711       XDrawString(display, frame.workspace_label, style->l_text_gc, dx,
712                   (style->font->ascent + 1),
713                   (char *) screen->getCurrentWorkspace()->getName(), dlen);
714   }
715 }
716
717
718 void Toolbar::redrawPrevWorkspaceButton(Bool pressed, Bool redraw) {
719   if (redraw) {
720     if (pressed) {
721       if (frame.pbutton)
722         XSetWindowBackgroundPixmap(display, frame.psbutton, frame.pbutton);
723       else
724         XSetWindowBackground(display, frame.psbutton, frame.pbutton_pixel);
725     } else {
726       if (frame.button)
727         XSetWindowBackgroundPixmap(display, frame.psbutton, frame.button);
728       else
729         XSetWindowBackground(display, frame.psbutton, frame.button_pixel);
730     }
731     XClearWindow(display, frame.psbutton);
732   }
733
734   int hh = frame.button_w / 2, hw = frame.button_w / 2;
735
736   XPoint pts[3];
737   pts[0].x = hw - 2; pts[0].y = hh;
738   pts[1].x = 4; pts[1].y = 2;
739   pts[2].x = 0; pts[2].y = -4;
740
741   XFillPolygon(display, frame.psbutton, screen->getToolbarStyle()->b_pic_gc,
742                pts, 3, Convex, CoordModePrevious);
743 }
744
745
746 void Toolbar::redrawNextWorkspaceButton(Bool pressed, Bool redraw) {
747   if (redraw) {
748     if (pressed) {
749       if (frame.pbutton)
750         XSetWindowBackgroundPixmap(display, frame.nsbutton, frame.pbutton);
751       else
752         XSetWindowBackground(display, frame.nsbutton, frame.pbutton_pixel);
753     } else {
754       if (frame.button)
755         XSetWindowBackgroundPixmap(display, frame.nsbutton, frame.button);
756       else
757         XSetWindowBackground(display, frame.nsbutton, frame.button_pixel);
758     }
759     XClearWindow(display, frame.nsbutton);
760   }
761
762   int hh = frame.button_w / 2, hw = frame.button_w / 2;
763
764   XPoint pts[3];
765   pts[0].x = hw - 2; pts[0].y = hh - 2;
766   pts[1].x = 4; pts[1].y =  2;
767   pts[2].x = -4; pts[2].y = 2;
768
769   XFillPolygon(display, frame.nsbutton, screen->getToolbarStyle()->b_pic_gc,
770                pts, 3, Convex, CoordModePrevious);
771 }
772
773
774 void Toolbar::redrawPrevWindowButton(Bool pressed, Bool redraw) {
775   if (redraw) {
776     if (pressed) {
777       if (frame.pbutton)
778         XSetWindowBackgroundPixmap(display, frame.pwbutton, frame.pbutton);
779       else
780         XSetWindowBackground(display, frame.pwbutton, frame.pbutton_pixel);
781     } else {
782       if (frame.button)
783         XSetWindowBackgroundPixmap(display, frame.pwbutton, frame.button);
784       else
785         XSetWindowBackground(display, frame.pwbutton, frame.button_pixel);
786     }
787     XClearWindow(display, frame.pwbutton);
788   }
789
790   int hh = frame.button_w / 2, hw = frame.button_w / 2;
791
792   XPoint pts[3];
793   pts[0].x = hw - 2; pts[0].y = hh;
794   pts[1].x = 4; pts[1].y = 2;
795   pts[2].x = 0; pts[2].y = -4;
796
797   XFillPolygon(display, frame.pwbutton, screen->getToolbarStyle()->b_pic_gc,
798                pts, 3, Convex, CoordModePrevious);
799 }
800
801
802 void Toolbar::redrawNextWindowButton(Bool pressed, Bool redraw) {
803   if (redraw) {
804     if (pressed) {
805       if (frame.pbutton)
806         XSetWindowBackgroundPixmap(display, frame.nwbutton, frame.pbutton);
807       else
808         XSetWindowBackground(display, frame.nwbutton, frame.pbutton_pixel);
809     } else {
810       if (frame.button)
811         XSetWindowBackgroundPixmap(display, frame.nwbutton, frame.button);
812       else
813         XSetWindowBackground(display, frame.nwbutton, frame.button_pixel);
814     }
815     XClearWindow(display, frame.nwbutton);
816   }
817
818   int hh = frame.button_w / 2, hw = frame.button_w / 2;
819
820   XPoint pts[3];
821   pts[0].x = hw - 2; pts[0].y = hh - 2;
822   pts[1].x = 4; pts[1].y =  2;
823   pts[2].x = -4; pts[2].y = 2;
824
825   XFillPolygon(display, frame.nwbutton, screen->getToolbarStyle()->b_pic_gc,
826                pts, 3, Convex, CoordModePrevious);
827 }
828
829
830 void Toolbar::edit(void) {
831   Window window;
832   int foo;
833
834   editing = True;
835   if (XGetInputFocus(display, &window, &foo) &&
836       window == frame.workspace_label)
837     return;
838
839   XSetInputFocus(display, frame.workspace_label,
840                  ((screen->isSloppyFocus()) ? RevertToPointerRoot :
841                   RevertToParent),
842                  CurrentTime);
843   XClearWindow(display, frame.workspace_label);
844
845   openbox->setNoFocus(True);
846   if (openbox->getFocusedWindow())
847     openbox->getFocusedWindow()->setFocusFlag(False);
848
849   XDrawRectangle(display, frame.workspace_label,
850                  screen->getWindowStyle()->l_text_focus_gc,
851                  frame.workspace_label_w / 2, 0, 1,
852                  frame.label_h - 1);
853   
854   // change the background of the window to that of an active window label
855   Pixmap tmp = frame.wlabel;
856   BTexture *texture = &(screen->getWindowStyle()->l_focus);
857   if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
858     frame.wlabel = None;
859     XSetWindowBackground(display, frame.workspace_label,
860                          texture->getColor()->getPixel());
861   } else {
862     frame.wlabel =
863       image_ctrl->renderImage(frame.workspace_label_w, frame.label_h, texture);
864     XSetWindowBackgroundPixmap(display, frame.workspace_label, frame.wlabel);
865   }
866   if (tmp) image_ctrl->removeImage(tmp);
867 }
868
869
870 void Toolbar::buttonPressEvent(XButtonEvent *be) {
871   if (be->button == 1) {
872     if (be->window == frame.psbutton)
873       redrawPrevWorkspaceButton(True, True);
874     else if (be->window == frame.nsbutton)
875       redrawNextWorkspaceButton(True, True);
876     else if (be->window == frame.pwbutton)
877       redrawPrevWindowButton(True, True);
878     else if (be->window == frame.nwbutton)
879       redrawNextWindowButton(True, True);
880 #ifndef   HAVE_STRFTIME
881     else if (be->window == frame.clock) {
882       XClearWindow(display, frame.clock);
883       checkClock(True, True);
884     }
885 #endif // HAVE_STRFTIME
886     else if (! on_top) {
887       Window w[1] = { frame.window };
888       screen->raiseWindows(w, 1);
889     }
890   } else if (be->button == 2 && (! on_top)) {
891     XLowerWindow(display, frame.window);
892   } else if (be->button == 3) {
893     if (! toolbarmenu->isVisible()) {
894       int x, y;
895
896       x = be->x_root - (toolbarmenu->getWidth() / 2);
897       y = be->y_root - (toolbarmenu->getHeight() / 2);
898
899       if (x < 0)
900         x = 0;
901       else if (x + toolbarmenu->getWidth() > screen->getWidth())
902         x = screen->getWidth() - toolbarmenu->getWidth();
903
904       if (y < 0)
905         y = 0;
906       else if (y + toolbarmenu->getHeight() > screen->getHeight())
907         y = screen->getHeight() - toolbarmenu->getHeight();
908
909       toolbarmenu->move(x, y);
910       toolbarmenu->show();
911     } else
912       toolbarmenu->hide();
913   }
914 }
915
916
917
918 void Toolbar::buttonReleaseEvent(XButtonEvent *re) {
919   if (re->button == 1) {
920     if (re->window == frame.psbutton) {
921       redrawPrevWorkspaceButton(False, True);
922
923       if (re->x >= 0 && re->x < (signed) frame.button_w &&
924           re->y >= 0 && re->y < (signed) frame.button_w)
925        if (screen->getCurrentWorkspace()->getWorkspaceID() > 0)
926           screen->changeWorkspaceID(screen->getCurrentWorkspace()->
927                                     getWorkspaceID() - 1);
928         else
929           screen->changeWorkspaceID(screen->getCount() - 1);
930     } else if (re->window == frame.nsbutton) {
931       redrawNextWorkspaceButton(False, True);
932
933       if (re->x >= 0 && re->x < (signed) frame.button_w &&
934           re->y >= 0 && re->y < (signed) frame.button_w)
935         if (screen->getCurrentWorkspace()->getWorkspaceID() <
936             screen->getCount() - 1)
937           screen->changeWorkspaceID(screen->getCurrentWorkspace()->
938                                     getWorkspaceID() + 1);
939         else
940           screen->changeWorkspaceID(0);
941     } else if (re->window == frame.pwbutton) {
942       redrawPrevWindowButton(False, True);
943
944       if (re->x >= 0 && re->x < (signed) frame.button_w &&
945           re->y >= 0 && re->y < (signed) frame.button_w)
946         screen->prevFocus();
947     } else if (re->window == frame.nwbutton) {
948       redrawNextWindowButton(False, True);
949
950       if (re->x >= 0 && re->x < (signed) frame.button_w &&
951           re->y >= 0 && re->y < (signed) frame.button_w)
952         screen->nextFocus();
953     } else if (re->window == frame.window_label)
954       screen->raiseFocus();
955 #ifndef   HAVE_STRFTIME
956     else if (re->window == frame.clock) {
957       XClearWindow(display, frame.clock);
958       checkClock(True);
959     }
960 #endif // HAVE_STRFTIME
961   }
962 }
963
964
965 void Toolbar::enterNotifyEvent(XCrossingEvent *) {
966   if (! do_auto_hide)
967     return;
968
969   if (hidden) {
970     if (! hide_timer->isTiming()) hide_timer->start();
971   } else {
972     if (hide_timer->isTiming()) hide_timer->stop();
973   }
974 }
975
976 void Toolbar::leaveNotifyEvent(XCrossingEvent *) {
977   if (! do_auto_hide)
978     return;
979
980   if (hidden) {
981     if (hide_timer->isTiming()) hide_timer->stop();
982   } else if (! toolbarmenu->isVisible()) {
983     if (! hide_timer->isTiming()) hide_timer->start();
984   }
985 }
986
987
988 void Toolbar::exposeEvent(XExposeEvent *ee) {
989   if (ee->window == frame.clock) checkClock(True);
990   else if (ee->window == frame.workspace_label && (! editing))
991     redrawWorkspaceLabel();
992   else if (ee->window == frame.window_label) redrawWindowLabel();
993   else if (ee->window == frame.psbutton) redrawPrevWorkspaceButton();
994   else if (ee->window == frame.nsbutton) redrawNextWorkspaceButton();
995   else if (ee->window == frame.pwbutton) redrawPrevWindowButton();
996   else if (ee->window == frame.nwbutton) redrawNextWindowButton();
997 }
998
999
1000 void Toolbar::keyPressEvent(XKeyEvent *ke) {
1001   if (ke->window == frame.workspace_label && editing) {
1002     openbox->grab();
1003
1004     if (! new_workspace_name) {
1005       new_workspace_name = new char[128];
1006       new_name_pos = 0;
1007
1008       if (! new_workspace_name) return;
1009     }
1010
1011     KeySym ks;
1012     char keychar[1];
1013     XLookupString(ke, keychar, 1, &ks, 0);
1014
1015     // either we are told to end with a return or we hit the end of the buffer
1016     if (ks == XK_Return || new_name_pos == 127) {
1017       *(new_workspace_name + new_name_pos) = 0;
1018
1019       editing = False;
1020
1021       openbox->setNoFocus(False);
1022       if (openbox->getFocusedWindow()) {
1023         openbox->getFocusedWindow()->setInputFocus();
1024         openbox->getFocusedWindow()->setFocusFlag(True);
1025       } else {
1026         XSetInputFocus(display, PointerRoot, None, CurrentTime);
1027       }
1028       // check to make sure that new_name[0] != 0... otherwise we have a null
1029       // workspace name which causes serious problems, especially for the
1030       // Openbox::LoadRC() method.
1031       if (*new_workspace_name) {
1032         screen->getCurrentWorkspace()->setName(new_workspace_name);
1033         screen->getCurrentWorkspace()->getMenu()->hide();
1034         screen->getWorkspacemenu()->
1035           remove(screen->getCurrentWorkspace()->getWorkspaceID() + 2);
1036         screen->getWorkspacemenu()->
1037           insert(screen->getCurrentWorkspace()->getName(),
1038                  screen->getCurrentWorkspace()->getMenu(),
1039                  screen->getCurrentWorkspace()->getWorkspaceID() + 2);
1040         screen->getWorkspacemenu()->update();
1041       }
1042
1043       delete [] new_workspace_name;
1044       new_workspace_name = (char *) 0;
1045       new_name_pos = 0;
1046
1047       // reset the background to that of the workspace label (its normal
1048       // setting)
1049       Pixmap tmp = frame.wlabel;
1050       BTexture *texture = &(screen->getToolbarStyle()->label);
1051       if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
1052         frame.wlabel = None;
1053         XSetWindowBackground(display, frame.workspace_label,
1054                             texture->getColor()->getPixel());
1055       } else {
1056         frame.wlabel =
1057           image_ctrl->renderImage(frame.workspace_label_w, frame.label_h, texture);
1058         XSetWindowBackgroundPixmap(display, frame.workspace_label, frame.wlabel);
1059       }
1060       if (tmp) image_ctrl->removeImage(tmp);
1061   
1062       reconfigure();
1063     } else if (! (ks == XK_Shift_L || ks == XK_Shift_R ||
1064                   ks == XK_Control_L || ks == XK_Control_R ||
1065                   ks == XK_Caps_Lock || ks == XK_Shift_Lock ||
1066                   ks == XK_Meta_L || ks == XK_Meta_R ||
1067                   ks == XK_Alt_L || ks == XK_Alt_R ||
1068                   ks == XK_Super_L || ks == XK_Super_R ||
1069                   ks == XK_Hyper_L || ks == XK_Hyper_R)) {
1070       if (ks == XK_BackSpace) {
1071         if (new_name_pos > 0) {
1072           --new_name_pos;
1073           *(new_workspace_name + new_name_pos) = '\0';
1074         } else {
1075           *new_workspace_name = '\0';
1076         }
1077       } else {
1078         *(new_workspace_name + new_name_pos) = *keychar;
1079         ++new_name_pos;
1080         *(new_workspace_name + new_name_pos) = '\0';
1081       }
1082
1083       XClearWindow(display, frame.workspace_label);
1084       int l = strlen(new_workspace_name), tw, x;
1085
1086       if (i18n->multibyte()) {
1087         XRectangle ink, logical;
1088         XmbTextExtents(screen->getToolbarStyle()->fontset,
1089                        new_workspace_name, l, &ink, &logical);
1090         tw = logical.width;
1091       } else {
1092         tw = XTextWidth(screen->getToolbarStyle()->font,
1093                         new_workspace_name, l);
1094       }
1095       x = (frame.workspace_label_w - tw) / 2;
1096
1097       if (x < (signed) frame.bevel_w) x = frame.bevel_w;
1098
1099       WindowStyle *style = screen->getWindowStyle();
1100       if (i18n->multibyte())
1101         XmbDrawString(display, frame.workspace_label, style->fontset,
1102                       style->l_text_focus_gc, x,
1103                       (1 - style->fontset_extents->max_ink_extent.y),
1104                       new_workspace_name, l);
1105       else
1106         XDrawString(display, frame.workspace_label, style->l_text_focus_gc, x,
1107                     (style->font->ascent + 1),
1108                     new_workspace_name, l);
1109       
1110       XDrawRectangle(display, frame.workspace_label,
1111                      screen->getWindowStyle()->l_text_focus_gc, x + tw, 0, 1,
1112                      frame.label_h - 1);
1113     }
1114     
1115     openbox->ungrab();
1116   }
1117 }
1118
1119
1120 void Toolbar::timeout(void) {
1121   checkClock(True);
1122
1123   timeval now;
1124   gettimeofday(&now, 0);
1125   clock_timer->setTimeout((60 - (now.tv_sec % 60)) * 1000);
1126 }
1127
1128
1129 void Toolbar::HideHandler::timeout(void) {
1130   toolbar->hidden = ! toolbar->hidden;
1131   if (toolbar->hidden)
1132     XMoveWindow(toolbar->display, toolbar->frame.window,
1133                 toolbar->frame.x_hidden, toolbar->frame.y_hidden);
1134   else
1135     XMoveWindow(toolbar->display, toolbar->frame.window,
1136                 toolbar->frame.x, toolbar->frame.y);
1137 }
1138
1139
1140 Toolbarmenu::Toolbarmenu(Toolbar *tb) : Basemenu(tb->screen) {
1141   toolbar = tb;
1142
1143   setLabel(i18n->getMessage(ToolbarSet, ToolbarToolbarTitle, "Toolbar"));
1144   setInternalMenu();
1145
1146   placementmenu = new Placementmenu(this);
1147
1148   insert(i18n->getMessage(CommonSet, CommonPlacementTitle, "Placement"),
1149          placementmenu);
1150   insert(i18n->getMessage(CommonSet, CommonAlwaysOnTop, "Always on top"), 1);
1151   insert(i18n->getMessage(CommonSet, CommonAutoHide, "Auto hide"), 2);
1152   insert(i18n->getMessage(ToolbarSet, ToolbarEditWkspcName,
1153                           "Edit current workspace name"), 3);
1154
1155   update();
1156
1157   if (toolbar->isOnTop()) setItemSelected(1, True);
1158   if (toolbar->doAutoHide()) setItemSelected(2, True);
1159 }
1160
1161
1162 Toolbarmenu::~Toolbarmenu(void) {
1163   delete placementmenu;
1164 }
1165
1166
1167 void Toolbarmenu::itemSelected(int button, int index) {
1168   if (button != 1)
1169     return;
1170
1171   BasemenuItem *item = find(index);
1172   if (! item) return;
1173
1174   switch (item->function()) {
1175   case 1: { // always on top
1176     Bool change = ((toolbar->isOnTop()) ? False : True);
1177     toolbar->on_top = change;
1178     setItemSelected(1, change);
1179
1180     if (toolbar->isOnTop()) toolbar->screen->raiseWindows((Window *) 0, 0);
1181     break;
1182   }
1183
1184   case 2: { // auto hide
1185     Bool change = ((toolbar->doAutoHide()) ?  False : True);
1186     toolbar->do_auto_hide = change;
1187     setItemSelected(2, change);
1188
1189 #ifdef    SLIT
1190     toolbar->screen->getSlit()->reposition();
1191 #endif // SLIT
1192     break;
1193   }
1194
1195   case 3: { // edit current workspace name
1196     toolbar->edit();
1197     hide();
1198
1199     break;
1200   }
1201   } // switch
1202 }
1203
1204
1205 void Toolbarmenu::internal_hide(void) {
1206   Basemenu::internal_hide();
1207   if (toolbar->doAutoHide() && ! toolbar->isEditing())
1208     toolbar->hide_handler.timeout();
1209 }
1210
1211
1212 void Toolbarmenu::reconfigure(void) {
1213   placementmenu->reconfigure();
1214
1215   Basemenu::reconfigure();
1216 }
1217
1218
1219 Toolbarmenu::Placementmenu::Placementmenu(Toolbarmenu *tm)
1220   : Basemenu(tm->toolbar->screen) {
1221   toolbarmenu = tm;
1222
1223   setLabel(i18n->getMessage(ToolbarSet, ToolbarToolbarPlacement,
1224                             "Toolbar Placement"));
1225   setInternalMenu();
1226   setMinimumSublevels(3);
1227
1228   insert(i18n->getMessage(CommonSet, CommonPlacementTopLeft,
1229                           "Top Left"), Toolbar::TopLeft);
1230   insert(i18n->getMessage(CommonSet, CommonPlacementBottomLeft,
1231                           "Bottom Left"), Toolbar::BottomLeft);
1232   insert(i18n->getMessage(CommonSet, CommonPlacementTopCenter,
1233                           "Top Center"), Toolbar::TopCenter);
1234   insert(i18n->getMessage(CommonSet, CommonPlacementBottomCenter,
1235                           "Bottom Center"), Toolbar::BottomCenter);
1236   insert(i18n->getMessage(CommonSet, CommonPlacementTopRight,
1237                           "Top Right"), Toolbar::TopRight);
1238   insert(i18n->getMessage(CommonSet, CommonPlacementBottomRight,
1239                           "Bottom Right"), Toolbar::BottomRight);
1240   update();
1241 }
1242
1243
1244 void Toolbarmenu::Placementmenu::itemSelected(int button, int index) {
1245   if (button != 1)
1246     return;
1247
1248   BasemenuItem *item = find(index);
1249   if (! item) return;
1250
1251   toolbarmenu->toolbar->screen->saveToolbarPlacement(item->function());
1252   hide();
1253   toolbarmenu->toolbar->reconfigure();
1254
1255 #ifdef    SLIT
1256   // reposition the slit as well to make sure it doesn't intersect the
1257   // toolbar
1258   toolbarmenu->toolbar->screen->getSlit()->reposition();
1259 #endif // SLIT
1260 }