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