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