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