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>
45 Slit::Slit(BScreen
&scr
) : screen(scr
), openbox(scr
.getOpenbox()) {
46 on_top
= screen
.isSlitOnTop();
47 hidden
= do_auto_hide
= screen
.doSlitAutoHide();
49 display
= screen
.getBaseDisplay().getXDisplay();
50 frame
.window
= frame
.pixmap
= None
;
52 timer
= new BTimer(openbox
, *this);
53 timer
->setTimeout(openbox
.getAutoRaiseDelay());
54 timer
->fireOnce(True
);
56 clientList
= new LinkedList
<SlitClient
>;
58 slitmenu
= new Slitmenu(*this);
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
;
71 frame
.area
= Rect(0, 0, 1, 1);
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);
88 if (timer
->isTiming()) timer
->stop();
94 screen
.getImageControl()->removeImage(frame
.pixmap
);
96 openbox
.removeSlitSearch(frame
.window
);
98 XDestroyWindow(display
, frame
.window
);
104 void Slit::addClient(Window w
) {
107 if (openbox
.validateWindow(w
)) {
108 SlitClient
*client
= new SlitClient
;
109 client
->client_window
= w
;
111 XWMHints
*wmhints
= XGetWMHints(display
, w
);
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
);
120 client
->icon_window
= wmhints
->icon_window
;
121 client
->window
= client
->icon_window
;
123 client
->icon_window
= None
;
124 client
->window
= client
->client_window
;
129 client
->icon_window
= None
;
130 client
->window
= client
->client_window
;
133 XWindowAttributes attrib
;
134 if (XGetWindowAttributes(display
, client
->window
, &attrib
)) {
135 client
->width
= attrib
.width
;
136 client
->height
= attrib
.height
;
138 client
->width
= client
->height
= 64;
141 XSetWindowBorderWidth(display
, client
->window
, 0);
143 XSelectInput(display
, frame
.window
, NoEventMask
);
144 XSelectInput(display
, client
->window
, NoEventMask
);
146 XReparentWindow(display
, client
->window
, frame
.window
, 0, 0);
147 XMapRaised(display
, client
->window
);
148 XChangeSaveSet(display
, client
->window
, SetModeInsert
);
150 XSelectInput(display
, frame
.window
, SubstructureRedirectMask
|
151 ButtonPressMask
| EnterWindowMask
| LeaveWindowMask
);
152 XSelectInput(display
, client
->window
, StructureNotifyMask
|
153 SubstructureNotifyMask
| EnterWindowMask
);
156 clientList
->insert(client
);
158 openbox
.saveSlitSearch(client
->client_window
, this);
159 openbox
.saveSlitSearch(client
->icon_window
, this);
167 void Slit::removeClient(SlitClient
*client
, Bool remap
) {
168 openbox
.removeSlitSearch(client
->client_window
);
169 openbox
.removeSlitSearch(client
->icon_window
);
170 clientList
->remove(client
);
172 screen
.removeNetizen(client
->window
);
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
);
186 client
= (SlitClient
*) 0;
190 void Slit::removeClient(Window w
, Bool remap
) {
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
);
205 if (reconf
) reconfigure();
211 void Slit::reconfigure(void) {
212 frame
.area
.setSize(0, 0);
213 LinkedListIterator
<SlitClient
> it(clientList
);
216 switch (screen
.getSlitDirection()) {
218 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
219 frame
.area
.setH(frame
.area
.h() + client
->height
+ screen
.getBevelWidth());
221 if (frame
.area
.w() < client
->width
)
222 frame
.area
.setW(client
->width
);
225 if (frame
.area
.w() < 1)
228 frame
.area
.setW(frame
.area
.w() + (screen
.getBevelWidth() * 2));
230 if (frame
.area
.h() < 1)
233 frame
.area
.setH(frame
.area
.h() + screen
.getBevelWidth());
238 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
239 frame
.area
.setW(frame
.area
.w() + client
->width
+ screen
.getBevelWidth());
241 if (frame
.area
.h() < client
->height
)
242 frame
.area
.setH(client
->height
);
245 if (frame
.area
.w() < 1)
248 frame
.area
.setW(frame
.area
.w() + screen
.getBevelWidth());
250 if (frame
.area
.h() < 1)
253 frame
.area
.setH(frame
.area
.h() + (screen
.getBevelWidth() * 2));
260 XSetWindowBorderWidth(display
,frame
.window
, screen
.getBorderWidth());
261 XSetWindowBorder(display
, frame
.window
,
262 screen
.getBorderColor()->getPixel());
264 if (! clientList
->count())
265 XUnmapWindow(display
, frame
.window
);
267 XMapWindow(display
, frame
.window
);
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
)) {
274 XSetWindowBackground(display
, frame
.window
,
275 texture
->getColor()->getPixel());
277 frame
.pixmap
= image_ctrl
->renderImage(frame
.area
.w(), frame
.area
.h(),
279 XSetWindowBackgroundPixmap(display
, frame
.window
, frame
.pixmap
);
281 if (tmp
) image_ctrl
->removeImage(tmp
);
282 XClearWindow(display
, frame
.window
);
287 switch (screen
.getSlitDirection()) {
290 y
= screen
.getBevelWidth();
292 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
293 x
= (frame
.area
.w() - client
->width
) / 2;
295 XMoveResizeWindow(display
, client
->window
, x
, y
,
296 client
->width
, client
->height
);
297 XMapWindow(display
, client
->window
);
299 // for ICCCM compliance
304 event
.type
= ConfigureNotify
;
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
;
317 XSendEvent(display
, client
->window
, False
, StructureNotifyMask
, &event
);
319 y
+= client
->height
+ screen
.getBevelWidth();
325 x
= screen
.getBevelWidth();
328 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
329 y
= (frame
.area
.h() - client
->height
) / 2;
331 XMoveResizeWindow(display
, client
->window
, x
, y
,
332 client
->width
, client
->height
);
333 XMapWindow(display
, client
->window
);
335 // for ICCCM compliance
340 event
.type
= ConfigureNotify
;
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
;
353 XSendEvent(display
, client
->window
, False
, StructureNotifyMask
, &event
);
355 x
+= client
->width
+ screen
.getBevelWidth();
361 slitmenu
->reconfigure();
365 void Slit::reposition(void) {
366 // place the slit in the appropriate place
367 switch (screen
.getSlitPlacement()) {
369 frame
.area
.setOrigin(0, 0);
370 if (screen
.getSlitDirection() == Vertical
) {
371 frame
.hidden
= Point(screen
.getBevelWidth() - screen
.getBorderWidth()
372 - frame
.area
.w(), 0);
374 frame
.hidden
= Point(0, screen
.getBevelWidth() - screen
.getBorderWidth()
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());
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());
392 frame
.hidden
= Point(0, screen
.size().h() - screen
.getBevelWidth()
393 - screen
.getBorderWidth());
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());
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());
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);
417 frame
.hidden
= Point(frame
.area
.x(), screen
.getBevelWidth()
418 - screen
.getBorderWidth() - frame
.area
.h());
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());
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());
439 frame
.hidden
= Point(frame
.area
.x(), screen
.size().h() - screen
.getBevelWidth()
440 - screen
.getBorderWidth());
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();
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());
457 frame
.hidden
.setY(frame
.area
.y());
459 frame
.area
.setY(frame
.area
.y() - tbar
->getExposedHeight());
460 if (screen
.getSlitDirection() == Vertical
)
461 frame
.hidden
.setY(frame
.area
.y() - tbar
->getExposedHeight());
463 frame
.hidden
.setY(frame
.area
.y());
468 XMoveResizeWindow(display
, frame
.window
, frame
.hidden
.x(),
469 frame
.hidden
.y(), frame
.area
.w(), frame
.area
.h());
471 XMoveResizeWindow(display
, frame
.window
, frame
.area
.x(),
472 frame
.area
.y(), frame
.area
.w(), frame
.area
.h());
476 void Slit::shutdown(void) {
477 while (clientList
->count())
478 removeClient(clientList
->first());
482 void Slit::buttonPressEvent(XButtonEvent
*e
) {
483 if (e
->window
!= frame
.window
) return;
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()) {
494 x
= e
->x_root
- (slitmenu
->getWidth() / 2);
495 y
= e
->y_root
- (slitmenu
->getHeight() / 2);
499 else if (x
+ slitmenu
->getWidth() > screen
.size().w())
500 x
= screen
.size().w() - slitmenu
->getWidth();
504 else if (y
+ slitmenu
->getHeight() > screen
.size().h())
505 y
= screen
.size().h() - slitmenu
->getHeight();
507 slitmenu
->move(x
, y
);
516 void Slit::enterNotifyEvent(XCrossingEvent
*) {
521 if (! timer
->isTiming()) timer
->start();
523 if (timer
->isTiming()) timer
->stop();
528 void Slit::leaveNotifyEvent(XCrossingEvent
*) {
533 if (timer
->isTiming()) timer
->stop();
534 } else if (! slitmenu
->isVisible()) {
535 if (! timer
->isTiming()) timer
->start();
540 void Slit::configureRequestEvent(XConfigureRequestEvent
*e
) {
543 if (openbox
.validateWindow(e
->window
)) {
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
;
555 XConfigureWindow(display
, e
->window
, e
->value_mask
, &xwc
);
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
;
571 if (reconf
) reconfigure();
579 void Slit::timeout(void) {
582 XMoveWindow(display
, frame
.window
, frame
.hidden
.x(), frame
.hidden
.y());
584 XMoveWindow(display
, frame
.window
, frame
.area
.x(), frame
.area
.y());
588 Slitmenu::Slitmenu(Slit
&sl
) : Basemenu(sl
.screen
), slit(sl
) {
589 setLabel(i18n
->getMessage(SlitSet
, SlitSlitTitle
, "Slit"));
592 directionmenu
= new Directionmenu(*this);
593 placementmenu
= new Placementmenu(*this);
595 insert(i18n
->getMessage(CommonSet
, CommonDirectionTitle
, "Direction"),
597 insert(i18n
->getMessage(CommonSet
, CommonPlacementTitle
, "Placement"),
599 insert(i18n
->getMessage(CommonSet
, CommonAlwaysOnTop
, "Always on top"), 1);
600 insert(i18n
->getMessage(CommonSet
, CommonAutoHide
, "Auto hide"), 2);
604 if (slit
.isOnTop()) setItemSelected(2, True
);
605 if (slit
.doAutoHide()) setItemSelected(3, True
);
609 Slitmenu::~Slitmenu(void) {
610 delete directionmenu
;
611 delete placementmenu
;
615 void Slitmenu::itemSelected(int button
, int index
) {
619 BasemenuItem
*item
= find(index
);
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
);
628 if (slit
.isOnTop()) slit
.screen
.raiseWindows((Window
*) 0, 0);
632 case 2: { // auto hide
633 Bool change
= ((slit
.doAutoHide()) ? False
: True
);
634 slit
.do_auto_hide
= change
;
635 setItemSelected(3, change
);
643 void Slitmenu::internal_hide(void) {
644 Basemenu::internal_hide();
645 if (slit
.doAutoHide())
650 void Slitmenu::reconfigure(void) {
651 directionmenu
->reconfigure();
652 placementmenu
->reconfigure();
654 Basemenu::reconfigure();
658 Slitmenu::Directionmenu::Directionmenu(Slitmenu
&sm
)
659 : Basemenu(sm
.slit
.screen
), slitmenu(sm
) {
660 setLabel(i18n
->getMessage(SlitSet
, SlitSlitDirection
, "Slit Direction"));
663 insert(i18n
->getMessage(CommonSet
, CommonDirectionHoriz
, "Horizontal"),
665 insert(i18n
->getMessage(CommonSet
, CommonDirectionVert
, "Vertical"),
670 if (sm
.slit
.screen
.getSlitDirection() == Slit::Horizontal
)
671 setItemSelected(0, True
);
673 setItemSelected(1, True
);
677 void Slitmenu::Directionmenu::itemSelected(int button
, int index
) {
681 BasemenuItem
*item
= find(index
);
684 slitmenu
.slit
.screen
.saveSlitDirection(item
->function());
686 if (item
->function() == Slit::Horizontal
) {
687 setItemSelected(0, True
);
688 setItemSelected(1, False
);
690 setItemSelected(0, False
);
691 setItemSelected(1, True
);
695 slitmenu
.slit
.reconfigure();
699 Slitmenu::Placementmenu::Placementmenu(Slitmenu
&sm
)
700 : Basemenu(sm
.slit
.screen
), slitmenu(sm
) {
702 setLabel(i18n
->getMessage(SlitSet
, SlitSlitPlacement
, "Slit Placement"));
703 setMinimumSublevels(3);
706 insert(i18n
->getMessage(CommonSet
, CommonPlacementTopLeft
, "Top Left"),
708 insert(i18n
->getMessage(CommonSet
, CommonPlacementCenterLeft
, "Center Left"),
710 insert(i18n
->getMessage(CommonSet
, CommonPlacementBottomLeft
, "Bottom Left"),
712 insert(i18n
->getMessage(CommonSet
, CommonPlacementTopCenter
, "Top Center"),
715 insert(i18n
->getMessage(CommonSet
, CommonPlacementBottomCenter
,
718 insert(i18n
->getMessage(CommonSet
, CommonPlacementTopRight
, "Top Right"),
720 insert(i18n
->getMessage(CommonSet
, CommonPlacementCenterRight
,
723 insert(i18n
->getMessage(CommonSet
, CommonPlacementBottomRight
,
731 void Slitmenu::Placementmenu::itemSelected(int button
, int index
) {
735 BasemenuItem
*item
= find(index
);
736 if (! (item
&& item
->function())) return;
738 slitmenu
.slit
.screen
.saveSlitPlacement(item
->function());
740 slitmenu
.slit
.reconfigure();