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