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