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