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