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
.x
= frame
.y
= 0;
72 frame
.width
= frame
.height
= 1;
75 XCreateWindow(display
, screen
.getRootWindow(), frame
.x
, frame
.y
,
76 frame
.width
, frame
.height
, 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
.getWidth() + 10,
117 screen
.getHeight() + 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) {
214 LinkedListIterator
<SlitClient
> it(clientList
);
217 switch (screen
.getSlitDirection()) {
219 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
220 frame
.height
+= client
->height
+ screen
.getBevelWidth();
222 if (frame
.width
< client
->width
)
223 frame
.width
= client
->width
;
229 frame
.width
+= (screen
.getBevelWidth() * 2);
231 if (frame
.height
< 1)
234 frame
.height
+= screen
.getBevelWidth();
239 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
240 frame
.width
+= client
->width
+ screen
.getBevelWidth();
242 if (frame
.height
< client
->height
)
243 frame
.height
= client
->height
;
249 frame
.width
+= screen
.getBevelWidth();
251 if (frame
.height
< 1)
254 frame
.height
+= (screen
.getBevelWidth() * 2);
261 XSetWindowBorderWidth(display
,frame
.window
, screen
.getBorderWidth());
262 XSetWindowBorder(display
, frame
.window
,
263 screen
.getBorderColor()->getPixel());
265 if (! clientList
->count())
266 XUnmapWindow(display
, frame
.window
);
268 XMapWindow(display
, frame
.window
);
270 Pixmap tmp
= frame
.pixmap
;
271 BImageControl
*image_ctrl
= screen
.getImageControl();
272 BTexture
*texture
= &(screen
.getToolbarStyle()->toolbar
);
273 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
275 XSetWindowBackground(display
, frame
.window
,
276 texture
->getColor()->getPixel());
278 frame
.pixmap
= image_ctrl
->renderImage(frame
.width
, frame
.height
,
280 XSetWindowBackgroundPixmap(display
, frame
.window
, frame
.pixmap
);
282 if (tmp
) image_ctrl
->removeImage(tmp
);
283 XClearWindow(display
, frame
.window
);
288 switch (screen
.getSlitDirection()) {
291 y
= screen
.getBevelWidth();
293 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
294 x
= (frame
.width
- client
->width
) / 2;
296 XMoveResizeWindow(display
, client
->window
, x
, y
,
297 client
->width
, client
->height
);
298 XMapWindow(display
, client
->window
);
300 // for ICCCM compliance
305 event
.type
= ConfigureNotify
;
307 event
.xconfigure
.display
= display
;
308 event
.xconfigure
.event
= client
->window
;
309 event
.xconfigure
.window
= client
->window
;
310 event
.xconfigure
.x
= x
;
311 event
.xconfigure
.y
= y
;
312 event
.xconfigure
.width
= client
->width
;
313 event
.xconfigure
.height
= client
->height
;
314 event
.xconfigure
.border_width
= 0;
315 event
.xconfigure
.above
= frame
.window
;
316 event
.xconfigure
.override_redirect
= False
;
318 XSendEvent(display
, client
->window
, False
, StructureNotifyMask
, &event
);
320 y
+= client
->height
+ screen
.getBevelWidth();
326 x
= screen
.getBevelWidth();
329 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
330 y
= (frame
.height
- client
->height
) / 2;
332 XMoveResizeWindow(display
, client
->window
, x
, y
,
333 client
->width
, client
->height
);
334 XMapWindow(display
, client
->window
);
336 // for ICCCM compliance
341 event
.type
= ConfigureNotify
;
343 event
.xconfigure
.display
= display
;
344 event
.xconfigure
.event
= client
->window
;
345 event
.xconfigure
.window
= client
->window
;
346 event
.xconfigure
.x
= x
;
347 event
.xconfigure
.y
= y
;
348 event
.xconfigure
.width
= client
->width
;
349 event
.xconfigure
.height
= client
->height
;
350 event
.xconfigure
.border_width
= 0;
351 event
.xconfigure
.above
= frame
.window
;
352 event
.xconfigure
.override_redirect
= False
;
354 XSendEvent(display
, client
->window
, False
, StructureNotifyMask
, &event
);
356 x
+= client
->width
+ screen
.getBevelWidth();
362 slitmenu
->reconfigure();
366 void Slit::reposition(void) {
367 // place the slit in the appropriate place
368 switch (screen
.getSlitPlacement()) {
372 if (screen
.getSlitDirection() == Vertical
) {
373 frame
.x_hidden
= screen
.getBevelWidth() - screen
.getBorderWidth()
378 frame
.y_hidden
= screen
.getBevelWidth() - screen
.getBorderWidth()
385 frame
.y
= (screen
.getHeight() - frame
.height
) / 2;
386 frame
.x_hidden
= screen
.getBevelWidth() - screen
.getBorderWidth()
388 frame
.y_hidden
= frame
.y
;
393 frame
.y
= screen
.getHeight() - frame
.height
394 - (screen
.getBorderWidth() * 2);
395 if (screen
.getSlitDirection() == Vertical
) {
396 frame
.x_hidden
= screen
.getBevelWidth() - screen
.getBorderWidth()
398 frame
.y_hidden
= frame
.y
;
401 frame
.y_hidden
= screen
.getHeight() - screen
.getBevelWidth()
402 - screen
.getBorderWidth();
407 frame
.x
= (screen
.getWidth() - frame
.width
) / 2;
409 frame
.x_hidden
= frame
.x
;
410 frame
.y_hidden
= screen
.getBevelWidth() - screen
.getBorderWidth()
415 frame
.x
= (screen
.getWidth() - frame
.width
) / 2;
416 frame
.y
= screen
.getHeight() - frame
.height
417 - (screen
.getBorderWidth() * 2);
418 frame
.x_hidden
= frame
.x
;
419 frame
.y_hidden
= screen
.getHeight() - screen
.getBevelWidth()
420 - screen
.getBorderWidth();
424 frame
.x
= screen
.getWidth() - frame
.width
425 - (screen
.getBorderWidth() * 2);
427 if (screen
.getSlitDirection() == Vertical
) {
428 frame
.x_hidden
= screen
.getWidth() - screen
.getBevelWidth()
429 - screen
.getBorderWidth();
432 frame
.x_hidden
= frame
.x
;
433 frame
.y_hidden
= screen
.getBevelWidth() - screen
.getBorderWidth()
440 frame
.x
= screen
.getWidth() - frame
.width
441 - (screen
.getBorderWidth() * 2);
442 frame
.y
= (screen
.getHeight() - frame
.height
) / 2;
443 frame
.x_hidden
= screen
.getWidth() - screen
.getBevelWidth()
444 - screen
.getBorderWidth();
445 frame
.y_hidden
= frame
.y
;
449 frame
.x
= screen
.getWidth() - frame
.width
450 - (screen
.getBorderWidth() * 2);
451 frame
.y
= screen
.getHeight() - frame
.height
452 - (screen
.getBorderWidth() * 2);
453 if (screen
.getSlitDirection() == Vertical
) {
454 frame
.x_hidden
= screen
.getWidth() - screen
.getBevelWidth()
455 - screen
.getBorderWidth();
456 frame
.y_hidden
= frame
.y
;
458 frame
.x_hidden
= frame
.x
;
459 frame
.y_hidden
= screen
.getHeight() - screen
.getBevelWidth()
460 - screen
.getBorderWidth();
465 Toolbar
*tbar
= screen
.getToolbar();
466 int sw
= frame
.width
+ (screen
.getBorderWidth() * 2),
467 sh
= frame
.height
+ (screen
.getBorderWidth() * 2),
468 tw
= tbar
->getWidth() + screen
.getBorderWidth(),
469 th
= tbar
->getHeight() + screen
.getBorderWidth();
471 if (tbar
->getX() < frame
.x
+ sw
&& tbar
->getX() + tw
> frame
.x
&&
472 tbar
->getY() < frame
.y
+ sh
&& tbar
->getY() + th
> frame
.y
) {
474 frame
.y
+= tbar
->getExposedHeight();
475 if (screen
.getSlitDirection() == Vertical
)
476 frame
.y_hidden
+= tbar
->getExposedHeight();
478 frame
.y_hidden
= frame
.y
;
480 frame
.y
-= tbar
->getExposedHeight();
481 if (screen
.getSlitDirection() == Vertical
)
482 frame
.y_hidden
-= tbar
->getExposedHeight();
484 frame
.y_hidden
= frame
.y
;
489 XMoveResizeWindow(display
, frame
.window
, frame
.x_hidden
,
490 frame
.y_hidden
, frame
.width
, frame
.height
);
492 XMoveResizeWindow(display
, frame
.window
, frame
.x
,
493 frame
.y
, frame
.width
, frame
.height
);
497 void Slit::shutdown(void) {
498 while (clientList
->count())
499 removeClient(clientList
->first());
503 void Slit::buttonPressEvent(XButtonEvent
*e
) {
504 if (e
->window
!= frame
.window
) return;
506 if (e
->button
== Button1
&& (! on_top
)) {
507 Window w
[1] = { frame
.window
};
508 screen
.raiseWindows(w
, 1);
509 } else if (e
->button
== Button2
&& (! on_top
)) {
510 XLowerWindow(display
, frame
.window
);
511 } else if (e
->button
== Button3
) {
512 if (! slitmenu
->isVisible()) {
515 x
= e
->x_root
- (slitmenu
->getWidth() / 2);
516 y
= e
->y_root
- (slitmenu
->getHeight() / 2);
520 else if (x
+ slitmenu
->getWidth() > screen
.getWidth())
521 x
= screen
.getWidth() - slitmenu
->getWidth();
525 else if (y
+ slitmenu
->getHeight() > screen
.getHeight())
526 y
= screen
.getHeight() - slitmenu
->getHeight();
528 slitmenu
->move(x
, y
);
537 void Slit::enterNotifyEvent(XCrossingEvent
*) {
542 if (! timer
->isTiming()) timer
->start();
544 if (timer
->isTiming()) timer
->stop();
549 void Slit::leaveNotifyEvent(XCrossingEvent
*) {
554 if (timer
->isTiming()) timer
->stop();
555 } else if (! slitmenu
->isVisible()) {
556 if (! timer
->isTiming()) timer
->start();
561 void Slit::configureRequestEvent(XConfigureRequestEvent
*e
) {
564 if (openbox
.validateWindow(e
->window
)) {
570 xwc
.width
= e
->width
;
571 xwc
.height
= e
->height
;
572 xwc
.border_width
= 0;
573 xwc
.sibling
= e
->above
;
574 xwc
.stack_mode
= e
->detail
;
576 XConfigureWindow(display
, e
->window
, e
->value_mask
, &xwc
);
578 LinkedListIterator
<SlitClient
> it(clientList
);
579 SlitClient
*client
= it
.current();
580 for (; client
; it
++, client
= it
.current())
581 if (client
->window
== e
->window
)
582 if (client
->width
!= ((unsigned) e
->width
) ||
583 client
->height
!= ((unsigned) e
->height
)) {
584 client
->width
= (unsigned) e
->width
;
585 client
->height
= (unsigned) e
->height
;
592 if (reconf
) reconfigure();
600 void Slit::timeout(void) {
603 XMoveWindow(display
, frame
.window
, frame
.x_hidden
, frame
.y_hidden
);
605 XMoveWindow(display
, frame
.window
, frame
.x
, frame
.y
);
609 Slitmenu::Slitmenu(Slit
&sl
) : Basemenu(sl
.screen
), slit(sl
) {
610 setLabel(i18n
->getMessage(SlitSet
, SlitSlitTitle
, "Slit"));
613 directionmenu
= new Directionmenu(*this);
614 placementmenu
= new Placementmenu(*this);
616 insert(i18n
->getMessage(CommonSet
, CommonDirectionTitle
, "Direction"),
618 insert(i18n
->getMessage(CommonSet
, CommonPlacementTitle
, "Placement"),
620 insert(i18n
->getMessage(CommonSet
, CommonAlwaysOnTop
, "Always on top"), 1);
621 insert(i18n
->getMessage(CommonSet
, CommonAutoHide
, "Auto hide"), 2);
625 if (slit
.isOnTop()) setItemSelected(2, True
);
626 if (slit
.doAutoHide()) setItemSelected(3, True
);
630 Slitmenu::~Slitmenu(void) {
631 delete directionmenu
;
632 delete placementmenu
;
636 void Slitmenu::itemSelected(int button
, int index
) {
640 BasemenuItem
*item
= find(index
);
643 switch (item
->function()) {
644 case 1: { // always on top
645 Bool change
= ((slit
.isOnTop()) ? False
: True
);
646 slit
.on_top
= change
;
647 setItemSelected(2, change
);
649 if (slit
.isOnTop()) slit
.screen
.raiseWindows((Window
*) 0, 0);
653 case 2: { // auto hide
654 Bool change
= ((slit
.doAutoHide()) ? False
: True
);
655 slit
.do_auto_hide
= change
;
656 setItemSelected(3, change
);
664 void Slitmenu::internal_hide(void) {
665 Basemenu::internal_hide();
666 if (slit
.doAutoHide())
671 void Slitmenu::reconfigure(void) {
672 directionmenu
->reconfigure();
673 placementmenu
->reconfigure();
675 Basemenu::reconfigure();
679 Slitmenu::Directionmenu::Directionmenu(Slitmenu
&sm
)
680 : Basemenu(sm
.slit
.screen
), slitmenu(sm
) {
681 setLabel(i18n
->getMessage(SlitSet
, SlitSlitDirection
, "Slit Direction"));
684 insert(i18n
->getMessage(CommonSet
, CommonDirectionHoriz
, "Horizontal"),
686 insert(i18n
->getMessage(CommonSet
, CommonDirectionVert
, "Vertical"),
691 if (sm
.slit
.screen
.getSlitDirection() == Slit::Horizontal
)
692 setItemSelected(0, True
);
694 setItemSelected(1, True
);
698 void Slitmenu::Directionmenu::itemSelected(int button
, int index
) {
702 BasemenuItem
*item
= find(index
);
705 slitmenu
.slit
.screen
.saveSlitDirection(item
->function());
707 if (item
->function() == Slit::Horizontal
) {
708 setItemSelected(0, True
);
709 setItemSelected(1, False
);
711 setItemSelected(0, False
);
712 setItemSelected(1, True
);
716 slitmenu
.slit
.reconfigure();
720 Slitmenu::Placementmenu::Placementmenu(Slitmenu
&sm
)
721 : Basemenu(sm
.slit
.screen
), slitmenu(sm
) {
723 setLabel(i18n
->getMessage(SlitSet
, SlitSlitPlacement
, "Slit Placement"));
724 setMinimumSublevels(3);
727 insert(i18n
->getMessage(CommonSet
, CommonPlacementTopLeft
, "Top Left"),
729 insert(i18n
->getMessage(CommonSet
, CommonPlacementCenterLeft
, "Center Left"),
731 insert(i18n
->getMessage(CommonSet
, CommonPlacementBottomLeft
, "Bottom Left"),
733 insert(i18n
->getMessage(CommonSet
, CommonPlacementTopCenter
, "Top Center"),
736 insert(i18n
->getMessage(CommonSet
, CommonPlacementBottomCenter
,
739 insert(i18n
->getMessage(CommonSet
, CommonPlacementTopRight
, "Top Right"),
741 insert(i18n
->getMessage(CommonSet
, CommonPlacementCenterRight
,
744 insert(i18n
->getMessage(CommonSet
, CommonPlacementBottomRight
,
752 void Slitmenu::Placementmenu::itemSelected(int button
, int index
) {
756 BasemenuItem
*item
= find(index
);
757 if (! (item
&& item
->function())) return;
759 slitmenu
.slit
.screen
.saveSlitPlacement(item
->function());
761 slitmenu
.slit
.reconfigure();