]> icculus.org git repositories - mikachu/openbox.git/blob - src/Slit.cc
add some cvsignore's
[mikachu/openbox.git] / src / Slit.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Slit.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
32 #include "i18n.hh"
33 #include "blackbox.hh"
34 #include "Image.hh"
35 #include "Screen.hh"
36 #include "Slit.hh"
37 #include "Toolbar.hh"
38
39
40 Slit::Slit(BScreen *scr) {
41   screen = scr;
42   blackbox = screen->getBlackbox();
43   slitstr = "session.screen" + itostring(screen->getScreenNumber()) + ".slit.";
44   config = blackbox->getConfig();
45
46   load_rc();
47
48   display = screen->getBaseDisplay()->getXDisplay();
49   frame.window = frame.pixmap = None;
50
51   timer = new BTimer(blackbox, this);
52   timer->setTimeout(blackbox->getAutoRaiseDelay());
53
54   slitmenu = new Slitmenu(this);
55
56   XSetWindowAttributes attrib;
57   unsigned long create_mask = CWBackPixmap | CWBackPixel | CWBorderPixel |
58                               CWColormap | CWOverrideRedirect | CWEventMask;
59   attrib.background_pixmap = None;
60   attrib.background_pixel = attrib.border_pixel =
61     screen->getBorderColor()->pixel();
62   attrib.colormap = screen->getColormap();
63   attrib.override_redirect = True;
64   attrib.event_mask = SubstructureRedirectMask | ButtonPressMask |
65                       EnterWindowMask | LeaveWindowMask;
66
67   frame.rect.setSize(1, 1);
68
69   frame.window =
70     XCreateWindow(display, screen->getRootWindow(),
71                   frame.rect.x(), frame.rect.y(),
72                   frame.rect.width(), frame.rect.height(),
73                   screen->getBorderWidth(), screen->getDepth(), InputOutput,
74                   screen->getVisual(), create_mask, &attrib);
75   blackbox->saveSlitSearch(frame.window, this);
76
77   screen->addStrut(&strut);
78
79   reconfigure();
80 }
81
82
83 Slit::~Slit(void) {
84   delete timer;
85
86   delete slitmenu;
87
88   screen->removeStrut(&strut);
89   screen->updateAvailableArea();
90
91   screen->getImageControl()->removeImage(frame.pixmap);
92
93   blackbox->removeSlitSearch(frame.window);
94
95   XDestroyWindow(display, frame.window);
96 }
97
98
99 void Slit::addClient(Window w) {
100   if (! blackbox->validateWindow(w))
101     return;
102
103   SlitClient *client = new SlitClient;
104   client->client_window = w;
105
106   XWMHints *wmhints = XGetWMHints(display, w);
107
108   if (wmhints) {
109     if ((wmhints->flags & IconWindowHint) &&
110         (wmhints->icon_window != None)) {
111       // some dock apps use separate windows, we need to hide these
112       XMoveWindow(display, client->client_window, screen->getWidth() + 10,
113                   screen->getHeight() + 10);
114       XMapWindow(display, client->client_window);
115
116       client->icon_window = wmhints->icon_window;
117       client->window = client->icon_window;
118     } else {
119       client->icon_window = None;
120       client->window = client->client_window;
121     }
122
123     XFree(wmhints);
124   } else {
125     client->icon_window = None;
126     client->window = client->client_window;
127   }
128
129   XWindowAttributes attrib;
130   if (XGetWindowAttributes(display, client->window, &attrib)) {
131     client->rect.setSize(attrib.width, attrib.height);
132   } else {
133     client->rect.setSize(64, 64);
134   }
135
136   XSetWindowBorderWidth(display, client->window, 0);
137
138   XGrabServer(display);
139   XSelectInput(display, frame.window, NoEventMask);
140   XSelectInput(display, client->window, NoEventMask);
141   XReparentWindow(display, client->window, frame.window, 0, 0);
142   XMapRaised(display, client->window);
143   XChangeSaveSet(display, client->window, SetModeInsert);
144   XSelectInput(display, frame.window, SubstructureRedirectMask |
145                ButtonPressMask | EnterWindowMask | LeaveWindowMask);
146   XSelectInput(display, client->window, StructureNotifyMask |
147                SubstructureNotifyMask | EnterWindowMask);
148
149   XUngrabServer(display);
150
151   clientList.push_back(client);
152
153   blackbox->saveSlitSearch(client->client_window, this);
154   blackbox->saveSlitSearch(client->icon_window, this);
155   reconfigure();
156 }
157
158
159 void Slit::removeClient(SlitClient *client, bool remap) {
160   blackbox->removeSlitSearch(client->client_window);
161   blackbox->removeSlitSearch(client->icon_window);
162   clientList.remove(client);
163
164   screen->removeNetizen(client->window);
165
166   if (remap && blackbox->validateWindow(client->window)) {
167     XGrabServer(display);
168     XSelectInput(display, frame.window, NoEventMask);
169     XSelectInput(display, client->window, NoEventMask);
170     XReparentWindow(display, client->window, screen->getRootWindow(),
171                     client->rect.x(), client->rect.y());
172     XChangeSaveSet(display, client->window, SetModeDelete);
173     XSelectInput(display, frame.window, SubstructureRedirectMask |
174                  ButtonPressMask | EnterWindowMask | LeaveWindowMask);
175     XUngrabServer(display);
176   }
177
178   delete client;
179   client = (SlitClient *) 0;
180 }
181
182
183 struct SlitClientMatch {
184   Window window;
185   SlitClientMatch(Window w): window(w) {}
186   inline bool operator()(const Slit::SlitClient* client) const {
187     return (client->window == window);
188   }
189 };
190
191
192 void Slit::removeClient(Window w, bool remap) {
193   SlitClientList::iterator it = clientList.begin();
194   const SlitClientList::iterator end = clientList.end();
195
196   it = std::find_if(it, end, SlitClientMatch(w));
197   if (it != end) {
198     removeClient(*it, remap);
199     reconfigure();
200   }
201 }
202
203
204 void Slit::saveOnTop(bool b) {
205   on_top = b;
206   config->setValue(slitstr + "onTop", on_top);
207 }
208
209 void Slit::saveAutoHide(bool b) {
210   do_auto_hide = b;
211   config->setValue(slitstr + "autoHide", do_auto_hide);
212 }
213
214 void Slit::savePlacement(int p) {
215   placement = p;
216   const char *pname;
217   switch (placement) {
218   case TopLeft: pname = "TopLeft"; break;
219   case CenterLeft: pname = "CenterLeft"; break;
220   case BottomLeft: pname = "BottomLeft"; break;
221   case TopCenter: pname = "TopCenter"; break;
222   case BottomCenter: pname = "BottomCenter"; break;
223   case TopRight: pname = "TopRight"; break;
224   case BottomRight: pname = "BottomRight"; break;
225   case CenterRight: default: pname = "CenterRight"; break;
226   }
227   config->setValue(slitstr + "placement", pname);
228 }
229
230 void Slit::saveDirection(int d) {
231   direction = d;
232   config->setValue(slitstr + "direction", (direction == Horizontal ?
233                                           "Horizontal" : "Vertical"));
234 }
235
236 void Slit::save_rc(void) {
237   saveOnTop(on_top);
238   saveAutoHide(do_auto_hide);
239   savePlacement(placement);
240   saveDirection(direction);
241 }
242
243 void Slit::load_rc(void) {
244   std::string s;
245
246   if (! config->getValue(slitstr + "onTop", on_top))
247     on_top = false;
248
249   if (! config->getValue(slitstr + "autoHide", do_auto_hide))
250     do_auto_hide = false;
251   hidden = do_auto_hide;
252
253   if (config->getValue(slitstr + "direction", s) && s == "Horizontal")
254     direction = Horizontal;
255   else
256     direction = Vertical;
257   
258   if (config->getValue(slitstr + "placement", s)) {
259     if (s == "TopLeft")
260       placement = TopLeft;
261     else if (s == "CenterLeft")
262       placement = CenterLeft;
263     else if (s == "BottomLeft")
264       placement = BottomLeft;
265     else if (s == "TopCenter")
266       placement = TopCenter;
267     else if (s == "BottomCenter")
268       placement = BottomCenter;
269     else if (s == "TopRight")
270       placement = TopRight;
271     else if (s == "BottomRight")
272       placement = BottomRight;
273     else //if (s == "CenterRight")
274       placement = CenterRight;
275   } else
276     placement = CenterRight;
277 }
278
279
280 void Slit::reconfigure(void) {
281   SlitClientList::iterator it = clientList.begin();
282   const SlitClientList::iterator end = clientList.end();
283   SlitClient *client;
284
285   unsigned int width = 0, height = 0;
286
287   switch (direction) {
288   case Vertical:
289     for (; it != end; ++it) {
290       client = *it;
291       height += client->rect.height() + screen->getBevelWidth();
292
293       if (width < client->rect.width())
294         width = client->rect.width();
295     }
296
297     if (width < 1)
298       width = 1;
299     else
300       width += (screen->getBevelWidth() * 2);
301
302     if (height < 1)
303       height = 1;
304     else
305       height += screen->getBevelWidth();
306
307     break;
308
309   case Horizontal:
310     for (; it != end; ++it) {
311       client = *it;
312       width += client->rect.width() + screen->getBevelWidth();
313
314       if (height < client->rect.height())
315         height = client->rect.height();
316     }
317
318     if (width < 1)
319       width = 1;
320     else
321       width += screen->getBevelWidth();
322
323     if (height < 1)
324       height = 1;
325     else
326       height += (screen->getBevelWidth() * 2);
327
328     break;
329   }
330   frame.rect.setSize(width, height);
331
332   reposition();
333
334   XSetWindowBorderWidth(display ,frame.window, screen->getBorderWidth());
335   XSetWindowBorder(display, frame.window,
336                    screen->getBorderColor()->pixel());
337
338   if (clientList.empty())
339     XUnmapWindow(display, frame.window);
340   else
341     XMapWindow(display, frame.window);
342
343   BTexture *texture = &(screen->getToolbarStyle()->toolbar);
344   frame.pixmap = texture->render(frame.rect.width(), frame.rect.height(),
345                                  frame.pixmap);
346   if (! frame.pixmap)
347     XSetWindowBackground(display, frame.window, texture->color().pixel());
348   else
349     XSetWindowBackgroundPixmap(display, frame.window, frame.pixmap);
350
351   XClearWindow(display, frame.window);
352
353   it = clientList.begin();
354
355   int x, y;
356
357   switch (direction) {
358   case Vertical:
359     x = 0;
360     y = screen->getBevelWidth();
361
362     for (; it != end; ++it) {
363       client = *it;
364       x = (frame.rect.width() - client->rect.width()) / 2;
365
366       XMoveResizeWindow(display, client->window, x, y,
367                         client->rect.width(), client->rect.height());
368       XMapWindow(display, client->window);
369
370       // for ICCCM compliance
371       client->rect.setPos(x, y);
372
373       XEvent event;
374       event.type = ConfigureNotify;
375
376       event.xconfigure.display = display;
377       event.xconfigure.event = client->window;
378       event.xconfigure.window = client->window;
379       event.xconfigure.x = x;
380       event.xconfigure.y = y;
381       event.xconfigure.width = client->rect.width();
382       event.xconfigure.height = client->rect.height();
383       event.xconfigure.border_width = 0;
384       event.xconfigure.above = frame.window;
385       event.xconfigure.override_redirect = False;
386
387       XSendEvent(display, client->window, False, StructureNotifyMask, &event);
388
389       y += client->rect.height() + screen->getBevelWidth();
390     }
391
392     break;
393
394   case Horizontal:
395     x = screen->getBevelWidth();
396     y = 0;
397
398     for (; it != end; ++it) {
399       client = *it;
400       y = (frame.rect.height() - client->rect.height()) / 2;
401
402       XMoveResizeWindow(display, client->window, x, y,
403                         client->rect.width(), client->rect.height());
404       XMapWindow(display, client->window);
405
406       // for ICCCM compliance
407       client->rect.setPos(x, y);
408
409       XEvent event;
410       event.type = ConfigureNotify;
411
412       event.xconfigure.display = display;
413       event.xconfigure.event = client->window;
414       event.xconfigure.window = client->window;
415       event.xconfigure.x = x;
416       event.xconfigure.y = y;
417       event.xconfigure.width = client->rect.width();
418       event.xconfigure.height = client->rect.height();
419       event.xconfigure.border_width = 0;
420       event.xconfigure.above = frame.window;
421       event.xconfigure.override_redirect = False;
422
423       XSendEvent(display, client->window, False, StructureNotifyMask, &event);
424
425       x += client->rect.width() + screen->getBevelWidth();
426     }
427     break;
428   }
429
430   slitmenu->reconfigure();
431 }
432
433
434 void Slit::updateStrut(void) {
435   strut.top = strut.bottom = strut.left = strut.right = 0;
436
437   if (! clientList.empty()) {
438     // when not hidden both borders are in use, when hidden only one is
439     unsigned int border_width = screen->getBorderWidth();
440     if (! do_auto_hide)
441       border_width *= 2;
442
443     switch (direction) {
444     case Vertical:
445       switch (placement) {
446       case TopCenter:
447         strut.top = getExposedHeight() + border_width;
448         break;
449       case BottomCenter:
450         strut.bottom = getExposedHeight() + border_width;
451         break;
452       case TopLeft:
453       case CenterLeft:
454       case BottomLeft:
455         strut.left = getExposedWidth() + border_width;
456         break;
457       case TopRight:
458       case CenterRight:
459       case BottomRight:
460         strut.right = getExposedWidth() + border_width;
461         break;
462       }
463       break;
464     case Horizontal:
465       switch (placement) {
466       case TopCenter:
467       case TopLeft:
468       case TopRight:
469         strut.top = getExposedHeight() + border_width;
470         break;
471       case BottomCenter:
472       case BottomLeft:
473       case BottomRight:
474         strut.bottom = getExposedHeight() + border_width;
475         break;
476       case CenterLeft:
477         strut.left = getExposedWidth() + border_width;
478         break;
479       case CenterRight:
480         strut.right = getExposedWidth() + border_width;
481         break;
482       }
483       break;
484     }
485   }
486
487   // update area with new Strut info
488   screen->updateAvailableArea();
489 }
490
491
492 void Slit::reposition(void) {
493   // place the slit in the appropriate place
494   switch (placement) {
495   case TopLeft:
496     frame.rect.setPos(0, 0);
497
498     if (direction == Vertical) {
499       frame.x_hidden = screen->getBevelWidth() - screen->getBorderWidth()
500                        - frame.rect.width();
501       frame.y_hidden = 0;
502     } else {
503       frame.x_hidden = 0;
504       frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth()
505                        - frame.rect.height();
506     }
507     break;
508
509   case CenterLeft:
510     frame.rect.setPos(0, (screen->getHeight() - frame.rect.height()) / 2);
511
512     frame.x_hidden = screen->getBevelWidth() - screen->getBorderWidth()
513                      - frame.rect.width();
514     frame.y_hidden = frame.rect.y();
515     break;
516
517   case BottomLeft:
518     frame.rect.setPos(0, (screen->getHeight() - frame.rect.height()
519                           - (screen->getBorderWidth() * 2)));
520
521     if (direction == Vertical) {
522       frame.x_hidden = screen->getBevelWidth() - screen->getBorderWidth()
523                        - frame.rect.width();
524       frame.y_hidden = frame.rect.y();
525     } else {
526       frame.x_hidden = 0;
527       frame.y_hidden = screen->getHeight() - screen->getBevelWidth()
528                        - screen->getBorderWidth();
529     }
530     break;
531
532   case TopCenter:
533     frame.rect.setPos((screen->getWidth() - frame.rect.width()) / 2, 0);
534
535     frame.x_hidden = frame.rect.x();
536     frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth()
537                      - frame.rect.height();
538     break;
539
540   case BottomCenter:
541     frame.rect.setPos((screen->getWidth() - frame.rect.width()) / 2,
542                       (screen->getHeight() - frame.rect.height()
543                        - (screen->getBorderWidth() * 2)));
544     frame.x_hidden = frame.rect.x();
545     frame.y_hidden = screen->getHeight() - screen->getBevelWidth()
546                      - screen->getBorderWidth();
547     break;
548
549   case TopRight:
550     frame.rect.setPos((screen->getWidth() - frame.rect.width()
551                        - (screen->getBorderWidth() * 2)), 0);
552
553     if (direction == Vertical) {
554       frame.x_hidden = screen->getWidth() - screen->getBevelWidth()
555                        - screen->getBorderWidth();
556       frame.y_hidden = 0;
557     } else {
558       frame.x_hidden = frame.rect.x();
559       frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth()
560                        - frame.rect.height();
561     }
562     break;
563
564   case CenterRight:
565   default:
566     frame.rect.setPos((screen->getWidth() - frame.rect.width()
567                        - (screen->getBorderWidth() * 2)),
568                       (screen->getHeight() - frame.rect.height()) / 2);
569
570     frame.x_hidden = screen->getWidth() - screen->getBevelWidth()
571                      - screen->getBorderWidth();
572     frame.y_hidden = frame.rect.y();
573     break;
574
575   case BottomRight:
576     frame.rect.setPos((screen->getWidth() - frame.rect.width()
577                        - (screen->getBorderWidth() * 2)),
578                       (screen->getHeight() - frame.rect.height()
579                        - (screen->getBorderWidth() * 2)));
580
581     if (direction == Vertical) {
582       frame.x_hidden = screen->getWidth() - screen->getBevelWidth()
583                        - screen->getBorderWidth();
584       frame.y_hidden = frame.rect.y();
585     } else {
586       frame.x_hidden = frame.rect.x();
587       frame.y_hidden = screen->getHeight() - screen->getBevelWidth()
588                        - screen->getBorderWidth();
589     }
590     break;
591   }
592
593   Rect tbar_rect = screen->getToolbar()->getRect();
594   tbar_rect.setSize(tbar_rect.width() + (screen->getBorderWidth() * 2),
595                     tbar_rect.height() + (screen->getBorderWidth() * 2));
596   Rect slit_rect = frame.rect;
597   slit_rect.setSize(slit_rect.width() + (screen->getBorderWidth() * 2),
598                     slit_rect.height() + (screen->getBorderWidth() * 2));
599
600   if (slit_rect.intersects(tbar_rect)) {
601     Toolbar *tbar = screen->getToolbar();
602     frame.y_hidden = frame.rect.y();
603
604     int delta = tbar->getExposedHeight() + (screen->getBorderWidth() * 2);
605     if (frame.rect.bottom() <= tbar_rect.bottom()) {
606       delta = -delta;
607     }
608     frame.rect.setY(frame.rect.y() + delta);
609     if (direction == Vertical)
610       frame.y_hidden += delta;
611   }
612
613   updateStrut();
614
615   if (hidden)
616     XMoveResizeWindow(display, frame.window, frame.x_hidden,
617                       frame.y_hidden, frame.rect.width(), frame.rect.height());
618   else
619     XMoveResizeWindow(display, frame.window, frame.rect.x(), frame.rect.y(),
620                       frame.rect.width(), frame.rect.height());
621 }
622
623
624 void Slit::shutdown(void) {
625   while (! clientList.empty())
626     removeClient(clientList.front());
627 }
628
629
630 void Slit::buttonPressEvent(const XButtonEvent *e) {
631   if (e->window != frame.window) return;
632
633   if (e->button == Button1 && (! on_top)) {
634     Window w[1] = { frame.window };
635     screen->raiseWindows(w, 1);
636   } else if (e->button == Button2 && (! on_top)) {
637     XLowerWindow(display, frame.window);
638   } else if (e->button == Button3) {
639     if (! slitmenu->isVisible()) {
640       int x, y;
641
642       x = e->x_root - (slitmenu->getWidth() / 2);
643       y = e->y_root - (slitmenu->getHeight() / 2);
644
645       if (x < 0)
646         x = 0;
647       else if (x + slitmenu->getWidth() > screen->getWidth())
648         x = screen->getWidth() - slitmenu->getWidth();
649
650       if (y < 0)
651         y = 0;
652       else if (y + slitmenu->getHeight() > screen->getHeight())
653         y = screen->getHeight() - slitmenu->getHeight();
654
655       slitmenu->move(x, y);
656       slitmenu->show();
657     } else {
658       slitmenu->hide();
659     }
660   }
661 }
662
663
664 void Slit::enterNotifyEvent(const XCrossingEvent *) {
665   if (! do_auto_hide)
666     return;
667
668   if (hidden) {
669     if (! timer->isTiming()) timer->start();
670   } else {
671     if (timer->isTiming()) timer->stop();
672   }
673 }
674
675
676 void Slit::leaveNotifyEvent(const XCrossingEvent *) {
677   if (! do_auto_hide)
678     return;
679
680   if (hidden) {
681     if (timer->isTiming()) timer->stop();
682   } else if (! slitmenu->isVisible()) {
683     if (! timer->isTiming()) timer->start();
684   }
685 }
686
687
688 void Slit::configureRequestEvent(const XConfigureRequestEvent *e) {
689   if (! blackbox->validateWindow(e->window))
690     return;
691
692   XWindowChanges xwc;
693
694   xwc.x = e->x;
695   xwc.y = e->y;
696   xwc.width = e->width;
697   xwc.height = e->height;
698   xwc.border_width = 0;
699   xwc.sibling = e->above;
700   xwc.stack_mode = e->detail;
701
702   XConfigureWindow(display, e->window, e->value_mask, &xwc);
703
704   SlitClientList::iterator it = clientList.begin();
705   const SlitClientList::iterator end = clientList.end();
706   for (; it != end; ++it) {
707     SlitClient *client = *it;
708     if (client->window == e->window &&
709         (static_cast<signed>(client->rect.width()) != e->width ||
710          static_cast<signed>(client->rect.height()) != e->height)) {
711       client->rect.setSize(e->width, e->height);
712
713       reconfigure();
714       return;
715     }
716   }
717 }
718
719
720 void Slit::timeout(void) {
721   hidden = ! hidden;
722   if (hidden)
723     XMoveWindow(display, frame.window, frame.x_hidden, frame.y_hidden);
724   else
725     XMoveWindow(display, frame.window, frame.rect.x(), frame.rect.y());
726 }
727
728
729 void Slit::toggleAutoHide(void) {
730   saveAutoHide(do_auto_hide ?  False : True);
731
732   updateStrut();
733
734   if (do_auto_hide == False && hidden) {
735     // force the slit to be visible
736     if (timer->isTiming()) timer->stop();
737     timeout();
738   }
739 }
740
741
742 void Slit::unmapNotifyEvent(const XUnmapEvent *e) {
743   removeClient(e->window);
744 }
745
746
747 Slitmenu::Slitmenu(Slit *sl) : Basemenu(sl->screen) {
748   slit = sl;
749
750   setLabel(i18n(SlitSet, SlitSlitTitle, "Slit"));
751   setInternalMenu();
752
753   directionmenu = new Directionmenu(this);
754   placementmenu = new Placementmenu(this);
755
756   insert(i18n(CommonSet, CommonDirectionTitle, "Direction"),
757          directionmenu);
758   insert(i18n(CommonSet, CommonPlacementTitle, "Placement"),
759          placementmenu);
760   insert(i18n(CommonSet, CommonAlwaysOnTop, "Always on top"), 1);
761   insert(i18n(CommonSet, CommonAutoHide, "Auto hide"), 2);
762
763   update();
764
765   if (slit->isOnTop()) setItemSelected(2, True);
766   if (slit->doAutoHide()) setItemSelected(3, True);
767 }
768
769
770 Slitmenu::~Slitmenu(void) {
771   delete directionmenu;
772   delete placementmenu;
773 }
774
775
776 void Slitmenu::itemSelected(int button, unsigned int index) {
777   if (button != 1)
778     return;
779
780   BasemenuItem *item = find(index);
781   if (! item) return;
782
783   switch (item->function()) {
784   case 1: { // always on top
785     slit->saveOnTop(! slit->isOnTop());
786     setItemSelected(2, slit->isOnTop());
787
788     if (slit->isOnTop()) slit->screen->raiseWindows((Window *) 0, 0);
789     break;
790   }
791
792   case 2: { // auto hide
793     slit->toggleAutoHide();
794     setItemSelected(3, slit->doAutoHide());
795
796     break;
797   }
798   } // switch
799 }
800
801
802 void Slitmenu::internal_hide(void) {
803   Basemenu::internal_hide();
804   if (slit->doAutoHide())
805     slit->timeout();
806 }
807
808
809 void Slitmenu::reconfigure(void) {
810   directionmenu->reconfigure();
811   placementmenu->reconfigure();
812
813   Basemenu::reconfigure();
814 }
815
816
817 Slitmenu::Directionmenu::Directionmenu(Slitmenu *sm)
818   : Basemenu(sm->slit->screen), slit(sm->slit) {
819
820   setLabel(i18n(SlitSet, SlitSlitDirection, "Slit Direction"));
821   setInternalMenu();
822
823   insert(i18n(CommonSet, CommonDirectionHoriz, "Horizontal"),
824          Slit::Horizontal);
825   insert(i18n(CommonSet, CommonDirectionVert, "Vertical"),
826          Slit::Vertical);
827
828   update();
829   setValues();
830 }
831
832
833 void Slitmenu::Directionmenu::reconfigure(void) {
834   setValues();
835   Basemenu::reconfigure();
836 }   
837
838
839 void Slitmenu::Directionmenu::setValues(void) {
840   const bool horiz = slit->getDirection() == Slit::Horizontal;
841   setItemSelected(0, horiz);
842   setItemSelected(1, ! horiz);
843 }
844
845
846 void Slitmenu::Directionmenu::itemSelected(int button, unsigned int index) {
847   if (button != 1)
848     return;
849
850   BasemenuItem *item = find(index);
851   if (! item) return;
852
853   slit->saveDirection(item->function());
854   hide();
855   slit->reconfigure();
856 }
857
858
859 Slitmenu::Placementmenu::Placementmenu(Slitmenu *sm)
860   : Basemenu(sm->slit->screen), slit(sm->slit) {
861
862   setLabel(i18n(SlitSet, SlitSlitPlacement, "Slit Placement"));
863   setMinimumSublevels(3);
864   setInternalMenu();
865
866   insert(i18n(CommonSet, CommonPlacementTopLeft, "Top Left"),
867          Slit::TopLeft);
868   insert(i18n(CommonSet, CommonPlacementCenterLeft, "Center Left"),
869          Slit::CenterLeft);
870   insert(i18n(CommonSet, CommonPlacementBottomLeft, "Bottom Left"),
871          Slit::BottomLeft);
872   insert(i18n(CommonSet, CommonPlacementTopCenter, "Top Center"),
873          Slit::TopCenter);
874   insert("");
875   insert(i18n(CommonSet, CommonPlacementBottomCenter, "Bottom Center"),
876          Slit::BottomCenter);
877   insert(i18n(CommonSet, CommonPlacementTopRight, "Top Right"),
878          Slit::TopRight);
879   insert(i18n(CommonSet, CommonPlacementCenterRight, "Center Right"),
880          Slit::CenterRight);
881   insert(i18n(CommonSet, CommonPlacementBottomRight, "Bottom Right"),
882          Slit::BottomRight);
883
884   update();
885
886   setValues();
887 }
888
889
890 void Slitmenu::Placementmenu::reconfigure(void) {
891   setValues();
892   Basemenu::reconfigure();
893 }   
894
895
896 void Slitmenu::Placementmenu::setValues(void) {
897   int place = 0;
898   switch (slit->getPlacement()) {
899   case Slit::BottomRight:
900     place++;
901   case Slit::CenterRight:
902     place++;
903   case Slit::TopRight:
904     place++;
905   case Slit::BottomCenter:
906     place++;
907   case Slit::TopCenter:
908     place++;
909   case Slit::BottomLeft:
910     place++;
911   case Slit::CenterLeft:
912     place++;
913   case Slit::TopLeft:
914     break;
915   }
916   setItemSelected(0, 0 == place);
917   setItemSelected(1, 1 == place);
918   setItemSelected(2, 2 == place);
919   setItemSelected(3, 3 == place);
920   setItemSelected(5, 4 == place);
921   setItemSelected(6, 5 == place);
922   setItemSelected(7, 6 == place);
923   setItemSelected(8, 7 == place);
924 }
925
926
927 void Slitmenu::Placementmenu::itemSelected(int button, unsigned int index) {
928   if (button != 1)
929     return;
930
931   BasemenuItem *item = find(index);
932   if (! (item && item->function())) return;
933
934   slit->savePlacement(item->function());
935   hide();
936   slit->reconfigure();
937 }
938