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