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
) {
47 openbox
= screen
->getOpenbox();
49 on_top
= screen
->isSlitOnTop();
50 hidden
= do_auto_hide
= screen
->doSlitAutoHide();
52 display
= screen
->getBaseDisplay()->getXDisplay();
53 frame
.window
= frame
.pixmap
= None
;
55 timer
= new BTimer(*openbox
, *this);
56 timer
->setTimeout(openbox
->getAutoRaiseDelay());
57 timer
->fireOnce(True
);
59 clientList
= new LinkedList
<SlitClient
>;
61 slitmenu
= new Slitmenu(*this);
63 XSetWindowAttributes attrib
;
64 unsigned long create_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
|
65 CWColormap
| CWOverrideRedirect
| CWEventMask
;
66 attrib
.background_pixmap
= None
;
67 attrib
.background_pixel
= attrib
.border_pixel
=
68 screen
->getBorderColor()->getPixel();
69 attrib
.colormap
= screen
->getColormap();
70 attrib
.override_redirect
= True
;
71 attrib
.event_mask
= SubstructureRedirectMask
| ButtonPressMask
|
72 EnterWindowMask
| LeaveWindowMask
;
74 frame
.x
= frame
.y
= 0;
75 frame
.width
= frame
.height
= 1;
78 XCreateWindow(display
, screen
->getRootWindow(), frame
.x
, frame
.y
,
79 frame
.width
, frame
.height
, screen
->getBorderWidth(),
80 screen
->getDepth(), InputOutput
, screen
->getVisual(),
81 create_mask
, &attrib
);
82 openbox
->saveSlitSearch(frame
.window
, this);
91 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
->getWidth() + 10,
120 screen
->getHeight() + 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
->insert(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
);
173 clientList
->remove(client
);
175 screen
->removeNetizen(client
->window
);
177 if (remap
&& openbox
->validateWindow(client
->window
)) {
178 XSelectInput(display
, frame
.window
, NoEventMask
);
179 XSelectInput(display
, client
->window
, NoEventMask
);
180 XReparentWindow(display
, client
->window
, screen
->getRootWindow(),
181 client
->x
, client
->y
);
182 XChangeSaveSet(display
, client
->window
, SetModeDelete
);
183 XSelectInput(display
, frame
.window
, SubstructureRedirectMask
|
184 ButtonPressMask
| EnterWindowMask
| LeaveWindowMask
);
189 client
= (SlitClient
*) 0;
193 void Slit::removeClient(Window w
, Bool remap
) {
198 LinkedListIterator
<SlitClient
> it(clientList
);
199 for (SlitClient
*tmp
= it
.current(); tmp
; it
++, tmp
= it
.current()) {
200 if (tmp
->window
== w
) {
201 removeClient(tmp
, remap
);
208 if (reconf
) reconfigure();
214 void Slit::reconfigure(void) {
217 LinkedListIterator
<SlitClient
> it(clientList
);
220 switch (screen
->getSlitDirection()) {
222 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
223 frame
.height
+= client
->height
+ screen
->getBevelWidth();
225 if (frame
.width
< client
->width
)
226 frame
.width
= client
->width
;
232 frame
.width
+= (screen
->getBevelWidth() * 2);
234 if (frame
.height
< 1)
237 frame
.height
+= screen
->getBevelWidth();
242 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
243 frame
.width
+= client
->width
+ screen
->getBevelWidth();
245 if (frame
.height
< client
->height
)
246 frame
.height
= client
->height
;
252 frame
.width
+= screen
->getBevelWidth();
254 if (frame
.height
< 1)
257 frame
.height
+= (screen
->getBevelWidth() * 2);
264 XSetWindowBorderWidth(display
,frame
.window
, screen
->getBorderWidth());
265 XSetWindowBorder(display
, frame
.window
,
266 screen
->getBorderColor()->getPixel());
268 if (! clientList
->count())
269 XUnmapWindow(display
, frame
.window
);
271 XMapWindow(display
, frame
.window
);
273 Pixmap tmp
= frame
.pixmap
;
274 BImageControl
*image_ctrl
= screen
->getImageControl();
275 BTexture
*texture
= &(screen
->getToolbarStyle()->toolbar
);
276 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
278 XSetWindowBackground(display
, frame
.window
,
279 texture
->getColor()->getPixel());
281 frame
.pixmap
= image_ctrl
->renderImage(frame
.width
, frame
.height
,
283 XSetWindowBackgroundPixmap(display
, frame
.window
, frame
.pixmap
);
285 if (tmp
) image_ctrl
->removeImage(tmp
);
286 XClearWindow(display
, frame
.window
);
291 switch (screen
->getSlitDirection()) {
294 y
= screen
->getBevelWidth();
296 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
297 x
= (frame
.width
- client
->width
) / 2;
299 XMoveResizeWindow(display
, client
->window
, x
, y
,
300 client
->width
, client
->height
);
301 XMapWindow(display
, client
->window
);
303 // for ICCCM compliance
308 event
.type
= ConfigureNotify
;
310 event
.xconfigure
.display
= display
;
311 event
.xconfigure
.event
= client
->window
;
312 event
.xconfigure
.window
= client
->window
;
313 event
.xconfigure
.x
= x
;
314 event
.xconfigure
.y
= y
;
315 event
.xconfigure
.width
= client
->width
;
316 event
.xconfigure
.height
= client
->height
;
317 event
.xconfigure
.border_width
= 0;
318 event
.xconfigure
.above
= frame
.window
;
319 event
.xconfigure
.override_redirect
= False
;
321 XSendEvent(display
, client
->window
, False
, StructureNotifyMask
, &event
);
323 y
+= client
->height
+ screen
->getBevelWidth();
329 x
= screen
->getBevelWidth();
332 for (client
= it
.current(); client
; it
++, client
= it
.current()) {
333 y
= (frame
.height
- client
->height
) / 2;
335 XMoveResizeWindow(display
, client
->window
, x
, y
,
336 client
->width
, client
->height
);
337 XMapWindow(display
, client
->window
);
339 // for ICCCM compliance
344 event
.type
= ConfigureNotify
;
346 event
.xconfigure
.display
= display
;
347 event
.xconfigure
.event
= client
->window
;
348 event
.xconfigure
.window
= client
->window
;
349 event
.xconfigure
.x
= x
;
350 event
.xconfigure
.y
= y
;
351 event
.xconfigure
.width
= client
->width
;
352 event
.xconfigure
.height
= client
->height
;
353 event
.xconfigure
.border_width
= 0;
354 event
.xconfigure
.above
= frame
.window
;
355 event
.xconfigure
.override_redirect
= False
;
357 XSendEvent(display
, client
->window
, False
, StructureNotifyMask
, &event
);
359 x
+= client
->width
+ screen
->getBevelWidth();
365 slitmenu
->reconfigure();
369 void Slit::reposition(void) {
370 // place the slit in the appropriate place
371 switch (screen
->getSlitPlacement()) {
375 if (screen
->getSlitDirection() == Vertical
) {
376 frame
.x_hidden
= screen
->getBevelWidth() - screen
->getBorderWidth()
381 frame
.y_hidden
= screen
->getBevelWidth() - screen
->getBorderWidth()
388 frame
.y
= (screen
->getHeight() - frame
.height
) / 2;
389 frame
.x_hidden
= screen
->getBevelWidth() - screen
->getBorderWidth()
391 frame
.y_hidden
= frame
.y
;
396 frame
.y
= screen
->getHeight() - frame
.height
397 - (screen
->getBorderWidth() * 2);
398 if (screen
->getSlitDirection() == Vertical
) {
399 frame
.x_hidden
= screen
->getBevelWidth() - screen
->getBorderWidth()
401 frame
.y_hidden
= frame
.y
;
404 frame
.y_hidden
= screen
->getHeight() - screen
->getBevelWidth()
405 - screen
->getBorderWidth();
410 frame
.x
= (screen
->getWidth() - frame
.width
) / 2;
412 frame
.x_hidden
= frame
.x
;
413 frame
.y_hidden
= screen
->getBevelWidth() - screen
->getBorderWidth()
418 frame
.x
= (screen
->getWidth() - frame
.width
) / 2;
419 frame
.y
= screen
->getHeight() - frame
.height
420 - (screen
->getBorderWidth() * 2);
421 frame
.x_hidden
= frame
.x
;
422 frame
.y_hidden
= screen
->getHeight() - screen
->getBevelWidth()
423 - screen
->getBorderWidth();
427 frame
.x
= screen
->getWidth() - frame
.width
428 - (screen
->getBorderWidth() * 2);
430 if (screen
->getSlitDirection() == Vertical
) {
431 frame
.x_hidden
= screen
->getWidth() - screen
->getBevelWidth()
432 - screen
->getBorderWidth();
435 frame
.x_hidden
= frame
.x
;
436 frame
.y_hidden
= screen
->getBevelWidth() - screen
->getBorderWidth()
443 frame
.x
= screen
->getWidth() - frame
.width
444 - (screen
->getBorderWidth() * 2);
445 frame
.y
= (screen
->getHeight() - frame
.height
) / 2;
446 frame
.x_hidden
= screen
->getWidth() - screen
->getBevelWidth()
447 - screen
->getBorderWidth();
448 frame
.y_hidden
= frame
.y
;
452 frame
.x
= screen
->getWidth() - frame
.width
453 - (screen
->getBorderWidth() * 2);
454 frame
.y
= screen
->getHeight() - frame
.height
455 - (screen
->getBorderWidth() * 2);
456 if (screen
->getSlitDirection() == Vertical
) {
457 frame
.x_hidden
= screen
->getWidth() - screen
->getBevelWidth()
458 - screen
->getBorderWidth();
459 frame
.y_hidden
= frame
.y
;
461 frame
.x_hidden
= frame
.x
;
462 frame
.y_hidden
= screen
->getHeight() - screen
->getBevelWidth()
463 - screen
->getBorderWidth();
468 Toolbar
*tbar
= screen
->getToolbar();
469 int sw
= frame
.width
+ (screen
->getBorderWidth() * 2),
470 sh
= frame
.height
+ (screen
->getBorderWidth() * 2),
471 tw
= tbar
->getWidth() + screen
->getBorderWidth(),
472 th
= tbar
->getHeight() + screen
->getBorderWidth();
474 if (tbar
->getX() < frame
.x
+ sw
&& tbar
->getX() + tw
> frame
.x
&&
475 tbar
->getY() < frame
.y
+ sh
&& tbar
->getY() + th
> frame
.y
) {
477 frame
.y
+= tbar
->getExposedHeight();
478 if (screen
->getSlitDirection() == Vertical
)
479 frame
.y_hidden
+= tbar
->getExposedHeight();
481 frame
.y_hidden
= frame
.y
;
483 frame
.y
-= tbar
->getExposedHeight();
484 if (screen
->getSlitDirection() == Vertical
)
485 frame
.y_hidden
-= tbar
->getExposedHeight();
487 frame
.y_hidden
= frame
.y
;
492 XMoveResizeWindow(display
, frame
.window
, frame
.x_hidden
,
493 frame
.y_hidden
, frame
.width
, frame
.height
);
495 XMoveResizeWindow(display
, frame
.window
, frame
.x
,
496 frame
.y
, frame
.width
, frame
.height
);
500 void Slit::shutdown(void) {
501 while (clientList
->count())
502 removeClient(clientList
->first());
506 void Slit::buttonPressEvent(XButtonEvent
*e
) {
507 if (e
->window
!= frame
.window
) return;
509 if (e
->button
== Button1
&& (! on_top
)) {
510 Window w
[1] = { frame
.window
};
511 screen
->raiseWindows(w
, 1);
512 } else if (e
->button
== Button2
&& (! on_top
)) {
513 XLowerWindow(display
, frame
.window
);
514 } else if (e
->button
== Button3
) {
515 if (! slitmenu
->isVisible()) {
518 x
= e
->x_root
- (slitmenu
->getWidth() / 2);
519 y
= e
->y_root
- (slitmenu
->getHeight() / 2);
523 else if (x
+ slitmenu
->getWidth() > screen
->getWidth())
524 x
= screen
->getWidth() - slitmenu
->getWidth();
528 else if (y
+ slitmenu
->getHeight() > screen
->getHeight())
529 y
= screen
->getHeight() - slitmenu
->getHeight();
531 slitmenu
->move(x
, y
);
540 void Slit::enterNotifyEvent(XCrossingEvent
*) {
545 if (! timer
->isTiming()) timer
->start();
547 if (timer
->isTiming()) timer
->stop();
552 void Slit::leaveNotifyEvent(XCrossingEvent
*) {
557 if (timer
->isTiming()) timer
->stop();
558 } else if (! slitmenu
->isVisible()) {
559 if (! timer
->isTiming()) timer
->start();
564 void Slit::configureRequestEvent(XConfigureRequestEvent
*e
) {
567 if (openbox
->validateWindow(e
->window
)) {
573 xwc
.width
= e
->width
;
574 xwc
.height
= e
->height
;
575 xwc
.border_width
= 0;
576 xwc
.sibling
= e
->above
;
577 xwc
.stack_mode
= e
->detail
;
579 XConfigureWindow(display
, e
->window
, e
->value_mask
, &xwc
);
581 LinkedListIterator
<SlitClient
> it(clientList
);
582 SlitClient
*client
= it
.current();
583 for (; client
; it
++, client
= it
.current())
584 if (client
->window
== e
->window
)
585 if (client
->width
!= ((unsigned) e
->width
) ||
586 client
->height
!= ((unsigned) e
->height
)) {
587 client
->width
= (unsigned) e
->width
;
588 client
->height
= (unsigned) e
->height
;
595 if (reconf
) reconfigure();
603 void Slit::timeout(void) {
606 XMoveWindow(display
, frame
.window
, frame
.x_hidden
, frame
.y_hidden
);
608 XMoveWindow(display
, frame
.window
, frame
.x
, frame
.y
);
612 Slitmenu::Slitmenu(Slit
&sl
) : Basemenu(*sl
.screen
), slit(sl
) {
613 setLabel(i18n
->getMessage(SlitSet
, SlitSlitTitle
, "Slit"));
616 directionmenu
= new Directionmenu(*this);
617 placementmenu
= new Placementmenu(*this);
619 insert(i18n
->getMessage(CommonSet
, CommonDirectionTitle
, "Direction"),
621 insert(i18n
->getMessage(CommonSet
, CommonPlacementTitle
, "Placement"),
623 insert(i18n
->getMessage(CommonSet
, CommonAlwaysOnTop
, "Always on top"), 1);
624 insert(i18n
->getMessage(CommonSet
, CommonAutoHide
, "Auto hide"), 2);
628 if (slit
.isOnTop()) setItemSelected(2, True
);
629 if (slit
.doAutoHide()) setItemSelected(3, True
);
633 Slitmenu::~Slitmenu(void) {
634 delete directionmenu
;
635 delete placementmenu
;
639 void Slitmenu::itemSelected(int button
, int index
) {
643 BasemenuItem
*item
= find(index
);
646 switch (item
->function()) {
647 case 1: { // always on top
648 Bool change
= ((slit
.isOnTop()) ? False
: True
);
649 slit
.on_top
= change
;
650 setItemSelected(2, change
);
652 if (slit
.isOnTop()) slit
.screen
->raiseWindows((Window
*) 0, 0);
656 case 2: { // auto hide
657 Bool change
= ((slit
.doAutoHide()) ? False
: True
);
658 slit
.do_auto_hide
= change
;
659 setItemSelected(3, change
);
667 void Slitmenu::internal_hide(void) {
668 Basemenu::internal_hide();
669 if (slit
.doAutoHide())
674 void Slitmenu::reconfigure(void) {
675 directionmenu
->reconfigure();
676 placementmenu
->reconfigure();
678 Basemenu::reconfigure();
682 Slitmenu::Directionmenu::Directionmenu(Slitmenu
&sm
)
683 : Basemenu(*sm
.slit
.screen
), slitmenu(sm
) {
684 setLabel(i18n
->getMessage(SlitSet
, SlitSlitDirection
, "Slit Direction"));
687 insert(i18n
->getMessage(CommonSet
, CommonDirectionHoriz
, "Horizontal"),
689 insert(i18n
->getMessage(CommonSet
, CommonDirectionVert
, "Vertical"),
694 if (sm
.slit
.screen
->getSlitDirection() == Slit::Horizontal
)
695 setItemSelected(0, True
);
697 setItemSelected(1, True
);
701 void Slitmenu::Directionmenu::itemSelected(int button
, int index
) {
705 BasemenuItem
*item
= find(index
);
708 slitmenu
.slit
.screen
->saveSlitDirection(item
->function());
710 if (item
->function() == Slit::Horizontal
) {
711 setItemSelected(0, True
);
712 setItemSelected(1, False
);
714 setItemSelected(0, False
);
715 setItemSelected(1, True
);
719 slitmenu
.slit
.reconfigure();
723 Slitmenu::Placementmenu::Placementmenu(Slitmenu
&sm
)
724 : Basemenu(*sm
.slit
.screen
), slitmenu(sm
) {
726 setLabel(i18n
->getMessage(SlitSet
, SlitSlitPlacement
, "Slit Placement"));
727 setMinimumSublevels(3);
730 insert(i18n
->getMessage(CommonSet
, CommonPlacementTopLeft
, "Top Left"),
732 insert(i18n
->getMessage(CommonSet
, CommonPlacementCenterLeft
, "Center Left"),
734 insert(i18n
->getMessage(CommonSet
, CommonPlacementBottomLeft
, "Bottom Left"),
736 insert(i18n
->getMessage(CommonSet
, CommonPlacementTopCenter
, "Top Center"),
739 insert(i18n
->getMessage(CommonSet
, CommonPlacementBottomCenter
,
742 insert(i18n
->getMessage(CommonSet
, CommonPlacementTopRight
, "Top Right"),
744 insert(i18n
->getMessage(CommonSet
, CommonPlacementCenterRight
,
747 insert(i18n
->getMessage(CommonSet
, CommonPlacementBottomRight
,
755 void Slitmenu::Placementmenu::itemSelected(int button
, int index
) {
759 BasemenuItem
*item
= find(index
);
760 if (! (item
&& item
->function())) return;
762 slitmenu
.slit
.screen
->saveSlitPlacement(item
->function());
764 slitmenu
.slit
.reconfigure();