1
// Slit.cc for Blackbox - an X11 Window manager
2
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
4
// Permission is hereby granted, free of charge, to any person obtaining a
5
// copy of this software and associated documentation files (the "Software"),
6
// to deal in the Software without restriction, including without limitation
7
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
// and/or sell copies of the Software, and to permit persons to whom the
9
// Software is furnished to do so, subject to the following conditions:
11
// The above copyright notice and this permission notice shall be included in
12
// all copies or substantial portions of the Software.
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
// DEALINGS IN THE SOFTWARE.
22
// stupid macros needed to access some functions in version 2 of the GNU C
29
# include "../config.h"
30
#endif // HAVE_CONFIG_H
34
#include <X11/keysym.h>
46
Slit::Slit(BScreen *scr) {
48
fluxbox = Fluxbox::instance();
50
on_top = screen->isSlitOnTop();
51
hidden = do_auto_hide = screen->doSlitAutoHide();
53
display = screen->getBaseDisplay()->getXDisplay();
54
frame.window = frame.pixmap = None;
56
timer = new BTimer(fluxbox, this);
57
timer->setTimeout(fluxbox->getAutoRaiseDelay());
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.x = frame.y = 0;
74
frame.width = frame.height = 1;
77
XCreateWindow(display, screen->getRootWindow(), frame.x, frame.y,
78
frame.width, frame.height, screen->getBorderWidth(),
79
screen->getDepth(), InputOutput, screen->getVisual(),
80
create_mask, &attrib);
81
fluxbox->saveSlitSearch(frame.window, this);
94
screen->getImageControl()->removeImage(frame.pixmap);
96
fluxbox->removeSlitSearch(frame.window);
98
XDestroyWindow(display, frame.window);
104
void Slit::addClient(Window w) {
107
fprintf(stderr, "%s(%d): adding Client\n", __FILE__, __LINE__);
109
if (fluxbox->validateWindow(w)) {
110
SlitClient *client = new SlitClient;
111
client->client_window = w;
113
XWMHints *wmhints = XGetWMHints(display, w);
116
if ((wmhints->flags & IconWindowHint) &&
117
(wmhints->icon_window != None)) {
118
XMoveWindow(display, client->client_window, screen->getWidth() + 10,
119
screen->getHeight() + 10);
120
XMapWindow(display, client->client_window);
121
client->icon_window = wmhints->icon_window;
122
client->window = client->icon_window;
124
client->icon_window = None;
125
client->window = client->client_window;
130
client->icon_window = None;
131
client->window = client->client_window;
134
XWindowAttributes attrib;
135
if (XGetWindowAttributes(display, client->window, &attrib)) {
136
client->width = attrib.width;
137
client->height = attrib.height;
139
client->width = client->height = 64;
141
#else //KDE stuff starts here
142
XWindowAttributes attrib;
143
//Check and see if new client is a KDE dock applet
144
//If so force reasonable size
145
bool iskdedockapp=false;
148
unsigned long *data = (unsigned long *) 0, uljunk;
150
// Check if KDE v2.x dock applet
151
if (XGetWindowProperty(fluxbox->getXDisplay(), w,
152
fluxbox->getKWM2DockwindowAtom(), 0l, 1l, False,
153
fluxbox->getKWM2DockwindowAtom(),
154
&ajunk, &ijunk, &uljunk, &uljunk,
155
(unsigned char **) &data) == Success) {
156
iskdedockapp = (data && data[0] != 0);
157
XFree((char *) data);
160
// Check if KDE v1.x dock applet
162
if (XGetWindowProperty(fluxbox->getXDisplay(), w,
163
fluxbox->getKWM1DockwindowAtom(), 0l, 1l, False,
164
fluxbox->getKWM1DockwindowAtom(),
165
&ajunk, &ijunk, &uljunk, &uljunk,
166
(unsigned char **) &data) == Success) {
167
iskdedockapp = (data && data[0] != 0);
168
XFree((char *) data);
173
client->width = client->height = 24;
175
if (XGetWindowAttributes(display, client->window, &attrib)) {
176
client->width = attrib.width;
177
client->height = attrib.height;
179
client->width = client->height = 64;
183
XSetWindowBorderWidth(display, client->window, 0);
185
XSelectInput(display, frame.window, NoEventMask);
186
XSelectInput(display, client->window, NoEventMask);
188
XReparentWindow(display, client->window, frame.window, 0, 0);
189
XMapRaised(display, client->window);
190
XChangeSaveSet(display, client->window, SetModeInsert);
192
XSelectInput(display, frame.window, SubstructureRedirectMask |
193
ButtonPressMask | EnterWindowMask | LeaveWindowMask);
194
XSelectInput(display, client->window, StructureNotifyMask |
195
SubstructureNotifyMask | EnterWindowMask);
198
clientList.push_back(client);
200
fluxbox->saveSlitSearch(client->client_window, this);
201
fluxbox->saveSlitSearch(client->icon_window, this);
209
void Slit::removeClient(SlitClient *client, bool remap) {
210
fluxbox->removeSlitSearch(client->client_window);
211
fluxbox->removeSlitSearch(client->icon_window);
213
clientList.remove(client);
215
screen->removeNetizen(client->window);
217
if (remap && fluxbox->validateWindow(client->window)) {
218
XSelectInput(display, frame.window, NoEventMask);
219
XSelectInput(display, client->window, NoEventMask);
220
XReparentWindow(display, client->window, screen->getRootWindow(),
221
client->x, client->y);
222
XChangeSaveSet(display, client->window, SetModeDelete);
223
XSelectInput(display, frame.window, SubstructureRedirectMask |
224
ButtonPressMask | EnterWindowMask | LeaveWindowMask);
232
void Slit::removeClient(Window w, bool remap) {
237
SlitClients::iterator it = clientList.begin();
238
SlitClients::iterator it_end = clientList.end();
239
for (; it != it_end; ++it) {
240
if ((*it)->window == w) {
241
removeClient((*it), remap);
247
if (reconf) reconfigure();
253
void Slit::reconfigure(void) {
257
switch (screen->getSlitDirection()) {
260
SlitClients::iterator it = clientList.begin();
261
SlitClients::iterator it_end = clientList.end();
262
for (; it != it_end; ++it) {
263
frame.height += (*it)->height + screen->getBevelWidth();
265
if (frame.width < (*it)->width)
266
frame.width = (*it)->width;
273
frame.width += (screen->getBevelWidth() * 2);
275
if (frame.height < 1)
278
frame.height += screen->getBevelWidth();
284
SlitClients::iterator it = clientList.begin();
285
SlitClients::iterator it_end = clientList.end();
286
for (; it != it_end; ++it) {
287
frame.width += (*it)->width + screen->getBevelWidth();
289
if (frame.height < (*it)->height)
290
frame.height = (*it)->height;
297
frame.width += screen->getBevelWidth();
299
if (frame.height < 1)
302
frame.height += (screen->getBevelWidth() * 2);
309
XSetWindowBorderWidth(display ,frame.window, screen->getBorderWidth());
310
XSetWindowBorder(display, frame.window,
311
screen->getBorderColor()->getPixel());
313
if (clientList.size()==0)
314
XUnmapWindow(display, frame.window);
316
XMapWindow(display, frame.window);
318
Pixmap tmp = frame.pixmap;
319
BImageControl *image_ctrl = screen->getImageControl();
320
BTexture *texture = &(screen->getToolbarStyle()->toolbar);
321
if (texture->getTexture() == (BImage::FLAT | BImage::SOLID)) {
323
XSetWindowBackground(display, frame.window,
324
texture->getColor()->getPixel());
326
frame.pixmap = image_ctrl->renderImage(frame.width, frame.height,
328
XSetWindowBackgroundPixmap(display, frame.window, frame.pixmap);
330
if (tmp) image_ctrl->removeImage(tmp);
331
XClearWindow(display, frame.window);
335
switch (screen->getSlitDirection()) {
338
y = screen->getBevelWidth();
341
SlitClients::iterator it = clientList.begin();
342
SlitClients::iterator it_end = clientList.end();
343
for (; it != it_end; ++it) {
344
x = (frame.width - (*it)->width) / 2;
346
XMoveResizeWindow(display, (*it)->window, x, y,
347
(*it)->width, (*it)->height);
348
XMapWindow(display, (*it)->window);
350
// for ICCCM compliance
355
event.type = ConfigureNotify;
357
event.xconfigure.display = display;
358
event.xconfigure.event = (*it)->window;
359
event.xconfigure.window = (*it)->window;
360
event.xconfigure.x = x;
361
event.xconfigure.y = y;
362
event.xconfigure.width = (*it)->width;
363
event.xconfigure.height = (*it)->height;
364
event.xconfigure.border_width = 0;
365
event.xconfigure.above = frame.window;
366
event.xconfigure.override_redirect = False;
368
XSendEvent(display, (*it)->window, False, StructureNotifyMask,
371
y += (*it)->height + screen->getBevelWidth();
378
x = screen->getBevelWidth();
382
SlitClients::iterator it = clientList.begin();
383
SlitClients::iterator it_end = clientList.end();
384
for (; it != it_end; ++it) {
385
y = (frame.height - (*it)->height) / 2;
387
XMoveResizeWindow(display, (*it)->window, x, y,
388
(*it)->width, (*it)->height);
389
XMapWindow(display, (*it)->window);
391
// for ICCCM compliance
396
event.type = ConfigureNotify;
398
event.xconfigure.display = display;
399
event.xconfigure.event = (*it)->window;
400
event.xconfigure.window = (*it)->window;
401
event.xconfigure.x = frame.x + x + screen->getBorderWidth();
402
event.xconfigure.y = frame.y + y + screen->getBorderWidth();
403
event.xconfigure.width = (*it)->width;
404
event.xconfigure.height = (*it)->height;
405
event.xconfigure.border_width = 0;
406
event.xconfigure.above = frame.window;
407
event.xconfigure.override_redirect = False;
409
XSendEvent(display, (*it)->window, False, StructureNotifyMask,
412
x += (*it)->width + screen->getBevelWidth();
419
slitmenu->reconfigure();
423
void Slit::reposition(void) {
424
// place the slit in the appropriate place
425
switch (screen->getSlitPlacement()) {
429
if (screen->getSlitDirection() == VERTICAL) {
430
frame.x_hidden = screen->getBevelWidth() -
431
screen->getBorderWidth() - frame.width;
435
frame.y_hidden = screen->getBevelWidth() -
436
screen->getBorderWidth() - frame.height;
442
frame.y = (screen->getHeight() - frame.height) / 2;
443
frame.x_hidden = screen->getBevelWidth() -
444
screen->getBorderWidth() - frame.width;
445
frame.y_hidden = frame.y;
450
frame.y = screen->getHeight() - frame.height - screen->getBorderWidth2x();
451
if (screen->getSlitDirection() == VERTICAL) {
452
frame.x_hidden = screen->getBevelWidth() - screen->getBorderWidth()
454
frame.y_hidden = frame.y;
457
frame.y_hidden = screen->getHeight() -
458
screen->getBevelWidth() - screen->getBorderWidth();
463
frame.x = (screen->getWidth() - frame.width) / 2;
465
frame.x_hidden = frame.x;
466
frame.y_hidden = screen->getBevelWidth() -
467
screen->getBorderWidth() - frame.height;
471
frame.x = (screen->getWidth() - frame.width) / 2;
472
frame.y = screen->getHeight() - frame.height - screen->getBorderWidth2x();
473
frame.x_hidden = frame.x;
474
frame.y_hidden = screen->getHeight() -
475
screen->getBevelWidth() - screen->getBorderWidth();
479
frame.x = screen->getWidth() - frame.width - screen->getBorderWidth2x();
481
if (screen->getSlitDirection() == VERTICAL) {
482
frame.x_hidden = screen->getWidth() -
483
screen->getBevelWidth() - screen->getBorderWidth();
486
frame.x_hidden = frame.x;
487
frame.y_hidden = screen->getBevelWidth() -
488
screen->getBorderWidth() - frame.height;
494
frame.x = screen->getWidth() - frame.width - screen->getBorderWidth2x();
495
frame.y = (screen->getHeight() - frame.height) / 2;
496
frame.x_hidden = screen->getWidth() -
497
screen->getBevelWidth() - screen->getBorderWidth();
498
frame.y_hidden = frame.y;
502
frame.x = screen->getWidth() - frame.width - screen->getBorderWidth2x();
503
frame.y = screen->getHeight() - frame.height - screen->getBorderWidth2x();
504
if (screen->getSlitDirection() == VERTICAL) {
505
frame.x_hidden = screen->getWidth() -
506
screen->getBevelWidth() - screen->getBorderWidth();
507
frame.y_hidden = frame.y;
509
frame.x_hidden = frame.x;
510
frame.y_hidden = screen->getHeight() -
511
screen->getBevelWidth() - screen->getBorderWidth();
516
Toolbar *tbar = screen->getToolbar();
517
int sw = frame.width + screen->getBorderWidth2x(),
518
sh = frame.height + screen->getBorderWidth2x(),
519
tw = tbar->getWidth() + screen->getBorderWidth(),
520
th = tbar->getHeight() + screen->getBorderWidth();
522
if (tbar->getX() < frame.x + sw && tbar->getX() + tw > frame.x &&
523
tbar->getY() < frame.y + sh && tbar->getY() + th > frame.y) {
525
frame.y += tbar->getExposedHeight();
526
if (screen->getSlitDirection() == VERTICAL)
527
frame.y_hidden += tbar->getExposedHeight();
529
frame.y_hidden = frame.y;
531
frame.y -= tbar->getExposedHeight();
532
if (screen->getSlitDirection() == VERTICAL)
533
frame.y_hidden -= tbar->getExposedHeight();
535
frame.y_hidden = frame.y;
540
XMoveResizeWindow(display, frame.window, frame.x_hidden,
541
frame.y_hidden, frame.width, frame.height);
543
XMoveResizeWindow(display, frame.window, frame.x,
544
frame.y, frame.width, frame.height);
548
void Slit::shutdown(void) {
549
while (clientList.size() != 0)
550
removeClient(clientList.front());
554
void Slit::buttonPressEvent(XButtonEvent *e) {
555
if (e->window != frame.window) return;
557
if (e->button == Button1 && (! on_top)) {
558
Window w[1] = { frame.window };
559
screen->raiseWindows(w, 1);
560
} else if (e->button == Button2 && (! on_top)) {
561
XLowerWindow(display, frame.window);
562
} else if (e->button == Button3) {
563
if (! slitmenu->isVisible()) {
566
x = e->x_root - (slitmenu->getWidth() / 2);
567
y = e->y_root - (slitmenu->getHeight() / 2);
571
else if (x + slitmenu->getWidth() > screen->getWidth())
572
x = screen->getWidth() - slitmenu->getWidth();
576
else if (y + slitmenu->getHeight() > screen->getHeight())
577
y = screen->getHeight() - slitmenu->getHeight();
579
slitmenu->move(x, y);
587
void Slit::enterNotifyEvent(XCrossingEvent *) {
592
if (! timer->isTiming()) timer->start();
594
if (timer->isTiming()) timer->stop();
599
void Slit::leaveNotifyEvent(XCrossingEvent *) {
604
if (timer->isTiming()) timer->stop();
605
} else if (! slitmenu->isVisible()) {
606
if (! timer->isTiming()) timer->start();
611
void Slit::configureRequestEvent(XConfigureRequestEvent *e) {
614
if (fluxbox->validateWindow(e->window)) {
620
xwc.width = e->width;
621
xwc.height = e->height;
622
xwc.border_width = 0;
623
xwc.sibling = e->above;
624
xwc.stack_mode = e->detail;
626
XConfigureWindow(display, e->window, e->value_mask, &xwc);
628
SlitClients::iterator it = clientList.begin();
629
SlitClients::iterator it_end = clientList.end();
630
for (; it != it_end; ++it)
631
if ((*it)->window == e->window)
632
if ((*it)->width != ((unsigned) e->width) ||
633
(*it)->height != ((unsigned) e->height)) {
634
(*it)->width = (unsigned) e->width;
635
(*it)->height = (unsigned) e->height;
642
if (reconf) reconfigure();
650
void Slit::timeout(void) {
653
XMoveWindow(display, frame.window, frame.x_hidden, frame.y_hidden);
655
XMoveWindow(display, frame.window, frame.x, frame.y);
659
Slitmenu::Slitmenu(Slit *sl) : Basemenu(sl->screen) {
661
I18n *i18n = I18n::instance();
663
setLabel(i18n->getMessage(
665
SlitSet, SlitSlitTitle,
672
directionmenu = new Directionmenu(this);
673
placementmenu = new Placementmenu(this);
675
insert(i18n->getMessage(
677
CommonSet, CommonDirectionTitle,
683
insert(i18n->getMessage(
685
CommonSet, CommonPlacementTitle,
691
insert(i18n->getMessage(
693
CommonSet, CommonAlwaysOnTop,
697
"Always on top"), 1);
698
insert(i18n->getMessage(
700
CommonSet, CommonAutoHide,
708
if (slit->isOnTop()) setItemSelected(2, True);
709
if (slit->doAutoHide()) setItemSelected(3, True);
713
Slitmenu::~Slitmenu(void) {
714
delete directionmenu;
715
delete placementmenu;
719
void Slitmenu::itemSelected(int button, int index) {
721
BasemenuItem *item = find(index);
724
switch (item->function()) {
725
case 1: // always on top
727
Bool change = ((slit->isOnTop()) ? False : True);
728
slit->on_top = change;
729
setItemSelected(2, change);
731
if (slit->isOnTop()) slit->screen->raiseWindows((Window *) 0, 0);
737
Bool change = ((slit->doAutoHide()) ? False : True);
738
slit->do_auto_hide = change;
739
setItemSelected(3, change);
748
void Slitmenu::internal_hide(void) {
749
Basemenu::internal_hide();
750
if (slit->doAutoHide())
755
void Slitmenu::reconfigure(void) {
756
directionmenu->reconfigure();
757
placementmenu->reconfigure();
759
Basemenu::reconfigure();
763
Slitmenu::Directionmenu::Directionmenu(Slitmenu *sm) : Basemenu(sm->slit->screen) {
765
I18n *i18n = I18n::instance();
767
setLabel(i18n->getMessage(
769
SlitSet, SlitSlitDirection,
776
insert(i18n->getMessage(
778
CommonSet, CommonDirectionHoriz,
784
insert(i18n->getMessage(
786
CommonSet, CommonDirectionVert,
795
if (sm->slit->screen->getSlitDirection() == Slit::HORIZONTAL)
796
setItemSelected(0, True);
798
setItemSelected(1, True);
802
void Slitmenu::Directionmenu::itemSelected(int button, int index) {
804
BasemenuItem *item = find(index);
807
slitmenu->slit->screen->saveSlitDirection(item->function());
809
if (item->function() == Slit::HORIZONTAL) {
810
setItemSelected(0, True);
811
setItemSelected(1, False);
813
setItemSelected(0, False);
814
setItemSelected(1, True);
818
slitmenu->slit->reconfigure();
823
Slitmenu::Placementmenu::Placementmenu(Slitmenu *sm) : Basemenu(sm->slit->screen) {
825
I18n *i18n = I18n::instance();
827
setLabel(i18n->getMessage(
829
SlitSet, SlitSlitPlacement,
834
setMinimumSublevels(3);
837
insert(i18n->getMessage(
839
CommonSet, CommonPlacementTopLeft,
845
insert(i18n->getMessage(
847
CommonSet, CommonPlacementCenterLeft,
853
insert(i18n->getMessage(
855
CommonSet, CommonPlacementBottomLeft,
861
insert(i18n->getMessage(
863
CommonSet, CommonPlacementTopCenter,
870
insert(i18n->getMessage(
872
CommonSet, CommonPlacementBottomCenter,
878
insert(i18n->getMessage(
880
CommonSet, CommonPlacementTopRight,
886
insert(i18n->getMessage(
888
CommonSet, CommonPlacementCenterRight,
894
insert(i18n->getMessage(
896
CommonSet, CommonPlacementBottomRight,
907
void Slitmenu::Placementmenu::itemSelected(int button, int index) {
909
BasemenuItem *item = find(index);
912
if (item->function()) {
913
slitmenu->slit->screen->saveSlitPlacement(item->function());
915
slitmenu->slit->reconfigure();