]> icculus.org git repositories - mikachu/openbox.git/blob - src/Toolbar.cc
add another return, and return a value for a non-void funtion.
[mikachu/openbox.git] / src / Toolbar.cc
1 // -*- mode: C++; indent-tabs-mode: nil; -*-
2 // Toolbar.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef    HAVE_CONFIG_H
25 #  include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #include <X11/keysym.h>
30
31 #ifdef HAVE_STRING_H
32 #  include <string.h>
33 #endif // HAVE_STRING_H
34
35 #ifdef    HAVE_STDIO_H
36 #  include <stdio.h>
37 #endif // HAVE_STDIO_H
38
39 #ifdef    TIME_WITH_SYS_TIME
40 # include <sys/time.h>
41 # include <time.h>
42 #else // !TIME_WITH_SYS_TIME
43 # ifdef    HAVE_SYS_TIME_H
44 #  include <sys/time.h>
45 # else // !HAVE_SYS_TIME_H
46 #  include <time.h>
47 # endif // HAVE_SYS_TIME_H
48 #endif // TIME_WITH_SYS_TIME
49 }
50
51 #include <string>
52 using std::string;
53
54 #include "i18n.hh"
55 #include "blackbox.hh"
56 #include "Clientmenu.hh"
57 #include "Font.hh"
58 #include "GCCache.hh"
59 #include "Iconmenu.hh"
60 #include "Image.hh"
61 #include "Rootmenu.hh"
62 #include "Screen.hh"
63 #include "Toolbar.hh"
64 #include "Window.hh"
65 #include "Workspace.hh"
66 #include "Workspacemenu.hh"
67 #include "Slit.hh"
68
69
70 static long aMinuteFromNow(void) {
71   timeval now;
72   gettimeofday(&now, 0);
73   return ((60 - (now.tv_sec % 60)) * 1000);
74 }
75
76
77 Toolbar::Toolbar(BScreen *scrn) {
78   screen = scrn;
79   blackbox = screen->getBlackbox();
80   toolbarstr = "session.screen" + itostring(screen->getScreenNumber()) +
81     ".toolbar.";
82   config = blackbox->getConfig();
83
84   load_rc();
85
86   // get the clock updating every minute
87   clock_timer = new BTimer(blackbox, this);
88   clock_timer->setTimeout(aMinuteFromNow());
89   clock_timer->recurring(True);
90   clock_timer->start();
91   frame.minute = frame.hour = -1;
92
93   hide_handler.toolbar = this;
94   hide_timer = new BTimer(blackbox, &hide_handler);
95   hide_timer->setTimeout(blackbox->getAutoRaiseDelay());
96
97   editing = False;
98   new_name_pos = 0;
99   frame.grab_x = frame.grab_y = 0;
100
101   toolbarmenu = new Toolbarmenu(this);
102
103   display = blackbox->getXDisplay();
104   XSetWindowAttributes attrib;
105   unsigned long create_mask = CWBackPixmap | CWBackPixel | CWBorderPixel |
106                               CWColormap | CWOverrideRedirect | CWEventMask;
107   attrib.background_pixmap = None;
108   attrib.background_pixel = attrib.border_pixel =
109     screen->getBorderColor()->pixel();
110   attrib.colormap = screen->getColormap();
111   attrib.override_redirect = True;
112   attrib.event_mask = ButtonPressMask | ButtonReleaseMask |
113                       EnterWindowMask | LeaveWindowMask;
114
115   frame.window =
116     XCreateWindow(display, screen->getRootWindow(), 0, 0, 1, 1, 0,
117                   screen->getDepth(), InputOutput, screen->getVisual(),
118                   create_mask, &attrib);
119   blackbox->saveToolbarSearch(frame.window, this);
120
121   attrib.event_mask = ButtonPressMask | ButtonReleaseMask | ExposureMask |
122                       KeyPressMask | EnterWindowMask;
123
124   frame.workspace_label =
125     XCreateWindow(display, frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
126                   InputOutput, screen->getVisual(), create_mask, &attrib);
127   blackbox->saveToolbarSearch(frame.workspace_label, this);
128
129   frame.window_label =
130     XCreateWindow(display, frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
131                   InputOutput, screen->getVisual(), create_mask, &attrib);
132   blackbox->saveToolbarSearch(frame.window_label, this);
133
134   frame.clock =
135     XCreateWindow(display, frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
136                   InputOutput, screen->getVisual(), create_mask, &attrib);
137   blackbox->saveToolbarSearch(frame.clock, this);
138
139   frame.psbutton =
140     XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
141                   InputOutput, screen->getVisual(), create_mask, &attrib);
142   blackbox->saveToolbarSearch(frame.psbutton, this);
143
144   frame.nsbutton =
145     XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
146                   InputOutput, screen->getVisual(), create_mask, &attrib);
147   blackbox->saveToolbarSearch(frame.nsbutton, this);
148
149   frame.pwbutton =
150     XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
151                   InputOutput, screen->getVisual(), create_mask, &attrib);
152   blackbox->saveToolbarSearch(frame.pwbutton, this);
153
154   frame.nwbutton =
155     XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(),
156                   InputOutput, screen->getVisual(), create_mask, &attrib);
157   blackbox->saveToolbarSearch(frame.nwbutton, this);
158
159   frame.base = frame.label = frame.wlabel = frame.clk = frame.button =
160     frame.pbutton = None;
161
162   reconfigure();
163   mapToolbar();
164 }
165
166
167 Toolbar::~Toolbar(void) {
168   unmapToolbar();
169
170   if (frame.base) screen->getImageControl()->removeImage(frame.base);
171   if (frame.label) screen->getImageControl()->removeImage(frame.label);
172   if (frame.wlabel) screen->getImageControl()->removeImage(frame.wlabel);
173   if (frame.clk) screen->getImageControl()->removeImage(frame.clk);
174   if (frame.button) screen->getImageControl()->removeImage(frame.button);
175   if (frame.pbutton) screen->getImageControl()->removeImage(frame.pbutton);
176
177   blackbox->removeToolbarSearch(frame.window);
178   blackbox->removeToolbarSearch(frame.workspace_label);
179   blackbox->removeToolbarSearch(frame.window_label);
180   blackbox->removeToolbarSearch(frame.clock);
181   blackbox->removeToolbarSearch(frame.psbutton);
182   blackbox->removeToolbarSearch(frame.nsbutton);
183   blackbox->removeToolbarSearch(frame.pwbutton);
184   blackbox->removeToolbarSearch(frame.nwbutton);
185
186   XDestroyWindow(display, frame.workspace_label);
187   XDestroyWindow(display, frame.window_label);
188   XDestroyWindow(display, frame.clock);
189
190   XDestroyWindow(display, frame.window);
191
192   delete hide_timer;
193   delete clock_timer;
194   delete toolbarmenu;
195 }
196
197
198 void Toolbar::mapToolbar() {
199   if (!screen->doHideToolbar()) {
200     //not hidden, so windows should not maximize over the toolbar
201     XMapSubwindows(display, frame.window);
202     XMapWindow(display, frame.window);
203   }
204   screen->addStrut(&strut);
205   updateStrut();
206 }
207
208
209 void Toolbar::unmapToolbar() {
210   if (toolbarmenu->isVisible())
211     toolbarmenu->hide();
212   //hidden so we can maximize over the toolbar
213   screen->removeStrut(&strut);
214   screen->updateAvailableArea();
215
216   XUnmapWindow(display, frame.window);
217   updateStrut();
218 }
219
220
221 void Toolbar::saveOnTop(bool b) {
222   on_top = b;
223   config->setValue(toolbarstr + "onTop", on_top);
224 }
225
226
227 void Toolbar::saveAutoHide(bool b) {
228   do_auto_hide = b;
229   config->setValue(toolbarstr + "autoHide", do_auto_hide);
230 }
231
232
233 void Toolbar::saveWidthPercent(unsigned int w) {
234   width_percent = w;
235   config->setValue(toolbarstr + "widthPercent", width_percent);
236 }
237
238
239 void Toolbar::savePlacement(int p) {
240   placement = p;
241   const char *pname;
242   switch (placement) {
243   case TopLeft: pname = "TopLeft"; break;
244   case BottomLeft: pname = "BottomLeft"; break;
245   case TopCenter: pname = "TopCenter"; break;
246   case TopRight: pname = "TopRight"; break;
247   case BottomRight: pname = "BottomRight"; break;
248   case BottomCenter: default: pname = "BottomCenter"; break;
249   }
250   config->setValue(toolbarstr + "placement", pname);
251 }
252
253
254 void Toolbar::save_rc(void) {
255   saveOnTop(on_top);
256   saveAutoHide(do_auto_hide);
257   saveWidthPercent(width_percent);
258   savePlacement(placement);
259 }
260
261
262 void Toolbar::load_rc(void) {
263   string s;
264   
265   if (! config->getValue(toolbarstr + "onTop", on_top))
266     on_top = false;
267
268   if (! config->getValue(toolbarstr + "autoHide", do_auto_hide))
269     do_auto_hide = false;
270   hidden = do_auto_hide;
271
272   if (! config->getValue(toolbarstr + "widthPercent", width_percent) ||
273       width_percent == 0 || width_percent > 100)
274     width_percent = 66;
275
276   if (config->getValue(toolbarstr + "placement", s)) {
277     if (s == "TopLeft")
278       placement = TopLeft;
279     else if (s == "BottomLeft")
280       placement = BottomLeft;
281     else if (s == "TopCenter")
282       placement = TopCenter;
283     else if (s == "TopRight")
284       placement = TopRight;
285     else if (s == "BottomRight")
286       placement = BottomRight;
287     else //if (s == "BottomCenter")
288       placement = BottomCenter;
289   } else
290     placement = BottomCenter;
291 }
292
293
294 void Toolbar::reconfigure(void) {
295   unsigned int width, height;
296  
297   width = (screen->getWidth() * width_percent) / 100;
298   height = screen->getToolbarStyle()->font->height();
299
300   frame.bevel_w = screen->getBevelWidth();
301   frame.button_w = height;
302   height += 2;
303   frame.label_h = height;
304   height += (frame.bevel_w * 2);
305
306   frame.rect.setSize(width, height);
307
308   int x, y;
309   switch (placement) {
310   case TopLeft:
311   case TopRight:
312   case TopCenter:
313     if (placement == TopLeft)
314       x = 0;
315     else if (placement == TopRight)
316       x = screen->getWidth() - frame.rect.width()
317         - (screen->getBorderWidth() * 2);
318     else
319       x = (screen->getWidth() - frame.rect.width()) / 2;
320
321     y = 0;
322
323     frame.x_hidden = x;
324     frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth()
325                      - frame.rect.height();
326     break;
327
328   case BottomLeft:
329   case BottomRight:
330   case BottomCenter:
331   default:
332     if (placement == BottomLeft)
333       x = 0;
334     else if (placement == BottomRight)
335       x = screen->getWidth() - frame.rect.width()
336         - (screen->getBorderWidth() * 2);
337     else
338       x = (screen->getWidth() - frame.rect.width()) / 2;
339
340     y = screen->getHeight() - frame.rect.height()
341       - (screen->getBorderWidth() * 2);
342
343     frame.x_hidden = x;
344     frame.y_hidden = screen->getHeight() - screen->getBevelWidth()
345                      - screen->getBorderWidth();
346     break;
347   }
348
349   frame.rect.setPos(x, y);
350
351   updateStrut();
352
353 #ifdef    HAVE_STRFTIME
354   time_t ttmp = time(NULL);
355
356   frame.clock_w = 0;
357   if (ttmp != -1) {
358     struct tm *tt = localtime(&ttmp);
359     if (tt) {
360       char t[1024];
361       int len = strftime(t, 1024, screen->getStrftimeFormat(), tt);
362       if (len == 0) { // invalid time format found
363         screen->saveStrftimeFormat("%I:%M %p"); // so use the default
364         strftime(t, 1024, screen->getStrftimeFormat(), tt);
365       }
366       // find the length of the rendered string and add room for two extra
367       // characters to it.  This allows for variable width output of the fonts
368       BFont *font = screen->getToolbarStyle()->font;
369       frame.clock_w = font->measureString(t) + font->maxCharWidth() * 2;
370     }
371   }
372 #else // !HAVE_STRFTIME
373   {
374     string s = i18n(ToolbarSet, ToolbarNoStrftimeLength, "00:00000");
375     frame.clock_w = screen->getToolbarStyle()->font->measureString(s);
376   }
377 #endif // HAVE_STRFTIME
378
379   frame.workspace_label_w = 0;
380
381   for (unsigned int i = 0; i < screen->getWorkspaceCount(); i++) {
382     const string& workspace_name = screen->getWorkspace(i)->getName();
383     width = screen->getToolbarStyle()->font->measureString(workspace_name);
384     if (width > frame.workspace_label_w) frame.workspace_label_w = width;
385   }
386
387   frame.workspace_label_w = frame.clock_w =
388     std::max(frame.workspace_label_w, frame.clock_w) + (frame.bevel_w * 4);
389
390   // XXX: where'd the +6 come from?
391   frame.window_label_w =
392     (frame.rect.width() - (frame.clock_w + (frame.button_w * 4) +
393                            frame.workspace_label_w + (frame.bevel_w * 8) + 6));
394
395   if (hidden) {
396     XMoveResizeWindow(display, frame.window, frame.x_hidden, frame.y_hidden,
397                       frame.rect.width(), frame.rect.height());
398   } else {
399     XMoveResizeWindow(display, frame.window, frame.rect.x(), frame.rect.y(),
400                       frame.rect.width(), frame.rect.height());
401   }
402
403   XMoveResizeWindow(display, frame.workspace_label, frame.bevel_w,
404                     frame.bevel_w, frame.workspace_label_w,
405                     frame.label_h);
406   XMoveResizeWindow(display, frame.psbutton,
407                     ((frame.bevel_w * 2) + frame.workspace_label_w + 1),
408                     frame.bevel_w + 1, frame.button_w, frame.button_w);
409   XMoveResizeWindow(display, frame.nsbutton,
410                     ((frame.bevel_w * 3) + frame.workspace_label_w +
411                      frame.button_w + 2), frame.bevel_w + 1, frame.button_w,
412                     frame.button_w);
413   XMoveResizeWindow(display, frame.window_label,
414                     ((frame.bevel_w * 4) + (frame.button_w * 2) +
415                      frame.workspace_label_w + 3), frame.bevel_w,
416                     frame.window_label_w, frame.label_h);
417   XMoveResizeWindow(display, frame.pwbutton,
418                     ((frame.bevel_w * 5) + (frame.button_w * 2) +
419                      frame.workspace_label_w + frame.window_label_w + 4),
420                     frame.bevel_w + 1, frame.button_w, frame.button_w);
421   XMoveResizeWindow(display, frame.nwbutton,
422                     ((frame.bevel_w * 6) + (frame.button_w * 3) +
423                      frame.workspace_label_w + frame.window_label_w + 5),
424                     frame.bevel_w + 1, frame.button_w, frame.button_w);
425   XMoveResizeWindow(display, frame.clock,
426                     frame.rect.width() - frame.clock_w - (frame.bevel_w * 2),
427                     frame.bevel_w, frame.clock_w, frame.label_h);
428
429   ToolbarStyle *style = screen->getToolbarStyle();
430   frame.base = style->toolbar.render(frame.rect.width(), frame.rect.height(),
431                                      frame.base);
432   if (! frame.base)
433     XSetWindowBackground(display, frame.window,
434                          style->toolbar.color().pixel());
435   else
436     XSetWindowBackgroundPixmap(display, frame.window, frame.base);
437
438   frame.label = style->window.render(frame.window_label_w, frame.label_h,
439                                      frame.label);
440   if (! frame.label)
441     XSetWindowBackground(display, frame.window_label,
442                          style->window.color().pixel());
443   else
444     XSetWindowBackgroundPixmap(display, frame.window_label, frame.label);
445
446   frame.wlabel = style->label.render(frame.workspace_label_w, frame.label_h,
447                                 frame.wlabel);
448   if (! frame.wlabel)
449     XSetWindowBackground(display, frame.workspace_label,
450                          style->label.color().pixel());
451   else
452     XSetWindowBackgroundPixmap(display, frame.workspace_label, frame.wlabel);
453
454   frame.clk = style->clock.render(frame.clock_w, frame.label_h, frame.clk);
455   if (! frame.clk)
456     XSetWindowBackground(display, frame.clock, style->clock.color().pixel());
457   else
458     XSetWindowBackgroundPixmap(display, frame.clock, frame.clk);
459
460   frame.button = style->button.render(frame.button_w, frame.button_w,
461                                 frame.button);
462   if (! frame.button) {
463     frame.button_pixel = style->button.color().pixel();
464     XSetWindowBackground(display, frame.psbutton, frame.button_pixel);
465     XSetWindowBackground(display, frame.nsbutton, frame.button_pixel);
466     XSetWindowBackground(display, frame.pwbutton, frame.button_pixel);
467     XSetWindowBackground(display, frame.nwbutton, frame.button_pixel);
468   } else {
469     XSetWindowBackgroundPixmap(display, frame.psbutton, frame.button);
470     XSetWindowBackgroundPixmap(display, frame.nsbutton, frame.button);
471     XSetWindowBackgroundPixmap(display, frame.pwbutton, frame.button);
472     XSetWindowBackgroundPixmap(display, frame.nwbutton, frame.button);
473   }
474
475   frame.pbutton = style->pressed.render(frame.button_w, frame.button_w,
476                                         frame.pbutton);
477   if (! frame.pbutton)
478     frame.pbutton_pixel = style->pressed.color().pixel();
479
480   XSetWindowBorder(display, frame.window,
481                    screen->getBorderColor()->pixel());
482   XSetWindowBorderWidth(display, frame.window, screen->getBorderWidth());
483
484   XClearWindow(display, frame.window);
485   XClearWindow(display, frame.workspace_label);
486   XClearWindow(display, frame.window_label);
487   XClearWindow(display, frame.clock);
488   XClearWindow(display, frame.psbutton);
489   XClearWindow(display, frame.nsbutton);
490   XClearWindow(display, frame.pwbutton);
491   XClearWindow(display, frame.nwbutton);
492
493   redrawWindowLabel();
494   redrawWorkspaceLabel();
495   redrawPrevWorkspaceButton();
496   redrawNextWorkspaceButton();
497   redrawPrevWindowButton();
498   redrawNextWindowButton();
499   checkClock(True);
500
501   toolbarmenu->reconfigure();
502 }
503
504
505 void Toolbar::updateStrut(void) {
506   // left and right are always 0
507   strut.top = strut.bottom = 0;
508
509   // when hidden only one border is visible
510   unsigned int border_width = screen->getBorderWidth();
511   if (! do_auto_hide)
512     border_width *= 2;
513
514   if (! screen->doHideToolbar()) {
515     switch(placement) {
516     case TopLeft:
517     case TopCenter:
518     case TopRight:
519       strut.top = getExposedHeight() + border_width;
520       break;
521     default:
522       strut.bottom = getExposedHeight() + border_width;
523     }
524   }
525
526   screen->updateAvailableArea();
527 }
528
529
530 #ifdef    HAVE_STRFTIME
531 void Toolbar::checkClock(bool redraw) {
532 #else // !HAVE_STRFTIME
533 void Toolbar::checkClock(bool redraw, bool date) {
534 #endif // HAVE_STRFTIME
535   time_t tmp = 0;
536   struct tm *tt = 0;
537
538   if ((tmp = time(NULL)) != -1) {
539     if (! (tt = localtime(&tmp))) return;
540     if (tt->tm_min != frame.minute || tt->tm_hour != frame.hour) {
541       frame.hour = tt->tm_hour;
542       frame.minute = tt->tm_min;
543       XClearWindow(display, frame.clock);
544       redraw = True;
545     }
546   }
547
548   if (redraw) {
549 #ifdef    HAVE_STRFTIME
550     char t[1024];
551     if (! strftime(t, 1024, screen->getStrftimeFormat(), tt))
552       return;
553 #else // !HAVE_STRFTIME
554     char t[9];
555     if (date) {
556       // format the date... with special consideration for y2k ;)
557       if (screen->getDateFormat() == Blackbox::B_EuropeanDate)
558         sprintf(t, 18n(ToolbarSet, ToolbarNoStrftimeDateFormatEu,
559                        "%02d.%02d.%02d"),
560                 tt->tm_mday, tt->tm_mon + 1,
561                 (tt->tm_year >= 100) ? tt->tm_year - 100 : tt->tm_year);
562       else
563         sprintf(t, i18n(ToolbarSet, ToolbarNoStrftimeDateFormat,
564                         "%02d/%02d/%02d"),
565                 tt->tm_mon + 1, tt->tm_mday,
566                 (tt->tm_year >= 100) ? tt->tm_year - 100 : tt->tm_year);
567     } else {
568       if (screen->isClock24Hour())
569         sprintf(t, i18n(ToolbarSet, ToolbarNoStrftimeTimeFormat24,
570                         "  %02d:%02d "),
571                 frame.hour, frame.minute);
572       else
573         sprintf(t, i18n(ToolbarSet, ToolbarNoStrftimeTimeFormat12,
574                         "%02d:%02d %sm"),
575                 ((frame.hour > 12) ? frame.hour - 12 :
576                  ((frame.hour == 0) ? 12 : frame.hour)), frame.minute,
577                 ((frame.hour >= 12) ?
578                  i18n(ToolbarSet, ToolbarNoStrftimeTimeFormatP, "p") :
579                  i18n(ToolbarSet, ToolbarNoStrftimeTimeFormatA, "a")));
580     }
581 #endif // HAVE_STRFTIME
582
583     ToolbarStyle *style = screen->getToolbarStyle();
584
585     int pos = frame.bevel_w * 2; // this is modified by doJustify()
586     style->doJustify(t, pos, frame.clock_w, frame.bevel_w * 4);
587     style->font->drawString(frame.clock, pos, 1, style->c_text, t);
588   }
589 }
590
591
592 void Toolbar::redrawWindowLabel(bool redraw) {
593   BlackboxWindow *foc = screen->getBlackbox()->getFocusedWindow();
594   if (! foc) {
595     XClearWindow(display, frame.window_label);
596     return;
597   }
598
599   if (redraw)
600     XClearWindow(display, frame.window_label);
601
602   if (foc->getScreen() != screen) return;
603
604   const char *title = foc->getTitle();
605   ToolbarStyle *style = screen->getToolbarStyle();
606
607   int pos = frame.bevel_w * 2; // modified by doJustify()
608   style->doJustify(title, pos, frame.window_label_w, frame.bevel_w * 4);
609   style->font->drawString(frame.window_label, pos, 1, style->w_text, title);
610 }
611
612
613 void Toolbar::redrawWorkspaceLabel(bool redraw) {
614   const string& name = screen->getCurrentWorkspace()->getName();
615
616   if (redraw)
617     XClearWindow(display, frame.workspace_label);
618
619   ToolbarStyle *style = screen->getToolbarStyle();
620
621   int pos = frame.bevel_w * 2;
622   style->doJustify(name.c_str(), pos, frame.workspace_label_w,
623                    frame.bevel_w * 4);
624   style->font->drawString(frame.workspace_label, pos, 1, style->l_text, name);
625 }
626
627
628 void Toolbar::redrawPrevWorkspaceButton(bool pressed, bool redraw) {
629   if (redraw) {
630     if (pressed) {
631       if (frame.pbutton)
632         XSetWindowBackgroundPixmap(display, frame.psbutton, frame.pbutton);
633       else
634         XSetWindowBackground(display, frame.psbutton, frame.pbutton_pixel);
635     } else {
636       if (frame.button)
637         XSetWindowBackgroundPixmap(display, frame.psbutton, frame.button);
638       else
639         XSetWindowBackground(display, frame.psbutton, frame.button_pixel);
640     }
641     XClearWindow(display, frame.psbutton);
642   }
643
644   int hh = frame.button_w / 2, hw = frame.button_w / 2;
645
646   XPoint pts[3];
647   pts[0].x = hw - 2; pts[0].y = hh;
648   pts[1].x = 4; pts[1].y = 2;
649   pts[2].x = 0; pts[2].y = -4;
650
651   ToolbarStyle *style = screen->getToolbarStyle();
652   BPen pen(style->b_pic);
653   XFillPolygon(display, frame.psbutton, pen.gc(),
654                pts, 3, Convex, CoordModePrevious);
655 }
656
657
658 void Toolbar::redrawNextWorkspaceButton(bool pressed, bool redraw) {
659   if (redraw) {
660     if (pressed) {
661       if (frame.pbutton)
662         XSetWindowBackgroundPixmap(display, frame.nsbutton, frame.pbutton);
663       else
664         XSetWindowBackground(display, frame.nsbutton, frame.pbutton_pixel);
665     } else {
666       if (frame.button)
667         XSetWindowBackgroundPixmap(display, frame.nsbutton, frame.button);
668       else
669         XSetWindowBackground(display, frame.nsbutton, frame.button_pixel);
670     }
671     XClearWindow(display, frame.nsbutton);
672   }
673
674   int hh = frame.button_w / 2, hw = frame.button_w / 2;
675
676   XPoint pts[3];
677   pts[0].x = hw - 2; pts[0].y = hh - 2;
678   pts[1].x = 4; pts[1].y =  2;
679   pts[2].x = -4; pts[2].y = 2;
680
681   ToolbarStyle *style = screen->getToolbarStyle();
682   BPen pen(style->b_pic);
683   XFillPolygon(display, frame.nsbutton, pen.gc(),
684                pts, 3, Convex, CoordModePrevious);
685 }
686
687
688 void Toolbar::redrawPrevWindowButton(bool pressed, bool redraw) {
689   if (redraw) {
690     if (pressed) {
691       if (frame.pbutton)
692         XSetWindowBackgroundPixmap(display, frame.pwbutton, frame.pbutton);
693       else
694         XSetWindowBackground(display, frame.pwbutton, frame.pbutton_pixel);
695     } else {
696       if (frame.button)
697         XSetWindowBackgroundPixmap(display, frame.pwbutton, frame.button);
698       else
699         XSetWindowBackground(display, frame.pwbutton, frame.button_pixel);
700     }
701     XClearWindow(display, frame.pwbutton);
702   }
703
704   int hh = frame.button_w / 2, hw = frame.button_w / 2;
705
706   XPoint pts[3];
707   pts[0].x = hw - 2; pts[0].y = hh;
708   pts[1].x = 4; pts[1].y = 2;
709   pts[2].x = 0; pts[2].y = -4;
710
711   ToolbarStyle *style = screen->getToolbarStyle();
712   BPen pen(style->b_pic);
713   XFillPolygon(display, frame.pwbutton, pen.gc(),
714                pts, 3, Convex, CoordModePrevious);
715 }
716
717
718 void Toolbar::redrawNextWindowButton(bool pressed, bool redraw) {
719   if (redraw) {
720     if (pressed) {
721       if (frame.pbutton)
722         XSetWindowBackgroundPixmap(display, frame.nwbutton, frame.pbutton);
723       else
724         XSetWindowBackground(display, frame.nwbutton, frame.pbutton_pixel);
725     } else {
726       if (frame.button)
727         XSetWindowBackgroundPixmap(display, frame.nwbutton, frame.button);
728       else
729         XSetWindowBackground(display, frame.nwbutton, frame.button_pixel);
730     }
731     XClearWindow(display, frame.nwbutton);
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 - 2;
738   pts[1].x = 4; pts[1].y =  2;
739   pts[2].x = -4; pts[2].y = 2;
740
741   ToolbarStyle *style = screen->getToolbarStyle();
742   BPen pen(style->b_pic);
743   XFillPolygon(display, frame.nwbutton, pen.gc(), pts, 3, Convex,
744                CoordModePrevious);
745 }
746
747
748 void Toolbar::edit(void) {
749   Window window;
750   int foo;
751
752   editing = True;
753   XGetInputFocus(display, &window, &foo);
754   if (window == frame.workspace_label)
755     return;
756
757   XSetInputFocus(display, frame.workspace_label,
758                  RevertToPointerRoot, CurrentTime);
759   XClearWindow(display, frame.workspace_label);
760
761   blackbox->setNoFocus(True);
762   if (blackbox->getFocusedWindow())
763     blackbox->getFocusedWindow()->setFocusFlag(False);
764
765   ToolbarStyle *style = screen->getToolbarStyle();
766   BPen pen(style->l_text);
767   XDrawRectangle(display, frame.workspace_label, pen.gc(),
768                  frame.workspace_label_w / 2, 0, 1,
769                  frame.label_h - 1);
770   // change the background of the window to that of an active window label
771   BTexture *texture = &(screen->getWindowStyle()->l_focus);
772   frame.wlabel = texture->render(frame.workspace_label_w, frame.label_h,
773                                  frame.wlabel);
774   if (! frame.wlabel)
775     XSetWindowBackground(display, frame.workspace_label,
776                          texture->color().pixel());
777   else
778     XSetWindowBackgroundPixmap(display, frame.workspace_label, frame.wlabel);
779 }
780
781
782 void Toolbar::buttonPressEvent(const XButtonEvent *be) {
783   if (be->button == 1) {
784     if (be->window == frame.psbutton)
785       redrawPrevWorkspaceButton(True, True);
786     else if (be->window == frame.nsbutton)
787       redrawNextWorkspaceButton(True, True);
788     else if (be->window == frame.pwbutton)
789       redrawPrevWindowButton(True, True);
790     else if (be->window == frame.nwbutton)
791       redrawNextWindowButton(True, True);
792 #ifndef   HAVE_STRFTIME
793     else if (be->window == frame.clock) {
794       XClearWindow(display, frame.clock);
795       checkClock(True, True);
796     }
797 #endif // HAVE_STRFTIME
798     else if (! on_top) {
799       Window w[1] = { frame.window };
800       screen->raiseWindows(w, 1);
801     }
802   } else if (be->button == 2 && (! on_top)) {
803     XLowerWindow(display, frame.window);
804   } else if (be->button == 3) {
805     if (toolbarmenu->isVisible()) {
806       toolbarmenu->hide();
807     } else {
808       int x, y;
809
810       x = be->x_root - (toolbarmenu->getWidth() / 2);
811       y = be->y_root - (toolbarmenu->getHeight() / 2);
812
813       if (x < 0)
814         x = 0;
815       else if (x + toolbarmenu->getWidth() > screen->getWidth())
816         x = screen->getWidth() - toolbarmenu->getWidth();
817
818       if (y < 0)
819         y = 0;
820       else if (y + toolbarmenu->getHeight() > screen->getHeight())
821         y = screen->getHeight() - toolbarmenu->getHeight();
822
823       toolbarmenu->move(x, y);
824       toolbarmenu->show();
825     }
826   }
827 }
828
829
830
831 void Toolbar::buttonReleaseEvent(const XButtonEvent *re) {
832   if (re->button == 1) {
833     if (re->window == frame.psbutton) {
834       redrawPrevWorkspaceButton(False, True);
835
836       if (re->x >= 0 && re->x < static_cast<signed>(frame.button_w) &&
837           re->y >= 0 && re->y < static_cast<signed>(frame.button_w))
838        if (screen->getCurrentWorkspace()->getID() > 0)
839           screen->changeWorkspaceID(screen->getCurrentWorkspace()->
840                                     getID() - 1);
841         else
842           screen->changeWorkspaceID(screen->getWorkspaceCount() - 1);
843     } else if (re->window == frame.nsbutton) {
844       redrawNextWorkspaceButton(False, True);
845
846       if (re->x >= 0 && re->x < static_cast<signed>(frame.button_w) &&
847           re->y >= 0 && re->y < static_cast<signed>(frame.button_w))
848         if (screen->getCurrentWorkspace()->getID() <
849             (screen->getWorkspaceCount() - 1))
850           screen->changeWorkspaceID(screen->getCurrentWorkspace()->
851                                     getID() + 1);
852         else
853           screen->changeWorkspaceID(0);
854     } else if (re->window == frame.pwbutton) {
855       redrawPrevWindowButton(False, True);
856
857       if (re->x >= 0 && re->x < static_cast<signed>(frame.button_w) &&
858           re->y >= 0 && re->y < static_cast<signed>(frame.button_w))
859         screen->prevFocus();
860     } else if (re->window == frame.nwbutton) {
861       redrawNextWindowButton(False, True);
862
863       if (re->x >= 0 && re->x < static_cast<signed>(frame.button_w) &&
864           re->y >= 0 && re->y < static_cast<signed>(frame.button_w))
865         screen->nextFocus();
866     } else if (re->window == frame.window_label)
867       screen->raiseFocus();
868 #ifndef   HAVE_STRFTIME
869     else if (re->window == frame.clock) {
870       XClearWindow(display, frame.clock);
871       checkClock(True);
872     }
873 #endif // HAVE_STRFTIME
874   }
875 }
876
877
878 void Toolbar::enterNotifyEvent(const XCrossingEvent *) {
879   if (! do_auto_hide)
880     return;
881
882   if (hidden) {
883     if (! hide_timer->isTiming()) hide_timer->start();
884   } else {
885     if (hide_timer->isTiming()) hide_timer->stop();
886   }
887 }
888
889 void Toolbar::leaveNotifyEvent(const XCrossingEvent *) {
890   if (! do_auto_hide)
891     return;
892
893   if (hidden) {
894     if (hide_timer->isTiming()) hide_timer->stop();
895   } else if (! toolbarmenu->isVisible()) {
896     if (! hide_timer->isTiming()) hide_timer->start();
897   }
898 }
899
900
901 void Toolbar::exposeEvent(const XExposeEvent *ee) {
902   if (ee->window == frame.clock) checkClock(True);
903   else if (ee->window == frame.workspace_label && (! editing))
904     redrawWorkspaceLabel();
905   else if (ee->window == frame.window_label) redrawWindowLabel();
906   else if (ee->window == frame.psbutton) redrawPrevWorkspaceButton();
907   else if (ee->window == frame.nsbutton) redrawNextWorkspaceButton();
908   else if (ee->window == frame.pwbutton) redrawPrevWindowButton();
909   else if (ee->window == frame.nwbutton) redrawNextWindowButton();
910 }
911
912
913 void Toolbar::keyPressEvent(const XKeyEvent *ke) {
914   if (ke->window == frame.workspace_label && editing) {
915     if (new_workspace_name.empty()) {
916       new_name_pos = 0;
917     }
918
919     KeySym ks;
920     char keychar[1];
921     XLookupString(const_cast<XKeyEvent*>(ke), keychar, 1, &ks, 0);
922
923     // either we are told to end with a return or we hit 127 chars
924     if (ks == XK_Return || new_name_pos == 127) {
925       editing = False;
926
927       blackbox->setNoFocus(False);
928       if (blackbox->getFocusedWindow()) {
929         blackbox->getFocusedWindow()->setInputFocus();
930       } else {
931         blackbox->setFocusedWindow(0);
932       }
933
934       Workspace *wkspc = screen->getCurrentWorkspace();
935       wkspc->setName(new_workspace_name);
936       wkspc->getMenu()->hide();
937
938       screen->getWorkspacemenu()->changeItemLabel(wkspc->getID() + 2,
939                                                   wkspc->getName());
940       screen->getWorkspacemenu()->update();
941
942       new_workspace_name.erase();
943       new_name_pos = 0;
944
945       // reset the background to that of the workspace label (its normal
946       // setting)
947       BTexture *texture = &(screen->getToolbarStyle()->label);
948       frame.wlabel = texture->render(frame.workspace_label_w, frame.label_h,
949                                      frame.wlabel);
950       if (! frame.wlabel)
951         XSetWindowBackground(display, frame.workspace_label,
952                              texture->color().pixel());
953       else
954         XSetWindowBackgroundPixmap(display, frame.workspace_label,
955                                    frame.wlabel);
956       reconfigure();
957     } else if (! (ks == XK_Shift_L || ks == XK_Shift_R ||
958                   ks == XK_Control_L || ks == XK_Control_R ||
959                   ks == XK_Caps_Lock || ks == XK_Shift_Lock ||
960                   ks == XK_Meta_L || ks == XK_Meta_R ||
961                   ks == XK_Alt_L || ks == XK_Alt_R ||
962                   ks == XK_Super_L || ks == XK_Super_R ||
963                   ks == XK_Hyper_L || ks == XK_Hyper_R)) {
964       if (ks == XK_BackSpace) {
965         if (new_name_pos > 0) {
966           --new_name_pos;
967           new_workspace_name.erase(new_name_pos);
968         } else {
969           new_workspace_name.resize(0);
970         }
971       } else {
972         new_workspace_name += (*keychar);
973         ++new_name_pos;
974       }
975
976       XClearWindow(display, frame.workspace_label);
977       unsigned int tw, x;
978
979       tw = screen->getToolbarStyle()->font->measureString(new_workspace_name);
980       x = (frame.workspace_label_w - tw) / 2;
981
982       if (x < frame.bevel_w) x = frame.bevel_w;
983
984       ToolbarStyle *style = screen->getToolbarStyle();
985       style->font->drawString(frame.workspace_label, x, 1, style->l_text,
986                               new_workspace_name);
987       BPen pen(style->l_text);
988       XDrawRectangle(display, frame.workspace_label, pen.gc(), x + tw, 0, 1,
989                      frame.label_h - 1);
990     }
991   }
992 }
993
994
995 void Toolbar::timeout(void) {
996   checkClock(True);
997
998   clock_timer->setTimeout(aMinuteFromNow());
999 }
1000
1001
1002 void Toolbar::HideHandler::timeout(void) {
1003   toolbar->hidden = ! toolbar->hidden;
1004   if (toolbar->hidden)
1005     XMoveWindow(toolbar->display, toolbar->frame.window,
1006                 toolbar->frame.x_hidden, toolbar->frame.y_hidden);
1007   else
1008     XMoveWindow(toolbar->display, toolbar->frame.window,
1009                 toolbar->frame.rect.x(), toolbar->frame.rect.y());
1010 }
1011
1012
1013 void Toolbar::toggleAutoHide(void) {
1014   saveAutoHide(! doAutoHide());
1015
1016   updateStrut();
1017   screen->getSlit()->reposition();
1018
1019   if (do_auto_hide == False && hidden) {
1020     // force the slit to be visible
1021     if (hide_timer->isTiming()) hide_timer->stop();
1022     hide_handler.timeout();
1023   }
1024 }
1025
1026
1027 Toolbarmenu::Toolbarmenu(Toolbar *tb) : Basemenu(tb->screen) {
1028   toolbar = tb;
1029
1030   setLabel(i18n(ToolbarSet, ToolbarToolbarTitle, "Toolbar"));
1031   setInternalMenu();
1032
1033   placementmenu = new Placementmenu(this);
1034
1035   insert(i18n(CommonSet, CommonPlacementTitle, "Placement"),
1036          placementmenu);
1037   insert(i18n(CommonSet, CommonAlwaysOnTop, "Always on top"), 1);
1038   insert(i18n(CommonSet, CommonAutoHide, "Auto hide"), 2);
1039   insert(i18n(ToolbarSet, ToolbarEditWkspcName,
1040               "Edit current workspace name"), 3);
1041
1042   update();
1043   setValues();
1044 }
1045
1046
1047 void Toolbarmenu::setValues() {
1048   setItemSelected(1, toolbar->isOnTop());
1049   setItemSelected(2, toolbar->doAutoHide());
1050 }
1051
1052
1053 Toolbarmenu::~Toolbarmenu(void) {
1054   delete placementmenu;
1055 }
1056
1057
1058 void Toolbarmenu::itemSelected(int button, unsigned int index) {
1059   if (button != 1)
1060     return;
1061
1062   BasemenuItem *item = find(index);
1063   if (! item) return;
1064
1065   switch (item->function()) {
1066   case 1: { // always on top
1067     toolbar->saveOnTop(! toolbar->isOnTop());
1068     setItemSelected(1, toolbar->isOnTop());
1069
1070     if (toolbar->isOnTop()) getScreen()->raiseWindows((Window *) 0, 0);
1071     break;
1072   }
1073
1074   case 2: { // auto hide
1075     toolbar->toggleAutoHide();
1076     setItemSelected(2, toolbar->doAutoHide());
1077
1078     break;
1079   }
1080
1081   case 3: { // edit current workspace name
1082     toolbar->edit();
1083     hide();
1084
1085     break;
1086   }
1087   } // switch
1088 }
1089
1090
1091 void Toolbarmenu::internal_hide(void) {
1092   Basemenu::internal_hide();
1093   if (toolbar->doAutoHide() && ! toolbar->isEditing())
1094     toolbar->hide_handler.timeout();
1095 }
1096
1097
1098 void Toolbarmenu::reconfigure(void) {
1099   setValues();
1100   placementmenu->reconfigure();
1101
1102   Basemenu::reconfigure();
1103 }
1104
1105
1106 Toolbarmenu::Placementmenu::Placementmenu(Toolbarmenu *tm)
1107   : Basemenu(tm->toolbar->screen), toolbar(tm->toolbar) {
1108   setLabel(i18n(ToolbarSet, ToolbarToolbarPlacement, "Toolbar Placement"));
1109   setInternalMenu();
1110   setMinimumSublevels(3);
1111
1112   insert(i18n(CommonSet, CommonPlacementTopLeft, "Top Left"),
1113          Toolbar::TopLeft);
1114   insert(i18n(CommonSet, CommonPlacementBottomLeft, "Bottom Left"),
1115          Toolbar::BottomLeft);
1116   insert(i18n(CommonSet, CommonPlacementTopCenter, "Top Center"),
1117          Toolbar::TopCenter);
1118   insert(i18n(CommonSet, CommonPlacementBottomCenter, "Bottom Center"),
1119          Toolbar::BottomCenter);
1120   insert(i18n(CommonSet, CommonPlacementTopRight, "Top Right"),
1121          Toolbar::TopRight);
1122   insert(i18n(CommonSet, CommonPlacementBottomRight, "Bottom Right"),
1123          Toolbar::BottomRight);
1124   update();
1125   setValues();
1126 }
1127
1128
1129 void Toolbarmenu::Placementmenu::setValues(void) {
1130   int place = 0;
1131   switch (toolbar->getPlacement()) {
1132   case Toolbar::BottomRight:
1133     place++;
1134   case Toolbar::TopRight:
1135     place++;
1136   case Toolbar::BottomCenter:
1137     place++;
1138   case Toolbar::TopCenter:
1139     place++;
1140   case Toolbar::BottomLeft:
1141     place++;
1142   case Toolbar::TopLeft:
1143     break;
1144   }
1145   setItemSelected(0, 0 == place);
1146   setItemSelected(1, 1 == place);
1147   setItemSelected(2, 2 == place);
1148   setItemSelected(3, 3 == place);
1149   setItemSelected(4, 4 == place);
1150   setItemSelected(5, 5 == place);
1151 }
1152
1153
1154 void Toolbarmenu::Placementmenu::reconfigure(void) {
1155   setValues();
1156   Basemenu::reconfigure();
1157 }
1158
1159
1160 void Toolbarmenu::Placementmenu::itemSelected(int button, unsigned int index) {
1161   if (button != 1)
1162     return;
1163
1164   BasemenuItem *item = find(index);
1165   if (! item) return;
1166
1167   toolbar->savePlacement(item->function());
1168   hide();
1169   toolbar->reconfigure();
1170
1171   // reposition the slit as well to make sure it doesn't intersect the
1172   // toolbar
1173   getScreen()->getSlit()->reposition();
1174 }
1175
1176
1177 void ToolbarStyle::doJustify(const std::string &text, int &start_pos,
1178                              unsigned int max_length,
1179                              unsigned int modifier) const {
1180   size_t text_len = text.size();
1181   unsigned int length;
1182
1183   do {
1184     length = font->measureString(string(text, 0, text_len)) + modifier;
1185   } while (length > max_length && text_len-- > 0);
1186
1187   switch (justify) {
1188   case RightJustify:
1189     start_pos += max_length - length;
1190     break;
1191
1192   case CenterJustify:
1193     start_pos += (max_length - length) / 2;
1194     break;
1195
1196   case LeftJustify:
1197   default:
1198     break;
1199   }
1200 }