]> icculus.org git repositories - dana/openbox.git/blob - src/Slit.cc
This commit was manufactured by cvs2svn to create tag
[dana/openbox.git] / src / Slit.cc
1 // Slit.cc for Openbox
2 // Copyright (c) 2001 Sean 'Shaleh' Perry <shaleh@debian.org>
3 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
22
23 // stupid macros needed to access some functions in version 2 of the GNU C
24 // library
25 #ifndef   _GNU_SOURCE
26 #define   _GNU_SOURCE
27 #endif // _GNU_SOURCE
28
29 #ifdef    HAVE_CONFIG_H
30 #  include "../config.h"
31 #endif // HAVE_CONFIG_H
32
33 #ifdef    SLIT
34
35 #include <X11/keysym.h>
36
37 #include "i18n.h"
38 #include "openbox.h"
39 #include "Image.h"
40 #include "Screen.h"
41 #include "Slit.h"
42 #include "Toolbar.h"
43
44 #ifdef    HAVE_SSTREAM
45 #  include <sstream>
46 #endif // HAVE_SSTREAM
47
48 #include <string>
49
50 Slit::Slit(BScreen &scr, Resource &conf) : screen(scr),
51   openbox(scr.getOpenbox()), config(conf)
52 {
53   load();
54   
55   display = screen.getBaseDisplay().getXDisplay();
56   frame.window = frame.pixmap = None;
57
58   timer = new BTimer(openbox, *this);
59   timer->setTimeout(openbox.getAutoRaiseDelay());
60   timer->fireOnce(True);
61
62   clientList = new LinkedList<SlitClient>;
63
64   slitmenu = new Slitmenu(*this);
65
66   XSetWindowAttributes attrib;
67   unsigned long create_mask = CWBackPixmap | CWBackPixel | CWBorderPixel |
68                               CWColormap | CWOverrideRedirect | CWEventMask;
69   attrib.background_pixmap = None;
70   attrib.background_pixel = attrib.border_pixel =
71     screen.getBorderColor()->getPixel();
72   attrib.colormap = screen.getColormap();
73   attrib.override_redirect = True;
74   attrib.event_mask = SubstructureRedirectMask | ButtonPressMask |
75                       EnterWindowMask | LeaveWindowMask;
76
77   frame.area = Rect(0, 0, 1, 1);
78   
79   frame.window =
80     XCreateWindow(display, screen.getRootWindow(),
81                   frame.area.x(), frame.area.y(),
82                   frame.area.w(), frame.area.h(), screen.getBorderWidth(),
83                   screen.getDepth(), InputOutput, screen.getVisual(),
84                   create_mask, &attrib);
85   openbox.saveSlitSearch(frame.window, this);
86
87   reconfigure();
88 }
89
90
91 Slit::~Slit() {
92   openbox.grab();
93
94   if (timer->isTiming()) timer->stop();
95   delete timer;
96
97   delete clientList;
98   delete slitmenu;
99
100   screen.getImageControl()->removeImage(frame.pixmap);
101
102   openbox.removeSlitSearch(frame.window);
103
104   XDestroyWindow(display, frame.window);
105
106   openbox.ungrab();
107 }
108
109
110 void Slit::addClient(Window w) {
111   openbox.grab();
112
113   if (openbox.validateWindow(w)) {
114     SlitClient *client = new SlitClient;
115     client->client_window = w;
116
117     XWMHints *wmhints = XGetWMHints(display, w);
118
119     if (wmhints) {
120       if ((wmhints->flags & IconWindowHint) &&
121           (wmhints->icon_window != None)) {
122         XMoveWindow(display, client->client_window, screen.size().w() + 10,
123                     screen.size().h() + 10);
124         XMapWindow(display, client->client_window);
125
126         client->icon_window = wmhints->icon_window;
127         client->window = client->icon_window;
128       } else {
129         client->icon_window = None;
130         client->window = client->client_window;
131       }
132
133       XFree(wmhints);
134     } else {
135       client->icon_window = None;
136       client->window = client->client_window;
137     }
138
139     XWindowAttributes attrib;
140     if (XGetWindowAttributes(display, client->window, &attrib)) {
141       client->width = attrib.width;
142       client->height = attrib.height;
143     } else {
144       client->width = client->height = 64;
145     }
146
147     XSetWindowBorderWidth(display, client->window, 0);
148
149     XSelectInput(display, frame.window, NoEventMask);
150     XSelectInput(display, client->window, NoEventMask);
151
152     XReparentWindow(display, client->window, frame.window, 0, 0);
153     XMapRaised(display, client->window);
154     XChangeSaveSet(display, client->window, SetModeInsert);
155
156     XSelectInput(display, frame.window, SubstructureRedirectMask |
157                  ButtonPressMask | EnterWindowMask | LeaveWindowMask);
158     XSelectInput(display, client->window, StructureNotifyMask |
159                  SubstructureNotifyMask | EnterWindowMask);
160     XFlush(display);
161
162     clientList->insert(client);
163
164     openbox.saveSlitSearch(client->client_window, this);
165     openbox.saveSlitSearch(client->icon_window, this);
166     reconfigure();
167   }
168
169   openbox.ungrab();
170 }
171
172
173 void Slit::removeClient(SlitClient *client, Bool remap) {
174   openbox.removeSlitSearch(client->client_window);
175   openbox.removeSlitSearch(client->icon_window);
176   clientList->remove(client);
177
178   screen.removeNetizen(client->window);
179
180   if (remap && openbox.validateWindow(client->window)) {
181     XSelectInput(display, frame.window, NoEventMask);
182     XSelectInput(display, client->window, NoEventMask);
183     XReparentWindow(display, client->window, screen.getRootWindow(),
184                     client->x, client->y);
185     XChangeSaveSet(display, client->window, SetModeDelete);
186     XSelectInput(display, frame.window, SubstructureRedirectMask |
187                  ButtonPressMask | EnterWindowMask | LeaveWindowMask);
188     XFlush(display);
189   }
190
191   delete client;
192   client = (SlitClient *) 0;
193 }
194
195
196 void Slit::removeClient(Window w, Bool remap) {
197   openbox.grab();
198
199   Bool reconf = False;
200
201   LinkedListIterator<SlitClient> it(clientList);
202   for (SlitClient *tmp = it.current(); tmp; it++, tmp = it.current()) {
203     if (tmp->window == w) {
204       removeClient(tmp, remap);
205       reconf = True;
206
207       break;
208     }
209   }
210
211   if (reconf) reconfigure();
212
213   openbox.ungrab();
214 }
215
216 void Slit::setOnTop(bool b) {
217   m_ontop = b;
218   std::ostringstream s;
219   s << "session.screen" << screen.getScreenNumber() << ".slit.onTop";
220   config.setValue(s.str(), m_ontop ? "True" : "False");
221 }
222
223 void Slit::setAutoHide(bool b) {
224   m_autohide = b;
225   std::ostringstream s;
226   s << "session.screen" << screen.getScreenNumber() << ".slit.autoHide";
227   config.setValue(s.str(), m_autohide ? "True" : "False");
228 }
229
230 void Slit::setPlacement(int p) {
231   m_placement = p;
232   std::ostringstream s;
233   s << "session.screen" << screen.getScreenNumber() << ".slit.placement";
234   const char *placement;
235   switch (m_placement) {
236   case TopLeft: placement = "TopLeft"; break;
237   case CenterLeft: placement = "CenterLeft"; break;
238   case BottomLeft: placement = "BottomLeft"; break;
239   case TopCenter: placement = "TopCenter"; break;
240   case BottomCenter: placement = "BottomCenter"; break;
241   case TopRight: placement = "TopRight"; break;
242   case BottomRight: placement = "BottomRight"; break;
243   case CenterRight: default: placement = "CenterRight"; break;
244   }
245   config.setValue(s.str(), placement);
246 }
247
248 void Slit::setDirection(int d) {
249   m_direction = d;
250   std::ostringstream s;
251   s << "session.screen" << screen.getScreenNumber() << ".slit.direction";
252   config.setValue(s.str(),
253                   m_direction == Horizontal ? "Horizontal" : "Vertical");
254 }
255
256 void Slit::save() {
257   setOnTop(m_ontop);
258   setAutoHide(m_autohide);
259   setPlacement(m_placement);
260   setDirection(m_direction);
261 }
262
263 void Slit::load() {
264   std::ostringstream rscreen, rname, rclass;
265   std::string s;
266   bool b;
267   rscreen << "session.screen" << screen.getScreenNumber() << '.';
268
269   rname << rscreen.str() << "slit.placement";
270   rclass << rscreen.str() << "Slit.Placement";
271   if (config.getValue(rname.str(), rclass.str(), s)) {
272     if (0 == strncasecmp(s.c_str(), "TopLeft", s.length()))
273       m_placement = TopLeft;
274     else if (0 == strncasecmp(s.c_str(), "CenterLeft", s.length()))
275       m_placement = CenterLeft;
276     else if (0 == strncasecmp(s.c_str(), "BottomLeft", s.length()))
277       m_placement = BottomLeft;
278     else if (0 == strncasecmp(s.c_str(), "TopCenter", s.length()))
279       m_placement = TopCenter;
280     else if (0 == strncasecmp(s.c_str(), "BottomCenter", s.length()))
281       m_placement = BottomCenter;
282     else if (0 == strncasecmp(s.c_str(), "TopRight", s.length()))
283       m_placement = TopRight;
284     else if (0 == strncasecmp(s.c_str(), "BottomRight", s.length()))
285       m_placement = BottomRight;
286     else if (0 == strncasecmp(s.c_str(), "CenterRight", s.length()))
287       m_placement = CenterRight;
288   } else
289     m_placement = CenterRight;
290
291   rname.seekp(0); rclass.seekp(0);
292   rname << rscreen.str() << "slit.direction";
293   rclass << rscreen.str() << "Slit.Direction";
294   if (config.getValue(rname.str(), rclass.str(), s)) {
295     if (0 == strncasecmp(s.c_str(), "Horizontal", s.length()))
296       m_direction = Horizontal;
297     else if (0 == strncasecmp(s.c_str(), "Vertical", s.length()))
298       m_direction = Vertical;
299   } else
300     m_direction = Vertical;
301  
302   rname.seekp(0); rclass.seekp(0);
303   rname << rscreen.str() << "slit.onTop";
304   rclass << rscreen.str() << "Slit.OnTop";
305   if (config.getValue(rname.str(), rclass.str(), b))
306     m_ontop = b;
307   else
308     m_ontop = false;
309
310   rname.seekp(0); rclass.seekp(0);
311   rname << rscreen.str() << "slit.autoHide";
312   rclass << rscreen.str() << "Slit.AutoHide";
313   if (config.getValue(rname.str(), rclass.str(), b))
314     m_hidden = m_autohide = b;
315   else
316     m_hidden = m_autohide = false;
317 }
318
319 void Slit::reconfigure(void) {
320   frame.area.setSize(0, 0);
321   LinkedListIterator<SlitClient> it(clientList);
322   SlitClient *client;
323
324   switch (m_direction) {
325   case Vertical:
326     for (client = it.current(); client; it++, client = it.current()) {
327       frame.area.setH(frame.area.h() + client->height + screen.getBevelWidth());
328
329       if (frame.area.w() < client->width)
330         frame.area.setW(client->width);
331     }
332
333     if (frame.area.w() < 1)
334       frame.area.setW(1);
335     else
336       frame.area.setW(frame.area.w() + (screen.getBevelWidth() * 2));
337
338     if (frame.area.h() < 1)
339       frame.area.setH(1);
340     else
341       frame.area.setH(frame.area.h() + screen.getBevelWidth());
342
343     break;
344
345   case Horizontal:
346     for (client = it.current(); client; it++, client = it.current()) {
347       frame.area.setW(frame.area.w() + client->width + screen.getBevelWidth());
348
349       if (frame.area.h() < client->height)
350         frame.area.setH(client->height);
351     }
352
353     if (frame.area.w() < 1)
354       frame.area.setW(1);
355     else
356       frame.area.setW(frame.area.w() + screen.getBevelWidth());
357
358     if (frame.area.h() < 1)
359       frame.area.setH(1);
360     else
361       frame.area.setH(frame.area.h() + (screen.getBevelWidth() * 2));
362
363     break;
364   }
365
366   reposition();
367
368   XSetWindowBorderWidth(display ,frame.window, screen.getBorderWidth());
369   XSetWindowBorder(display, frame.window,
370                    screen.getBorderColor()->getPixel());
371
372   if (! clientList->count())
373     XUnmapWindow(display, frame.window);
374   else
375     XMapWindow(display, frame.window);
376
377   Pixmap tmp = frame.pixmap;
378   BImageControl *image_ctrl = screen.getImageControl();
379   BTexture *texture = &(screen.getToolbarStyle()->toolbar);
380   if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
381     frame.pixmap = None;
382     XSetWindowBackground(display, frame.window,
383                          texture->getColor()->getPixel());
384   } else {
385     frame.pixmap = image_ctrl->renderImage(frame.area.w(), frame.area.h(),
386                                            texture);
387     XSetWindowBackgroundPixmap(display, frame.window, frame.pixmap);
388   }
389   if (tmp) image_ctrl->removeImage(tmp);
390   XClearWindow(display, frame.window);
391
392   int x, y;
393   it.reset();
394
395   switch (m_direction) {
396   case Vertical:
397     x = 0;
398     y = screen.getBevelWidth();
399
400     for (client = it.current(); client; it++, client = it.current()) {
401       x = (frame.area.w() - client->width) / 2;
402
403       XMoveResizeWindow(display, client->window, x, y,
404                         client->width, client->height);
405       XMapWindow(display, client->window);
406
407       // for ICCCM compliance
408       client->x = x;
409       client->y = y;
410
411       XEvent event;
412       event.type = ConfigureNotify;
413
414       event.xconfigure.display = display;
415       event.xconfigure.event = client->window;
416       event.xconfigure.window = client->window;
417       event.xconfigure.x = x;
418       event.xconfigure.y = y;
419       event.xconfigure.width = client->width;
420       event.xconfigure.height = client->height;
421       event.xconfigure.border_width = 0;
422       event.xconfigure.above = frame.window;
423       event.xconfigure.override_redirect = False;
424
425       XSendEvent(display, client->window, False, StructureNotifyMask, &event);
426
427       y += client->height + screen.getBevelWidth();
428     }
429
430     break;
431
432   case Horizontal:
433     x = screen.getBevelWidth();
434     y = 0;
435
436     for (client = it.current(); client; it++, client = it.current()) {
437       y = (frame.area.h() - client->height) / 2;
438
439       XMoveResizeWindow(display, client->window, x, y,
440                         client->width, client->height);
441       XMapWindow(display, client->window);
442
443       // for ICCCM compliance
444       client->x = x;
445       client->y = y;
446
447       XEvent event;
448       event.type = ConfigureNotify;
449
450       event.xconfigure.display = display;
451       event.xconfigure.event = client->window;
452       event.xconfigure.window = client->window;
453       event.xconfigure.x = x;
454       event.xconfigure.y = y;
455       event.xconfigure.width = client->width;
456       event.xconfigure.height = client->height;
457       event.xconfigure.border_width = 0;
458       event.xconfigure.above = frame.window;
459       event.xconfigure.override_redirect = False;
460
461       XSendEvent(display, client->window, False, StructureNotifyMask, &event);
462
463       x += client->width + screen.getBevelWidth();
464     }
465
466     break;
467   }
468
469   slitmenu->reconfigure();
470 }
471
472
473 void Slit::reposition(void) {
474   // place the slit in the appropriate place
475   switch (m_placement) {
476   case TopLeft:
477     frame.area.setOrigin(0, 0);
478     if (m_direction == Vertical) {
479       frame.hidden = Point(screen.getBevelWidth() - screen.getBorderWidth()
480                            - frame.area.w(), 0);
481     } else {
482       frame.hidden = Point(0, screen.getBevelWidth() - screen.getBorderWidth()
483                            - frame.area.h());
484     }
485     break;
486
487   case CenterLeft:
488     frame.area.setOrigin(0, (screen.size().h() - frame.area.h()) / 2);
489     frame.hidden = Point(screen.getBevelWidth() - screen.getBorderWidth()
490                          - frame.area.w(), frame.area.y());
491     break;
492
493   case BottomLeft:
494     frame.area.setOrigin(0, screen.size().h() - frame.area.h()
495                          - (screen.getBorderWidth() * 2));
496     if (m_direction == Vertical)
497       frame.hidden = Point(screen.getBevelWidth() - screen.getBorderWidth()
498                            - frame.area.w(), frame.area.y());
499     else
500       frame.hidden = Point(0, screen.size().h() - screen.getBevelWidth()
501                            - screen.getBorderWidth());
502     break;
503
504   case TopCenter:
505     frame.area.setOrigin((screen.size().w() - frame.area.w()) / 2, 0);
506     frame.hidden = Point(frame.area.x(), screen.getBevelWidth()
507                          - screen.getBorderWidth() - frame.area.h());
508     break;
509
510   case BottomCenter:
511     frame.area.setOrigin((screen.size().w() - frame.area.w()) / 2,
512                          screen.size().h() - frame.area.h()
513                          - (screen.getBorderWidth() * 2));
514     frame.hidden = Point(frame.area.x(), screen.size().h()
515                          - screen.getBevelWidth() - screen.getBorderWidth());
516     break;
517
518   case TopRight:
519     frame.area.setOrigin(screen.size().w() - frame.area.w()
520                          - (screen.getBorderWidth() * 2), 0);
521     if (m_direction == Vertical)
522       frame.hidden = Point(screen.size().w() - screen.getBevelWidth()
523                            - screen.getBorderWidth(), 0);
524     else
525       frame.hidden = Point(frame.area.x(), screen.getBevelWidth()
526                            - screen.getBorderWidth() - frame.area.h());
527     break;
528
529   case CenterRight:
530   default:
531     frame.area.setOrigin(screen.size().w() - frame.area.w()
532                          - (screen.getBorderWidth() * 2),
533                          (screen.size().h() - frame.area.h()) / 2);
534     frame.hidden = Point(screen.size().w() - screen.getBevelWidth()
535                          - screen.getBorderWidth(), frame.area.y());
536     break;
537
538   case BottomRight:
539     frame.area.setOrigin(screen.size().w() - frame.area.w()
540                          - (screen.getBorderWidth() * 2),
541                          screen.size().h() - frame.area.h()
542                          - (screen.getBorderWidth() * 2));
543     if (m_direction == Vertical)
544       frame.hidden = Point(screen.size().w() - screen.getBevelWidth()
545                            - screen.getBorderWidth(), frame.area.y());
546     else
547       frame.hidden = Point(frame.area.x(), screen.size().h() -
548                            screen.getBevelWidth() - screen.getBorderWidth());
549     break;
550   }
551
552   Toolbar *tbar = screen.getToolbar();
553   int sw = frame.area.w() + (screen.getBorderWidth() * 2),
554       sh = frame.area.h() + (screen.getBorderWidth() * 2),
555       tw = tbar->area().w() + screen.getBorderWidth(),
556       th = tbar->area().h() + screen.getBorderWidth();
557
558   if (tbar->area().x() < frame.area.x() + sw &&
559       tbar->area().x() + tw > frame.area.x() &&
560       tbar->area().y() < frame.area.y() + sh &&
561       tbar->area().y() + th > frame.area.y()) {
562     if (frame.area.y() < th) {
563       frame.area.setY(frame.area.y() + tbar->getExposedHeight());
564       if (m_direction == Vertical)
565         frame.hidden.setY(frame.hidden.y() + tbar->getExposedHeight());
566       else
567         frame.hidden.setY(frame.area.y());
568     } else {
569       frame.area.setY(frame.area.y() - tbar->getExposedHeight());
570       if (m_direction == Vertical)
571         frame.hidden.setY(frame.area.y() - tbar->getExposedHeight());
572       else
573         frame.hidden.setY(frame.area.y());
574     }
575   }
576
577   if (m_hidden)
578     XMoveResizeWindow(display, frame.window, frame.hidden.x(),
579                       frame.hidden.y(), frame.area.w(), frame.area.h());
580   else
581     XMoveResizeWindow(display, frame.window, frame.area.x(),
582                       frame.area.y(), frame.area.w(), frame.area.h());
583 }
584
585
586 void Slit::shutdown(void) {
587   while (clientList->count())
588     removeClient(clientList->first());
589 }
590
591
592 void Slit::buttonPressEvent(XButtonEvent *e) {
593   if (e->window != frame.window) return;
594
595   if (e->button == Button1 && !m_ontop) {
596     Window w[1] = { frame.window };
597     screen.raiseWindows(w, 1);
598   } else if (e->button == Button2 && !m_ontop) {
599     XLowerWindow(display, frame.window);
600   } else if (e->button == Button3) {
601     if (! slitmenu->isVisible()) {
602       int x, y;
603
604       x = e->x_root - (slitmenu->getWidth() / 2);
605       y = e->y_root - (slitmenu->getHeight() / 2);
606
607       if (x < 0)
608         x = 0;
609       else if (x + slitmenu->getWidth() > screen.size().w())
610         x = screen.size().w() - slitmenu->getWidth();
611
612       if (y < 0)
613         y = 0;
614       else if (y + slitmenu->getHeight() > screen.size().h())
615         y = screen.size().h() - slitmenu->getHeight();
616
617       slitmenu->move(x, y);
618       slitmenu->show();
619     } else {
620       slitmenu->hide();
621     }
622   }
623 }
624
625
626 void Slit::enterNotifyEvent(XCrossingEvent *) {
627   if (!m_autohide)
628     return;
629
630   if (m_hidden) {
631     if (! timer->isTiming()) timer->start();
632   } else {
633     if (timer->isTiming()) timer->stop();
634   }
635 }
636
637
638 void Slit::leaveNotifyEvent(XCrossingEvent *) {
639   if (!m_autohide)
640     return;
641
642   if (m_hidden) {
643     if (timer->isTiming()) timer->stop();
644   } else if (! slitmenu->isVisible()) {
645     if (!timer->isTiming()) timer->start();
646   }
647 }
648
649
650 void Slit::configureRequestEvent(XConfigureRequestEvent *e) {
651   openbox.grab();
652
653   if (openbox.validateWindow(e->window)) {
654     Bool reconf = False;
655     XWindowChanges xwc;
656
657     xwc.x = e->x;
658     xwc.y = e->y;
659     xwc.width = e->width;
660     xwc.height = e->height;
661     xwc.border_width = 0;
662     xwc.sibling = e->above;
663     xwc.stack_mode = e->detail;
664
665     XConfigureWindow(display, e->window, e->value_mask, &xwc);
666
667     LinkedListIterator<SlitClient> it(clientList);
668     SlitClient *client = it.current();
669     for (; client; it++, client = it.current())
670       if (client->window == e->window)
671         if (client->width != ((unsigned) e->width) ||
672             client->height != ((unsigned) e->height)) {
673           client->width = (unsigned) e->width;
674           client->height = (unsigned) e->height;
675
676           reconf = True;
677
678           break;
679         }
680
681     if (reconf) reconfigure();
682
683   }
684
685   openbox.ungrab();
686 }
687
688
689 void Slit::timeout(void) {
690   m_hidden = !m_hidden;
691   if (m_hidden)
692     XMoveWindow(display, frame.window, frame.hidden.x(), frame.hidden.y());
693   else
694     XMoveWindow(display, frame.window, frame.area.x(), frame.area.y());
695 }
696
697
698 Slitmenu::Slitmenu(Slit &sl) : Basemenu(sl.screen), slit(sl) {
699   setLabel(i18n->getMessage(SlitSet, SlitSlitTitle, "Slit"));
700   setInternalMenu();
701
702   directionmenu = new Directionmenu(*this);
703   placementmenu = new Placementmenu(*this);
704
705   insert(i18n->getMessage(CommonSet, CommonDirectionTitle, "Direction"),
706          directionmenu);
707   insert(i18n->getMessage(CommonSet, CommonPlacementTitle, "Placement"),
708          placementmenu);
709   insert(i18n->getMessage(CommonSet, CommonAlwaysOnTop, "Always on top"), 1);
710   insert(i18n->getMessage(CommonSet, CommonAutoHide, "Auto hide"), 2);
711
712   update();
713
714   setValues();
715 }
716
717 void Slitmenu::setValues() {
718   setItemSelected(2, slit.onTop());
719   setItemSelected(3, slit.autoHide());
720 }
721
722
723 Slitmenu::~Slitmenu(void) {
724   delete directionmenu;
725   delete placementmenu;
726 }
727
728
729 void Slitmenu::itemSelected(int button, int index) {
730   if (button != 1)
731     return;
732
733   BasemenuItem *item = find(index);
734   if (! item) return;
735
736   switch (item->function()) {
737   case 1: { // always on top
738     bool change = ((slit.onTop()) ?  false : true);
739     slit.setOnTop(change);
740     setItemSelected(2, change);
741
742     if (slit.onTop()) slit.screen.raiseWindows((Window *) 0, 0);
743     break;
744   }
745
746   case 2: { // auto hide
747     Bool change = ((slit.autoHide()) ?  false : true);
748     slit.setAutoHide(change);
749     setItemSelected(3, change);
750
751     break;
752   }
753   } // switch
754 }
755
756
757 void Slitmenu::internal_hide(void) {
758   Basemenu::internal_hide();
759   if (slit.autoHide())
760     slit.timeout();
761 }
762
763
764 void Slitmenu::reconfigure(void) {
765   setValues();
766   directionmenu->reconfigure();
767   placementmenu->reconfigure();
768
769   Basemenu::reconfigure();
770 }
771
772
773 Slitmenu::Directionmenu::Directionmenu(Slitmenu &sm)
774   : Basemenu(sm.slit.screen), slitmenu(sm) {
775   setLabel(i18n->getMessage(SlitSet, SlitSlitDirection, "Slit Direction"));
776   setInternalMenu();
777
778   insert(i18n->getMessage(CommonSet, CommonDirectionHoriz, "Horizontal"),
779          Slit::Horizontal);
780   insert(i18n->getMessage(CommonSet, CommonDirectionVert, "Vertical"),
781          Slit::Vertical);
782
783   update();
784
785   setValues();
786 }
787
788
789 void Slitmenu::Directionmenu::setValues() {
790   if (slitmenu.slit.direction() == Slit::Horizontal)
791     setItemSelected(0, True);
792   else
793     setItemSelected(1, True);
794 }
795
796 void Slitmenu::Directionmenu::reconfigure() {
797   setValues();
798 }
799
800
801 void Slitmenu::Directionmenu::itemSelected(int button, int index) {
802   if (button != 1)
803     return;
804
805   BasemenuItem *item = find(index);
806   if (! item) return;
807
808   slitmenu.slit.setDirection(item->function());
809
810   if (item->function() == Slit::Horizontal) {
811     setItemSelected(0, True);
812     setItemSelected(1, False);
813   } else {
814     setItemSelected(0, False);
815     setItemSelected(1, True);
816   }
817
818   hide();
819   slitmenu.slit.reconfigure();
820 }
821
822
823 Slitmenu::Placementmenu::Placementmenu(Slitmenu &sm)
824   : Basemenu(sm.slit.screen), slitmenu(sm) {
825
826   setLabel(i18n->getMessage(SlitSet, SlitSlitPlacement, "Slit Placement"));
827   setMinimumSublevels(3);
828   setInternalMenu();
829
830   insert(i18n->getMessage(CommonSet, CommonPlacementTopLeft, "Top Left"),
831          Slit::TopLeft);
832   insert(i18n->getMessage(CommonSet, CommonPlacementCenterLeft, "Center Left"),
833          Slit::CenterLeft);
834   insert(i18n->getMessage(CommonSet, CommonPlacementBottomLeft, "Bottom Left"),
835          Slit::BottomLeft);
836   insert(i18n->getMessage(CommonSet, CommonPlacementTopCenter, "Top Center"),
837          Slit::TopCenter);
838   insert("");
839   insert(i18n->getMessage(CommonSet, CommonPlacementBottomCenter, 
840                           "Bottom Center"),
841          Slit::BottomCenter);
842   insert(i18n->getMessage(CommonSet, CommonPlacementTopRight, "Top Right"),
843          Slit::TopRight);
844   insert(i18n->getMessage(CommonSet, CommonPlacementCenterRight,
845                           "Center Right"),
846          Slit::CenterRight);
847   insert(i18n->getMessage(CommonSet, CommonPlacementBottomRight,
848                           "Bottom Right"),
849          Slit::BottomRight);
850
851   update();
852 }
853
854
855 void Slitmenu::Placementmenu::itemSelected(int button, int index) {
856   if (button != 1)
857     return;
858
859   BasemenuItem *item = find(index);
860   if (! (item && item->function())) return;
861
862   slitmenu.slit.setPlacement(item->function());
863   hide();
864   slitmenu.slit.reconfigure();
865 }
866
867 #endif // SLIT