2 // Copyright (c) 2001 Sean 'Shaleh' Perry <shaleh@debian.org>
3 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
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:
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
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.
23 // stupid macros needed to access some functions in version 2 of the GNU C
30 # include "../config.h"
31 #endif // HAVE_CONFIG_H
35 #include <X11/keysym.h>
48 Slit::Slit(BScreen &scr, Resource &conf) : openbox(scr.getOpenbox()),
49 screen(scr), config(conf)
53 display = screen.getBaseDisplay().getXDisplay();
54 frame.window = frame.pixmap = None;
56 timer = new BTimer(openbox, *this);
57 // the time out is set in ::reconfigure()
58 timer->fireOnce(True);
60 slitmenu = new Slitmenu(*this);
62 XSetWindowAttributes attrib;
63 unsigned long create_mask = CWBackPixmap | CWBackPixel | CWBorderPixel |
64 CWColormap | CWOverrideRedirect | CWEventMask;
65 attrib.background_pixmap = None;
66 attrib.background_pixel = attrib.border_pixel =
67 screen.getBorderColor()->getPixel();
68 attrib.colormap = screen.getColormap();
69 attrib.override_redirect = True;
70 attrib.event_mask = SubstructureRedirectMask | ButtonPressMask |
71 EnterWindowMask | LeaveWindowMask;
73 frame.area = Rect(0, 0, 1, 1);
76 XCreateWindow(display, screen.getRootWindow(),
77 frame.area.x(), frame.area.y(),
78 frame.area.w(), frame.area.h(), screen.getBorderWidth(),
79 screen.getDepth(), InputOutput, screen.getVisual(),
80 create_mask, &attrib);
81 openbox.saveSlitSearch(frame.window, this);
90 if (timer->isTiming()) timer->stop();
97 screen.getImageControl()->removeImage(frame.pixmap);
99 openbox.removeSlitSearch(frame.window);
101 XDestroyWindow(display, frame.window);
107 void Slit::addClient(Window w) {
110 if (openbox.validateWindow(w)) {
111 SlitClient *client = new SlitClient;
112 client->client_window = w;
114 XWMHints *wmhints = XGetWMHints(display, w);
117 if ((wmhints->flags & IconWindowHint) &&
118 (wmhints->icon_window != None)) {
119 XMoveWindow(display, client->client_window, screen.size().w() + 10,
120 screen.size().h() + 10);
121 XMapWindow(display, client->client_window);
123 client->icon_window = wmhints->icon_window;
124 client->window = client->icon_window;
126 client->icon_window = None;
127 client->window = client->client_window;
132 client->icon_window = None;
133 client->window = client->client_window;
136 XWindowAttributes attrib;
137 if (XGetWindowAttributes(display, client->window, &attrib)) {
138 client->width = attrib.width;
139 client->height = attrib.height;
141 client->width = client->height = 64;
144 XSetWindowBorderWidth(display, client->window, 0);
146 XSelectInput(display, frame.window, NoEventMask);
147 XSelectInput(display, client->window, NoEventMask);
149 XReparentWindow(display, client->window, frame.window, 0, 0);
150 XMapRaised(display, client->window);
151 XChangeSaveSet(display, client->window, SetModeInsert);
153 XSelectInput(display, frame.window, SubstructureRedirectMask |
154 ButtonPressMask | EnterWindowMask | LeaveWindowMask);
155 XSelectInput(display, client->window, StructureNotifyMask |
156 SubstructureNotifyMask | EnterWindowMask);
159 clientList.push_back(client);
161 openbox.saveSlitSearch(client->client_window, this);
162 openbox.saveSlitSearch(client->icon_window, this);
170 void Slit::removeClient(SlitClient *client, Bool remap) {
171 openbox.removeSlitSearch(client->client_window);
172 openbox.removeSlitSearch(client->icon_window);
174 clientList.remove(client);
176 screen.removeNetizen(client->window);
178 if (remap && openbox.validateWindow(client->window)) {
179 XSelectInput(display, frame.window, NoEventMask);
180 XSelectInput(display, client->window, NoEventMask);
181 XReparentWindow(display, client->window, screen.getRootWindow(),
182 client->x, client->y);
183 XChangeSaveSet(display, client->window, SetModeDelete);
184 XSelectInput(display, frame.window, SubstructureRedirectMask |
185 ButtonPressMask | EnterWindowMask | LeaveWindowMask);
190 client = (SlitClient *) 0;
194 void Slit::removeClient(Window w, Bool remap) {
199 slitClientList::iterator it;
200 for (it = clientList.begin(); it != clientList.end(); it++)
201 if ((*it)->window == w) {
202 removeClient(*it, remap);
213 void Slit::setOnTop(bool b) {
216 s << "session.screen" << screen.getScreenNumber() << ".slit.onTop" << ends;
217 config.setValue(s.str(), m_ontop ? "True" : "False");
218 s.rdbuf()->freeze(0);
221 void Slit::setAutoHide(bool b) {
224 s << "session.screen" << screen.getScreenNumber() << ".slit.autoHide" << ends;
225 config.setValue(s.str(), m_autohide ? "True" : "False");
226 s.rdbuf()->freeze(0);
229 void Slit::setPlacement(int p) {
232 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;
245 config.setValue(s.str(), placement);
246 s.rdbuf()->freeze(0);
249 void Slit::setDirection(int d) {
252 s << "session.screen" << screen.getScreenNumber() << ".slit.direction"
254 config.setValue(s.str(),
255 m_direction == Horizontal ? "Horizontal" : "Vertical");
256 s.rdbuf()->freeze(0);
261 setAutoHide(m_autohide);
262 setPlacement(m_placement);
263 setDirection(m_direction);
267 std::ostrstream rscreen, rname, rclass;
270 rscreen << "session.screen" << screen.getScreenNumber() << '.' << ends;
272 rname << rscreen.str() << "slit.placement" << ends;
273 rclass << rscreen.str() << "Slit.Placement" << ends;
274 if (config.getValue(rname.str(), rclass.str(), s)) {
275 if (0 == strncasecmp(s.c_str(), "TopLeft", s.length()))
276 m_placement = TopLeft;
277 else if (0 == strncasecmp(s.c_str(), "CenterLeft", s.length()))
278 m_placement = CenterLeft;
279 else if (0 == strncasecmp(s.c_str(), "BottomLeft", s.length()))
280 m_placement = BottomLeft;
281 else if (0 == strncasecmp(s.c_str(), "TopCenter", s.length()))
282 m_placement = TopCenter;
283 else if (0 == strncasecmp(s.c_str(), "BottomCenter", s.length()))
284 m_placement = BottomCenter;
285 else if (0 == strncasecmp(s.c_str(), "TopRight", s.length()))
286 m_placement = TopRight;
287 else if (0 == strncasecmp(s.c_str(), "BottomRight", s.length()))
288 m_placement = BottomRight;
289 else if (0 == strncasecmp(s.c_str(), "CenterRight", s.length()))
290 m_placement = CenterRight;
292 m_placement = CenterRight;
294 rname.seekp(0); rclass.seekp(0);
295 rname.rdbuf()->freeze(0); rclass.rdbuf()->freeze(0);
296 rname << rscreen.str() << "slit.direction" << ends;
297 rclass << rscreen.str() << "Slit.Direction" << ends;
298 if (config.getValue(rname.str(), rclass.str(), s)) {
299 if (0 == strncasecmp(s.c_str(), "Horizontal", s.length()))
300 m_direction = Horizontal;
301 else if (0 == strncasecmp(s.c_str(), "Vertical", s.length()))
302 m_direction = Vertical;
304 m_direction = Vertical;
306 rname.seekp(0); rclass.seekp(0);
307 rname.rdbuf()->freeze(0); rclass.rdbuf()->freeze(0);
308 rname << rscreen.str() << "slit.onTop" << ends;
309 rclass << rscreen.str() << "Slit.OnTop" << ends;
310 if (config.getValue(rname.str(), rclass.str(), b))
315 rname.seekp(0); rclass.seekp(0);
316 rname.rdbuf()->freeze(0); rclass.rdbuf()->freeze(0);
317 rname << rscreen.str() << "slit.autoHide" << ends;
318 rclass << rscreen.str() << "Slit.AutoHide" << ends;
319 if (config.getValue(rname.str(), rclass.str(), b))
320 m_hidden = m_autohide = b;
322 m_hidden = m_autohide = false;
324 rscreen.rdbuf()->freeze(0);
325 rname.rdbuf()->freeze(0); rclass.rdbuf()->freeze(0);
328 void Slit::reconfigure(void) {
329 timer->setTimeout(openbox.getAutoRaiseDelay());
331 frame.area.setSize(0, 0);
332 slitClientList::const_iterator it;
334 switch (m_direction) {
336 for (it = clientList.begin(); it != clientList.end(); it++) {
337 frame.area.setH(frame.area.h() + (*it)->height + screen.getBevelWidth());
339 if (frame.area.w() < (*it)->width)
340 frame.area.setW((*it)->width);
343 if (frame.area.w() < 1)
346 frame.area.setW(frame.area.w() + (screen.getBevelWidth() * 2));
348 if (frame.area.h() < 1)
351 frame.area.setH(frame.area.h() + screen.getBevelWidth());
356 for (it = clientList.begin(); it != clientList.end(); it++) {
357 frame.area.setW(frame.area.w() + (*it)->width + screen.getBevelWidth());
359 if (frame.area.h() < (*it)->height)
360 frame.area.setH((*it)->height);
363 if (frame.area.w() < 1)
366 frame.area.setW(frame.area.w() + screen.getBevelWidth());
368 if (frame.area.h() < 1)
371 frame.area.setH(frame.area.h() + (screen.getBevelWidth() * 2));
378 XSetWindowBorderWidth(display ,frame.window, screen.getBorderWidth());
379 XSetWindowBorder(display, frame.window,
380 screen.getBorderColor()->getPixel());
382 if (! clientList.size())
383 XUnmapWindow(display, frame.window);
385 XMapWindow(display, frame.window);
387 Pixmap tmp = frame.pixmap;
388 BImageControl *image_ctrl = screen.getImageControl();
389 BTexture *texture = &(screen.getToolbarStyle()->toolbar);
390 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
392 XSetWindowBackground(display, frame.window,
393 texture->getColor()->getPixel());
395 frame.pixmap = image_ctrl->renderImage(frame.area.w(), frame.area.h(),
397 XSetWindowBackgroundPixmap(display, frame.window, frame.pixmap);
399 if (tmp) image_ctrl->removeImage(tmp);
400 XClearWindow(display, frame.window);
404 switch (m_direction) {
407 y = screen.getBevelWidth();
409 for (it = clientList.begin(); it != clientList.end(); it++) {
410 x = (frame.area.w() - (*it)->width) / 2;
412 XMoveResizeWindow(display, (*it)->window, x, y,
413 (*it)->width, (*it)->height);
414 XMapWindow(display, (*it)->window);
416 // for ICCCM compliance
421 event.type = ConfigureNotify;
423 event.xconfigure.display = display;
424 event.xconfigure.event = (*it)->window;
425 event.xconfigure.window = (*it)->window;
426 event.xconfigure.x = x;
427 event.xconfigure.y = y;
428 event.xconfigure.width = (*it)->width;
429 event.xconfigure.height = (*it)->height;
430 event.xconfigure.border_width = 0;
431 event.xconfigure.above = frame.window;
432 event.xconfigure.override_redirect = False;
434 XSendEvent(display, (*it)->window, False, StructureNotifyMask, &event);
436 y += (*it)->height + screen.getBevelWidth();
442 x = screen.getBevelWidth();
445 for (it = clientList.begin(); it != clientList.end(); it++) {
446 y = (frame.area.h() - (*it)->height) / 2;
448 XMoveResizeWindow(display, (*it)->window, x, y,
449 (*it)->width, (*it)->height);
450 XMapWindow(display, (*it)->window);
452 // for ICCCM compliance
457 event.type = ConfigureNotify;
459 event.xconfigure.display = display;
460 event.xconfigure.event = (*it)->window;
461 event.xconfigure.window = (*it)->window;
462 event.xconfigure.x = x;
463 event.xconfigure.y = y;
464 event.xconfigure.width = (*it)->width;
465 event.xconfigure.height = (*it)->height;
466 event.xconfigure.border_width = 0;
467 event.xconfigure.above = frame.window;
468 event.xconfigure.override_redirect = False;
470 XSendEvent(display, (*it)->window, False, StructureNotifyMask, &event);
472 x += (*it)->width + screen.getBevelWidth();
478 slitmenu->reconfigure();
482 void Slit::reposition(void) {
483 // place the slit in the appropriate place
484 switch (m_placement) {
486 frame.area.setOrigin(0, 0);
487 if (m_direction == Vertical) {
488 frame.hidden = Point(screen.getBevelWidth() - screen.getBorderWidth()
489 - frame.area.w(), 0);
491 frame.hidden = Point(0, screen.getBevelWidth() - screen.getBorderWidth()
497 frame.area.setOrigin(0, (screen.size().h() - frame.area.h()) / 2);
498 frame.hidden = Point(screen.getBevelWidth() - screen.getBorderWidth()
499 - frame.area.w(), frame.area.y());
503 frame.area.setOrigin(0, screen.size().h() - frame.area.h()
504 - (screen.getBorderWidth() * 2));
505 if (m_direction == Vertical)
506 frame.hidden = Point(screen.getBevelWidth() - screen.getBorderWidth()
507 - frame.area.w(), frame.area.y());
509 frame.hidden = Point(0, screen.size().h() - screen.getBevelWidth()
510 - screen.getBorderWidth());
514 frame.area.setOrigin((screen.size().w() - frame.area.w()) / 2, 0);
515 frame.hidden = Point(frame.area.x(), screen.getBevelWidth()
516 - screen.getBorderWidth() - frame.area.h());
520 frame.area.setOrigin((screen.size().w() - frame.area.w()) / 2,
521 screen.size().h() - frame.area.h()
522 - (screen.getBorderWidth() * 2));
523 frame.hidden = Point(frame.area.x(), screen.size().h()
524 - screen.getBevelWidth() - screen.getBorderWidth());
528 frame.area.setOrigin(screen.size().w() - frame.area.w()
529 - (screen.getBorderWidth() * 2), 0);
530 if (m_direction == Vertical)
531 frame.hidden = Point(screen.size().w() - screen.getBevelWidth()
532 - screen.getBorderWidth(), 0);
534 frame.hidden = Point(frame.area.x(), screen.getBevelWidth()
535 - screen.getBorderWidth() - frame.area.h());
540 frame.area.setOrigin(screen.size().w() - frame.area.w()
541 - (screen.getBorderWidth() * 2),
542 (screen.size().h() - frame.area.h()) / 2);
543 frame.hidden = Point(screen.size().w() - screen.getBevelWidth()
544 - screen.getBorderWidth(), frame.area.y());
548 frame.area.setOrigin(screen.size().w() - frame.area.w()
549 - (screen.getBorderWidth() * 2),
550 screen.size().h() - frame.area.h()
551 - (screen.getBorderWidth() * 2));
552 if (m_direction == Vertical)
553 frame.hidden = Point(screen.size().w() - screen.getBevelWidth()
554 - screen.getBorderWidth(), frame.area.y());
556 frame.hidden = Point(frame.area.x(), screen.size().h() -
557 screen.getBevelWidth() - screen.getBorderWidth());
561 Toolbar *tbar = screen.getToolbar();
562 int sw = frame.area.w() + (screen.getBorderWidth() * 2),
563 sh = frame.area.h() + (screen.getBorderWidth() * 2),
564 tw = tbar->area().w() + screen.getBorderWidth(),
565 th = tbar->area().h() + screen.getBorderWidth();
567 if (tbar->area().x() < frame.area.x() + sw &&
568 tbar->area().x() + tw > frame.area.x() &&
569 tbar->area().y() < frame.area.y() + sh &&
570 tbar->area().y() + th > frame.area.y()) {
571 if (frame.area.y() < th) {
572 frame.area.setY(frame.area.y() + tbar->getExposedHeight());
573 if (m_direction == Vertical)
574 frame.hidden.setY(frame.hidden.y() + tbar->getExposedHeight());
576 frame.hidden.setY(frame.area.y());
578 frame.area.setY(frame.area.y() - tbar->getExposedHeight());
579 if (m_direction == Vertical)
580 frame.hidden.setY(frame.area.y() - tbar->getExposedHeight());
582 frame.hidden.setY(frame.area.y());
587 XMoveResizeWindow(display, frame.window, frame.hidden.x(),
588 frame.hidden.y(), frame.area.w(), frame.area.h());
590 XMoveResizeWindow(display, frame.window, frame.area.x(),
591 frame.area.y(), frame.area.w(), frame.area.h());
595 void Slit::shutdown(void) {
596 while (clientList.size())
597 removeClient(clientList.front());
601 void Slit::buttonPressEvent(XButtonEvent *e) {
602 if (e->window != frame.window) return;
604 if (e->button == Button1 && !m_ontop) {
605 Window w[1] = { frame.window };
606 screen.raiseWindows(w, 1);
607 } else if (e->button == Button2 && !m_ontop) {
608 XLowerWindow(display, frame.window);
609 } else if (e->button == Button3) {
610 if (! slitmenu->isVisible()) {
613 x = e->x_root - (slitmenu->getWidth() / 2);
614 y = e->y_root - (slitmenu->getHeight() / 2);
618 else if (x + slitmenu->getWidth() > screen.size().w())
619 x = screen.size().w() - slitmenu->getWidth();
623 else if (y + slitmenu->getHeight() > screen.size().h())
624 y = screen.size().h() - slitmenu->getHeight();
626 slitmenu->move(x, y);
635 void Slit::enterNotifyEvent(XCrossingEvent *) {
640 if (! timer->isTiming()) timer->start();
642 if (timer->isTiming()) timer->stop();
647 void Slit::leaveNotifyEvent(XCrossingEvent *) {
652 if (timer->isTiming()) timer->stop();
653 } else if (! slitmenu->isVisible()) {
654 if (!timer->isTiming()) timer->start();
659 void Slit::configureRequestEvent(XConfigureRequestEvent *e) {
662 if (openbox.validateWindow(e->window)) {
668 xwc.width = e->width;
669 xwc.height = e->height;
670 xwc.border_width = 0;
671 xwc.sibling = e->above;
672 xwc.stack_mode = e->detail;
674 XConfigureWindow(display, e->window, e->value_mask, &xwc);
676 slitClientList::iterator it = clientList.begin();
677 for (; it != clientList.end(); it++) {
678 SlitClient *client = *it;
679 if (client->window == e->window)
680 if (client->width != ((unsigned) e->width) ||
681 client->height != ((unsigned) e->height)) {
682 client->width = (unsigned) e->width;
683 client->height = (unsigned) e->height;
696 void Slit::timeout(void) {
697 m_hidden = !m_hidden;
699 XMoveWindow(display, frame.window, frame.hidden.x(), frame.hidden.y());
701 XMoveWindow(display, frame.window, frame.area.x(), frame.area.y());
705 Slitmenu::Slitmenu(Slit &sl) : Basemenu(sl.screen), slit(sl) {
706 setLabel(i18n(SlitSet, SlitSlitTitle, "Slit"));
709 directionmenu = new Directionmenu(*this);
710 placementmenu = new Placementmenu(*this);
712 insert(i18n(CommonSet, CommonDirectionTitle, "Direction"),
714 insert(i18n(CommonSet, CommonPlacementTitle, "Placement"),
716 insert(i18n(CommonSet, CommonAlwaysOnTop, "Always on top"), 1);
717 insert(i18n(CommonSet, CommonAutoHide, "Auto hide"), 2);
724 void Slitmenu::setValues() {
725 setItemSelected(2, slit.onTop());
726 setItemSelected(3, slit.autoHide());
730 Slitmenu::~Slitmenu(void) {
731 delete directionmenu;
732 delete placementmenu;
736 void Slitmenu::itemSelected(int button, int index) {
740 BasemenuItem *item = find(index);
743 switch (item->function()) {
744 case 1: { // always on top
745 bool change = ((slit.onTop()) ? false : true);
746 slit.setOnTop(change);
747 setItemSelected(2, change);
749 if (slit.onTop()) slit.screen.raiseWindows((Window *) 0, 0);
753 case 2: { // auto hide
754 Bool change = ((slit.autoHide()) ? false : true);
755 slit.setAutoHide(change);
756 setItemSelected(3, change);
764 void Slitmenu::internal_hide(void) {
765 Basemenu::internal_hide();
771 void Slitmenu::reconfigure(void) {
773 directionmenu->reconfigure();
774 placementmenu->reconfigure();
776 Basemenu::reconfigure();
780 Slitmenu::Directionmenu::Directionmenu(Slitmenu &sm)
781 : Basemenu(sm.slit.screen), slitmenu(sm) {
782 setLabel(i18n(SlitSet, SlitSlitDirection, "Slit Direction"));
785 insert(i18n(CommonSet, CommonDirectionHoriz, "Horizontal"),
787 insert(i18n(CommonSet, CommonDirectionVert, "Vertical"),
796 void Slitmenu::Directionmenu::setValues() {
797 if (slitmenu.slit.direction() == Slit::Horizontal)
798 setItemSelected(0, True);
800 setItemSelected(1, True);
803 void Slitmenu::Directionmenu::reconfigure() {
805 Basemenu::reconfigure();
809 void Slitmenu::Directionmenu::itemSelected(int button, int index) {
813 BasemenuItem *item = find(index);
816 slitmenu.slit.setDirection(item->function());
818 if (item->function() == Slit::Horizontal) {
819 setItemSelected(0, True);
820 setItemSelected(1, False);
822 setItemSelected(0, False);
823 setItemSelected(1, True);
827 slitmenu.slit.reconfigure();
831 Slitmenu::Placementmenu::Placementmenu(Slitmenu &sm)
832 : Basemenu(sm.slit.screen), slitmenu(sm) {
834 setLabel(i18n(SlitSet, SlitSlitPlacement, "Slit Placement"));
835 setMinimumSublevels(3);
838 insert(i18n(CommonSet, CommonPlacementTopLeft, "Top Left"),
840 insert(i18n(CommonSet, CommonPlacementCenterLeft, "Center Left"),
842 insert(i18n(CommonSet, CommonPlacementBottomLeft, "Bottom Left"),
844 insert(i18n(CommonSet, CommonPlacementTopCenter, "Top Center"),
847 insert(i18n(CommonSet, CommonPlacementBottomCenter,
850 insert(i18n(CommonSet, CommonPlacementTopRight, "Top Right"),
852 insert(i18n(CommonSet, CommonPlacementCenterRight,
855 insert(i18n(CommonSet, CommonPlacementBottomRight,
863 void Slitmenu::Placementmenu::itemSelected(int button, int index) {
867 BasemenuItem *item = find(index);
868 if (! (item && item->function())) return;
870 slitmenu.slit.setPlacement(item->function());
872 slitmenu.slit.reconfigure();