1
// Window.cc for Fluxbox Window Manager
2
// Copyright (c) 2001 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
4
// Window.cc for Blackbox - an X11 Window manager
5
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
7
// Permission is hereby granted, free of charge, to any person obtaining a
8
// copy of this software and associated documentation files (the "Software"),
9
// to deal in the Software without restriction, including without limitation
10
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
// and/or sell copies of the Software, and to permit persons to whom the
12
// Software is furnished to do so, subject to the following conditions:
14
// The above copyright notice and this permission notice shall be included in
15
// all copies or substantial portions of the Software.
17
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
// DEALINGS IN THE SOFTWARE.
25
// $Id: Window.cc 4102 2005-09-08 00:41:05Z simonb $
29
#include "WinClient.hh"
32
#include "FbWinFrameTheme.hh"
34
#include "RootTheme.hh"
35
#include "Workspace.hh"
36
#include "FbWinFrame.hh"
37
#include "WinButton.hh"
38
#include "WinButtonTheme.hh"
39
#include "WindowCmd.hh"
40
#include "Remember.hh"
41
#include "MenuCreator.hh"
42
#include "StringUtil.hh"
44
#include "FbTk/I18n.hh"
45
#include "FbTk/TextButton.hh"
46
#include "FbTk/Compose.hh"
47
#include "FbTk/EventManager.hh"
48
#include "FbTk/KeyUtil.hh"
49
#include "FbTk/SimpleCommand.hh"
50
#include "FbTk/Select2nd.hh"
54
#endif // HAVE_CONFIG_H
56
#include <X11/extensions/shape.h>
64
#include <X11/Xatom.h>
65
#include <X11/keysym.h>
91
void grabButton(unsigned int button,
92
Window window, Cursor cursor) {
94
static Display *display = App::instance()->display();
96
const int numlock = KeyUtil::instance().numlock();
97
const int capslock = KeyUtil::instance().capslock();
98
const int scrolllock = KeyUtil::instance().scrolllock();
100
// Grab with Mod1 and with all lock modifiers
101
// (num, scroll and caps)
104
XGrabButton(display, button, Mod1Mask|numlock, window, True,
105
ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
106
GrabModeAsync, None, cursor);
108
XGrabButton(display, button, Mod1Mask|scrolllock, window, True,
109
ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
110
GrabModeAsync, None, cursor);
113
XGrabButton(display, button, Mod1Mask|capslock, window, True,
114
ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
115
GrabModeAsync, None, cursor);
118
XGrabButton(display, Button1, Mod1Mask|capslock|numlock, window, True,
119
ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
120
GrabModeAsync, None, cursor);
122
//capslock+scrolllock
123
XGrabButton(display, button, Mod1Mask|capslock|scrolllock, window, True,
124
ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
125
GrabModeAsync, None, cursor);
127
//capslock+numlock+scrolllock
128
XGrabButton(display, button, Mod1Mask|capslock|numlock|scrolllock, window,
130
ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
131
GrabModeAsync, None, cursor);
134
XGrabButton(display, button, Mod1Mask|numlock|scrolllock, window, True,
135
ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
136
GrabModeAsync, None, cursor);
140
// X event scanner for enter/leave notifies - adapted from twm
141
typedef struct scanargs {
143
Bool leave, inferior, enter;
146
// look for valid enter or leave events (that may invalidate the earlier one we are interested in)
147
static Bool queueScanner(Display *, XEvent *e, char *args) {
148
if (e->type == LeaveNotify &&
149
e->xcrossing.window == ((scanargs *) args)->w &&
150
e->xcrossing.mode == NotifyNormal) {
151
((scanargs *) args)->leave = true;
152
((scanargs *) args)->inferior = (e->xcrossing.detail == NotifyInferior);
153
} else if (e->type == EnterNotify &&
154
e->xcrossing.mode == NotifyUngrab)
155
((scanargs *) args)->enter = true;
160
/// returns the deepest transientFor, asserting against a close loop
161
WinClient *getRootTransientFor(WinClient *client) {
162
while (client->transientFor()) {
163
assert(client != client->transientFor());
164
client = client->transientFor();
170
/// raise window and do the same for each transient of the current window
171
void raiseFluxboxWindow(FluxboxWindow &win) {
178
// we need to lock actual restacking so that raising above active transient
179
// won't do anything nasty
180
if (!win.winClient().transientList().empty())
181
win.screen().layerManager().lock();
183
if (!win.isIconic()) {
184
win.screen().updateNetizenWindowRaise(win.clientWindow());
185
win.layerItem().raise();
188
// for each transient do raise
190
WinClient::TransientList::const_iterator it = win.winClient().transientList().begin();
191
WinClient::TransientList::const_iterator it_end = win.winClient().transientList().end();
192
for (; it != it_end; ++it) {
193
if ((*it)->fbwindow() && !(*it)->fbwindow()->isIconic())
194
// TODO: should we also check if it is the active client?
195
raiseFluxboxWindow(*(*it)->fbwindow());
201
if (!win.winClient().transientList().empty())
202
win.screen().layerManager().unlock();
206
/// lower window and do the same for each transient it holds
207
void lowerFluxboxWindow(FluxboxWindow &win) {
213
// we need to lock actual restacking so that raising above active transient
214
// won't do anything nasty
215
if (!win.winClient().transientList().empty())
216
win.screen().layerManager().lock();
218
if (!win.isIconic()) {
219
win.screen().updateNetizenWindowLower(win.clientWindow());
220
win.layerItem().lower();
223
WinClient::TransientList::const_iterator it = win.winClient().transientList().begin();
224
WinClient::TransientList::const_iterator it_end = win.winClient().transientList().end();
225
for (; it != it_end; ++it) {
226
if ((*it)->fbwindow() && !(*it)->fbwindow()->isIconic())
227
// TODO: should we also check if it is the active client?
228
lowerFluxboxWindow(*(*it)->fbwindow());
231
if (!win.winClient().transientList().empty())
232
win.screen().layerManager().unlock();
236
/// raise window and do the same for each transient it holds
237
void tempRaiseFluxboxWindow(FluxboxWindow &win) {
238
if (win.oplock) return;
241
if (!win.winClient().transientList().empty())
242
win.screen().layerManager().lock();
244
if (!win.isIconic()) {
245
// don't update netizen, as it is only temporary
246
win.layerItem().tempRaise();
249
// for each transient do raise
250
WinClient::TransientList::const_iterator it = win.winClient().transientList().begin();
251
WinClient::TransientList::const_iterator it_end = win.winClient().transientList().end();
252
for (; it != it_end; ++it) {
253
if ((*it)->fbwindow() && !(*it)->fbwindow()->isIconic())
254
// TODO: should we also check if it is the active client?
255
tempRaiseFluxboxWindow(*(*it)->fbwindow());
259
if (!win.winClient().transientList().empty())
260
win.screen().layerManager().unlock();
264
class SetClientCmd:public FbTk::Command {
266
explicit SetClientCmd(WinClient &client):m_client(client) {
269
if (m_client.fbwindow() != 0)
270
m_client.fbwindow()->setCurrentClient(m_client);
279
int FluxboxWindow::s_num_grabs = 0;
281
FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm,
282
FbTk::XLayer &layer):
287
m_workspacesig(*this),
291
m_themelistener(*this),
292
moving(false), resizing(false), shaded(false),
293
iconic(false), focused(false),
294
stuck(false), m_initialized(false), fullscreen(false),
297
m_screen(client.screen()),
298
display(FbTk::App::instance()->display()),
299
m_button_grab_x(0), m_button_grab_y(0),
300
m_last_move_x(0), m_last_move_y(0),
301
m_last_resize_h(1), m_last_resize_w(1),
302
m_workspace_number(0),
304
m_old_decoration(DECOR_NORMAL),
305
m_old_decoration_mask(0),
307
m_toggled_decos(false),
309
m_icon_hidden(false),
310
m_old_pos_x(0), m_old_pos_y(0),
311
m_old_width(1), m_old_height(1),
312
m_last_button_x(0), m_last_button_y(0),
313
m_frame(tm, client.screen().imageControl(), 0, 0, 100, 100),
314
m_layeritem(m_frame.window(), layer),
315
m_layernum(layer.getLayerNum()),
317
m_parent(client.screen().rootWindow()),
318
m_resize_corner(RIGHTBOTTOM) {
320
tm.reconfigSig().attach(&m_themelistener);
326
FluxboxWindow::~FluxboxWindow() {
327
if (WindowCmd<void>::window() == this)
328
WindowCmd<void>::setWindow(0);
331
cerr<<__FILE__<<"("<<__LINE__<<"): starting ~FluxboxWindow("<<this<<", "<<title()<<")"<<endl;
332
cerr<<__FILE__<<"("<<__LINE__<<"): num clients = "<<numClients()<<endl;
333
cerr<<__FILE__<<"("<<__LINE__<<"): curr client = "<<m_client<<endl;
334
cerr<<__FILE__<<"("<<__LINE__<<"): m_labelbuttons.size = "<<m_labelbuttons.size()<<endl;
342
attachTo(0, 0, true);
344
// no longer a valid window to do stuff with
345
Fluxbox::instance()->removeWindowSearchGroup(frame().window().window());
347
Client2ButtonMap::iterator it = m_labelbuttons.begin();
348
Client2ButtonMap::iterator it_end = m_labelbuttons.end();
349
for (; it != it_end; ++it)
350
frame().removeTab((*it).second);
352
m_labelbuttons.clear();
360
delete m_client; // this also removes client from our list
363
if (m_clientlist.size() > 1) {
364
cerr<<__FILE__<<"(~FluxboxWindow()) WARNING! clientlist > 1"<<endl;
365
while (!m_clientlist.empty()) {
366
detachClient(*m_clientlist.back());
370
// deal with extra menus
372
cerr<<__FILE__<<"("<<__LINE__<<"): ~FluxboxWindow("<<this<<")"<<endl;
377
void FluxboxWindow::init() {
379
// magic to detect if moved by hints
383
m_client->setFluxboxWindow(this);
384
m_client->setGroupLeftWindow(None); // nothing to the left.
386
// check for shape extension and whether the window is shaped
389
if (Fluxbox::instance()->haveShape()) {
390
Shape::setShapeNotify(winClient());
391
m_shaped = Shape::isShaped(winClient());
394
frame().setUseShape(!m_shaped);
396
//!! TODO init of client should be better
397
// we don't want to duplicate code here and in attachClient
398
m_clientlist.push_back(m_client);
400
cerr<<__FILE__<<": FluxboxWindow::init(this="<<this<<", client="<<hex<<
401
m_client->window()<<", frame = "<<frame().window().window()<<dec<<")"<<endl;
405
Fluxbox &fluxbox = *Fluxbox::instance();
407
// setup cursors for resize grips
408
frame().gripLeft().setCursor(frame().theme().lowerLeftAngleCursor());
409
frame().gripRight().setCursor(frame().theme().lowerRightAngleCursor());
411
associateClient(*m_client);
413
frame().setLabelButtonFocus(*m_labelbuttons[m_client]);
415
// redirect events from frame to us
416
frame().setEventHandler(*this);
418
frame().resize(m_client->width(), m_client->height());
420
m_last_focus_time.tv_sec = m_last_focus_time.tv_usec = 0;
422
m_blackbox_attrib.workspace = m_workspace_number = ~0;
424
m_blackbox_attrib.flags = m_blackbox_attrib.attrib = m_blackbox_attrib.stack = 0;
425
m_blackbox_attrib.premax_x = m_blackbox_attrib.premax_y = 0;
426
m_blackbox_attrib.premax_w = m_blackbox_attrib.premax_h = 0;
429
decorations.tab = true;
430
// enable decorations
431
decorations.enabled = true;
433
// set default values for decoration
434
decorations.menu = true; //override menu option
435
// all decorations on by default
436
decorations.titlebar = decorations.border = decorations.handle = true;
437
decorations.maximize = decorations.close =
438
decorations.sticky = decorations.shade = decorations.tab = true;
441
functions.resize = functions.move = functions.iconify = functions.maximize = functions.tabable = true;
442
decorations.close = false;
444
if (m_client->getBlackboxHint() != 0)
445
updateBlackboxHintsFromClient(*m_client);
447
updateMWMHintsFromClient(*m_client);
450
// fetch client size and placement
451
XWindowAttributes wattrib;
452
if (! m_client->getAttrib(wattrib) ||
453
!wattrib.screen || // no screen? ??
454
wattrib.override_redirect || // override redirect
455
m_client->initial_state == WithdrawnState) // Slit client
458
// save old border width so we can restore it later
459
m_client->old_bw = wattrib.border_width;
460
m_client->x = wattrib.x; m_client->y = wattrib.y;
462
m_timer.setTimeout(fluxbox.getAutoRaiseDelay());
463
FbTk::RefCount<FbTk::Command> raise_cmd(new FbTk::SimpleCommand<FluxboxWindow>(*this,
464
&FluxboxWindow::raise));
465
m_timer.setCommand(raise_cmd);
466
m_timer.fireOnce(true);
468
Fluxbox::instance()->saveWindowSearchGroup(frame().window().window(), this);
470
/**************************************************/
471
/* Read state above here, apply state below here. */
472
/**************************************************/
474
// update transient infomation
475
m_client->updateTransientInfo();
477
// adjust the window decorations based on transience and window sizes
478
if (m_client->isTransient() && !screen().decorateTransient()) {
479
decorations.maximize = functions.maximize = false;
480
decorations.handle = false;
483
if ((m_client->normal_hint_flags & PMinSize) &&
484
(m_client->normal_hint_flags & PMaxSize) &&
485
m_client->max_width != 0 && m_client->max_width <= m_client->min_width &&
486
m_client->max_height != 0 && m_client->max_height <= m_client->min_height) {
487
decorations.maximize = decorations.handle =
488
functions.resize = functions.maximize = false;
489
decorations.tab = false; //no tab for this window
492
associateClientWindow(true, wattrib.x, wattrib.y, wattrib.width, wattrib.height);
495
Fluxbox::instance()->attachSignals(*this);
497
// this window is managed, we are now allowed to modify actual state
498
m_initialized = true;
501
applyDecorations(true);
507
if (m_workspace_number < 0 || m_workspace_number >= screen().numberOfWorkspaces())
508
m_workspace_number = screen().currentWorkspaceID();
510
bool place_window = (m_old_pos_x == 0);
511
if (fluxbox.isStartup() || m_client->isTransient() ||
512
m_client->normal_hint_flags & (PPosition|USPosition)) {
514
frame().gravityTranslate(wattrib.x, wattrib.y, m_client->gravity(), false);
516
if (! fluxbox.isStartup()) {
518
int real_x = frame().x();
519
int real_y = frame().y();
522
real_y + frame().y() >= 0 &&
523
real_x <= (signed) screen().width() &&
524
real_y <= (signed) screen().height())
525
place_window = false;
528
place_window = false;
531
if (wattrib.width <= 0)
533
if (wattrib.height <= 0)
538
// if we're a transient then we should be on the same layer as our parent
539
if (m_client->isTransient() &&
540
m_client->transientFor()->fbwindow() &&
541
m_client->transientFor()->fbwindow() != this)
542
layerItem().setLayer(m_client->transientFor()->fbwindow()->layerItem().getLayer());
543
else // if no parent then set default layer
544
moveToLayer(m_layernum);
546
cerr<<"FluxboxWindow::init("<<title()<<") transientFor: "<<
547
m_client->transientFor()<<endl;
548
if (m_client->transientFor() && m_client->transientFor()->fbwindow()) {
549
cerr<<"FluxboxWindow::init("<<title()<<") transientFor->title(): "<<
550
m_client->transientFor()->fbwindow()->title()<<endl;
556
moveResize(frame().x(), frame().y(), frame().width(), frame().height());
558
screen().getWorkspace(m_workspace_number)->addWindow(*this, place_window);
559
setWorkspace(m_workspace_number);
561
if (maximized && functions.maximize) { // start maximized
562
// This will set it to the appropriate style of maximisation
563
int req_maximized = maximized;
564
// NOTE: don't manually change maximized ANYWHERE else, it isn't safe
565
maximized = MAX_NONE; // it is not maximized now
566
maximize(req_maximized);
572
deiconify(); //we're omnipresent and visible
575
if (shaded) { // start shaded
585
sendConfigureNotify();
594
FbTk::App::instance()->sync(false);
598
/// apply shape to this window
599
void FluxboxWindow::shape() {
602
XShapeCombineShape(display,
603
frame().window().window(), ShapeBounding,
604
0, frame().clientArea().y(), // xOff, yOff
606
ShapeBounding, ShapeSet);
614
/// attach a client to this window and destroy old window
615
void FluxboxWindow::attachClient(WinClient &client, int x, int y) {
616
//!! TODO: check for isGroupable in client
617
if (client.fbwindow() == this)
622
// reparent client win to this frame
623
frame().setClientWindow(client);
624
FbTk::EventManager &evm = *FbTk::EventManager::instance();
625
WinClient *was_focused = 0;
626
WinClient *focused_win = Fluxbox::instance()->getFocusedWindow();
628
// get the current window on the end of our client list
629
Window leftwin = None;
630
if (!clientList().empty())
631
leftwin = clientList().back()->window();
633
client.setGroupLeftWindow(leftwin);
635
if (client.fbwindow() != 0) {
636
FluxboxWindow *old_win = client.fbwindow(); // store old window
638
ClientList::iterator client_insert_pos = getClientInsertPosition(x, y);
639
FbTk::TextButton *button_insert_pos = NULL;
640
if (client_insert_pos != m_clientlist.end())
641
button_insert_pos = m_labelbuttons[*client_insert_pos];
643
// make sure we set new window search for each client
644
ClientList::iterator client_it = old_win->clientList().begin();
645
ClientList::iterator client_it_end = old_win->clientList().end();
646
for (; client_it != client_it_end; ++client_it) {
647
// reparent window to this
648
frame().setClientWindow(**client_it);
649
if ((*client_it) == focused_win)
650
was_focused = focused_win;
652
moveResizeClient(**client_it,
653
frame().clientArea().x(),
654
frame().clientArea().y(),
655
frame().clientArea().width(),
656
frame().clientArea().height());
658
// create a labelbutton for this client and
659
// associate it with the pointer
660
associateClient(*(*client_it));
662
//null if we want the new button at the end of the list
663
if (x >= 0 && button_insert_pos)
664
frame().moveLabelButtonLeftOf(*m_labelbuttons[*client_it], *button_insert_pos);
666
(*client_it)->saveBlackboxAttribs(m_blackbox_attrib);
669
// add client and move over all attached clients
670
// from the old window to this list
671
m_clientlist.splice(client_insert_pos, old_win->m_clientlist);
672
updateClientLeftWindow();
673
old_win->m_client = 0;
677
} else { // client.fbwindow() == 0
678
associateClient(client);
680
if (&client == focused_win)
681
was_focused = focused_win;
683
client.saveBlackboxAttribs(m_blackbox_attrib);
684
m_clientlist.push_back(&client);
687
// make sure that the state etc etc is updated for the new client
688
// TODO: one day these should probably be neatened to only act on the
689
// affected clients if possible
691
m_workspacesig.notify();
694
if (was_focused != 0) {
695
// already has focus, we're just assuming the state of the old window
696
setCurrentClient(*was_focused, false);
697
frame().setFocus(true);
700
frame().reconfigure();
702
// keep the current window on top
707
/// detach client from window and create a new window for it
708
bool FluxboxWindow::detachClient(WinClient &client) {
709
if (client.fbwindow() != this || numClients() <= 1)
712
// I'm not sure how to do this bit better
713
// we need to find the window we've got, and update the
714
// window to its right to have a left window set to the
715
// window which is to the left of the current.
716
// Think in terms of:
717
// window1 <- my_window <- window2
718
// we need to take out my_window, so update window2 leftwin to be window1
720
Window leftwin = None;
721
ClientList::iterator client_it_end = clientList().end();
722
ClientList::iterator client_it = clientList().begin();
723
ClientList::iterator client_it_before = client_it_end;
724
ClientList::iterator client_it_after = clientList().begin();
725
if (!clientList().empty()) {
727
if (clientList().front() == &client) {
731
client_it_before = clientList().begin();
734
while (client_it != client_it_end) {
735
if (*client_it == &client) {
745
// update the leftwin of the window to the right
746
if (client_it_before != client_it_end)
747
leftwin = (*client_it_before)->window();
749
if (client_it_after != client_it_end)
750
(*client_it_after)->setGroupLeftWindow(leftwin);
752
removeClient(client);
754
// m_client must be valid as there should be at least one other window
755
// otherwise this wouldn't be here (refer numClients() <= 1 return)
756
client.setFluxboxWindow(screen().createWindow(client));
762
void FluxboxWindow::detachCurrentClient() {
763
// should only operate if we had more than one client
764
if (numClients() <= 1)
766
detachClient(*m_client);
769
/// removes client from client list, does not create new fluxboxwindow for it
770
bool FluxboxWindow::removeClient(WinClient &client) {
771
if (client.fbwindow() != this || numClients() == 0)
775
cerr<<__FILE__<<"("<<__FUNCTION__<<")["<<this<<"]"<<endl;
778
// if it is our active client, deal with it...
779
if (m_client == &client) {
780
WinClient *next_client = screen().getLastFocusedWindow(*this, m_client);
781
if (next_client != 0)
782
setCurrentClient(*next_client, false);
787
m_clientlist.remove(&client);
789
if (m_client == &client) {
790
if (m_clientlist.empty())
793
// this really shouldn't happen
794
m_client = m_clientlist.back();
797
FbTk::EventManager &evm = *FbTk::EventManager::instance();
798
evm.remove(client.window());
800
FbTk::TextButton *label_btn = m_labelbuttons[&client];
801
if (label_btn != 0) {
802
frame().removeTab(label_btn);
806
m_labelbuttons.erase(&client);
807
frame().reconfigure();
808
updateClientLeftWindow();
811
cerr<<__FILE__<<"("<<__FUNCTION__<<")["<<this<<"] numClients = "<<numClients()<<endl;
817
/// returns WinClient of window we're searching for
818
WinClient *FluxboxWindow::findClient(Window win) {
819
ClientList::iterator it = find_if(clientList().begin(),
821
Compose(bind2nd(equal_to<Window>(), win),
822
mem_fun(&WinClient::window)));
823
return (it == clientList().end() ? 0 : *it);
826
/// raise and focus next client
827
void FluxboxWindow::nextClient() {
828
if (numClients() <= 1)
831
ClientList::iterator it = find(m_clientlist.begin(), m_clientlist.end(), m_client);
832
WinClient *client = 0;
833
if (it == m_clientlist.end()) {
834
client = m_clientlist.front();
837
if (it == m_clientlist.end())
838
client = m_clientlist.front();
842
setCurrentClient(*client, true);
845
void FluxboxWindow::prevClient() {
846
if (numClients() <= 1)
849
ClientList::iterator it = find(m_clientlist.begin(), m_clientlist.end(), m_client);
850
WinClient *client = 0;
851
if (it == m_clientlist.end()) {
852
client = m_clientlist.front();
854
if (it == m_clientlist.begin())
855
client = m_clientlist.back();
860
setCurrentClient(*client, true);
864
void FluxboxWindow::moveClientLeft() {
865
if (m_clientlist.size() == 1 ||
866
*m_clientlist.begin() == &winClient())
869
// move client in clientlist to the left
870
ClientList::iterator oldpos = find(m_clientlist.begin(), m_clientlist.end(), &winClient());
871
ClientList::iterator newpos = oldpos; newpos--;
872
std::swap(*newpos, *oldpos);
873
frame().moveLabelButtonLeft(*m_labelbuttons[&winClient()]);
875
updateClientLeftWindow();
879
void FluxboxWindow::moveClientRight() {
880
if (m_clientlist.size() == 1 ||
881
*m_clientlist.rbegin() == &winClient())
884
ClientList::iterator oldpos = find(m_clientlist.begin(), m_clientlist.end(), &winClient());
885
ClientList::iterator newpos = oldpos; newpos++;
886
std::swap(*newpos, *oldpos);
887
frame().moveLabelButtonRight(*m_labelbuttons[&winClient()]);
889
updateClientLeftWindow();
892
//std::list<*WinClient>::iterator FluxboxWindow::getClientInsertPosition(int x, int y) {
893
FluxboxWindow::ClientList::iterator FluxboxWindow::getClientInsertPosition(int x, int y) {
895
int dest_x = 0, dest_y = 0;
896
Window labelbutton = 0;
897
if (!XTranslateCoordinates(FbTk::App::instance()->display(),
898
parent().window(), frame().label().window(),
899
x, y, &dest_x, &dest_y,
901
return m_clientlist.end();
903
Client2ButtonMap::iterator it =
904
find_if(m_labelbuttons.begin(),
905
m_labelbuttons.end(),
906
Compose(bind2nd(equal_to<Window>(), labelbutton),
907
Compose(mem_fun(&TextButton::window),
908
Select2nd<Client2ButtonMap::value_type>())));
911
// label button not found
912
if (it == m_labelbuttons.end())
913
return m_clientlist.end();
915
Window child_return=0;
916
// make x and y relative to our labelbutton
917
if (!XTranslateCoordinates(FbTk::App::instance()->display(),
918
frame().label().window(), labelbutton,
919
dest_x, dest_y, &x, &y,
921
return m_clientlist.end();
923
ClientList::iterator client = find(m_clientlist.begin(),
926
if (x > (*it).second->width() / 2)
935
void FluxboxWindow::moveClientTo(WinClient &win, int x, int y) {
936
int dest_x = 0, dest_y = 0;
937
Window labelbutton = 0;
938
if (!XTranslateCoordinates(FbTk::App::instance()->display(),
939
parent().window(), frame().label().window(),
940
x, y, &dest_x, &dest_y,
944
Client2ButtonMap::iterator it =
945
find_if(m_labelbuttons.begin(),
946
m_labelbuttons.end(),
947
Compose(bind2nd(equal_to<Window>(), labelbutton),
948
Compose(mem_fun(&TextButton::window),
949
Select2nd<Client2ButtonMap::value_type>())));
951
// label button not found
952
if (it == m_labelbuttons.end())
955
Window child_return = 0;
956
//make x and y relative to our labelbutton
957
if (!XTranslateCoordinates(FbTk::App::instance()->display(),
958
frame().label().window(), labelbutton,
959
dest_x, dest_y, &x, &y,
962
if (x > (*it).second->width() / 2)
963
moveClientRightOf(win, *it->first);
965
moveClientLeftOf(win, *it->first);
970
void FluxboxWindow::moveClientLeftOf(WinClient &win, WinClient &dest) {
972
frame().moveLabelButtonLeftOf(*m_labelbuttons[&win], *m_labelbuttons[&dest]);
974
ClientList::iterator it = find(m_clientlist.begin(),
977
ClientList::iterator new_pos = find(m_clientlist.begin(),
981
// make sure we found them
982
if (it == m_clientlist.end() || new_pos==m_clientlist.end()) {
985
//moving a button to the left of itself results in no change
990
m_clientlist.erase(it);
991
//insert on the new place
992
m_clientlist.insert(new_pos, &win);
994
updateClientLeftWindow();
998
void FluxboxWindow::moveClientRightOf(WinClient &win, WinClient &dest) {
999
frame().moveLabelButtonRightOf(*m_labelbuttons[&win], *m_labelbuttons[&dest]);
1001
ClientList::iterator it = find(m_clientlist.begin(),
1004
ClientList::iterator new_pos = find(m_clientlist.begin(),
1008
// make sure we found them
1009
if (it == m_clientlist.end() || new_pos==m_clientlist.end()) {
1012
//moving a button to the right of itself results in no change
1013
if( new_pos == it) {
1017
m_clientlist.erase(it);
1018
//need to insert into the next position
1020
//insert on the new place
1021
if(new_pos == m_clientlist.end())
1022
m_clientlist.push_back(&win);
1024
m_clientlist.insert(new_pos, &win);
1026
updateClientLeftWindow();
1029
/// Update LEFT window atom on all clients.
1030
void FluxboxWindow::updateClientLeftWindow() {
1031
if (clientList().empty())
1034
// It should just update the affected clients but that
1035
// would require more complex code and we're assuming
1036
// the user dont have alot of windows grouped so this
1037
// wouldn't be too time consuming and it's easier to
1039
ClientList::iterator it = clientList().begin();
1040
ClientList::iterator it_end = clientList().end();
1041
// set no left window on first tab
1042
(*it)->setGroupLeftWindow(0);
1043
WinClient *last_client = *it;
1045
for (; it != it_end; ++it) {
1046
(*it)->setGroupLeftWindow(last_client->window());
1051
bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
1052
// make sure it's in our list
1053
if (client.fbwindow() != this)
1058
titleSig().notify();
1061
cerr<<"FluxboxWindow::"<<__FUNCTION__<<": labelbutton[client] = "<<
1062
m_labelbuttons[m_client]<<endl;
1064
// frame focused doesn't necessarily mean input focused
1065
frame().setLabelButtonFocus(*m_labelbuttons[m_client]);
1067
if (setinput && setInputFocus()) {
1074
bool FluxboxWindow::isGroupable() const {
1075
if (isResizable() && isMaximizable() && !winClient().isTransient())
1080
void FluxboxWindow::associateClientWindow(bool use_attrs,
1082
unsigned int width, unsigned int height) {
1083
m_client->setBorderWidth(0);
1084
updateTitleFromClient(*m_client);
1085
updateIconNameFromClient(*m_client);
1088
frame().moveResizeForClient(x, y,
1091
frame().resizeForClient(m_client->width(), m_client->height());
1093
frame().setClientWindow(*m_client);
1097
void FluxboxWindow::grabButtons() {
1099
// needed for click to focus
1100
XGrabButton(display, Button1, AnyModifier,
1101
frame().window().window(), True, ButtonPressMask,
1102
GrabModeSync, GrabModeSync, None, None);
1103
XUngrabButton(display, Button1, Mod1Mask|Mod2Mask|Mod3Mask, frame().window().window());
1105
if (Fluxbox::instance()->useMod1()) {
1106
XGrabButton(display, Button1, Mod1Mask, frame().window().window(), True,
1107
ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
1108
GrabModeAsync, None, frame().theme().moveCursor());
1110
//----grab with "all" modifiers
1111
grabButton(Button1, frame().window().window(), frame().theme().moveCursor());
1113
XGrabButton(display, Button2, Mod1Mask, frame().window().window(), True,
1114
ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None);
1116
XGrabButton(display, Button3, Mod1Mask, frame().window().window(), True,
1117
ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
1118
GrabModeAsync, None, None);
1120
//---grab with "all" modifiers
1121
grabButton(Button3, frame().window().window(), None);
1126
void FluxboxWindow::reconfigure() {
1130
setFocusFlag(focused);
1132
moveResize(frame().x(), frame().y(), frame().width(), frame().height());
1136
frame().setDoubleClickTime(Fluxbox::instance()->getDoubleClickInterval());
1138
frame().reconfigure();
1140
menu().reconfigure();
1144
/// update current client title and title in our frame
1145
void FluxboxWindow::updateTitleFromClient(WinClient &client) {
1146
client.updateTitle();
1147
// compare old title with new and see if we need to update
1149
if (m_labelbuttons[&client]->text() != client.title())
1150
m_labelbuttons[&client]->setText(client.title());
1153
/// update icon title from client
1154
void FluxboxWindow::updateIconNameFromClient(WinClient &client) {
1155
client.updateIconTitle();
1158
void FluxboxWindow::updateMWMHintsFromClient(WinClient &client) {
1159
const WinClient::MwmHints *hint = client.getMwmHint();
1163
if (!m_toggled_decos && hint->flags & MwmHintsDecorations) {
1164
if (hint->decorations & MwmDecorAll) {
1165
decorations.titlebar = decorations.handle = decorations.border =
1166
decorations.iconify = decorations.maximize =
1167
decorations.close = decorations.menu = true;
1169
decorations.titlebar = decorations.handle = decorations.border =
1170
decorations.iconify = decorations.maximize =
1171
decorations.close = decorations.tab = false;
1172
decorations.menu = true;
1173
if (hint->decorations & MwmDecorBorder)
1174
decorations.border = true;
1175
if (hint->decorations & MwmDecorHandle)
1176
decorations.handle = true;
1177
if (hint->decorations & MwmDecorTitle) {
1178
//only tab on windows with titlebar
1179
decorations.titlebar = decorations.tab = true;
1181
if (hint->decorations & MwmDecorMenu)
1182
decorations.menu = true;
1183
if (hint->decorations & MwmDecorIconify)
1184
decorations.iconify = true;
1185
if (hint->decorations & MwmDecorMaximize)
1186
decorations.maximize = true;
1190
// functions.tabable is ours, not special one
1191
// note that it means this window is "tabbable"
1192
if (hint->flags & MwmHintsFunctions) {
1193
if (hint->functions & MwmFuncAll) {
1194
functions.resize = functions.move = functions.iconify =
1195
functions.maximize = functions.close = true;
1197
functions.resize = functions.move = functions.iconify =
1198
functions.maximize = functions.close = false;
1200
if (hint->functions & MwmFuncResize)
1201
functions.resize = true;
1202
if (hint->functions & MwmFuncMove)
1203
functions.move = true;
1204
if (hint->functions & MwmFuncIconify)
1205
functions.iconify = true;
1206
if (hint->functions & MwmFuncMaximize)
1207
functions.maximize = true;
1208
if (hint->functions & MwmFuncClose)
1209
functions.close = true;
1214
void FluxboxWindow::updateRememberStateFromClient(WinClient &client) {
1216
Remember* rem= const_cast<Remember*>(static_cast<const Remember*>(Fluxbox::instance()->getAtomHandler("remember")));
1217
Application* app= 0;
1218
if ( rem && (app= (const_cast<Remember*>(rem))->find(client)) ) {
1219
if ( !m_toggled_decos && rem->isRemembered(client, Remember::REM_DECOSTATE) )
1220
setDecorationMask(app->decostate);
1225
void FluxboxWindow::updateFunctions() {
1228
bool changed = false;
1229
if (m_client->isClosable() != functions.close) {
1230
functions.close = m_client->isClosable();
1238
void FluxboxWindow::updateBlackboxHintsFromClient(const WinClient &client) {
1239
const FluxboxWindow::BlackboxHints *hint = client.getBlackboxHint();
1242
if (hint->flags & ATTRIB_SHADED)
1243
shaded = (hint->attrib & ATTRIB_SHADED);
1245
if (hint->flags & ATTRIB_HIDDEN)
1246
iconic = (hint->attrib & ATTRIB_HIDDEN);
1248
if ((hint->flags & ATTRIB_MAXHORIZ) &&
1249
(hint->flags & ATTRIB_MAXVERT))
1250
maximized = ((hint->attrib &
1252
ATTRIB_MAXVERT)) ? MAX_FULL : MAX_NONE);
1253
else if (hint->flags & ATTRIB_MAXVERT)
1254
maximized = ((hint->attrib &
1255
ATTRIB_MAXVERT) ? MAX_VERT : MAX_NONE);
1256
else if (hint->flags & ATTRIB_MAXHORIZ)
1257
maximized = ((hint->attrib &
1258
ATTRIB_MAXHORIZ) ? MAX_HORZ : MAX_NONE);
1260
if (hint->flags & ATTRIB_OMNIPRESENT)
1261
stuck = (hint->attrib & ATTRIB_OMNIPRESENT);
1263
if (hint->flags & ATTRIB_WORKSPACE)
1264
m_workspace_number = hint->workspace;
1266
if (hint->flags & ATTRIB_STACK)
1267
m_workspace_number = hint->stack;
1269
if (hint->flags & ATTRIB_DECORATION) {
1270
m_old_decoration = static_cast<Decoration>(hint->decoration);
1271
setDecoration(m_old_decoration, false);
1275
void FluxboxWindow::move(int x, int y, int gravity) {
1276
moveResize(x, y, frame().width(), frame().height(), gravity);
1279
void FluxboxWindow::resize(unsigned int width, unsigned int height) {
1280
moveResize(frame().x(), frame().y(), width, height);
1283
// send_event is just an override
1284
void FluxboxWindow::moveResize(int new_x, int new_y,
1285
unsigned int new_width, unsigned int new_height, int gravity, bool send_event) {
1287
// magic to detect if moved during initialisation
1288
if (!isInitialized())
1291
if (gravity != ForgetGravity) {
1292
frame().gravityTranslate(new_x, new_y, gravity, false);
1295
send_event = send_event || (frame().x() != new_x || frame().y() != new_y);
1297
if (new_width != frame().width() || new_height != frame().height()) {
1298
if ((((signed) frame().width()) + new_x) < 0)
1300
if ((((signed) frame().height()) + new_y) < 0)
1303
if (!isResizable()) {
1304
new_width = width();
1305
new_height = height();
1308
frame().moveResize(new_x, new_y, new_width, new_height);
1309
setFocusFlag(focused);
1313
} else if (send_event)
1314
frame().move(new_x, new_y);
1316
if (send_event && ! moving) {
1317
sendConfigureNotify();
1323
m_last_resize_x = new_x;
1324
m_last_resize_y = new_y;
1329
void FluxboxWindow::moveResizeForClient(int new_x, int new_y,
1330
unsigned int new_width, unsigned int new_height, int gravity) {
1332
// magic to detect if moved during initialisation
1333
if (!isInitialized())
1335
frame().moveResizeForClient(new_x, new_y, new_width, new_height, true, true, gravity);
1336
setFocusFlag(focused);
1338
sendConfigureNotify();
1343
m_last_resize_x = new_x;
1344
m_last_resize_y = new_y;
1352
// returns whether the focus was "set" to this window
1353
// it doesn't guarantee that it has focus, but says that we have
1354
// tried. A FocusqIn event should eventually arrive for that
1355
// window if it actually got the focus, then setFocusedFlag is called,
1356
// which updates all the graphics etc
1357
bool FluxboxWindow::setInputFocus() {
1359
if (((signed) (frame().x() + frame().width())) < 0) {
1360
if (((signed) (frame().y() + frame().height())) < 0) {
1361
moveResize(frame().window().borderWidth(), frame().window().borderWidth(),
1362
frame().width(), frame().height());
1363
} else if (frame().y() > (signed) screen().height()) {
1364
moveResize(frame().window().borderWidth(), screen().height() - frame().height(),
1365
frame().width(), frame().height());
1367
moveResize(frame().window().borderWidth(), frame().y() + frame().window().borderWidth(),
1368
frame().width(), frame().height());
1370
} else if (frame().x() > (signed) screen().width()) {
1371
if (((signed) (frame().y() + frame().height())) < 0) {
1372
moveResize(screen().width() - frame().width(), frame().window().borderWidth(),
1373
frame().width(), frame().height());
1374
} else if (frame().y() > (signed) screen().height()) {
1375
moveResize(screen().width() - frame().width(),
1376
screen().height() - frame().height(),
1377
frame().width(), frame().height());
1379
moveResize(screen().width() - frame().width(),
1380
frame().y() + frame().window().borderWidth(),
1381
frame().width(), frame().height());
1385
if (! m_client->validateClient())
1388
cerr<<"FluxboxWindow::"<<__FUNCTION__<<" isModal() = "<<m_client->isModal()<<endl;
1389
cerr<<"FluxboxWindow::"<<__FUNCTION__<<" transient size = "<<m_client->transients.size()<<endl;
1391
if (!m_client->transients.empty() && m_client->isModal()) {
1393
cerr<<__FUNCTION__<<": isModal and have transients client = "<<
1394
hex<<m_client->window()<<dec<<endl;
1395
cerr<<__FUNCTION__<<": this = "<<this<<endl;
1398
WinClient::TransientList::iterator it = m_client->transients.begin();
1399
WinClient::TransientList::iterator it_end = m_client->transients.end();
1400
for (; it != it_end; ++it) {
1402
cerr<<__FUNCTION__<<": transient 0x"<<(*it)<<endl;
1404
if ((*it)->isModal())
1405
return (*it)->fbwindow()->setCurrentClient(**it, true);
1411
if (m_client->getFocusMode() == WinClient::F_LOCALLYACTIVE ||
1412
m_client->getFocusMode() == WinClient::F_PASSIVE) {
1414
m_client->setInputFocus(RevertToPointerRoot, CurrentTime);
1416
FbTk::App *app = FbTk::App::instance();
1418
XFlush(app->display());
1420
m_client->sendFocus();
1426
ret = m_client->sendFocus();
1432
// don't hide the frame directly, use this function
1433
void FluxboxWindow::hide(bool interrupt_moving) {
1435
cerr<<__FILE__<<"("<<__FUNCTION__<<")["<<this<<"]"<<endl;
1437
// resizing always stops on hides
1441
if (interrupt_moving) {
1444
if (m_attaching_tab)
1445
attachTo(0, 0, true);
1452
void FluxboxWindow::show() {
1457
Unmaps the window and removes it from workspace list
1459
void FluxboxWindow::iconify() {
1460
if (isIconic()) // no need to iconify if we're already
1463
m_blackbox_attrib.flags |= ATTRIB_HIDDEN;
1464
m_blackbox_attrib.attrib |= ATTRIB_HIDDEN;
1468
setState(IconicState, false);
1472
ClientList::iterator client_it = m_clientlist.begin();
1473
const ClientList::iterator client_it_end = m_clientlist.end();
1474
for (; client_it != client_it_end; ++client_it) {
1475
WinClient &client = *(*client_it);
1476
client.setEventMask(NoEventMask);
1478
client.setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask);
1479
if (client.transientFor() &&
1480
client.transientFor()->fbwindow()) {
1481
if (!client.transientFor()->fbwindow()->isIconic()) {
1482
client.transientFor()->fbwindow()->iconify();
1486
if (!client.transientList().empty()) {
1487
WinClient::TransientList::iterator it = client.transientList().begin();
1488
WinClient::TransientList::iterator it_end = client.transientList().end();
1489
for (; it != it_end; it++)
1490
if ((*it)->fbwindow())
1491
(*it)->fbwindow()->iconify();
1495
// focus revert is done elsewhere (based on signal)
1498
void FluxboxWindow::deiconify(bool reassoc, bool do_raise) {
1499
if (numClients() == 0)
1505
if (iconic || reassoc) {
1506
screen().reassociateWindow(this, screen().currentWorkspace()->workspaceID(), false);
1507
} else if (moving || m_workspace_number != screen().currentWorkspace()->workspaceID()) {
1512
bool was_iconic = iconic;
1514
m_blackbox_attrib.flags &= ~ATTRIB_HIDDEN;
1517
setState(NormalState, false);
1519
ClientList::iterator client_it = clientList().begin();
1520
ClientList::iterator client_it_end = clientList().end();
1521
for (; client_it != client_it_end; ++client_it) {
1522
(*client_it)->setEventMask(NoEventMask);
1523
(*client_it)->show();
1524
(*client_it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask);
1527
if (reassoc && !m_client->transients.empty()) {
1528
// deiconify all transients
1529
client_it = clientList().begin();
1530
for (; client_it != client_it_end; ++client_it) {
1531
//TODO: Can this get stuck in a loop?
1532
WinClient::TransientList::iterator trans_it =
1533
(*client_it)->transientList().begin();
1534
WinClient::TransientList::iterator trans_it_end =
1535
(*client_it)->transientList().end();
1536
for (; trans_it != trans_it_end; ++trans_it) {
1537
if ((*trans_it)->fbwindow())
1538
(*trans_it)->fbwindow()->deiconify(true, false);
1545
if (was_iconic && screen().doFocusNew())
1556
Set window in withdrawn state
1558
void FluxboxWindow::withdraw(bool interrupt_moving) {
1560
cerr<<"FluxboxWindow::"<<__FUNCTION__<<": this = "<<this<<endl;
1564
hide(interrupt_moving);
1567
/** setFullscreen mode:
1569
- maximize as big as the screen is, dont care about slit / toolbar
1572
void FluxboxWindow::setFullscreen(bool flag) {
1574
const int head = screen().getHead(fbWindow());
1575
Fluxbox* fb = Fluxbox::instance();
1577
if (flag && !isFullscreen()) {
1585
frame().setUseShape(false);
1587
m_old_decoration_mask = decorationMask();
1588
m_old_layernum =layerNum();
1589
m_old_pos_x = frame().x();
1590
m_old_pos_y = frame().y();
1591
m_old_width = frame().width();
1592
m_old_height = frame().height();
1594
// clear decorations
1595
setDecorationMask(0);
1597
// be xinerama aware
1598
moveResize(screen().getHeadX(head), screen().getHeadY(head),
1599
screen().getHeadWidth(head), screen().getHeadHeight(head));
1600
moveToLayer(Fluxbox::instance()->getAboveDockLayer());
1604
stateSig().notify();
1606
} else if (!flag && isFullscreen()) {
1610
setDecorationMask(m_old_decoration_mask);
1611
frame().setUseShape(!m_shaped);
1613
moveResize(m_old_pos_x, m_old_pos_y, m_old_width, m_old_height);
1614
moveToLayer(m_old_layernum);
1616
m_old_decoration_mask = 0;
1617
m_old_layernum = Fluxbox::instance()->getNormalLayer();
1619
stateSig().notify();
1624
Maximize window both horizontal and vertical
1626
void FluxboxWindow::maximize(int type) {
1637
int head = screen().getHead(frame().window());
1638
int new_x = frame().x(),
1639
new_y = frame().y(),
1640
new_w = frame().width(),
1641
new_h = frame().height();
1643
int orig_max = maximized;
1645
// These evaluate whether we need to TOGGLE the value for that field
1646
// Why? If maximize is only set to zero outside this,
1647
// and we only EVER toggle them, then:
1648
// 1) We will never loose the old_ values
1649
// 2) It shouldn't get confused
1651
// Worst case being that some action will toggle the wrong way, but
1652
// we still won't lose the state in that case.
1654
// NOTE: There is one option to the way this works - what it does when
1655
// fully maximised and maximise(vert, horz) is selected.
1656
// There are 2 options here - either:
1657
// 1) maximiseVertical results in a vertically (not horz) maximised window, or
1658
// 2) " toggles vertical maximisation, thus resulting in a horizontally
1659
// maximised window.
1661
// The current implementation uses style 1, to change this, removed the
1662
// item corresponding to the [[ ]] comment
1664
// toggle maximize vertically?
1665
// when _don't_ we want to toggle?
1666
// - type is horizontal maximise, [[and we aren't fully maximised]] or
1667
// - [[ type is vertical maximise and we are fully maximised ]]
1668
// - type is none and we are not vertically maximised, or
1669
// - type is full and we are not horizontally maximised, but already vertically
1670
if (!(type == MAX_HORZ && orig_max != MAX_FULL ||
1671
type == MAX_VERT && orig_max == MAX_FULL ||
1672
type == MAX_NONE && !(orig_max & MAX_VERT) ||
1673
type == MAX_FULL && orig_max == MAX_VERT)) {
1674
// already maximized in that direction?
1675
if (orig_max & MAX_VERT) {
1676
new_y = m_old_pos_y;
1677
new_h = m_old_height;
1679
m_old_pos_y = new_y;
1680
m_old_height = new_h;
1681
new_y = screen().maxTop(head);
1682
new_h = screen().maxBottom(head) - new_y - 2*frame().window().borderWidth();
1684
maximized ^= MAX_VERT;
1687
// maximize horizontally?
1688
if (!(type == MAX_VERT && orig_max != MAX_FULL ||
1689
type == MAX_HORZ && orig_max == MAX_FULL ||
1690
type == MAX_NONE && !(orig_max & MAX_HORZ) ||
1691
type == MAX_FULL && orig_max == MAX_HORZ)) {
1692
// already maximized in that direction?
1693
if (orig_max & MAX_HORZ) {
1694
new_x = m_old_pos_x;
1695
new_w = m_old_width;
1697
// only save if we weren't already maximized
1698
m_old_pos_x = new_x;
1699
m_old_width = new_w;
1700
new_x = screen().maxLeft(head);
1701
new_w = screen().maxRight(head) - new_x - 2*frame().window().borderWidth();
1703
maximized ^= MAX_HORZ;
1706
moveResize(new_x, new_y, new_w, new_h);
1710
* Maximize window horizontal
1712
void FluxboxWindow::maximizeHorizontal() {
1717
* Maximize window vertical
1719
void FluxboxWindow::maximizeVertical() {
1724
* Maximize window fully
1726
void FluxboxWindow::maximizeFull() {
1731
void FluxboxWindow::setWorkspace(int n) {
1732
unsigned int old_wkspc = m_workspace_number;
1734
m_workspace_number = n;
1736
m_blackbox_attrib.flags |= ATTRIB_WORKSPACE;
1737
m_blackbox_attrib.workspace = m_workspace_number;
1739
// notify workspace change
1740
if (isInitialized() && !stuck && old_wkspc != m_workspace_number) {
1742
cerr<<this<<" notify workspace signal"<<endl;
1744
m_workspacesig.notify();
1748
void FluxboxWindow::setLayerNum(int layernum) {
1749
m_layernum = layernum;
1751
m_blackbox_attrib.flags |= ATTRIB_STACK;
1752
m_blackbox_attrib.stack = layernum;
1754
if (isInitialized()) {
1755
saveBlackboxAttribs();
1758
cerr<<this<<" notify layer signal"<<endl;
1761
m_layersig.notify();
1765
void FluxboxWindow::shade() {
1766
// we can only shade if we have a titlebar
1767
if (!decorations.titlebar)
1770
// we're toggling, so if they're equal now, we need to change it
1771
if (isInitialized() && m_frame.isShaded() == shaded)
1776
m_blackbox_attrib.flags ^= ATTRIB_SHADED;
1777
m_blackbox_attrib.attrib ^= ATTRIB_SHADED;
1779
if (isInitialized())
1780
setState(NormalState, false);
1783
m_blackbox_attrib.flags |= ATTRIB_SHADED;
1784
m_blackbox_attrib.attrib |= ATTRIB_SHADED;
1785
// shading is the same as iconic
1786
if (isInitialized())
1787
setState(IconicState, false);
1792
void FluxboxWindow::shadeOn() {
1799
void FluxboxWindow::shadeOff() {
1806
void FluxboxWindow::stick() {
1809
m_blackbox_attrib.flags ^= ATTRIB_OMNIPRESENT;
1810
m_blackbox_attrib.attrib ^= ATTRIB_OMNIPRESENT;
1817
m_blackbox_attrib.flags |= ATTRIB_OMNIPRESENT;
1818
m_blackbox_attrib.attrib |= ATTRIB_OMNIPRESENT;
1822
if (isInitialized()) {
1823
setState(m_current_state, false);
1824
// notify since some things consider "stuck" to be a pseudo-workspace
1825
m_workspacesig.notify();
1831
void FluxboxWindow::raise() {
1835
cerr<<"FluxboxWindow("<<title()<<")::raise()[layer="<<layerNum()<<"]"<<endl;
1838
WinClient *client = getRootTransientFor(m_client);
1840
// if we don't have any root window use this as root
1843
// if we have transient_for then we should put ourself last in
1844
// transients list so we get raised last and thus gets above the other transients
1845
if (m_client->transientFor() && m_client != m_client->transientFor()->transientList().back()) {
1846
// remove and push back so this window gets raised last
1847
m_client->transientFor()->transientList().remove(m_client);
1848
m_client->transientFor()->transientList().push_back(m_client);
1850
// raise this window and every transient in it with this one last
1851
if (client->fbwindow())
1852
raiseFluxboxWindow(*client->fbwindow());
1856
void FluxboxWindow::lower() {
1860
cerr<<"FluxboxWindow("<<title()<<")::lower()"<<endl;
1863
WinClient *client = getRootTransientFor(m_client);
1865
// if we don't have any root window use this as root
1869
if (client->fbwindow())
1870
lowerFluxboxWindow(*client->fbwindow());
1873
void FluxboxWindow::tempRaise() {
1878
WinClient *client = getRootTransientFor(m_client);
1880
// if we don't have any root window use this as root
1884
if (client->fbwindow())
1885
tempRaiseFluxboxWindow(*client->fbwindow());
1889
void FluxboxWindow::raiseLayer() {
1890
// don't let it up to menu layer
1891
if (layerNum() == (Fluxbox::instance()->getMenuLayer()+1))
1894
if (!isInitialized()) {
1900
WinClient *client = getRootTransientFor(m_client);
1902
// if we don't have any root window use this as root
1906
FluxboxWindow *win = client->fbwindow();
1909
if (!win->isIconic())
1910
screen().updateNetizenWindowRaise(client->window());
1912
win->layerItem().raiseLayer();
1914
// remember number just in case a transient happens to revisit this window
1915
int layer_num = win->layerItem().getLayerNum();
1916
win->setLayerNum(layer_num);
1918
WinClient::TransientList::const_iterator it = client->transientList().begin();
1919
WinClient::TransientList::const_iterator it_end = client->transientList().end();
1920
for (; it != it_end; ++it) {
1921
win = (*it)->fbwindow();
1922
if (win && !win->isIconic()) {
1923
screen().updateNetizenWindowRaise((*it)->window());
1924
win->layerItem().moveToLayer(layer_num);
1925
win->setLayerNum(layer_num);
1930
void FluxboxWindow::lowerLayer() {
1931
if (!isInitialized()) {
1938
WinClient *client = getRootTransientFor(m_client);
1940
// if we don't have any root window use this as root
1944
FluxboxWindow *win = client->fbwindow();
1947
if (!win->isIconic()) {
1948
screen().updateNetizenWindowLower(client->window());
1950
win->layerItem().lowerLayer();
1951
// remember number just in case a transient happens to revisit this window
1952
int layer_num = win->layerItem().getLayerNum();
1953
win->setLayerNum(layer_num);
1955
WinClient::TransientList::const_iterator it = client->transientList().begin();
1956
WinClient::TransientList::const_iterator it_end = client->transientList().end();
1957
for (; it != it_end; ++it) {
1958
win = (*it)->fbwindow();
1959
if (win && !win->isIconic()) {
1960
screen().updateNetizenWindowLower((*it)->window());
1961
win->layerItem().moveToLayer(layer_num);
1962
win->setLayerNum(layer_num);
1968
void FluxboxWindow::moveToLayer(int layernum) {
1970
cerr<<"FluxboxWindow("<<title()<<")::moveToLayer("<<layernum<<")"<<endl;
1973
Fluxbox * fluxbox = Fluxbox::instance();
1975
// don't let it set its layer into menu area
1976
if (layernum <= fluxbox->getMenuLayer()) {
1977
layernum = fluxbox->getMenuLayer() + 1;
1980
if (!isInitialized()) {
1981
m_layernum = layernum;
1986
WinClient *client = getRootTransientFor(m_client);
1988
// if we don't have any root window use this as root
1992
FluxboxWindow *win = client->fbwindow();
1995
if (!win->isIconic()) {
1996
screen().updateNetizenWindowRaise(client->window());
1998
win->layerItem().moveToLayer(layernum);
1999
// remember number just in case a transient happens to revisit this window
2000
layernum = win->layerItem().getLayerNum();
2001
win->setLayerNum(layernum);
2003
WinClient::TransientList::const_iterator it = client->transientList().begin();
2004
WinClient::TransientList::const_iterator it_end = client->transientList().end();
2005
for (; it != it_end; ++it) {
2006
win = (*it)->fbwindow();
2007
if (win && !win->isIconic()) {
2008
screen().updateNetizenWindowRaise((*it)->window());
2009
win->layerItem().moveToLayer(layernum);
2010
win->setLayerNum(layernum);
2015
void FluxboxWindow::setFocusHidden(bool value) {
2016
if (isInitialized())
2017
m_statesig.notify();
2020
void FluxboxWindow::setIconHidden(bool value) {
2021
m_icon_hidden= value;
2022
if (isInitialized())
2023
m_statesig.notify();
2027
// window has actually RECEIVED focus (got a FocusIn event)
2028
// so now we make it a focused frame etc
2029
void FluxboxWindow::setFocusFlag(bool focus) {
2030
bool was_focused = isFocused();
2033
cerr<<"FluxboxWindow("<<title()<<")::setFocusFlag("<<focus<<")"<<endl;
2035
// Record focus timestamp for window cycling enhancements
2037
gettimeofday(&m_last_focus_time, 0);
2038
screen().setFocusedWindow(*m_client);
2041
installColormap(focus);
2043
if (focus != frame().focused())
2044
frame().setFocus(focus);
2046
if ((screen().isMouseFocus())
2047
&& screen().doAutoRaise()) {
2054
// did focus change? notify listeners
2055
if (was_focused != focus)
2056
m_focussig.notify();
2060
void FluxboxWindow::installColormap(bool install) {
2061
if (m_client == 0) return;
2063
Fluxbox *fluxbox = Fluxbox::instance();
2065
if (! m_client->validateClient())
2068
int i = 0, ncmap = 0;
2069
Colormap *cmaps = XListInstalledColormaps(display, m_client->window(), &ncmap);
2070
XWindowAttributes wattrib;
2072
if (m_client->getAttrib(wattrib)) {
2074
// install the window's colormap
2075
for (i = 0; i < ncmap; i++) {
2076
if (*(cmaps + i) == wattrib.colormap) {
2077
// this window is using an installed color map... do not install
2079
break; //end for-loop (we dont need to check more)
2082
// otherwise, install the window's colormap
2084
XInstallColormap(display, wattrib.colormap);
2086
for (i = 0; i < ncmap; i++) { // uninstall the window's colormap
2087
if (*(cmaps + i) == wattrib.colormap)
2088
XUninstallColormap(display, wattrib.colormap);
2100
Saves blackbox attributes for every client in our list
2102
void FluxboxWindow::saveBlackboxAttribs() {
2103
for_each(m_clientlist.begin(), m_clientlist.end(),
2104
FbTk::ChangeProperty(
2106
FbAtoms::instance()->getFluxboxAttributesAtom(),
2108
(unsigned char *)&m_blackbox_attrib,
2109
PropBlackboxAttributesElements
2114
Sets state on each client in our list
2115
Use setting_up for setting startup state - it may not be committed yet
2116
That'll happen when its mapped
2118
void FluxboxWindow::setState(unsigned long new_state, bool setting_up) {
2119
if (numClients() == 0)
2122
m_current_state = new_state;
2124
unsigned long state[2];
2125
state[0] = (unsigned long) m_current_state;
2126
state[1] = (unsigned long) None;
2128
for_each(m_clientlist.begin(), m_clientlist.end(),
2129
FbTk::ChangeProperty(display, FbAtoms::instance()->getWMStateAtom(),
2131
(unsigned char *)state, 2));
2133
saveBlackboxAttribs();
2134
//notify state changed
2135
m_statesig.notify();
2139
bool FluxboxWindow::getState() {
2144
unsigned long *state, ulfoo, nitems;
2145
if (!m_client->property(FbAtoms::instance()->getWMStateAtom(),
2146
0l, 2l, false, FbAtoms::instance()->getWMStateAtom(),
2147
&atom_return, &foo, &nitems, &ulfoo,
2148
(unsigned char **) &state) || !state)
2152
m_current_state = static_cast<unsigned long>(state[0]);
2156
XFree(static_cast<void *>(state));
2162
* Sets the attributes to what they should be
2163
* but doesn't change the actual state
2164
* (so the caller can set defaults etc as well)
2166
void FluxboxWindow::restoreAttributes() {
2168
m_current_state = m_client->initial_state;
2169
if (m_current_state == IconicState)
2175
unsigned long ulfoo, nitems;
2176
FbAtoms *fbatoms = FbAtoms::instance();
2178
BlackboxAttributes *net;
2179
if (m_client->property(fbatoms->getFluxboxAttributesAtom(), 0l,
2180
PropBlackboxAttributesElements, false,
2181
fbatoms->getFluxboxAttributesAtom(), &atom_return, &foo,
2182
&nitems, &ulfoo, (unsigned char **) &net) &&
2184
if (nitems != (unsigned)PropBlackboxAttributesElements) {
2188
m_blackbox_attrib.flags = net->flags;
2189
m_blackbox_attrib.attrib = net->attrib;
2190
m_blackbox_attrib.workspace = net->workspace;
2191
m_blackbox_attrib.stack = net->stack;
2192
m_blackbox_attrib.premax_x = net->premax_x;
2193
m_blackbox_attrib.premax_y = net->premax_y;
2194
m_blackbox_attrib.premax_w = net->premax_w;
2195
m_blackbox_attrib.premax_h = net->premax_h;
2197
XFree(static_cast<void *>(net));
2201
if (m_blackbox_attrib.flags & ATTRIB_SHADED &&
2202
m_blackbox_attrib.attrib & ATTRIB_SHADED)
2205
if (m_blackbox_attrib.flags & ATTRIB_HIDDEN &&
2206
m_blackbox_attrib.attrib & ATTRIB_HIDDEN) {
2210
if (( m_blackbox_attrib.workspace != screen().currentWorkspaceID()) &&
2211
( m_blackbox_attrib.workspace < screen().numberOfWorkspaces()))
2212
m_workspace_number = m_blackbox_attrib.workspace;
2214
if (m_blackbox_attrib.flags & ATTRIB_OMNIPRESENT &&
2215
m_blackbox_attrib.attrib & ATTRIB_OMNIPRESENT)
2218
if (m_blackbox_attrib.flags & ATTRIB_STACK) {
2219
//!! TODO check value?
2220
m_layernum = m_blackbox_attrib.stack;
2223
if ((m_blackbox_attrib.flags & ATTRIB_MAXHORIZ) ||
2224
(m_blackbox_attrib.flags & ATTRIB_MAXVERT)) {
2225
int x = m_blackbox_attrib.premax_x, y = m_blackbox_attrib.premax_y;
2226
unsigned int w = m_blackbox_attrib.premax_w, h = m_blackbox_attrib.premax_h;
2227
maximized = MAX_NONE;
2228
if ((m_blackbox_attrib.flags & ATTRIB_MAXHORIZ) &&
2229
(m_blackbox_attrib.flags & ATTRIB_MAXVERT))
2230
maximized = MAX_FULL;
2231
else if (m_blackbox_attrib.flags & ATTRIB_MAXVERT)
2232
maximized = MAX_VERT;
2233
else if (m_blackbox_attrib.flags & ATTRIB_MAXHORIZ)
2234
maximized = MAX_HORZ;
2236
m_blackbox_attrib.premax_x = x;
2237
m_blackbox_attrib.premax_y = y;
2238
m_blackbox_attrib.premax_w = w;
2239
m_blackbox_attrib.premax_h = h;
2245
Show the window menu at pos mx, my
2247
void FluxboxWindow::showMenu(int menu_x, int menu_y) {
2248
// move menu directly under titlebar
2250
int head = screen().getHead(menu_x, menu_y);
2252
// but not under screen
2253
if (menu_y + menu().height() >= screen().maxBottom(head))
2254
menu_y = screen().maxBottom(head) - menu().height() - 1 - menu().fbwindow().borderWidth();
2256
if (menu_x < static_cast<signed>(screen().maxLeft(head)))
2257
menu_x = screen().maxLeft(head);
2258
else if (menu_x + static_cast<signed>(menu().width()) >= static_cast<signed>(screen().maxRight(head)))
2259
menu_x = screen().maxRight(head) - menu().width() - 1;
2261
WindowCmd<void>::setWindow(this);
2262
menu().move(menu_x, menu_y);
2265
menu().grabInputFocus();
2269
Moves the menu to last button press position and shows it,
2270
if it's already visible it'll be hidden
2272
void FluxboxWindow::popupMenu() {
2274
// hide menu if it was opened for this window before
2275
if (menu().isVisible() && WindowCmd<void>::window() == this) {
2280
menu().disableTitle();
2281
int menu_y = frame().titlebar().height() + frame().titlebar().borderWidth();
2282
if (!decorations.titlebar) // if we don't have any titlebar
2284
if (m_last_button_x < x() || m_last_button_x > x() + width())
2285
m_last_button_x = x();
2286
showMenu(m_last_button_x, menu_y + frame().y());
2291
Redirect any unhandled event to our handlers
2293
void FluxboxWindow::handleEvent(XEvent &event) {
2294
switch (event.type) {
2295
case ConfigureRequest:
2297
cerr<<"ConfigureRequest("<<title()<<")"<<endl;
2300
configureRequestEvent(event.xconfigurerequest);
2303
mapNotifyEvent(event.xmap);
2305
// This is already handled in Fluxbox::handleEvent
2307
// mapRequestEvent(event.xmaprequest);
2309
case PropertyNotify: {
2312
char *atomname = XGetAtomName(display, event.xproperty.atom);
2313
cerr<<"PropertyNotify("<<title()<<"), property = "<<atomname<<endl;
2317
WinClient *client = findClient(event.xproperty.window);
2319
propertyNotifyEvent(*client, event.xproperty.atom);
2326
if (Fluxbox::instance()->haveShape() &&
2327
event.type == Fluxbox::instance()->shapeEventbase() + ShapeNotify) {
2329
cerr<<"ShapeNotify("<<title()<<")"<<endl;
2331
XShapeEvent *shape_event = (XShapeEvent *)&event;
2333
if (shape_event->kind != ShapeBounding)
2336
if (shape_event->shaped) {
2342
XShapeCombineMask(display,
2343
frame().window().window(), ShapeBounding,
2348
FbTk::App::instance()->sync(false);
2357
void FluxboxWindow::mapRequestEvent(XMapRequestEvent &re) {
2359
// we're only concerned about client window event
2360
WinClient *client = findClient(re.window);
2363
cerr<<__FILE__<<"("<<__FUNCTION__<<"): Can't find client!"<<endl;
2368
// rest of current state checking is in initialisation
2369
if (m_current_state == WithdrawnState)
2373
// if this window was destroyed while autogrouping
2374
bool destroyed = false;
2376
// check WM_CLASS only when we changed state to NormalState from
2377
// WithdrawnState (ICCC 4.1.2.5)
2378
client->updateWMClassHint();
2380
Workspace *wsp = screen().getWorkspace(m_workspace_number);
2381
if (wsp != 0 && isGroupable())
2382
destroyed = wsp->checkGrouping(*this);
2384
// if we weren't grouped with another window we deiconify ourself
2385
if (!destroyed && !iconic)
2392
void FluxboxWindow::mapNotifyEvent(XMapEvent &ne) {
2393
WinClient *client = findClient(ne.window);
2397
cerr<<"FluxboxWindow::mapNotifyEvent: "
2398
<<"ne.override_redirect = "<<ne.override_redirect
2399
<<" isVisible() = "<<isVisible()<<endl;
2402
if (!ne.override_redirect && isVisible()) {
2404
cerr<<"FluxboxWindow::mapNotify: not override redirect ans visible!"<<endl;
2406
Fluxbox *fluxbox = Fluxbox::instance();
2408
if (! client->validateClient())
2411
setState(NormalState, false);
2413
if (client->isTransient() || screen().doFocusNew())
2414
setCurrentClient(*client, true);
2416
setFocusFlag(false);
2420
// Auto-group from tab?
2421
if (!client->isTransient()) {
2423
cerr<<__FILE__<<"("<<__FUNCTION__<<") TODO check grouping here"<<endl;
2432
Unmaps frame window and client window if
2433
event.window == m_client->window
2434
Returns true if *this should die
2437
void FluxboxWindow::unmapNotifyEvent(XUnmapEvent &ue) {
2438
WinClient *client = findClient(ue.window);
2443
cerr<<__FILE__<<"("<<__FUNCTION__<<"): 0x"<<hex<<client->window()<<dec<<endl;
2444
cerr<<__FILE__<<"("<<__FUNCTION__<<"): title="<<client->title()<<endl;
2447
restore(client, false);
2452
Checks if event is for m_client->window.
2453
If it isn't, we leave it until the window is unmapped, if it is,
2454
we just hide it for now.
2456
void FluxboxWindow::destroyNotifyEvent(XDestroyWindowEvent &de) {
2457
if (de.window == m_client->window()) {
2459
cerr<<__FILE__<<"("<<__LINE__<<"): DestroyNotifyEvent this="<<this<<" title = "<<title()<<endl;
2461
if (numClients() == 1)
2468
void FluxboxWindow::propertyNotifyEvent(WinClient &client, Atom atom) {
2471
case XA_WM_CLIENT_MACHINE:
2475
case XA_WM_TRANSIENT_FOR: {
2476
bool was_transient = client.isTransient();
2477
client.updateTransientInfo();
2478
// update our layer to be the same layer as our transient for
2479
if (client.isTransient() && !was_transient
2480
&& client.transientFor()->fbwindow())
2481
layerItem().setLayer(client.transientFor()->fbwindow()->layerItem().getLayer());
2486
client.updateWMHints();
2487
hintSig().notify(); // notify listeners
2490
case XA_WM_ICON_NAME:
2491
// update icon title and then do normal XA_WM_NAME stuff
2492
client.updateIconTitle();
2494
updateTitleFromClient(client);
2495
titleSig().notify();
2498
case XA_WM_NORMAL_HINTS: {
2500
cerr<<"XA_WM_NORMAL_HINTS("<<title()<<")"<<endl;
2502
int old_max_width = client.max_width;
2503
int old_min_width = client.min_width;
2504
int old_min_height = client.min_height;
2505
int old_max_height = client.max_height;
2506
bool changed = false;
2507
client.updateWMNormalHints();
2509
if ((client.normal_hint_flags & PMinSize) &&
2510
(client.normal_hint_flags & PMaxSize) &&
2511
(client.min_width != old_min_width ||
2512
client.max_width != old_max_width ||
2513
client.min_height != old_min_height ||
2514
client.max_height != old_max_height)) {
2515
if (client.max_width != 0 && client.max_width <= client.min_width &&
2516
client.max_height != 0 && client.max_height <= client.min_height) {
2517
if (decorations.maximize ||
2518
decorations.handle ||
2522
decorations.maximize = false;
2523
decorations.handle = false;
2524
functions.resize=false;
2525
functions.maximize=false;
2527
// TODO: is broken while handled by FbW, needs to be in WinClient
2528
if (! client.isTransient()) {
2529
if (!decorations.maximize ||
2530
!decorations.handle ||
2531
!functions.maximize)
2533
decorations.maximize = true;
2534
decorations.handle = true;
2535
functions.maximize = true;
2537
if (!functions.resize)
2539
functions.resize = true;
2546
moveResize(frame().x(), frame().y(),
2547
frame().width(), frame().height());
2553
FbAtoms *fbatoms = FbAtoms::instance();
2554
if (atom == fbatoms->getWMProtocolsAtom()) {
2555
client.updateWMProtocols();
2556
} else if (atom == fbatoms->getMWMHintsAtom()) {
2557
client.updateMWMHints();
2558
updateMWMHintsFromClient(client);
2559
updateRememberStateFromClient(client);
2560
applyDecorations(); // update decorations (if they changed)
2561
} else if (atom == fbatoms->getFluxboxHintsAtom()) {
2562
client.updateBlackboxHints();
2563
updateBlackboxHintsFromClient(client);
2564
if (client.getBlackboxHint() != 0 &&
2565
(client.getBlackboxHint()->flags & ATTRIB_DECORATION)) {
2566
updateRememberStateFromClient(client);
2567
applyDecorations(); // update decoration
2576
void FluxboxWindow::exposeEvent(XExposeEvent &ee) {
2577
frame().exposeEvent(ee);
2580
void FluxboxWindow::configureRequestEvent(XConfigureRequestEvent &cr) {
2582
WinClient *client = findClient(cr.window);
2583
if (client == 0 || isIconic())
2586
int cx = frame().x(), cy = frame().y(), ignore = 0;
2587
unsigned int cw = frame().width(), ch = frame().height();
2589
if (cr.value_mask & CWBorderWidth)
2590
client->old_bw = cr.border_width;
2592
if ((cr.value_mask & CWX) &&
2593
(cr.value_mask & CWY)) {
2596
frame().gravityTranslate(cx, cy, client->gravity(), false);
2597
} else if (cr.value_mask & CWX) {
2599
frame().gravityTranslate(cx, ignore, client->gravity(), false);
2600
} else if (cr.value_mask & CWY) {
2602
frame().gravityTranslate(ignore, cy, client->gravity(), false);
2605
if (cr.value_mask & CWWidth)
2608
if (cr.value_mask & CWHeight)
2611
// whether we should send ConfigureNotify to netizens
2612
// the request is for client window so we resize the frame to it first
2613
if (frame().width() != cw || frame().height() != ch) {
2614
if (frame().x() != cx || frame().y() != cy)
2615
frame().moveResizeForClient(cx, cy, cw, ch);
2617
frame().resizeForClient(cw, ch);
2618
} else if (frame().x() != cx || frame().y() != cy) {
2619
frame().move(cx, cy);
2622
if (cr.value_mask & CWStackMode) {
2623
switch (cr.detail) {
2637
sendConfigureNotify();
2642
void FluxboxWindow::buttonPressEvent(XButtonEvent &be) {
2643
m_last_button_x = be.x_root;
2644
m_last_button_y = be.y_root;
2646
// check frame events first
2647
frame().buttonPressEvent(be);
2649
if (be.button == 1 || (be.button == 3 && be.state == Mod1Mask)) {
2650
if ((! focused) && (! screen().isMouseFocus())) { //check focus
2654
if (frame().window().window() == be.window) {
2655
if (screen().clickRaises())
2658
cerr<<"FluxboxWindow::buttonPressEvent: AllowEvent"<<endl;
2661
XAllowEvents(display, ReplayPointer, be.time);
2663
m_button_grab_x = be.x_root - frame().x() - frame().window().borderWidth();
2664
m_button_grab_y = be.y_root - frame().y() - frame().window().borderWidth();
2665
} else if (frame().handle() == be.window)
2668
Fluxbox::instance()->hideExtraMenus(screen());
2669
screen().hideWindowMenus(this);
2673
void FluxboxWindow::buttonReleaseEvent(XButtonEvent &re) {
2675
if ((re.button == 1) && (re.state & Mod1Mask) && !screen().clickRaises())
2681
else if (isResizing())
2683
else if (m_attaching_tab)
2684
attachTo(re.x_root, re.y_root);
2685
else if (re.window == frame().window()) {
2686
if (re.button == 2 && re.state == Mod1Mask)
2687
ungrabPointer(CurrentTime);
2689
frame().buttonReleaseEvent(re);
2691
frame().buttonReleaseEvent(re);
2696
void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
2697
if (isMoving() && me.window == parent()) {
2698
me.window = frame().window().window();
2700
bool inside_titlebar = (frame().titlebar() == me.window || frame().label() == me.window ||
2701
frame().handle() == me.window || frame().window() == me.window);
2703
if (Fluxbox::instance()->getIgnoreBorder()
2704
&& !(me.state & Mod1Mask) // really should check for exact matches
2705
&& !(isMoving() || isResizing() || m_attaching_tab != 0)) {
2706
int borderw = frame().window().borderWidth();
2707
if (me.x_root < (frame().x() + borderw) ||
2708
me.y_root < (frame().y() + borderw) ||
2709
me.x_root > (frame().x() + (int)frame().width() + borderw) ||
2710
me.y_root > (frame().y() + (int)frame().height() + borderw))
2714
WinClient *client = 0;
2715
if (!inside_titlebar) {
2716
// determine if we're in titlebar
2717
Client2ButtonMap::iterator it =
2718
find_if(m_labelbuttons.begin(),
2719
m_labelbuttons.end(),
2720
Compose(bind2nd(equal_to<Window>(), me.window),
2721
Compose(mem_fun(&TextButton::window),
2722
Select2nd<Client2ButtonMap::value_type>())));
2723
if (it != m_labelbuttons.end()) {
2724
inside_titlebar = true;
2725
client = (*it).first;
2729
if ((me.state & Button1Mask) && functions.move &&
2734
startMoving(me.window);
2735
// save first event point
2736
m_last_resize_x = me.x_root;
2737
m_last_resize_y = me.y_root;
2738
m_button_grab_x = me.x_root - frame().x() - frame().window().borderWidth();
2739
m_button_grab_y = me.y_root - frame().y() - frame().window().borderWidth();
2741
int dx = me.x_root - m_button_grab_x,
2742
dy = me.y_root - m_button_grab_y;
2744
dx -= frame().window().borderWidth();
2745
dy -= frame().window().borderWidth();
2747
// Warp to next or previous workspace?, must have moved sideways some
2748
int moved_x = me.x_root - m_last_resize_x;
2749
// save last event point
2750
m_last_resize_x = me.x_root;
2751
m_last_resize_y = me.y_root;
2753
if (moved_x && screen().isWorkspaceWarping()) {
2754
unsigned int cur_id = screen().currentWorkspaceID();
2755
unsigned int new_id = cur_id;
2756
const int warpPad = screen().getEdgeSnapThreshold();
2757
// 1) if we're inside the border threshold
2758
// 2) if we moved in the right direction
2759
if (me.x_root >= int(screen().width()) - warpPad - 1 &&
2762
new_id = (cur_id + 1) % screen().numberOfWorkspaces();
2763
dx = - me.x_root; // move mouse back to x=0
2764
} else if (me.x_root <= warpPad &&
2767
new_id = (cur_id + screen().numberOfWorkspaces() - 1) % screen().numberOfWorkspaces();
2768
dx = screen().width() - me.x_root-1; // move mouse to screen width - 1
2770
if (new_id != cur_id) {
2772
XWarpPointer(display, None, None, 0, 0, 0, 0, dx, 0);
2773
screen().changeWorkspaceID(new_id);
2775
m_last_resize_x = me.x_root + dx;
2777
// dx is the difference, so our new x is what it would have been
2778
// without the warp, plus the difference.
2779
dx += me.x_root - m_button_grab_x;
2782
// dx = current left side, dy = current top
2785
if (! screen().doOpaqueMove()) {
2786
parent().drawRectangle(screen().rootTheme().opGC(),
2787
m_last_move_x, m_last_move_y,
2788
frame().width() + 2*frame().window().borderWidth()-1,
2789
frame().height() + 2*frame().window().borderWidth()-1);
2791
parent().drawRectangle(screen().rootTheme().opGC(),
2793
frame().width() + 2*frame().window().borderWidth()-1,
2794
frame().height() + 2*frame().window().borderWidth()-1);
2798
//moveResize(dx, dy, frame().width(), frame().height());
2799
// need to move the base window without interfering with transparency
2800
frame().window().moveResize(dx, dy, frame().width(), frame().height());
2803
screen().showPosition(dx, dy);
2805
} else if (functions.resize &&
2806
(((me.state & Button1Mask) && (me.window == frame().gripRight() ||
2807
me.window == frame().gripLeft())) ||
2808
me.window == frame().window())) {
2812
int cx = frame().width() / 2;
2813
int cy = frame().height() / 2;
2815
if (me.window == frame().gripRight())
2816
m_resize_corner = RIGHTBOTTOM;
2817
else if (me.window == frame().gripLeft())
2818
m_resize_corner = LEFTBOTTOM;
2819
else if (screen().getResizeModel() != BScreen::QUADRANTRESIZE)
2820
m_resize_corner = RIGHTBOTTOM;
2822
m_resize_corner = (me.y < cy) ? LEFTTOP : LEFTBOTTOM;
2824
m_resize_corner = (me.y < cy) ? RIGHTTOP : RIGHTBOTTOM;
2826
startResizing(me.window, me.x, me.y);
2827
} else if (resizing) {
2828
// draw over old rect
2829
parent().drawRectangle(screen().rootTheme().opGC(),
2830
m_last_resize_x, m_last_resize_y,
2831
m_last_resize_w - 1 + 2 * frame().window().borderWidth(),
2832
m_last_resize_h - 1 + 2 * frame().window().borderWidth());
2838
int dx = me.x - m_button_grab_x;
2839
int dy = me.y - m_button_grab_y;
2841
if (m_resize_corner == LEFTTOP || m_resize_corner == RIGHTTOP) {
2842
m_last_resize_h = frame().height() - dy;
2843
m_last_resize_y = frame().y() + dy;
2845
m_last_resize_h = frame().height() + dy;
2848
if (m_resize_corner == LEFTTOP || m_resize_corner == LEFTBOTTOM) {
2849
m_last_resize_w = frame().width() - dx;
2850
m_last_resize_x = frame().x() + dx;
2852
m_last_resize_w = frame().width() + dx;
2857
// draw resize rectangle
2858
parent().drawRectangle(screen().rootTheme().opGC(),
2859
m_last_resize_x, m_last_resize_y,
2860
m_last_resize_w - 1 + 2 * frame().window().borderWidth(),
2861
m_last_resize_h - 1 + 2 * frame().window().borderWidth());
2863
screen().showGeometry(gx, gy);
2865
} else if (functions.tabable &&
2866
(me.state & Button2Mask) && inside_titlebar && (client != 0 || m_attaching_tab != 0)) {
2868
// drag'n'drop code for tabs
2870
FbTk::TextButton &active_button = *m_labelbuttons[(m_attaching_tab==0)?client:m_attaching_tab];
2872
if (m_attaching_tab == 0) {
2873
if (s_num_grabs > 0)
2875
// start drag'n'drop for tab
2876
m_attaching_tab = client;
2877
grabPointer(me.window, False, ButtonMotionMask |
2878
ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
2879
None, frame(). theme().moveCursor(), CurrentTime);
2880
// relative position on button
2881
m_button_grab_x = me.x;
2882
m_button_grab_y = me.y;
2883
// last known root mouse position
2884
m_last_move_x = me.x_root - me.x;
2885
m_last_move_y = me.y_root - me.y;
2886
// hijack extra vars for initial grab location
2887
m_last_resize_x = me.x_root;
2888
m_last_resize_y = me.y_root;
2890
Fluxbox::instance()->grab();
2892
parent().drawRectangle(screen().rootTheme().opGC(),
2893
m_last_move_x, m_last_move_y,
2894
active_button.width(),
2895
active_button.height());
2899
// we already grabed and started to drag'n'drop tab
2900
// so we update drag'n'drop-rectangle
2901
int dx = me.x_root - m_button_grab_x, dy = me.y_root - m_button_grab_y;
2904
parent().drawRectangle(screen().rootTheme().opGC(),
2905
m_last_move_x, m_last_move_y,
2906
active_button.width(),
2907
active_button.height());
2910
// redraw rectangle at new pos
2913
parent().drawRectangle(screen().rootTheme().opGC(),
2914
m_last_move_x, m_last_move_y,
2915
active_button.width(),
2916
active_button.height());
2924
void FluxboxWindow::enterNotifyEvent(XCrossingEvent &ev) {
2926
// ignore grab activates, or if we're not visible
2927
if (ev.mode == NotifyGrab ||
2932
WinClient *client = 0;
2933
if (screen().isMouseTabFocus()) {
2934
// determine if we're in a label button (tab)
2935
Client2ButtonMap::iterator it =
2936
find_if(m_labelbuttons.begin(),
2937
m_labelbuttons.end(),
2938
Compose(bind2nd(equal_to<Window>(), ev.window),
2939
Compose(mem_fun(&TextButton::window),
2940
Select2nd<Client2ButtonMap::value_type>())));
2941
if (it != m_labelbuttons.end())
2942
client = (*it).first;
2946
if (ev.window == frame().window() ||
2947
ev.window == m_client->window() ||
2950
if (screen().isMouseFocus() && !isFocused()) {
2952
// check that there aren't any subsequent leave notify events in the
2957
sa.enter = sa.leave = False;
2958
XCheckIfEvent(display, &dummy, queueScanner, (char *) &sa);
2960
if ((!sa.leave || sa.inferior)) {
2966
if (screen().isMouseTabFocus() && client && client != m_client) {
2967
setCurrentClient(*client, isFocused());
2972
void FluxboxWindow::leaveNotifyEvent(XCrossingEvent &ev) {
2973
// I hope commenting this out is right - simon 21jul2003
2974
//if (ev.window == frame().window())
2975
//installColormap(false);
2978
// TODO: functions should not be affected by decoration
2979
void FluxboxWindow::setDecoration(Decoration decoration, bool apply) {
2980
switch (decoration) {
2982
decorations.titlebar = decorations.border = decorations.handle =
2983
decorations.iconify = decorations.maximize =
2984
decorations.tab = false; //tab is also a decor
2985
decorations.menu = true; // menu is present
2986
// functions.iconify = functions.maximize = true;
2987
// functions.move = true; // We need to move even without decor
2988
// functions.resize = true; // We need to resize even without decor
2993
decorations.titlebar = decorations.border = decorations.handle =
2994
decorations.iconify = decorations.maximize =
2995
decorations.menu = true;
2996
functions.resize = functions.move = functions.iconify =
2997
functions.maximize = true;
3001
decorations.titlebar = decorations.iconify = decorations.menu =
3002
functions.move = functions.iconify = true;
3003
decorations.border = decorations.handle = decorations.maximize =
3004
functions.resize = functions.maximize = false;
3008
decorations.titlebar = decorations.menu = functions.move = true;
3009
decorations.iconify = decorations.border = decorations.handle =
3010
decorations.maximize = functions.resize = functions.maximize =
3011
functions.iconify = false;
3015
// we might want to wait with apply decorations
3019
//!! TODO: make sure this is correct
3020
// is this reconfigure necessary???
3025
// commit current decoration values to actual displayed things
3026
void FluxboxWindow::applyDecorations(bool initial) {
3027
frame().clientArea().setBorderWidth(0); // client area bordered by other things
3029
int grav_x=0, grav_y=0;
3031
frame().gravityTranslate(grav_x, grav_y, -m_client->gravity(), false);
3033
unsigned int border_width = 0;
3034
if (decorations.border)
3035
border_width = frame().theme().border().width();
3037
bool client_move = false;
3039
if (initial || frame().window().borderWidth() != border_width) {
3041
frame().setBorderWidth(border_width);
3044
// we rely on frame not doing anything if it is already shown/hidden
3045
if (decorations.titlebar)
3046
client_move |= frame().showTitlebar();
3048
client_move |= frame().hideTitlebar();
3050
if (decorations.handle) {
3051
client_move |= frame().showHandle();
3053
client_move |= frame().hideHandle();
3055
// apply gravity once more
3056
frame().gravityTranslate(grav_x, grav_y, m_client->gravity(), false);
3058
// if the location changes, shift it
3059
if (grav_x != 0 || grav_y != 0) {
3060
move(grav_x + frame().x(), grav_y + frame().y());
3064
frame().reconfigure();
3065
if (!initial && client_move)
3066
sendConfigureNotify();
3070
void FluxboxWindow::toggleDecoration() {
3071
//don't toggle decor if the window is shaded
3075
m_toggled_decos= true;
3077
if (decorations.enabled) { //remove decorations
3078
decorations.enabled = false;
3079
setDecoration(DECOR_NONE);
3080
} else { //revert back to old decoration
3081
decorations.enabled = true;
3082
if (m_old_decoration == DECOR_NONE) { // make sure something happens
3083
setDecoration(DECOR_NORMAL);
3085
setDecoration(m_old_decoration);
3090
unsigned int FluxboxWindow::decorationMask() const {
3091
unsigned int ret = 0;
3092
if (decorations.titlebar)
3093
ret |= DECORM_TITLEBAR;
3094
if (decorations.handle)
3095
ret |= DECORM_HANDLE;
3096
if (decorations.border)
3097
ret |= DECORM_BORDER;
3098
if (decorations.iconify)
3099
ret |= DECORM_ICONIFY;
3100
if (decorations.maximize)
3101
ret |= DECORM_MAXIMIZE;
3102
if (decorations.close)
3103
ret |= DECORM_CLOSE;
3104
if (decorations.menu)
3106
if (decorations.sticky)
3107
ret |= DECORM_STICKY;
3108
if (decorations.shade)
3109
ret |= DECORM_SHADE;
3110
if (decorations.tab)
3112
if (decorations.enabled)
3113
ret |= DECORM_ENABLED;
3117
void FluxboxWindow::setDecorationMask(unsigned int mask) {
3118
decorations.titlebar = mask & DECORM_TITLEBAR;
3119
decorations.handle = mask & DECORM_HANDLE;
3120
decorations.border = mask & DECORM_BORDER;
3121
decorations.iconify = mask & DECORM_ICONIFY;
3122
decorations.maximize = mask & DECORM_MAXIMIZE;
3123
decorations.close = mask & DECORM_CLOSE;
3124
decorations.menu = mask & DECORM_MENU;
3125
decorations.sticky = mask & DECORM_STICKY;
3126
decorations.shade = mask & DECORM_SHADE;
3127
decorations.tab = mask & DECORM_TAB;
3128
decorations.enabled = mask & DECORM_ENABLED;
3132
void FluxboxWindow::startMoving(Window win) {
3133
if (s_num_grabs > 0)
3137
maximized = MAX_NONE;
3139
Fluxbox *fluxbox = Fluxbox::instance();
3140
// grabbing (and masking) on the root window allows us to
3141
// freely map and unmap the window we're moving.
3142
grabPointer(screen().rootWindow().window(), False, Button1MotionMask |
3143
ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
3144
screen().rootWindow().window(), frame().theme().moveCursor(), CurrentTime);
3146
if (menu().isVisible())
3149
fluxbox->maskWindowEvents(screen().rootWindow().window(), this);
3151
m_last_move_x = frame().x();
3152
m_last_move_y = frame().y();
3153
if (! screen().doOpaqueMove()) {
3155
parent().drawRectangle(screen().rootTheme().opGC(),
3156
frame().x(), frame().y(),
3157
frame().width() + 2*frame().window().borderWidth()-1,
3158
frame().height() + 2*frame().window().borderWidth()-1);
3159
screen().showPosition(frame().x(), frame().y());
3163
void FluxboxWindow::stopMoving(bool interrupted) {
3165
Fluxbox *fluxbox = Fluxbox::instance();
3167
fluxbox->maskWindowEvents(0, 0);
3169
if (! screen().doOpaqueMove()) {
3170
parent().drawRectangle(screen().rootTheme().opGC(),
3171
m_last_move_x, m_last_move_y,
3172
frame().width() + 2*frame().window().borderWidth()-1,
3173
frame().height() + 2*frame().window().borderWidth()-1);
3175
moveResize(m_last_move_x, m_last_move_y, frame().width(), frame().height());
3176
if (m_workspace_number != screen().currentWorkspaceID()) {
3177
screen().reassociateWindow(this, screen().currentWorkspaceID(), true);
3182
} else if (!interrupted) {
3183
moveResize(frame().x(), frame().y(), frame().width(), frame().height(), ForgetGravity, true);
3184
frame().notifyMoved(true);
3188
screen().hidePosition();
3189
ungrabPointer(CurrentTime);
3191
FbTk::App::instance()->sync(false); //make sure the redraw is made before we continue
3194
void FluxboxWindow::pauseMoving() {
3195
if (screen().doOpaqueMove()) {
3199
parent().drawRectangle(screen().rootTheme().opGC(),
3200
m_last_move_x, m_last_move_y,
3201
frame().width() + 2*frame().window().borderWidth()-1,
3202
frame().height() + 2*frame().window().borderWidth()-1);
3207
void FluxboxWindow::resumeMoving() {
3208
if (screen().doOpaqueMove()) {
3212
if (m_workspace_number == screen().currentWorkspaceID()) {
3217
FbTk::App::instance()->sync(false);
3219
parent().drawRectangle(screen().rootTheme().opGC(),
3220
m_last_move_x, m_last_move_y,
3221
frame().width() + 2*frame().window().borderWidth()-1,
3222
frame().height() + 2*frame().window().borderWidth()-1);
3227
* Helper function that snaps a window to another window
3228
* We snap if we're closer than the x/ylimits.
3230
inline void snapToWindow(int &xlimit, int &ylimit,
3231
int left, int right, int top, int bottom,
3232
int oleft, int oright, int otop, int obottom) {
3233
// Only snap if we're adjacent to the edge we're looking at
3235
// for left + right, need to be in the right y range
3236
if (top <= obottom && bottom >= otop) {
3238
if (abs(left-oleft) < abs(xlimit)) xlimit = -(left-oleft);
3239
if (abs(right-oleft) < abs(xlimit)) xlimit = -(right-oleft);
3242
if (abs(left-oright) < abs(xlimit)) xlimit = -(left-oright);
3243
if (abs(right-oright) < abs(xlimit)) xlimit = -(right-oright);
3246
// for top + bottom, need to be in the right x range
3247
if (left <= oright && right >= oleft) {
3249
if (abs(top-otop) < abs(ylimit)) ylimit = -(top-otop);
3250
if (abs(bottom-otop) < abs(ylimit)) ylimit = -(bottom-otop);
3253
if (abs(top-obottom) < abs(ylimit)) ylimit = -(top-obottom);
3254
if (abs(bottom-obottom) < abs(ylimit)) ylimit = -(bottom-obottom);
3260
* Do Whatever snapping magic is necessary, and return using the orig_left
3261
* and orig_top variables to indicate the new x,y position
3263
void FluxboxWindow::doSnapping(int &orig_left, int &orig_top) {
3265
* Snap to screen/head edges
3269
if (screen().getEdgeSnapThreshold() == 0) return;
3271
// Keep track of our best offsets so far
3272
// We need to find things less than or equal to the threshold
3273
int dx = screen().getEdgeSnapThreshold() + 1;
3274
int dy = screen().getEdgeSnapThreshold() + 1;
3276
// we only care about the left/top etc that includes borders
3279
if (decorationMask() & (DECORM_ENABLED|DECORM_BORDER|DECORM_HANDLE))
3280
borderW = frame().window().borderWidth();
3282
int top = orig_top; // orig include the borders
3283
int left = orig_left;
3285
int right = orig_left + width() + 2 * borderW;
3286
int bottom = orig_top + height() + 2 * borderW;
3288
/////////////////////////////////////
3289
// begin by checking the screen (or Xinerama head) edges
3292
if (screen().numHeads() > 0) {
3293
// head "0" == whole screen width + height, which we skip since the
3294
// sum of all the heads covers those edges
3295
for (h = 1; h <= screen().numHeads(); h++) {
3296
snapToWindow(dx, dy, left, right, top, bottom,
3297
screen().maxLeft(h),
3298
screen().maxRight(h),
3300
screen().maxBottom(h));
3302
for (h = 1; h <= screen().numHeads(); h++) {
3303
snapToWindow(dx, dy, left, right, top, bottom,
3304
screen().getHeadX(h),
3305
screen().getHeadX(h) + screen().getHeadWidth(h),
3306
screen().getHeadY(h),
3307
screen().getHeadY(h) + screen().getHeadHeight(h));
3310
snapToWindow(dx, dy, left, right, top, bottom,
3311
screen().maxLeft(0),
3312
screen().maxRight(0),
3314
screen().maxBottom(0));
3316
snapToWindow(dx, dy, left, right, top, bottom,
3317
screen().getHeadX(0),
3318
screen().getHeadX(0) + screen().getHeadWidth(0),
3319
screen().getHeadY(0),
3320
screen().getHeadY(0) + screen().getHeadHeight(0));
3324
/////////////////////////////////////
3325
// now check window edges
3327
Workspace::Windows &wins =
3328
screen().currentWorkspace()->windowList();
3330
Workspace::Windows::iterator it = wins.begin();
3331
Workspace::Windows::iterator it_end = wins.end();
3334
for (; it != it_end; it++) {
3336
continue; // skip myself
3338
bw = (*it)->decorationMask() & (DECORM_ENABLED|DECORM_BORDER|DECORM_HANDLE) ?
3339
(*it)->frame().window().borderWidth() : 0;
3341
snapToWindow(dx, dy, left, right, top, bottom,
3343
(*it)->x() + (*it)->width() + 2 * bw,
3345
(*it)->y() + (*it)->height() + 2 * bw);
3349
if (dx <= screen().getEdgeSnapThreshold())
3351
if (dy <= screen().getEdgeSnapThreshold())
3357
void FluxboxWindow::startResizing(Window win, int x, int y) {
3358
if (s_num_grabs > 0 || isShaded() || isIconic() )
3362
maximized = MAX_NONE;
3364
const Cursor& cursor = (m_resize_corner == LEFTTOP) ? frame().theme().upperLeftAngleCursor() :
3365
(m_resize_corner == RIGHTTOP) ? frame().theme().upperRightAngleCursor() :
3366
(m_resize_corner == RIGHTBOTTOM) ? frame().theme().lowerRightAngleCursor() :
3367
frame().theme().lowerLeftAngleCursor();
3369
grabPointer(win, false, ButtonMotionMask | ButtonReleaseMask,
3370
GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
3373
m_button_grab_x = x;
3374
m_button_grab_y = y;
3375
m_last_resize_x = frame().x();
3376
m_last_resize_y = frame().y();
3377
m_last_resize_w = frame().width();
3378
m_last_resize_h = frame().height();
3383
screen().showGeometry(gx, gy);
3385
parent().drawRectangle(screen().rootTheme().opGC(),
3386
m_last_resize_x, m_last_resize_y,
3387
m_last_resize_w - 1 + 2 * frame().window().borderWidth(),
3388
m_last_resize_h - 1 + 2 * frame().window().borderWidth());
3391
void FluxboxWindow::stopResizing(bool interrupted) {
3394
parent().drawRectangle(screen().rootTheme().opGC(),
3395
m_last_resize_x, m_last_resize_y,
3396
m_last_resize_w - 1 + 2 * frame().window().borderWidth(),
3397
m_last_resize_h - 1 + 2 * frame().window().borderWidth());
3399
screen().hideGeometry();
3404
moveResize(m_last_resize_x, m_last_resize_y,
3405
m_last_resize_w, m_last_resize_h);
3408
ungrabPointer(CurrentTime);
3411
void FluxboxWindow::attachTo(int x, int y, bool interrupted) {
3412
if (m_attaching_tab == 0)
3415
parent().drawRectangle(screen().rootTheme().opGC(),
3416
m_last_move_x, m_last_move_y,
3417
m_labelbuttons[m_attaching_tab]->width(),
3418
m_labelbuttons[m_attaching_tab]->height());
3420
ungrabPointer(CurrentTime);
3422
Fluxbox::instance()->ungrab();
3424
// make sure we clean up here, since this object may be deleted inside attachClient
3425
WinClient *old_attached = m_attaching_tab;
3426
m_attaching_tab = 0;
3431
int dest_x = 0, dest_y = 0;
3433
if (XTranslateCoordinates(display, parent().window(),
3435
x, y, &dest_x, &dest_y, &child)) {
3437
bool inside_titlebar = false;
3438
// search for a fluxboxwindow
3439
WinClient *client = Fluxbox::instance()->searchWindow(child);
3440
FluxboxWindow *attach_to_win = 0;
3443
inside_titlebar = client->fbwindow()->hasTitlebar() &&
3444
client->fbwindow()->y() + client->fbwindow()->titlebarHeight() > dest_y;
3446
Fluxbox::TabsAttachArea area= Fluxbox::instance()->getTabsAttachArea();
3447
if (area == Fluxbox::ATTACH_AREA_WINDOW)
3448
attach_to_win = client->fbwindow();
3449
else if (area == Fluxbox::ATTACH_AREA_TITLEBAR && inside_titlebar) {
3450
attach_to_win = client->fbwindow();
3454
if (attach_to_win != this &&
3455
attach_to_win != 0 && attach_to_win->isTabable()) {
3457
attach_to_win->attachClient(*old_attached,x,y );
3458
// we could be deleted here, DO NOT do anything else that alters this object
3459
} else if (attach_to_win != this || (attach_to_win == this && !inside_titlebar)) {
3460
// disconnect client if we didn't drop on a window
3461
WinClient &client = *old_attached;
3462
detachClient(*old_attached);
3463
// move window by relative amount of mouse movement
3464
// since just detached, move relative to old location
3465
if (client.fbwindow() != 0) {
3466
client.fbwindow()->move(frame().x() - m_last_resize_x + x, frame().y() - m_last_resize_y + y);
3467
client.fbwindow()->show();
3469
} else if( attach_to_win == this && attach_to_win->isTabable()) {
3470
//reording of tabs within a frame
3471
moveClientTo(*old_attached, x, y);
3476
void FluxboxWindow::restore(WinClient *client, bool remap) {
3477
if (client->fbwindow() != this)
3480
XChangeSaveSet(display, client->window(), SetModeDelete);
3481
client->setEventMask(NoEventMask);
3483
int wx = frame().x(), wy = frame().y(); // not actually used here
3484
frame().gravityTranslate(wx, wy, -client->gravity(), true); // negative to invert
3486
// Why was this hide done? It broke vncviewer (and mplayer?),
3487
// since it would reparent when going fullscreen.
3488
// is it needed for anything? Reparent should imply unmap
3489
// ok, it should hide sometimes, e.g. if the reparent was sent by a client
3492
// restore old border width
3493
client->setBorderWidth(client->old_bw);
3496
if (! XCheckTypedWindowEvent(display, client->window(), ReparentNotify,
3499
cerr<<"FluxboxWindow::restore: reparent 0x"<<hex<<client->window()<<dec<<" to root"<<endl;
3502
// reparent to root window
3503
client->reparent(screen().rootWindow(), frame().x(), frame().y(), false);
3512
installColormap(false);
3518
cerr<<"FluxboxWindow::restore: remap = "<<remap<<endl;
3519
cerr<<__FILE__<<"("<<__FUNCTION__<<"): numClients() = "<<numClients()<<endl;
3521
if (numClients() == 0) {
3527
void FluxboxWindow::restore(bool remap) {
3528
if (numClients() == 0)
3531
cerr<<"restore("<<remap<<")"<<endl;
3533
while (!clientList().empty()) {
3534
restore(clientList().back(), remap);
3535
// deleting winClient removes it from the clientList
3539
bool FluxboxWindow::isVisible() const {
3540
return frame().isVisible();
3543
FbTk::FbWindow &FluxboxWindow::fbWindow() {
3544
return frame().window();
3547
const FbTk::FbWindow &FluxboxWindow::fbWindow() const {
3548
return frame().window();
3551
FbTk::Menu &FluxboxWindow::menu() {
3552
return screen().windowMenu();
3555
const FbTk::Menu &FluxboxWindow::menu() const {
3556
return screen().windowMenu();
3559
unsigned int FluxboxWindow::titlebarHeight() const {
3560
return frame().titlebarHeight();
3563
Window FluxboxWindow::clientWindow() const {
3566
return m_client->window();
3569
const std::string &FluxboxWindow::title() const {
3570
static string empty_string("");
3572
return empty_string;
3573
return m_client->title();
3576
const std::string &FluxboxWindow::iconTitle() const {
3577
static string empty_string("");
3579
return empty_string;
3580
return m_client->iconTitle();
3583
int FluxboxWindow::initialState() const { return m_client->initial_state; }
3585
void FluxboxWindow::changeBlackboxHints(const BlackboxHints &net) {
3586
if ((net.flags & ATTRIB_SHADED) &&
3587
((m_blackbox_attrib.attrib & ATTRIB_SHADED) !=
3588
(net.attrib & ATTRIB_SHADED)))
3591
if ((net.flags & ATTRIB_HIDDEN) &&
3592
((m_blackbox_attrib.attrib & ATTRIB_HIDDEN) !=
3593
(net.attrib & ATTRIB_HIDDEN))) {
3594
bool want_iconic = net.attrib & ATTRIB_HIDDEN;
3595
if (!iconic && want_iconic)
3597
else if (iconic && !want_iconic)
3601
if (net.flags & (ATTRIB_MAXVERT | ATTRIB_MAXHORIZ)) {
3602
// make maximise look like the net maximise flags
3603
int want_max = MAX_NONE;
3605
if (net.flags & ATTRIB_MAXVERT)
3606
want_max |= MAX_VERT;
3607
if (net.flags & ATTRIB_MAXHORIZ)
3608
want_max |= MAX_HORZ;
3610
if (want_max == MAX_NONE && maximized != MAX_NONE) {
3612
} else if (want_max == MAX_FULL && maximized != MAX_FULL) {
3614
// horz and vert are a little trickier to morph
3617
// either we want vert and aren't
3618
// or we want horizontal, and are vertically (or full) at present
3619
if (want_max == MAX_VERT && !(maximized & MAX_VERT) ||
3620
want_max == MAX_HORZ && (maximized & MAX_VERT)) {
3623
// note that if we want horz, it WONT be vert any more from above
3624
if (want_max == MAX_HORZ && !(maximized & MAX_HORZ) ||
3625
want_max == MAX_VERT && (maximized & MAX_HORZ)) {
3630
if ((net.flags & ATTRIB_OMNIPRESENT) &&
3631
((m_blackbox_attrib.attrib & ATTRIB_OMNIPRESENT) !=
3632
(net.attrib & ATTRIB_OMNIPRESENT)))
3635
if ((net.flags & ATTRIB_WORKSPACE) &&
3636
(m_workspace_number != net.workspace)) {
3638
screen().reassociateWindow(this, net.workspace, true);
3640
if (screen().currentWorkspaceID() != net.workspace)
3646
if (net.flags & ATTRIB_STACK) {
3647
if ((unsigned int) m_layernum != net.stack) {
3648
moveToLayer(net.stack);
3652
if (net.flags & ATTRIB_DECORATION) {
3653
m_old_decoration = static_cast<Decoration>(net.decoration);
3654
setDecoration(m_old_decoration);
3660
void FluxboxWindow::fixsize(int *user_w, int *user_h) {
3661
int titlebar_height = (decorations.titlebar ?
3662
frame().titlebar().height() +
3663
frame().titlebar().borderWidth() : 0);
3664
int handle_height = (decorations.handle ?
3665
frame().handle().height() +
3666
frame().handle().borderWidth() : 0);
3667
int decoration_height = titlebar_height + handle_height;
3669
// dx is new width = current width + difference between new and old x values
3670
//int dx = frame().width() + frame().x() - m_last_resize_x;
3671
int dw = m_last_resize_w;
3673
// dy = new height (w/o decorations), similarly
3674
int dh = m_last_resize_h - decoration_height;
3676
m_client->applySizeHints(dw, dh, user_w, user_h);
3678
// update last resize
3679
m_last_resize_w = dw;
3680
m_last_resize_h = dh + decoration_height;
3682
// move X if necessary
3683
if (m_resize_corner == LEFTTOP || m_resize_corner == LEFTBOTTOM) {
3684
m_last_resize_x = frame().x() + frame().width() - m_last_resize_w;
3687
if (m_resize_corner == LEFTTOP || m_resize_corner == RIGHTTOP) {
3688
m_last_resize_y = frame().y() + frame().height() - m_last_resize_h;
3693
void FluxboxWindow::moveResizeClient(WinClient &client, int x, int y,
3694
unsigned int height, unsigned int width) {
3695
client.moveResize(x, y,
3696
frame().clientArea().width(),
3697
frame().clientArea().height());
3698
client.sendConfigureNotify(frame().x() + frame().clientArea().x(),
3699
frame().y() + frame().clientArea().y(),
3700
frame().clientArea().width(),
3701
frame().clientArea().height());
3704
void FluxboxWindow::sendConfigureNotify(bool send_to_netizens) {
3705
ClientList::iterator client_it = m_clientlist.begin();
3706
ClientList::iterator client_it_end = m_clientlist.end();
3707
for (; client_it != client_it_end; ++client_it) {
3708
WinClient &client = *(*client_it);
3710
Send event telling where the root position
3711
of the client window is. (ie frame pos + client pos inside the frame = send pos)
3714
client.x = frame().x();
3715
client.y = frame().y();
3716
moveResizeClient(client,
3717
frame().clientArea().x(),
3718
frame().clientArea().y(),
3719
frame().clientArea().width(),
3720
frame().clientArea().height());
3722
if (send_to_netizens) {
3724
event.type = ConfigureNotify;
3726
event.xconfigure.display = display;
3727
event.xconfigure.event = client.window();
3728
event.xconfigure.window = client.window();
3729
event.xconfigure.x = frame().x() + frame().clientArea().x();
3730
event.xconfigure.y = frame().y() + frame().clientArea().y();
3731
event.xconfigure.width = client.width();
3732
event.xconfigure.height = client.height();
3733
event.xconfigure.border_width = client.old_bw;
3734
event.xconfigure.above = frame().window().window();
3735
event.xconfigure.override_redirect = false;
3737
screen().updateNetizenConfigNotify(event);
3743
void FluxboxWindow::close() {
3745
m_client->sendClose(false);
3748
void FluxboxWindow::kill() {
3750
m_client->sendClose(true);
3753
void FluxboxWindow::setupWindow() {
3754
// sets up our window
3755
// we allow both to be done at once to share the commands
3757
WinButtonTheme &winbutton_theme = screen().winButtonTheme();
3759
using namespace FbTk;
3760
typedef RefCount<Command> CommandRef;
3761
typedef SimpleCommand<FluxboxWindow> WindowCmd;
3763
CommandRef iconify_cmd(new WindowCmd(*this, &FluxboxWindow::iconify));
3764
CommandRef maximize_cmd(new WindowCmd(*this, &FluxboxWindow::maximizeFull));
3765
CommandRef maximize_vert_cmd(new WindowCmd(*this, &FluxboxWindow::maximizeVertical));
3766
CommandRef maximize_horiz_cmd(new WindowCmd(*this, &FluxboxWindow::maximizeHorizontal));
3767
CommandRef close_cmd(new WindowCmd(*this, &FluxboxWindow::close));
3768
CommandRef shade_cmd(new WindowCmd(*this, &FluxboxWindow::shade));
3769
CommandRef shade_on_cmd(new WindowCmd(*this, &FluxboxWindow::shadeOn));
3770
CommandRef shade_off_cmd(new WindowCmd(*this, &FluxboxWindow::shadeOff));
3771
CommandRef next_tab_cmd(new WindowCmd(*this, &FluxboxWindow::nextClient));
3772
CommandRef prev_tab_cmd(new WindowCmd(*this, &FluxboxWindow::prevClient));
3773
CommandRef raise_cmd(new WindowCmd(*this, &FluxboxWindow::raise));
3774
CommandRef lower_cmd(new WindowCmd(*this, &FluxboxWindow::lower));
3775
CommandRef raise_and_focus_cmd(new WindowCmd(*this, &FluxboxWindow::raiseAndFocus));
3776
CommandRef stick_cmd(new WindowCmd(*this, &FluxboxWindow::stick));
3777
CommandRef show_menu_cmd(new WindowCmd(*this, &FluxboxWindow::popupMenu));
3779
// clear old buttons from frame
3780
frame().removeAllButtons();
3781
//!! TODO: fix this ugly hack
3782
// get titlebar configuration
3783
const vector<Fluxbox::Titlebar> *dir = &Fluxbox::instance()->getTitlebarLeft();
3784
for (char c=0; c<2; c++) {
3785
for (size_t i=0; i< dir->size(); ++i) {
3786
//create new buttons
3787
FbTk::Button *newbutton = 0;
3788
if (isIconifiable() && (*dir)[i] == Fluxbox::MINIMIZE) {
3789
newbutton = new WinButton(*this, winbutton_theme,
3790
WinButton::MINIMIZE,
3793
newbutton->setOnClick(iconify_cmd);
3795
} else if (isMaximizable() && (*dir)[i] == Fluxbox::MAXIMIZE) {
3796
newbutton = new WinButton(*this, winbutton_theme,
3797
WinButton::MAXIMIZE,
3801
newbutton->setOnClick(maximize_cmd, 1);
3802
newbutton->setOnClick(maximize_horiz_cmd, 3);
3803
newbutton->setOnClick(maximize_vert_cmd, 2);
3805
} else if (m_client->isClosable() && (*dir)[i] == Fluxbox::CLOSE) {
3806
newbutton = new WinButton(*this, winbutton_theme,
3811
newbutton->setOnClick(close_cmd);
3813
} else if ((*dir)[i] == Fluxbox::STICK) {
3814
WinButton *winbtn = new WinButton(*this, winbutton_theme,
3818
stateSig().attach(winbtn);
3819
winbtn->setOnClick(stick_cmd);
3821
} else if ((*dir)[i] == Fluxbox::SHADE) {
3822
WinButton *winbtn = new WinButton(*this, winbutton_theme,
3826
stateSig().attach(winbtn);
3827
winbtn->setOnClick(shade_cmd);
3829
} else if ((*dir)[i] == Fluxbox::MENUICON) {
3830
WinButton* winbtn = new WinButton(*this, winbutton_theme,
3831
WinButton::MENUICON,
3834
hintSig().attach(winbtn);
3835
titleSig().attach(winbtn);
3836
winbtn->setOnClick(show_menu_cmd);
3840
if (newbutton != 0) {
3843
frame().addLeftButton(newbutton);
3845
frame().addRightButton(newbutton);
3848
dir = &Fluxbox::instance()->getTitlebarRight();
3851
frame().reconfigure();
3854
frame().setOnClickTitlebar(raise_and_focus_cmd, 1, false, true); // on press with button 1
3855
frame().setOnClickTitlebar(shade_cmd, 1, true); // doubleclick with button 1
3856
frame().setOnClickTitlebar(show_menu_cmd, 3); // on release with button 3
3857
frame().setOnClickTitlebar(lower_cmd, 2); // on release with button 2
3860
if (screen().getScrollReverse())
3863
if (StringUtil::toLower(screen().getScrollAction()) == std::string("shade")) {
3864
frame().setOnClickTitlebar(shade_on_cmd, 5 - reverse); // shade on mouse roll
3865
frame().setOnClickTitlebar(shade_off_cmd, 4 + reverse); // unshade if rolled oposite direction
3866
} else if (StringUtil::toLower(screen().getScrollAction()) == std::string("nexttab")) {
3867
frame().setOnClickTitlebar(next_tab_cmd, 5 - reverse); // next tab
3868
frame().setOnClickTitlebar(prev_tab_cmd, 4 + reverse); // previous tab
3871
frame().setDoubleClickTime(Fluxbox::instance()->getDoubleClickInterval());
3879
* reconfigTheme: must be called after frame is reconfigured
3880
* Client windows need to be made the same size and location as
3881
* the frame's client area.
3883
void FluxboxWindow::reconfigTheme() {
3885
m_frame.setBorderWidth(decorations.border ?
3886
frame().theme().border().width() : 0);
3887
if (decorations.handle && frame().theme().handleWidth() != 0)
3888
frame().showHandle();
3890
frame().hideHandle();
3892
ClientList::iterator it = clientList().begin();
3893
ClientList::iterator it_end = clientList().end();
3895
int x = m_frame.clientArea().x(),
3896
y = m_frame.clientArea().y();
3898
unsigned int width = m_frame.clientArea().width(),
3899
height = m_frame.clientArea().height();
3901
for (; it != it_end; ++it) {
3902
(*it)->moveResize(x, y, width, height);
3905
sendConfigureNotify();
3908
// grab pointer and increase counter.
3909
// we need this to count grab pointers,
3910
// especially at startup, where we can drag/resize while starting
3911
// and causing it to send events to windows later on and make
3912
// two different windows do grab pointer which only one window
3913
// should do at the time
3914
void FluxboxWindow::grabPointer(Window grab_window,
3916
unsigned int event_mask,
3917
int pointer_mode, int keyboard_mode,
3921
XGrabPointer(FbTk::App::instance()->display(),
3925
pointer_mode, keyboard_mode,
3932
// ungrab and decrease counter
3933
void FluxboxWindow::ungrabPointer(Time time) {
3934
XUngrabPointer(FbTk::App::instance()->display(), time);
3936
if (s_num_grabs < 0)
3940
void FluxboxWindow::associateClient(WinClient &client) {
3942
FbWinFrame::ButtonId btn = frame().createTab(client.title(),
3943
new SetClientCmd(client));
3945
m_labelbuttons[&client] = btn;
3948
FbTk::EventManager &evm = *FbTk::EventManager::instance();
3950
evm.add(*this, btn->window()); // we take care of button events for this
3951
evm.add(*this, client.window());
3952
client.setFluxboxWindow(this);