]> icculus.org git repositories - mikachu/openbox.git/blob - src/Slit.cc
make work without --enable-xinerama
[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   int x = 0, y = 0;
494
495   switch (placement) {
496   case TopLeft:
497   case CenterLeft:
498   case BottomLeft:
499     x = 0;
500     frame.x_hidden = screen->getBevelWidth() - screen->getBorderWidth()
501       - frame.rect.width();
502
503     if (placement == TopLeft)
504       y = 0;
505     else if (placement == CenterLeft)
506       y = (screen->getHeight() - frame.rect.height()) / 2;
507     else
508       y = screen->getHeight() - frame.rect.height()
509   - (screen->getBorderWidth() * 2);
510
511     break;
512
513   case TopCenter:
514   case BottomCenter:
515     x = (screen->getWidth() - frame.rect.width()) / 2;
516     frame.x_hidden = x;
517
518     if (placement == TopCenter)
519       y = 0;
520     else
521       y = screen->getHeight() - frame.rect.height()
522   - (screen->getBorderWidth() * 2);
523
524     break;
525
526   case TopRight:
527   case CenterRight:
528   case BottomRight:
529     x = screen->getWidth() - frame.rect.width()
530       - (screen->getBorderWidth() * 2);
531     frame.x_hidden = screen->getWidth() - screen->getBevelWidth()
532       - screen->getBorderWidth();
533
534     if (placement == TopRight)
535       y = 0;
536     else if (placement == CenterRight)
537       y = (screen->getHeight() - frame.rect.height()) / 2;
538     else
539       y = screen->getHeight() - frame.rect.height()
540   - (screen->getBorderWidth() * 2);
541     break;
542   }
543
544   frame.rect.setPos(x, y);
545
546   // we have to add the border to the rect as it is not accounted for
547   Rect tbar_rect = screen->getToolbar()->getRect();
548   tbar_rect.setSize(tbar_rect.width() + (screen->getBorderWidth() * 2),
549                     tbar_rect.height() + (screen->getBorderWidth() * 2));
550   Rect slit_rect = frame.rect;
551   slit_rect.setSize(slit_rect.width() + (screen->getBorderWidth() * 2),
552                     slit_rect.height() + (screen->getBorderWidth() * 2));
553
554   if (slit_rect.intersects(tbar_rect)) {
555     int delta = screen->getToolbar()->getExposedHeight() +
556       screen->getBorderWidth();
557     if (frame.rect.bottom() <= tbar_rect.bottom())
558       delta = -delta;
559
560     frame.rect.setY(frame.rect.y() + delta);
561   }
562
563   if (placement == TopCenter)
564     frame.y_hidden = 0 - frame.rect.height() + screen->getBorderWidth() 
565       + screen->getBevelWidth();
566   else if (placement == BottomCenter)
567     frame.y_hidden = screen->getHeight() - screen->getBorderWidth()
568       - screen->getBevelWidth();
569   else
570     frame.y_hidden = frame.rect.y();
571
572   updateStrut();
573
574   if (hidden)
575     XMoveResizeWindow(display, frame.window,
576                       frame.x_hidden, frame.y_hidden,
577                       frame.rect.width(), frame.rect.height());
578   else
579     XMoveResizeWindow(display, frame.window,
580                       frame.rect.x(), frame.rect.y(),
581                       frame.rect.width(), frame.rect.height());
582 }
583
584
585 void Slit::shutdown(void) {
586   while (! clientList.empty())
587     removeClient(clientList.front());
588 }
589
590
591 void Slit::buttonPressEvent(const XButtonEvent *e) {
592   if (e->window != frame.window) return;
593
594   if (e->button == Button1 && (! on_top)) {
595     Window w[1] = { frame.window };
596     screen->raiseWindows(w, 1);
597   } else if (e->button == Button2 && (! on_top)) {
598     XLowerWindow(display, frame.window);
599   } else if (e->button == Button3) {
600     if (! slitmenu->isVisible()) {
601       int x, y;
602
603       x = e->x_root - (slitmenu->getWidth() / 2);
604       y = e->y_root - (slitmenu->getHeight() / 2);
605
606       if (x < 0)
607         x = 0;
608       else if (x + slitmenu->getWidth() > screen->getWidth())
609         x = screen->getWidth() - slitmenu->getWidth();
610
611       if (y < 0)
612         y = 0;
613       else if (y + slitmenu->getHeight() > screen->getHeight())
614         y = screen->getHeight() - slitmenu->getHeight();
615
616       slitmenu->move(x, y);
617       slitmenu->show();
618     } else {
619       slitmenu->hide();
620     }
621   }
622 }
623
624
625 void Slit::enterNotifyEvent(const XCrossingEvent *) {
626   if (! do_auto_hide)
627     return;
628
629   if (hidden) {
630     if (! timer->isTiming()) timer->start();
631   } else {
632     if (timer->isTiming()) timer->stop();
633   }
634 }
635
636
637 void Slit::leaveNotifyEvent(const XCrossingEvent *) {
638   if (! do_auto_hide)
639     return;
640
641   if (hidden) {
642     if (timer->isTiming()) timer->stop();
643   } else if (! slitmenu->isVisible()) {
644     if (! timer->isTiming()) timer->start();
645   }
646 }
647
648
649 void Slit::configureRequestEvent(const XConfigureRequestEvent *e) {
650   if (! blackbox->validateWindow(e->window))
651     return;
652
653   XWindowChanges xwc;
654
655   xwc.x = e->x;
656   xwc.y = e->y;
657   xwc.width = e->width;
658   xwc.height = e->height;
659   xwc.border_width = 0;
660   xwc.sibling = e->above;
661   xwc.stack_mode = e->detail;
662
663   XConfigureWindow(display, e->window, e->value_mask, &xwc);
664
665   SlitClientList::iterator it = clientList.begin();
666   const SlitClientList::iterator end = clientList.end();
667   for (; it != end; ++it) {
668     SlitClient *client = *it;
669     if (client->window == e->window &&
670         (static_cast<signed>(client->rect.width()) != e->width ||
671          static_cast<signed>(client->rect.height()) != e->height)) {
672       client->rect.setSize(e->width, e->height);
673
674       reconfigure();
675       return;
676     }
677   }
678 }
679
680
681 void Slit::timeout(void) {
682   hidden = ! hidden;
683   if (hidden)
684     XMoveWindow(display, frame.window, frame.x_hidden, frame.y_hidden);
685   else
686     XMoveWindow(display, frame.window, frame.rect.x(), frame.rect.y());
687 }
688
689
690 void Slit::toggleAutoHide(void) {
691   saveAutoHide(do_auto_hide ?  False : True);
692
693   updateStrut();
694
695   if (do_auto_hide == False && hidden) {
696     // force the slit to be visible
697     if (timer->isTiming()) timer->stop();
698     timeout();
699   }
700 }
701
702
703 void Slit::unmapNotifyEvent(const XUnmapEvent *e) {
704   removeClient(e->window);
705 }
706
707
708 Slitmenu::Slitmenu(Slit *sl) : Basemenu(sl->screen) {
709   slit = sl;
710
711   setLabel(i18n(SlitSet, SlitSlitTitle, "Slit"));
712   setInternalMenu();
713
714   directionmenu = new Directionmenu(this);
715   placementmenu = new Placementmenu(this);
716
717   insert(i18n(CommonSet, CommonDirectionTitle, "Direction"),
718          directionmenu);
719   insert(i18n(CommonSet, CommonPlacementTitle, "Placement"),
720          placementmenu);
721   insert(i18n(CommonSet, CommonAlwaysOnTop, "Always on top"), 1);
722   insert(i18n(CommonSet, CommonAutoHide, "Auto hide"), 2);
723
724   update();
725
726   if (slit->isOnTop()) setItemSelected(2, True);
727   if (slit->doAutoHide()) setItemSelected(3, True);
728 }
729
730
731 Slitmenu::~Slitmenu(void) {
732   delete directionmenu;
733   delete placementmenu;
734 }
735
736
737 void Slitmenu::itemSelected(int button, unsigned int index) {
738   if (button != 1)
739     return;
740
741   BasemenuItem *item = find(index);
742   if (! item) return;
743
744   switch (item->function()) {
745   case 1: { // always on top
746     slit->saveOnTop(! slit->isOnTop());
747     setItemSelected(2, slit->isOnTop());
748
749     if (slit->isOnTop()) slit->screen->raiseWindows((Window *) 0, 0);
750     break;
751   }
752
753   case 2: { // auto hide
754     slit->toggleAutoHide();
755     setItemSelected(3, slit->doAutoHide());
756
757     break;
758   }
759   } // switch
760 }
761
762
763 void Slitmenu::internal_hide(void) {
764   Basemenu::internal_hide();
765   if (slit->doAutoHide())
766     slit->timeout();
767 }
768
769
770 void Slitmenu::reconfigure(void) {
771   directionmenu->reconfigure();
772   placementmenu->reconfigure();
773
774   Basemenu::reconfigure();
775 }
776
777
778 Slitmenu::Directionmenu::Directionmenu(Slitmenu *sm)
779   : Basemenu(sm->slit->screen), slit(sm->slit) {
780
781   setLabel(i18n(SlitSet, SlitSlitDirection, "Slit Direction"));
782   setInternalMenu();
783
784   insert(i18n(CommonSet, CommonDirectionHoriz, "Horizontal"),
785          Slit::Horizontal);
786   insert(i18n(CommonSet, CommonDirectionVert, "Vertical"),
787          Slit::Vertical);
788
789   update();
790   setValues();
791 }
792
793
794 void Slitmenu::Directionmenu::reconfigure(void) {
795   setValues();
796   Basemenu::reconfigure();
797 }   
798
799
800 void Slitmenu::Directionmenu::setValues(void) {
801   const bool horiz = slit->getDirection() == Slit::Horizontal;
802   setItemSelected(0, horiz);
803   setItemSelected(1, ! horiz);
804 }
805
806
807 void Slitmenu::Directionmenu::itemSelected(int button, unsigned int index) {
808   if (button != 1)
809     return;
810
811   BasemenuItem *item = find(index);
812   if (! item) return;
813
814   slit->saveDirection(item->function());
815   hide();
816   slit->reconfigure();
817 }
818
819
820 Slitmenu::Placementmenu::Placementmenu(Slitmenu *sm)
821   : Basemenu(sm->slit->screen), slit(sm->slit) {
822
823   setLabel(i18n(SlitSet, SlitSlitPlacement, "Slit Placement"));
824   setMinimumSublevels(3);
825   setInternalMenu();
826
827   insert(i18n(CommonSet, CommonPlacementTopLeft, "Top Left"),
828          Slit::TopLeft);
829   insert(i18n(CommonSet, CommonPlacementCenterLeft, "Center Left"),
830          Slit::CenterLeft);
831   insert(i18n(CommonSet, CommonPlacementBottomLeft, "Bottom Left"),
832          Slit::BottomLeft);
833   insert(i18n(CommonSet, CommonPlacementTopCenter, "Top Center"),
834          Slit::TopCenter);
835   insert("");
836   insert(i18n(CommonSet, CommonPlacementBottomCenter, "Bottom Center"),
837          Slit::BottomCenter);
838   insert(i18n(CommonSet, CommonPlacementTopRight, "Top Right"),
839          Slit::TopRight);
840   insert(i18n(CommonSet, CommonPlacementCenterRight, "Center Right"),
841          Slit::CenterRight);
842   insert(i18n(CommonSet, CommonPlacementBottomRight, "Bottom Right"),
843          Slit::BottomRight);
844
845   update();
846
847   setValues();
848 }
849
850
851 void Slitmenu::Placementmenu::reconfigure(void) {
852   setValues();
853   Basemenu::reconfigure();
854 }   
855
856
857 void Slitmenu::Placementmenu::setValues(void) {
858   int place = 0;
859   switch (slit->getPlacement()) {
860   case Slit::BottomRight:
861     place++;
862   case Slit::CenterRight:
863     place++;
864   case Slit::TopRight:
865     place++;
866   case Slit::BottomCenter:
867     place++;
868   case Slit::TopCenter:
869     place++;
870   case Slit::BottomLeft:
871     place++;
872   case Slit::CenterLeft:
873     place++;
874   case Slit::TopLeft:
875     break;
876   }
877   setItemSelected(0, 0 == place);
878   setItemSelected(1, 1 == place);
879   setItemSelected(2, 2 == place);
880   setItemSelected(3, 3 == place);
881   setItemSelected(5, 4 == place);
882   setItemSelected(6, 5 == place);
883   setItemSelected(7, 6 == place);
884   setItemSelected(8, 7 == place);
885 }
886
887
888 void Slitmenu::Placementmenu::itemSelected(int button, unsigned int index) {
889   if (button != 1)
890     return;
891
892   BasemenuItem *item = find(index);
893   if (! (item && item->function())) return;
894
895   slit->savePlacement(item->function());
896   hide();
897   slit->reconfigure();
898 }
899