~ubuntu-branches/ubuntu/precise/fluxbox/precise

« back to all changes in this revision

Viewing changes to src/Window.cc

  • Committer: Bazaar Package Importer
  • Author(s): Dmitry E. Oboukhov
  • Date: 2008-07-01 10:38:14 UTC
  • mfrom: (2.1.12 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080701103814-khx2b6il152x9p93
Tags: 1.0.0+deb1-8
* x-dev has been removed from build-depends (out-of-date package).
* Standards-Version bumped to 3.8.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Window.cc for Fluxbox Window Manager
2
 
// Copyright (c) 2001 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
3
 
//
4
 
// Window.cc for Blackbox - an X11 Window manager
5
 
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
6
 
//
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:
13
 
//
14
 
// The above copyright notice and this permission notice shall be included in
15
 
// all copies or substantial portions of the Software.
16
 
//
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.
24
 
 
25
 
// $Id: Window.cc 4102 2005-09-08 00:41:05Z simonb $
26
 
 
27
 
#include "Window.hh"
28
 
 
29
 
#include "WinClient.hh"
30
 
#include "fluxbox.hh"
31
 
#include "Screen.hh"
32
 
#include "FbWinFrameTheme.hh"
33
 
#include "FbAtoms.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"
43
 
 
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"
51
 
 
52
 
#ifdef HAVE_CONFIG_H
53
 
#include "config.h"
54
 
#endif // HAVE_CONFIG_H
55
 
#ifdef SHAPE
56
 
#include <X11/extensions/shape.h>
57
 
#endif // SHAPE
58
 
 
59
 
//use GNU extensions
60
 
#ifndef  _GNU_SOURCE
61
 
#define  _GNU_SOURCE
62
 
#endif // _GNU_SOURCE
63
 
 
64
 
#include <X11/Xatom.h>
65
 
#include <X11/keysym.h>
66
 
 
67
 
#ifdef HAVE_CSTRING
68
 
  #include <cstring>
69
 
#else
70
 
  #include <string.h>
71
 
#endif
72
 
#ifdef HAVE_CSTDIO
73
 
  #include <cstdio>
74
 
#else
75
 
  #include <stdio.h>
76
 
#endif
77
 
#include <iostream>
78
 
#ifdef HAVE_CASSERT
79
 
  #include <cassert>
80
 
#else
81
 
  #include <assert.h>
82
 
#endif
83
 
#include <functional>
84
 
#include <algorithm>
85
 
 
86
 
using namespace std;
87
 
using namespace FbTk;
88
 
 
89
 
namespace {
90
 
 
91
 
void grabButton(unsigned int button,
92
 
                Window window, Cursor cursor) {
93
 
 
94
 
    static Display *display = App::instance()->display();
95
 
 
96
 
    const int numlock = KeyUtil::instance().numlock();
97
 
    const int capslock = KeyUtil::instance().capslock();
98
 
    const int scrolllock = KeyUtil::instance().scrolllock();
99
 
 
100
 
    // Grab with Mod1 and with all lock modifiers
101
 
    // (num, scroll and caps)
102
 
 
103
 
    //numlock
104
 
    XGrabButton(display, button, Mod1Mask|numlock, window, True,
105
 
                ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
106
 
                GrabModeAsync, None, cursor);
107
 
    //scrolllock
108
 
    XGrabButton(display, button, Mod1Mask|scrolllock, window, True,
109
 
                ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
110
 
                GrabModeAsync, None, cursor);
111
 
 
112
 
    //capslock
113
 
    XGrabButton(display, button, Mod1Mask|capslock, window, True,
114
 
                ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
115
 
                GrabModeAsync, None, cursor);
116
 
 
117
 
    //capslock+numlock
118
 
    XGrabButton(display, Button1, Mod1Mask|capslock|numlock, window, True,
119
 
                ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
120
 
                GrabModeAsync, None, cursor);
121
 
 
122
 
    //capslock+scrolllock
123
 
    XGrabButton(display, button, Mod1Mask|capslock|scrolllock, window, True,
124
 
                ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
125
 
                GrabModeAsync, None, cursor);
126
 
 
127
 
    //capslock+numlock+scrolllock
128
 
    XGrabButton(display, button, Mod1Mask|capslock|numlock|scrolllock, window,
129
 
                True,
130
 
                ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
131
 
                GrabModeAsync, None, cursor);
132
 
 
133
 
    //numlock+scrollLock
134
 
    XGrabButton(display, button, Mod1Mask|numlock|scrolllock, window, True,
135
 
                ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
136
 
                GrabModeAsync, None, cursor);
137
 
 
138
 
}
139
 
 
140
 
// X event scanner for enter/leave notifies - adapted from twm
141
 
typedef struct scanargs {
142
 
    Window w;
143
 
    Bool leave, inferior, enter;
144
 
} scanargs;
145
 
 
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;
156
 
 
157
 
    return false;
158
 
}
159
 
 
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();
165
 
    }
166
 
    return client;
167
 
}
168
 
 
169
 
 
170
 
/// raise window and do the same for each transient of the current window
171
 
void raiseFluxboxWindow(FluxboxWindow &win) {
172
 
    if (win.oplock) 
173
 
        return;
174
 
 
175
 
    win.oplock = true;
176
 
 
177
 
 
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();
182
 
 
183
 
    if (!win.isIconic()) {
184
 
        win.screen().updateNetizenWindowRaise(win.clientWindow());
185
 
        win.layerItem().raise();
186
 
    }
187
 
 
188
 
    // for each transient do raise
189
 
    
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());
196
 
    }
197
 
    
198
 
    win.oplock = false;
199
 
 
200
 
 
201
 
    if (!win.winClient().transientList().empty())
202
 
        win.screen().layerManager().unlock();
203
 
 
204
 
}
205
 
 
206
 
/// lower window and do the same for each transient it holds
207
 
void lowerFluxboxWindow(FluxboxWindow &win) {
208
 
    if (win.oplock) 
209
 
        return;
210
 
 
211
 
    win.oplock = true;
212
 
 
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();
217
 
 
218
 
    if (!win.isIconic()) {
219
 
        win.screen().updateNetizenWindowLower(win.clientWindow());
220
 
        win.layerItem().lower();
221
 
    }
222
 
 
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());
229
 
    }
230
 
    win.oplock = false;
231
 
    if (!win.winClient().transientList().empty())
232
 
        win.screen().layerManager().unlock();
233
 
 
234
 
}
235
 
 
236
 
/// raise window and do the same for each transient it holds
237
 
void tempRaiseFluxboxWindow(FluxboxWindow &win) {
238
 
    if (win.oplock) return;
239
 
    win.oplock = true;
240
 
 
241
 
    if (!win.winClient().transientList().empty())
242
 
        win.screen().layerManager().lock();
243
 
 
244
 
    if (!win.isIconic()) {
245
 
        // don't update netizen, as it is only temporary
246
 
        win.layerItem().tempRaise();
247
 
    }
248
 
 
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());
256
 
    }
257
 
    win.oplock = false;
258
 
 
259
 
    if (!win.winClient().transientList().empty())
260
 
        win.screen().layerManager().unlock();
261
 
 
262
 
}
263
 
 
264
 
class SetClientCmd:public FbTk::Command {
265
 
public:
266
 
    explicit SetClientCmd(WinClient &client):m_client(client) {
267
 
    }
268
 
    void execute() {
269
 
        if (m_client.fbwindow() != 0)
270
 
            m_client.fbwindow()->setCurrentClient(m_client);
271
 
    }
272
 
private:
273
 
    WinClient &m_client;
274
 
};
275
 
 
276
 
};
277
 
 
278
 
 
279
 
int FluxboxWindow::s_num_grabs = 0;
280
 
 
281
 
FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm,
282
 
                             FbTk::XLayer &layer):
283
 
    oplock(false),
284
 
    m_hintsig(*this),
285
 
    m_statesig(*this),
286
 
    m_layersig(*this),
287
 
    m_workspacesig(*this),
288
 
    m_diesig(*this),
289
 
    m_focussig(*this),
290
 
    m_titlesig(*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),
295
 
    maximized(MAX_NONE),
296
 
    m_attaching_tab(0),
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),
303
 
    m_current_state(0),
304
 
    m_old_decoration(DECOR_NORMAL),
305
 
    m_old_decoration_mask(0),
306
 
    m_client(&client),
307
 
    m_toggled_decos(false),
308
 
    m_shaped(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()),
316
 
    m_old_layernum(0),
317
 
    m_parent(client.screen().rootWindow()),
318
 
    m_resize_corner(RIGHTBOTTOM) {
319
 
 
320
 
    tm.reconfigSig().attach(&m_themelistener);
321
 
 
322
 
    init();
323
 
}
324
 
 
325
 
 
326
 
FluxboxWindow::~FluxboxWindow() {
327
 
    if (WindowCmd<void>::window() == this)
328
 
        WindowCmd<void>::setWindow(0);
329
 
 
330
 
#ifdef DEBUG
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;
335
 
#endif // DEBUG
336
 
 
337
 
    if (moving)
338
 
        stopMoving(true);
339
 
    if (resizing)
340
 
        stopResizing(true);
341
 
    if (m_attaching_tab)
342
 
        attachTo(0, 0, true);
343
 
 
344
 
    // no longer a valid window to do stuff with
345
 
    Fluxbox::instance()->removeWindowSearchGroup(frame().window().window());
346
 
 
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);
351
 
 
352
 
    m_labelbuttons.clear();
353
 
 
354
 
    m_timer.stop();
355
 
 
356
 
    // notify die
357
 
    m_diesig.notify();
358
 
 
359
 
    if (m_client != 0)
360
 
        delete m_client; // this also removes client from our list
361
 
    m_client = 0;
362
 
 
363
 
    if (m_clientlist.size() > 1) {
364
 
        cerr<<__FILE__<<"(~FluxboxWindow()) WARNING! clientlist > 1"<<endl;
365
 
        while (!m_clientlist.empty()) {
366
 
            detachClient(*m_clientlist.back());
367
 
        }
368
 
    }
369
 
 
370
 
    // deal with extra menus
371
 
#ifdef DEBUG
372
 
    cerr<<__FILE__<<"("<<__LINE__<<"): ~FluxboxWindow("<<this<<")"<<endl;
373
 
#endif // DEBUG
374
 
}
375
 
 
376
 
 
377
 
void FluxboxWindow::init() {
378
 
    m_attaching_tab = 0;
379
 
    // magic to detect if moved by hints
380
 
    m_old_pos_x = 0;
381
 
 
382
 
    assert(m_client);
383
 
    m_client->setFluxboxWindow(this);
384
 
    m_client->setGroupLeftWindow(None); // nothing to the left.
385
 
 
386
 
    // check for shape extension and whether the window is shaped
387
 
    m_shaped = false;
388
 
 
389
 
    if (Fluxbox::instance()->haveShape()) {
390
 
        Shape::setShapeNotify(winClient());
391
 
        m_shaped = Shape::isShaped(winClient());
392
 
    }
393
 
 
394
 
    frame().setUseShape(!m_shaped);
395
 
 
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);
399
 
#ifdef DEBUG
400
 
    cerr<<__FILE__<<": FluxboxWindow::init(this="<<this<<", client="<<hex<<
401
 
        m_client->window()<<", frame = "<<frame().window().window()<<dec<<")"<<endl;
402
 
 
403
 
#endif // DEBUG
404
 
 
405
 
    Fluxbox &fluxbox = *Fluxbox::instance();
406
 
 
407
 
    // setup cursors for resize grips
408
 
    frame().gripLeft().setCursor(frame().theme().lowerLeftAngleCursor());
409
 
    frame().gripRight().setCursor(frame().theme().lowerRightAngleCursor());
410
 
 
411
 
    associateClient(*m_client);
412
 
 
413
 
    frame().setLabelButtonFocus(*m_labelbuttons[m_client]);
414
 
 
415
 
    // redirect events from frame to us
416
 
    frame().setEventHandler(*this);
417
 
 
418
 
    frame().resize(m_client->width(), m_client->height());
419
 
 
420
 
    m_last_focus_time.tv_sec = m_last_focus_time.tv_usec = 0;
421
 
 
422
 
    m_blackbox_attrib.workspace = m_workspace_number = ~0;
423
 
 
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;
427
 
 
428
 
    //use tab as default
429
 
    decorations.tab = true;
430
 
    // enable decorations
431
 
    decorations.enabled = true;
432
 
 
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;
439
 
 
440
 
 
441
 
    functions.resize = functions.move = functions.iconify = functions.maximize = functions.tabable = true;
442
 
    decorations.close = false;
443
 
 
444
 
    if (m_client->getBlackboxHint() != 0)
445
 
        updateBlackboxHintsFromClient(*m_client);
446
 
    else
447
 
        updateMWMHintsFromClient(*m_client);
448
 
 
449
 
    //!!
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
456
 
        return;
457
 
 
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;
461
 
 
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);
467
 
 
468
 
    Fluxbox::instance()->saveWindowSearchGroup(frame().window().window(), this);
469
 
 
470
 
    /**************************************************/
471
 
    /* Read state above here, apply state below here. */
472
 
    /**************************************************/
473
 
 
474
 
    // update transient infomation
475
 
    m_client->updateTransientInfo();
476
 
 
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;
481
 
    }
482
 
 
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
490
 
    }
491
 
 
492
 
    associateClientWindow(true, wattrib.x, wattrib.y, wattrib.width, wattrib.height);
493
 
 
494
 
    
495
 
    Fluxbox::instance()->attachSignals(*this);
496
 
 
497
 
    // this window is managed, we are now allowed to modify actual state
498
 
    m_initialized = true;
499
 
 
500
 
 
501
 
    applyDecorations(true);
502
 
 
503
 
    grabButtons();
504
 
 
505
 
    restoreAttributes();
506
 
 
507
 
    if (m_workspace_number < 0 || m_workspace_number >= screen().numberOfWorkspaces())
508
 
        m_workspace_number = screen().currentWorkspaceID();
509
 
 
510
 
    bool place_window = (m_old_pos_x == 0);
511
 
    if (fluxbox.isStartup() || m_client->isTransient() ||
512
 
        m_client->normal_hint_flags & (PPosition|USPosition)) {
513
 
 
514
 
        frame().gravityTranslate(wattrib.x, wattrib.y, m_client->gravity(), false);
515
 
 
516
 
        if (! fluxbox.isStartup()) {
517
 
 
518
 
            int real_x = frame().x();
519
 
            int real_y = frame().y();
520
 
 
521
 
            if (real_x >= 0 &&
522
 
                real_y + frame().y() >= 0 &&
523
 
                real_x <= (signed) screen().width() &&
524
 
                real_y <= (signed) screen().height())
525
 
                place_window = false;
526
 
 
527
 
        } else
528
 
            place_window = false;
529
 
 
530
 
    }
531
 
    if (wattrib.width <= 0)
532
 
        wattrib.width = 1;
533
 
    if (wattrib.height <= 0)
534
 
        wattrib.height = 1;
535
 
 
536
 
 
537
 
 
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);
545
 
#ifdef DEBUG
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;
551
 
    }
552
 
#endif // DEBUG
553
 
 
554
 
 
555
 
    if (!place_window)
556
 
        moveResize(frame().x(), frame().y(), frame().width(), frame().height());
557
 
 
558
 
    screen().getWorkspace(m_workspace_number)->addWindow(*this, place_window);
559
 
    setWorkspace(m_workspace_number);
560
 
 
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);
567
 
    }
568
 
 
569
 
    if (stuck) {
570
 
        stuck = false;
571
 
        stick();
572
 
        deiconify(); //we're omnipresent and visible
573
 
    }
574
 
 
575
 
    if (shaded) { // start shaded
576
 
        shaded = false;
577
 
        shade();
578
 
    }
579
 
 
580
 
    if (iconic) {
581
 
        iconic = false;
582
 
        iconify();
583
 
    }
584
 
 
585
 
    sendConfigureNotify();
586
 
    // no focus default
587
 
    setFocusFlag(false);
588
 
 
589
 
    if (m_shaped)
590
 
        shape();
591
 
 
592
 
    setupWindow();
593
 
 
594
 
    FbTk::App::instance()->sync(false);
595
 
 
596
 
}
597
 
 
598
 
/// apply shape to this window
599
 
void FluxboxWindow::shape() {
600
 
#ifdef SHAPE
601
 
    if (m_shaped) {
602
 
        XShapeCombineShape(display,
603
 
                           frame().window().window(), ShapeBounding,
604
 
                           0, frame().clientArea().y(), // xOff, yOff
605
 
                           m_client->window(),
606
 
                           ShapeBounding, ShapeSet);
607
 
        XFlush(display);
608
 
    }
609
 
#endif // SHAPE
610
 
 
611
 
}
612
 
 
613
 
 
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)
618
 
        return;
619
 
 
620
 
    menu().hide();
621
 
 
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();
627
 
 
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();
632
 
 
633
 
    client.setGroupLeftWindow(leftwin);
634
 
 
635
 
    if (client.fbwindow() != 0) {
636
 
        FluxboxWindow *old_win = client.fbwindow(); // store old window
637
 
 
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];
642
 
        
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;
651
 
 
652
 
            moveResizeClient(**client_it,
653
 
                             frame().clientArea().x(),
654
 
                             frame().clientArea().y(),
655
 
                             frame().clientArea().width(),
656
 
                             frame().clientArea().height());
657
 
 
658
 
            // create a labelbutton for this client and
659
 
            // associate it with the pointer
660
 
            associateClient(*(*client_it));
661
 
            
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);
665
 
 
666
 
            (*client_it)->saveBlackboxAttribs(m_blackbox_attrib);
667
 
        }
668
 
        
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;
674
 
 
675
 
        delete old_win;
676
 
 
677
 
    } else { // client.fbwindow() == 0
678
 
        associateClient(client);
679
 
 
680
 
        if (&client == focused_win)
681
 
            was_focused = focused_win;
682
 
 
683
 
        client.saveBlackboxAttribs(m_blackbox_attrib);
684
 
        m_clientlist.push_back(&client);
685
 
    }
686
 
 
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
690
 
    m_statesig.notify();
691
 
    m_workspacesig.notify();
692
 
    m_layersig.notify();
693
 
 
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);
698
 
    }
699
 
 
700
 
    frame().reconfigure();
701
 
 
702
 
    // keep the current window on top
703
 
    m_client->raise();
704
 
}
705
 
 
706
 
 
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)
710
 
        return false;
711
 
 
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
719
 
 
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()) {
726
 
        ++client_it_after;
727
 
        if (clientList().front() == &client) {
728
 
            leftwin = None;
729
 
        } else {
730
 
            ++client_it;
731
 
            client_it_before = clientList().begin();
732
 
            ++client_it_after;
733
 
 
734
 
            while (client_it != client_it_end) {
735
 
                if (*client_it == &client) {
736
 
                    break;
737
 
                }
738
 
                ++client_it_before;
739
 
                ++client_it;
740
 
                ++client_it_after;
741
 
            }
742
 
        }
743
 
    }
744
 
 
745
 
    // update the leftwin of the window to the right
746
 
    if (client_it_before != client_it_end)
747
 
        leftwin = (*client_it_before)->window();
748
 
 
749
 
    if (client_it_after != client_it_end)
750
 
        (*client_it_after)->setGroupLeftWindow(leftwin);
751
 
 
752
 
    removeClient(client);
753
 
 
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));
757
 
    m_client->raise();
758
 
    setInputFocus();
759
 
    return true;
760
 
}
761
 
 
762
 
void FluxboxWindow::detachCurrentClient() {
763
 
    // should only operate if we had more than one client
764
 
    if (numClients() <= 1)
765
 
        return;
766
 
    detachClient(*m_client);
767
 
}
768
 
 
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)
772
 
        return false;
773
 
 
774
 
#ifdef DEBUG
775
 
    cerr<<__FILE__<<"("<<__FUNCTION__<<")["<<this<<"]"<<endl;
776
 
#endif // DEBUG
777
 
 
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);
783
 
    }
784
 
 
785
 
    menu().hide();
786
 
 
787
 
    m_clientlist.remove(&client);
788
 
 
789
 
    if (m_client == &client) {
790
 
        if (m_clientlist.empty())
791
 
            m_client = 0;
792
 
        else
793
 
            // this really shouldn't happen
794
 
            m_client = m_clientlist.back();
795
 
    }
796
 
 
797
 
    FbTk::EventManager &evm = *FbTk::EventManager::instance();
798
 
    evm.remove(client.window());
799
 
 
800
 
    FbTk::TextButton *label_btn = m_labelbuttons[&client];
801
 
    if (label_btn != 0) {
802
 
        frame().removeTab(label_btn);
803
 
        label_btn = 0;
804
 
    }
805
 
 
806
 
    m_labelbuttons.erase(&client);
807
 
    frame().reconfigure();
808
 
    updateClientLeftWindow();
809
 
 
810
 
#ifdef DEBUG
811
 
    cerr<<__FILE__<<"("<<__FUNCTION__<<")["<<this<<"] numClients = "<<numClients()<<endl;
812
 
#endif // DEBUG
813
 
 
814
 
    return true;
815
 
}
816
 
 
817
 
/// returns WinClient of window we're searching for
818
 
WinClient *FluxboxWindow::findClient(Window win) {
819
 
    ClientList::iterator it = find_if(clientList().begin(),
820
 
                                      clientList().end(),
821
 
                                      Compose(bind2nd(equal_to<Window>(), win),
822
 
                                              mem_fun(&WinClient::window)));
823
 
    return (it == clientList().end() ? 0 : *it);
824
 
}
825
 
 
826
 
/// raise and focus next client
827
 
void FluxboxWindow::nextClient() {
828
 
    if (numClients() <= 1)
829
 
        return;
830
 
 
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();
835
 
    } else {
836
 
        it++;
837
 
        if (it == m_clientlist.end())
838
 
            client = m_clientlist.front();
839
 
        else
840
 
            client = *it;
841
 
    }
842
 
    setCurrentClient(*client, true);
843
 
}
844
 
 
845
 
void FluxboxWindow::prevClient() {
846
 
    if (numClients() <= 1)
847
 
        return;
848
 
 
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();
853
 
    } else {
854
 
        if (it == m_clientlist.begin())
855
 
            client = m_clientlist.back();
856
 
        else
857
 
            client = *(--it);
858
 
    }
859
 
 
860
 
    setCurrentClient(*client, true);
861
 
}
862
 
 
863
 
 
864
 
void FluxboxWindow::moveClientLeft() {
865
 
    if (m_clientlist.size() == 1 ||
866
 
        *m_clientlist.begin() == &winClient())
867
 
        return;
868
 
    
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()]);
874
 
 
875
 
    updateClientLeftWindow();
876
 
 
877
 
}
878
 
 
879
 
void FluxboxWindow::moveClientRight() {
880
 
    if (m_clientlist.size() == 1 ||
881
 
        *m_clientlist.rbegin() == &winClient())
882
 
        return;
883
 
    
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()]);
888
 
 
889
 
    updateClientLeftWindow();
890
 
}
891
 
 
892
 
//std::list<*WinClient>::iterator FluxboxWindow::getClientInsertPosition(int x, int y) {
893
 
FluxboxWindow::ClientList::iterator FluxboxWindow::getClientInsertPosition(int x, int y) {
894
 
 
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,
900
 
                               &labelbutton))
901
 
        return m_clientlist.end();
902
 
 
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>())));
909
 
 
910
 
 
911
 
    // label button not found
912
 
    if (it == m_labelbuttons.end())
913
 
        return m_clientlist.end();
914
 
 
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,
920
 
                               &child_return))
921
 
        return m_clientlist.end();
922
 
 
923
 
    ClientList::iterator client = find(m_clientlist.begin(),
924
 
                                       m_clientlist.end(),
925
 
                                       it->first);
926
 
    if (x > (*it).second->width() / 2)
927
 
        client++;
928
 
 
929
 
    return client;
930
 
 
931
 
}
932
 
        
933
 
 
934
 
 
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,
941
 
                               &labelbutton))
942
 
        return;
943
 
 
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>())));
950
 
 
951
 
    // label button not found
952
 
    if (it == m_labelbuttons.end())
953
 
        return;
954
 
 
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,
960
 
                               &child_return))
961
 
        return;
962
 
    if (x > (*it).second->width() / 2)
963
 
        moveClientRightOf(win, *it->first);
964
 
    else
965
 
        moveClientLeftOf(win, *it->first);
966
 
 
967
 
}
968
 
 
969
 
 
970
 
void FluxboxWindow::moveClientLeftOf(WinClient &win, WinClient &dest) {
971
 
        
972
 
        frame().moveLabelButtonLeftOf(*m_labelbuttons[&win], *m_labelbuttons[&dest]);
973
 
        
974
 
        ClientList::iterator it = find(m_clientlist.begin(),
975
 
                                  m_clientlist.end(),
976
 
                                  &win);
977
 
        ClientList::iterator new_pos = find(m_clientlist.begin(),
978
 
                                       m_clientlist.end(),
979
 
                                       &dest);
980
 
 
981
 
        // make sure we found them
982
 
        if (it == m_clientlist.end() || new_pos==m_clientlist.end()) {
983
 
                return;
984
 
        }
985
 
        //moving a button to the left of itself results in no change
986
 
        if( new_pos == it) {
987
 
                return;
988
 
        }
989
 
        //remove from list
990
 
        m_clientlist.erase(it);
991
 
        //insert on the new place
992
 
        m_clientlist.insert(new_pos, &win);
993
 
        
994
 
        updateClientLeftWindow();
995
 
}
996
 
 
997
 
 
998
 
void FluxboxWindow::moveClientRightOf(WinClient &win, WinClient &dest) {
999
 
        frame().moveLabelButtonRightOf(*m_labelbuttons[&win], *m_labelbuttons[&dest]);
1000
 
 
1001
 
        ClientList::iterator it = find(m_clientlist.begin(),
1002
 
                                  m_clientlist.end(),
1003
 
                                  &win);
1004
 
        ClientList::iterator new_pos = find(m_clientlist.begin(),
1005
 
                                       m_clientlist.end(),
1006
 
                                       &dest);
1007
 
 
1008
 
        // make sure we found them
1009
 
        if (it == m_clientlist.end() || new_pos==m_clientlist.end()) {
1010
 
                return;
1011
 
        }
1012
 
        //moving a button to the right of itself results in no change
1013
 
        if( new_pos == it) {
1014
 
                return;
1015
 
        }
1016
 
        //remove from list
1017
 
        m_clientlist.erase(it);
1018
 
        //need to insert into the next position
1019
 
        new_pos++;
1020
 
        //insert on the new place
1021
 
        if(new_pos == m_clientlist.end())
1022
 
                m_clientlist.push_back(&win);
1023
 
        else
1024
 
                m_clientlist.insert(new_pos, &win);
1025
 
        
1026
 
        updateClientLeftWindow();
1027
 
}
1028
 
 
1029
 
/// Update LEFT window atom on all clients.
1030
 
void FluxboxWindow::updateClientLeftWindow() {
1031
 
    if (clientList().empty())
1032
 
        return;
1033
 
 
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
1038
 
    // implement.
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;
1044
 
    ++it;
1045
 
    for (; it != it_end; ++it) {
1046
 
        (*it)->setGroupLeftWindow(last_client->window());
1047
 
        last_client = *it;
1048
 
    }
1049
 
}
1050
 
 
1051
 
bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
1052
 
    // make sure it's in our list
1053
 
    if (client.fbwindow() != this)
1054
 
        return false;
1055
 
 
1056
 
    m_client = &client;
1057
 
    m_client->raise();
1058
 
    titleSig().notify();
1059
 
 
1060
 
#ifdef DEBUG
1061
 
    cerr<<"FluxboxWindow::"<<__FUNCTION__<<": labelbutton[client] = "<<
1062
 
        m_labelbuttons[m_client]<<endl;
1063
 
#endif // DEBUG
1064
 
    // frame focused doesn't necessarily mean input focused
1065
 
    frame().setLabelButtonFocus(*m_labelbuttons[m_client]);
1066
 
 
1067
 
    if (setinput && setInputFocus()) {
1068
 
        return true;
1069
 
    }
1070
 
    
1071
 
    return false;
1072
 
}
1073
 
 
1074
 
bool FluxboxWindow::isGroupable() const {
1075
 
    if (isResizable() && isMaximizable() && !winClient().isTransient())
1076
 
        return true;
1077
 
    return false;
1078
 
}
1079
 
 
1080
 
void FluxboxWindow::associateClientWindow(bool use_attrs,
1081
 
                                          int x, int y,
1082
 
                                          unsigned int width, unsigned int height) {
1083
 
    m_client->setBorderWidth(0);
1084
 
    updateTitleFromClient(*m_client);
1085
 
    updateIconNameFromClient(*m_client);
1086
 
 
1087
 
    if (use_attrs)
1088
 
        frame().moveResizeForClient(x, y,
1089
 
                                    width, height);
1090
 
    else
1091
 
        frame().resizeForClient(m_client->width(), m_client->height());
1092
 
 
1093
 
    frame().setClientWindow(*m_client);
1094
 
}
1095
 
 
1096
 
 
1097
 
void FluxboxWindow::grabButtons() {
1098
 
 
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());
1104
 
 
1105
 
    if (Fluxbox::instance()->useMod1()) {
1106
 
        XGrabButton(display, Button1, Mod1Mask, frame().window().window(), True,
1107
 
                    ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
1108
 
                    GrabModeAsync, None, frame().theme().moveCursor());
1109
 
 
1110
 
        //----grab with "all" modifiers
1111
 
        grabButton(Button1, frame().window().window(), frame().theme().moveCursor());
1112
 
 
1113
 
        XGrabButton(display, Button2, Mod1Mask, frame().window().window(), True,
1114
 
                    ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None);
1115
 
 
1116
 
        XGrabButton(display, Button3, Mod1Mask, frame().window().window(), True,
1117
 
                    ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
1118
 
                    GrabModeAsync, None, None);
1119
 
 
1120
 
        //---grab with "all" modifiers
1121
 
        grabButton(Button3, frame().window().window(), None);
1122
 
    }
1123
 
}
1124
 
 
1125
 
 
1126
 
void FluxboxWindow::reconfigure() {
1127
 
 
1128
 
    applyDecorations();
1129
 
 
1130
 
    setFocusFlag(focused);
1131
 
 
1132
 
    moveResize(frame().x(), frame().y(), frame().width(), frame().height());
1133
 
 
1134
 
    grabButtons();
1135
 
 
1136
 
    frame().setDoubleClickTime(Fluxbox::instance()->getDoubleClickInterval());
1137
 
 
1138
 
    frame().reconfigure();
1139
 
 
1140
 
    menu().reconfigure();
1141
 
 
1142
 
}
1143
 
 
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
1148
 
    // graphics
1149
 
    if (m_labelbuttons[&client]->text() != client.title())
1150
 
        m_labelbuttons[&client]->setText(client.title());
1151
 
}
1152
 
 
1153
 
/// update icon title from client
1154
 
void FluxboxWindow::updateIconNameFromClient(WinClient &client) {
1155
 
    client.updateIconTitle();
1156
 
}
1157
 
 
1158
 
void FluxboxWindow::updateMWMHintsFromClient(WinClient &client) {
1159
 
    const WinClient::MwmHints *hint = client.getMwmHint();
1160
 
 
1161
 
    if (!hint) return;
1162
 
 
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;
1168
 
        } else {
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;
1180
 
            }
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;
1187
 
        }
1188
 
    }
1189
 
 
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;
1196
 
        } else {
1197
 
            functions.resize = functions.move = functions.iconify =
1198
 
                functions.maximize = functions.close = false;
1199
 
 
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;
1210
 
        }
1211
 
    }
1212
 
}
1213
 
 
1214
 
void FluxboxWindow::updateRememberStateFromClient(WinClient &client) {
1215
 
#ifdef REMEMBER
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);
1221
 
    }
1222
 
#endif // REMEMBER
1223
 
}
1224
 
 
1225
 
void FluxboxWindow::updateFunctions() {
1226
 
    if (!m_client)
1227
 
        return;
1228
 
    bool changed = false;
1229
 
    if (m_client->isClosable() != functions.close) {
1230
 
        functions.close = m_client->isClosable();
1231
 
        changed = true;
1232
 
    }
1233
 
 
1234
 
    if (changed)
1235
 
        setupWindow();
1236
 
}
1237
 
 
1238
 
void FluxboxWindow::updateBlackboxHintsFromClient(const WinClient &client) {
1239
 
    const FluxboxWindow::BlackboxHints *hint = client.getBlackboxHint();
1240
 
    if (!hint) return;
1241
 
 
1242
 
    if (hint->flags & ATTRIB_SHADED)
1243
 
        shaded = (hint->attrib & ATTRIB_SHADED);
1244
 
 
1245
 
    if (hint->flags & ATTRIB_HIDDEN)
1246
 
        iconic = (hint->attrib & ATTRIB_HIDDEN);
1247
 
 
1248
 
    if ((hint->flags & ATTRIB_MAXHORIZ) &&
1249
 
        (hint->flags & ATTRIB_MAXVERT))
1250
 
        maximized = ((hint->attrib &
1251
 
                      (ATTRIB_MAXHORIZ |
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);
1259
 
 
1260
 
    if (hint->flags & ATTRIB_OMNIPRESENT)
1261
 
        stuck = (hint->attrib & ATTRIB_OMNIPRESENT);
1262
 
 
1263
 
    if (hint->flags & ATTRIB_WORKSPACE)
1264
 
        m_workspace_number = hint->workspace;
1265
 
 
1266
 
    if (hint->flags & ATTRIB_STACK)
1267
 
        m_workspace_number = hint->stack;
1268
 
 
1269
 
    if (hint->flags & ATTRIB_DECORATION) {
1270
 
        m_old_decoration = static_cast<Decoration>(hint->decoration);
1271
 
        setDecoration(m_old_decoration, false);
1272
 
    }
1273
 
}
1274
 
 
1275
 
void FluxboxWindow::move(int x, int y, int gravity) {
1276
 
    moveResize(x, y, frame().width(), frame().height(), gravity);
1277
 
}
1278
 
 
1279
 
void FluxboxWindow::resize(unsigned int width, unsigned int height) {
1280
 
    moveResize(frame().x(), frame().y(), width, height);
1281
 
}
1282
 
 
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) {
1286
 
 
1287
 
    // magic to detect if moved during initialisation
1288
 
    if (!isInitialized())
1289
 
        m_old_pos_x = 1;
1290
 
 
1291
 
    if (gravity != ForgetGravity) {
1292
 
        frame().gravityTranslate(new_x, new_y, gravity, false);
1293
 
    }
1294
 
 
1295
 
    send_event = send_event || (frame().x() != new_x || frame().y() != new_y);
1296
 
 
1297
 
    if (new_width != frame().width() || new_height != frame().height()) {
1298
 
        if ((((signed) frame().width()) + new_x) < 0)
1299
 
            new_x = 0;
1300
 
        if ((((signed) frame().height()) + new_y) < 0)
1301
 
            new_y = 0;
1302
 
 
1303
 
        if (!isResizable()) {
1304
 
            new_width = width();
1305
 
            new_height = height();
1306
 
        }
1307
 
 
1308
 
        frame().moveResize(new_x, new_y, new_width, new_height);
1309
 
        setFocusFlag(focused);
1310
 
 
1311
 
        shaded = false;
1312
 
        send_event = true;
1313
 
    } else if (send_event)
1314
 
        frame().move(new_x, new_y);
1315
 
 
1316
 
    if (send_event && ! moving) {
1317
 
        sendConfigureNotify();
1318
 
    }
1319
 
 
1320
 
    shape();
1321
 
 
1322
 
    if (!moving) {
1323
 
        m_last_resize_x = new_x;
1324
 
        m_last_resize_y = new_y;
1325
 
    }
1326
 
 
1327
 
}
1328
 
 
1329
 
void FluxboxWindow::moveResizeForClient(int new_x, int new_y,
1330
 
                               unsigned int new_width, unsigned int new_height, int gravity) {
1331
 
 
1332
 
    // magic to detect if moved during initialisation
1333
 
    if (!isInitialized())
1334
 
        m_old_pos_x = 1;
1335
 
    frame().moveResizeForClient(new_x, new_y, new_width, new_height, true, true, gravity);
1336
 
    setFocusFlag(focused);
1337
 
    shaded = false;
1338
 
    sendConfigureNotify();
1339
 
 
1340
 
    shape();
1341
 
 
1342
 
    if (!moving) {
1343
 
        m_last_resize_x = new_x;
1344
 
        m_last_resize_y = new_y;
1345
 
    }
1346
 
 
1347
 
}
1348
 
 
1349
 
 
1350
 
 
1351
 
 
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() {
1358
 
 
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());
1366
 
        } else {
1367
 
            moveResize(frame().window().borderWidth(), frame().y() + frame().window().borderWidth(),
1368
 
                       frame().width(), frame().height());
1369
 
        }
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());
1378
 
        } else {
1379
 
            moveResize(screen().width() - frame().width(),
1380
 
                       frame().y() + frame().window().borderWidth(),
1381
 
                       frame().width(), frame().height());
1382
 
        }
1383
 
    }
1384
 
 
1385
 
    if (! m_client->validateClient())
1386
 
        return false;
1387
 
#ifdef DEBUG
1388
 
    cerr<<"FluxboxWindow::"<<__FUNCTION__<<" isModal() = "<<m_client->isModal()<<endl;
1389
 
    cerr<<"FluxboxWindow::"<<__FUNCTION__<<" transient size = "<<m_client->transients.size()<<endl;
1390
 
#endif // DEBUG
1391
 
    if (!m_client->transients.empty() && m_client->isModal()) {
1392
 
#ifdef DEBUG
1393
 
        cerr<<__FUNCTION__<<": isModal and have transients client = "<<
1394
 
            hex<<m_client->window()<<dec<<endl;
1395
 
        cerr<<__FUNCTION__<<": this = "<<this<<endl;
1396
 
#endif // DEBUG
1397
 
 
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) {
1401
 
#ifdef DEBUG
1402
 
            cerr<<__FUNCTION__<<": transient 0x"<<(*it)<<endl;
1403
 
#endif // DEBUG
1404
 
            if ((*it)->isModal())
1405
 
                return (*it)->fbwindow()->setCurrentClient(**it, true);
1406
 
        }
1407
 
    }
1408
 
 
1409
 
    bool ret = false;
1410
 
 
1411
 
    if (m_client->getFocusMode() == WinClient::F_LOCALLYACTIVE ||
1412
 
        m_client->getFocusMode() == WinClient::F_PASSIVE) {
1413
 
 
1414
 
        m_client->setInputFocus(RevertToPointerRoot, CurrentTime);
1415
 
 
1416
 
        FbTk::App *app = FbTk::App::instance();
1417
 
 
1418
 
        XFlush(app->display());
1419
 
 
1420
 
        m_client->sendFocus();
1421
 
 
1422
 
        app->sync(false);
1423
 
 
1424
 
        ret = true;
1425
 
    } else {
1426
 
        ret = m_client->sendFocus();
1427
 
    }
1428
 
 
1429
 
    return ret;
1430
 
}
1431
 
 
1432
 
// don't hide the frame directly, use this function
1433
 
void FluxboxWindow::hide(bool interrupt_moving) {
1434
 
#ifdef DEBUG
1435
 
    cerr<<__FILE__<<"("<<__FUNCTION__<<")["<<this<<"]"<<endl;
1436
 
#endif // DEBUG
1437
 
    // resizing always stops on hides
1438
 
    if (resizing)
1439
 
        stopResizing(true);
1440
 
 
1441
 
    if (interrupt_moving) {
1442
 
        if (moving)
1443
 
            stopMoving(true);
1444
 
        if (m_attaching_tab)
1445
 
            attachTo(0, 0, true);
1446
 
    }
1447
 
 
1448
 
    menu().hide();
1449
 
    frame().hide();
1450
 
}
1451
 
 
1452
 
void FluxboxWindow::show() {
1453
 
    frame().show();
1454
 
}
1455
 
 
1456
 
/**
1457
 
   Unmaps the window and removes it from workspace list
1458
 
*/
1459
 
void FluxboxWindow::iconify() {
1460
 
    if (isIconic()) // no need to iconify if we're already
1461
 
        return;
1462
 
 
1463
 
    m_blackbox_attrib.flags |= ATTRIB_HIDDEN;
1464
 
    m_blackbox_attrib.attrib |= ATTRIB_HIDDEN;
1465
 
 
1466
 
    iconic = true;
1467
 
 
1468
 
    setState(IconicState, false);
1469
 
 
1470
 
    hide(true);
1471
 
 
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);
1477
 
        client.hide();
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();
1483
 
            }
1484
 
        }
1485
 
 
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();
1492
 
        }
1493
 
    }
1494
 
 
1495
 
    // focus revert is done elsewhere (based on signal)
1496
 
}
1497
 
 
1498
 
void FluxboxWindow::deiconify(bool reassoc, bool do_raise) {
1499
 
    if (numClients() == 0)
1500
 
        return;
1501
 
 
1502
 
    if (oplock) return;
1503
 
    oplock = true;
1504
 
 
1505
 
    if (iconic || reassoc) {
1506
 
        screen().reassociateWindow(this, screen().currentWorkspace()->workspaceID(), false);
1507
 
    } else if (moving || m_workspace_number != screen().currentWorkspace()->workspaceID()) {
1508
 
        oplock = false;
1509
 
        return;
1510
 
    }
1511
 
 
1512
 
    bool was_iconic = iconic;
1513
 
 
1514
 
    m_blackbox_attrib.flags &= ~ATTRIB_HIDDEN;
1515
 
    iconic = false;
1516
 
 
1517
 
    setState(NormalState, false);
1518
 
 
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);
1525
 
    }
1526
 
 
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);
1539
 
            }
1540
 
        }
1541
 
    }
1542
 
 
1543
 
    show();
1544
 
 
1545
 
    if (was_iconic && screen().doFocusNew())
1546
 
        setInputFocus();
1547
 
 
1548
 
 
1549
 
    oplock = false;
1550
 
 
1551
 
    if (do_raise)
1552
 
        raise();
1553
 
}
1554
 
 
1555
 
/**
1556
 
 Set window in withdrawn state
1557
 
*/
1558
 
void FluxboxWindow::withdraw(bool interrupt_moving) {
1559
 
#ifdef DEBUG
1560
 
    cerr<<"FluxboxWindow::"<<__FUNCTION__<<": this = "<<this<<endl;
1561
 
#endif // DEBUG
1562
 
    iconic = false;
1563
 
 
1564
 
    hide(interrupt_moving);
1565
 
}
1566
 
 
1567
 
/** setFullscreen mode:
1568
 
    
1569
 
    - maximize as big as the screen is, dont care about slit / toolbar
1570
 
    - raise to toplayer
1571
 
*/
1572
 
void FluxboxWindow::setFullscreen(bool flag) {
1573
 
 
1574
 
    const int head = screen().getHead(fbWindow());
1575
 
    Fluxbox* fb = Fluxbox::instance();
1576
 
    
1577
 
    if (flag && !isFullscreen()) {
1578
 
 
1579
 
        if (isIconic())
1580
 
            deiconify();
1581
 
 
1582
 
        if (isShaded())
1583
 
            shade();
1584
 
 
1585
 
        frame().setUseShape(false);
1586
 
 
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();
1593
 
        
1594
 
        // clear decorations
1595
 
        setDecorationMask(0);
1596
 
 
1597
 
        // be xinerama aware
1598
 
        moveResize(screen().getHeadX(head), screen().getHeadY(head),
1599
 
                   screen().getHeadWidth(head), screen().getHeadHeight(head));
1600
 
        moveToLayer(Fluxbox::instance()->getAboveDockLayer());
1601
 
 
1602
 
        fullscreen = true;
1603
 
 
1604
 
        stateSig().notify();
1605
 
 
1606
 
    } else if (!flag && isFullscreen()) {
1607
 
 
1608
 
        fullscreen = false;
1609
 
    
1610
 
        setDecorationMask(m_old_decoration_mask);
1611
 
        frame().setUseShape(!m_shaped);
1612
 
        
1613
 
        moveResize(m_old_pos_x, m_old_pos_y, m_old_width, m_old_height);
1614
 
        moveToLayer(m_old_layernum);
1615
 
 
1616
 
        m_old_decoration_mask = 0;
1617
 
        m_old_layernum = Fluxbox::instance()->getNormalLayer();
1618
 
       
1619
 
        stateSig().notify();
1620
 
    }
1621
 
}
1622
 
 
1623
 
/**
1624
 
   Maximize window both horizontal and vertical
1625
 
*/
1626
 
void FluxboxWindow::maximize(int type) {
1627
 
 
1628
 
    if (isFullscreen())
1629
 
        return;
1630
 
    
1631
 
    if (isIconic())
1632
 
        deiconify();
1633
 
 
1634
 
    if (isShaded())
1635
 
        shade();
1636
 
 
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();
1642
 
 
1643
 
    int orig_max = maximized;
1644
 
 
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
1650
 
 
1651
 
    // Worst case being that some action will toggle the wrong way, but
1652
 
    // we still won't lose the state in that case.
1653
 
 
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.
1660
 
    //
1661
 
    // The current implementation uses style 1, to change this, removed the
1662
 
    // item corresponding to the [[ ]] comment
1663
 
 
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;
1678
 
        } else {
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();
1683
 
        }
1684
 
        maximized ^= MAX_VERT;
1685
 
    }
1686
 
 
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;
1696
 
        } else {
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();
1702
 
        }
1703
 
        maximized ^= MAX_HORZ;
1704
 
    }
1705
 
 
1706
 
    moveResize(new_x, new_y, new_w, new_h);
1707
 
 
1708
 
}
1709
 
/**
1710
 
 * Maximize window horizontal
1711
 
 */
1712
 
void FluxboxWindow::maximizeHorizontal() {
1713
 
    maximize(MAX_HORZ);
1714
 
}
1715
 
 
1716
 
/**
1717
 
 * Maximize window vertical
1718
 
 */
1719
 
void FluxboxWindow::maximizeVertical() {
1720
 
    maximize(MAX_VERT);
1721
 
}
1722
 
 
1723
 
/**
1724
 
 * Maximize window fully
1725
 
 */
1726
 
void FluxboxWindow::maximizeFull() {
1727
 
    maximize(MAX_FULL);
1728
 
}
1729
 
 
1730
 
 
1731
 
void FluxboxWindow::setWorkspace(int n) {
1732
 
    unsigned int old_wkspc = m_workspace_number;
1733
 
 
1734
 
    m_workspace_number = n;
1735
 
 
1736
 
    m_blackbox_attrib.flags |= ATTRIB_WORKSPACE;
1737
 
    m_blackbox_attrib.workspace = m_workspace_number;
1738
 
 
1739
 
    // notify workspace change
1740
 
    if (isInitialized() && !stuck && old_wkspc != m_workspace_number) {
1741
 
#ifdef DEBUG
1742
 
        cerr<<this<<" notify workspace signal"<<endl;
1743
 
#endif // DEBUG
1744
 
        m_workspacesig.notify();
1745
 
    }
1746
 
}
1747
 
 
1748
 
void FluxboxWindow::setLayerNum(int layernum) {
1749
 
    m_layernum = layernum;
1750
 
 
1751
 
    m_blackbox_attrib.flags |= ATTRIB_STACK;
1752
 
    m_blackbox_attrib.stack = layernum;
1753
 
 
1754
 
    if (isInitialized()) {
1755
 
        saveBlackboxAttribs();
1756
 
 
1757
 
#ifdef DEBUG
1758
 
        cerr<<this<<" notify layer signal"<<endl;
1759
 
#endif // DEBUG
1760
 
 
1761
 
        m_layersig.notify();
1762
 
    }
1763
 
}
1764
 
 
1765
 
void FluxboxWindow::shade() {
1766
 
    // we can only shade if we have a titlebar
1767
 
    if (!decorations.titlebar)
1768
 
        return;
1769
 
 
1770
 
    // we're toggling, so if they're equal now, we need to change it
1771
 
    if (isInitialized() && m_frame.isShaded() == shaded)
1772
 
        frame().shade();
1773
 
 
1774
 
    if (shaded) {
1775
 
        shaded = false;
1776
 
        m_blackbox_attrib.flags ^= ATTRIB_SHADED;
1777
 
        m_blackbox_attrib.attrib ^= ATTRIB_SHADED;
1778
 
 
1779
 
        if (isInitialized())
1780
 
            setState(NormalState, false);
1781
 
    } else {
1782
 
        shaded = true;
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);
1788
 
    }
1789
 
 
1790
 
}
1791
 
 
1792
 
void FluxboxWindow::shadeOn() {
1793
 
 
1794
 
    if (!shaded)
1795
 
        shade();
1796
 
 
1797
 
}
1798
 
 
1799
 
void FluxboxWindow::shadeOff() {
1800
 
 
1801
 
    if (shaded)
1802
 
        shade();
1803
 
 
1804
 
}
1805
 
 
1806
 
void FluxboxWindow::stick() {
1807
 
 
1808
 
    if (stuck) {
1809
 
        m_blackbox_attrib.flags ^= ATTRIB_OMNIPRESENT;
1810
 
        m_blackbox_attrib.attrib ^= ATTRIB_OMNIPRESENT;
1811
 
 
1812
 
        stuck = false;
1813
 
 
1814
 
    } else {
1815
 
        stuck = true;
1816
 
 
1817
 
        m_blackbox_attrib.flags |= ATTRIB_OMNIPRESENT;
1818
 
        m_blackbox_attrib.attrib |= ATTRIB_OMNIPRESENT;
1819
 
 
1820
 
    }
1821
 
 
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();
1826
 
    }
1827
 
 
1828
 
}
1829
 
 
1830
 
 
1831
 
void FluxboxWindow::raise() {
1832
 
    if (isIconic())
1833
 
        deiconify();
1834
 
#ifdef DEBUG
1835
 
    cerr<<"FluxboxWindow("<<title()<<")::raise()[layer="<<layerNum()<<"]"<<endl;
1836
 
#endif // DEBUG
1837
 
    // get root window
1838
 
    WinClient *client = getRootTransientFor(m_client);
1839
 
 
1840
 
    // if we don't have any root window use this as root
1841
 
    if (client == 0)
1842
 
        client = m_client;
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);
1849
 
    }
1850
 
    // raise this window and every transient in it with this one last
1851
 
    if (client->fbwindow())
1852
 
        raiseFluxboxWindow(*client->fbwindow());
1853
 
        
1854
 
}
1855
 
 
1856
 
void FluxboxWindow::lower() {
1857
 
    if (isIconic())
1858
 
        deiconify();
1859
 
#ifdef DEBUG
1860
 
    cerr<<"FluxboxWindow("<<title()<<")::lower()"<<endl;
1861
 
#endif // DEBUG
1862
 
    // get root window
1863
 
    WinClient *client = getRootTransientFor(m_client);
1864
 
 
1865
 
    // if we don't have any root window use this as root
1866
 
    if (client == 0)
1867
 
        client = m_client;
1868
 
 
1869
 
    if (client->fbwindow())
1870
 
        lowerFluxboxWindow(*client->fbwindow());
1871
 
}
1872
 
 
1873
 
void FluxboxWindow::tempRaise() {
1874
 
    if (isIconic())
1875
 
        deiconify();
1876
 
 
1877
 
    // get root window
1878
 
    WinClient *client = getRootTransientFor(m_client);
1879
 
 
1880
 
    // if we don't have any root window use this as root
1881
 
    if (client == 0)
1882
 
        client = m_client;
1883
 
 
1884
 
    if (client->fbwindow())
1885
 
        tempRaiseFluxboxWindow(*client->fbwindow());
1886
 
}
1887
 
 
1888
 
 
1889
 
void FluxboxWindow::raiseLayer() {
1890
 
    // don't let it up to menu layer
1891
 
    if (layerNum() == (Fluxbox::instance()->getMenuLayer()+1))
1892
 
        return;
1893
 
 
1894
 
    if (!isInitialized()) {
1895
 
        m_layernum++;
1896
 
        return;
1897
 
    }
1898
 
 
1899
 
    // get root window
1900
 
    WinClient *client = getRootTransientFor(m_client);
1901
 
 
1902
 
    // if we don't have any root window use this as root
1903
 
    if (client == 0)
1904
 
        client = m_client;
1905
 
 
1906
 
    FluxboxWindow *win = client->fbwindow();
1907
 
    if (!win) return;
1908
 
 
1909
 
    if (!win->isIconic())
1910
 
        screen().updateNetizenWindowRaise(client->window());
1911
 
 
1912
 
    win->layerItem().raiseLayer();
1913
 
 
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);
1917
 
 
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);
1926
 
        }
1927
 
    }
1928
 
}
1929
 
 
1930
 
void FluxboxWindow::lowerLayer() {
1931
 
    if (!isInitialized()) {
1932
 
        if (m_layernum > 0)
1933
 
            m_layernum--;
1934
 
        return;
1935
 
    }
1936
 
 
1937
 
    // get root window
1938
 
    WinClient *client = getRootTransientFor(m_client);
1939
 
 
1940
 
    // if we don't have any root window use this as root
1941
 
    if (client == 0)
1942
 
        client = m_client;
1943
 
 
1944
 
    FluxboxWindow *win = client->fbwindow();
1945
 
    if (!win) return;
1946
 
 
1947
 
    if (!win->isIconic()) {
1948
 
        screen().updateNetizenWindowLower(client->window());
1949
 
    }
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);
1954
 
 
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);
1963
 
        }
1964
 
    }
1965
 
}
1966
 
 
1967
 
 
1968
 
void FluxboxWindow::moveToLayer(int layernum) {
1969
 
#ifdef DEBUG
1970
 
    cerr<<"FluxboxWindow("<<title()<<")::moveToLayer("<<layernum<<")"<<endl;
1971
 
#endif // DEBUG
1972
 
 
1973
 
    Fluxbox * fluxbox = Fluxbox::instance();
1974
 
 
1975
 
    // don't let it set its layer into menu area
1976
 
    if (layernum <= fluxbox->getMenuLayer()) {
1977
 
        layernum = fluxbox->getMenuLayer() + 1;
1978
 
    }
1979
 
 
1980
 
    if (!isInitialized()) {
1981
 
        m_layernum = layernum;
1982
 
        return;
1983
 
    }
1984
 
 
1985
 
    // get root window
1986
 
    WinClient *client = getRootTransientFor(m_client);
1987
 
 
1988
 
    // if we don't have any root window use this as root
1989
 
    if (client == 0)
1990
 
        client = m_client;
1991
 
 
1992
 
    FluxboxWindow *win = client->fbwindow();
1993
 
    if (!win) return;
1994
 
 
1995
 
    if (!win->isIconic()) {
1996
 
        screen().updateNetizenWindowRaise(client->window());
1997
 
    }
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);
2002
 
 
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);
2011
 
        }
2012
 
    }
2013
 
}
2014
 
 
2015
 
void FluxboxWindow::setFocusHidden(bool value) {
2016
 
    if (isInitialized())
2017
 
        m_statesig.notify();
2018
 
}
2019
 
 
2020
 
void FluxboxWindow::setIconHidden(bool value) {
2021
 
    m_icon_hidden= value;
2022
 
    if (isInitialized())
2023
 
        m_statesig.notify();
2024
 
}
2025
 
 
2026
 
 
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();
2031
 
    focused = focus;
2032
 
#ifdef DEBUG
2033
 
    cerr<<"FluxboxWindow("<<title()<<")::setFocusFlag("<<focus<<")"<<endl;
2034
 
#endif // DEBUG
2035
 
    // Record focus timestamp for window cycling enhancements
2036
 
    if (focused) {
2037
 
        gettimeofday(&m_last_focus_time, 0);
2038
 
        screen().setFocusedWindow(*m_client);
2039
 
    }
2040
 
 
2041
 
    installColormap(focus);
2042
 
 
2043
 
    if (focus != frame().focused())
2044
 
        frame().setFocus(focus);
2045
 
 
2046
 
    if ((screen().isMouseFocus())
2047
 
        && screen().doAutoRaise()) {
2048
 
        if (focused)
2049
 
            m_timer.start();
2050
 
        else
2051
 
            m_timer.stop();
2052
 
    }
2053
 
 
2054
 
    // did focus change? notify listeners
2055
 
    if (was_focused != focus)
2056
 
        m_focussig.notify();
2057
 
}
2058
 
 
2059
 
 
2060
 
void FluxboxWindow::installColormap(bool install) {
2061
 
    if (m_client == 0) return;
2062
 
 
2063
 
    Fluxbox *fluxbox = Fluxbox::instance();
2064
 
    fluxbox->grab();
2065
 
    if (! m_client->validateClient())
2066
 
        return;
2067
 
 
2068
 
    int i = 0, ncmap = 0;
2069
 
    Colormap *cmaps = XListInstalledColormaps(display, m_client->window(), &ncmap);
2070
 
    XWindowAttributes wattrib;
2071
 
    if (cmaps) { //!!
2072
 
        if (m_client->getAttrib(wattrib)) {
2073
 
            if (install) {
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
2078
 
                        install = false;
2079
 
                        break; //end for-loop (we dont need to check more)
2080
 
                    }
2081
 
                }
2082
 
                // otherwise, install the window's colormap
2083
 
                if (install)
2084
 
                    XInstallColormap(display, wattrib.colormap);
2085
 
            } else {
2086
 
                for (i = 0; i < ncmap; i++) { // uninstall the window's colormap
2087
 
                    if (*(cmaps + i) == wattrib.colormap)
2088
 
                       XUninstallColormap(display, wattrib.colormap);
2089
 
                }
2090
 
            }
2091
 
        }
2092
 
 
2093
 
        XFree(cmaps);
2094
 
    }
2095
 
 
2096
 
    fluxbox->ungrab();
2097
 
}
2098
 
 
2099
 
/**
2100
 
 Saves blackbox attributes for every client in our list
2101
 
 */
2102
 
void FluxboxWindow::saveBlackboxAttribs() {
2103
 
    for_each(m_clientlist.begin(), m_clientlist.end(),
2104
 
             FbTk::ChangeProperty(
2105
 
                 display,
2106
 
                 FbAtoms::instance()->getFluxboxAttributesAtom(),
2107
 
                 PropModeReplace,
2108
 
                 (unsigned char *)&m_blackbox_attrib,
2109
 
                 PropBlackboxAttributesElements
2110
 
                 ));
2111
 
}
2112
 
 
2113
 
/**
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
2117
 
 */
2118
 
void FluxboxWindow::setState(unsigned long new_state, bool setting_up) {
2119
 
    if (numClients() == 0)
2120
 
        return;
2121
 
 
2122
 
    m_current_state = new_state;
2123
 
    if (!setting_up) {
2124
 
        unsigned long state[2];
2125
 
        state[0] = (unsigned long) m_current_state;
2126
 
        state[1] = (unsigned long) None;
2127
 
 
2128
 
        for_each(m_clientlist.begin(), m_clientlist.end(),
2129
 
                 FbTk::ChangeProperty(display, FbAtoms::instance()->getWMStateAtom(),
2130
 
                                      PropModeReplace,
2131
 
                                      (unsigned char *)state, 2));
2132
 
 
2133
 
        saveBlackboxAttribs();
2134
 
        //notify state changed
2135
 
        m_statesig.notify();
2136
 
    }
2137
 
}
2138
 
 
2139
 
bool FluxboxWindow::getState() {
2140
 
 
2141
 
    Atom atom_return;
2142
 
    bool ret = false;
2143
 
    int foo;
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)
2149
 
        return false;
2150
 
 
2151
 
    if (nitems >= 1) {
2152
 
        m_current_state = static_cast<unsigned long>(state[0]);
2153
 
        ret = true;
2154
 
    }
2155
 
 
2156
 
    XFree(static_cast<void *>(state));
2157
 
 
2158
 
    return ret;
2159
 
}
2160
 
 
2161
 
/**
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)
2165
 
 */
2166
 
void FluxboxWindow::restoreAttributes() {
2167
 
    if (!getState()) {
2168
 
        m_current_state = m_client->initial_state;
2169
 
        if (m_current_state == IconicState)
2170
 
            iconic = true;
2171
 
    }
2172
 
 
2173
 
    Atom atom_return;
2174
 
    int foo;
2175
 
    unsigned long ulfoo, nitems;
2176
 
    FbAtoms *fbatoms = FbAtoms::instance();
2177
 
 
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) &&
2183
 
        net) {
2184
 
        if (nitems != (unsigned)PropBlackboxAttributesElements) {
2185
 
            XFree(net);
2186
 
            return;
2187
 
        }
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;
2196
 
 
2197
 
        XFree(static_cast<void *>(net));
2198
 
    } else
2199
 
        return;
2200
 
 
2201
 
    if (m_blackbox_attrib.flags & ATTRIB_SHADED &&
2202
 
        m_blackbox_attrib.attrib & ATTRIB_SHADED)
2203
 
        shaded = true;
2204
 
 
2205
 
    if (m_blackbox_attrib.flags & ATTRIB_HIDDEN &&
2206
 
        m_blackbox_attrib.attrib & ATTRIB_HIDDEN) {
2207
 
        iconic = true;
2208
 
    }
2209
 
 
2210
 
    if (( m_blackbox_attrib.workspace != screen().currentWorkspaceID()) &&
2211
 
        ( m_blackbox_attrib.workspace < screen().numberOfWorkspaces()))
2212
 
        m_workspace_number = m_blackbox_attrib.workspace;
2213
 
 
2214
 
    if (m_blackbox_attrib.flags & ATTRIB_OMNIPRESENT &&
2215
 
        m_blackbox_attrib.attrib & ATTRIB_OMNIPRESENT)
2216
 
        stuck = true;
2217
 
 
2218
 
    if (m_blackbox_attrib.flags & ATTRIB_STACK) {
2219
 
        //!! TODO check value?
2220
 
        m_layernum = m_blackbox_attrib.stack;
2221
 
    }
2222
 
 
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;
2235
 
 
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;
2240
 
    }
2241
 
 
2242
 
}
2243
 
 
2244
 
/**
2245
 
   Show the window menu at pos mx, my
2246
 
*/
2247
 
void FluxboxWindow::showMenu(int menu_x, int menu_y) {
2248
 
    // move menu directly under titlebar
2249
 
 
2250
 
    int head = screen().getHead(menu_x, menu_y);
2251
 
 
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();
2255
 
 
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;
2260
 
 
2261
 
    WindowCmd<void>::setWindow(this);
2262
 
    menu().move(menu_x, menu_y);
2263
 
    menu().show();
2264
 
    menu().raise();
2265
 
    menu().grabInputFocus();
2266
 
}
2267
 
 
2268
 
/**
2269
 
   Moves the menu to last button press position and shows it,
2270
 
   if it's already visible it'll be hidden
2271
 
 */
2272
 
void FluxboxWindow::popupMenu() {
2273
 
 
2274
 
    // hide menu if it was opened for this window before
2275
 
    if (menu().isVisible() && WindowCmd<void>::window() == this) {
2276
 
        menu().hide();
2277
 
        return;
2278
 
    }
2279
 
 
2280
 
    menu().disableTitle();
2281
 
    int menu_y = frame().titlebar().height() + frame().titlebar().borderWidth();
2282
 
    if (!decorations.titlebar) // if we don't have any titlebar
2283
 
        menu_y = 0;
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());
2287
 
}
2288
 
 
2289
 
 
2290
 
/**
2291
 
   Redirect any unhandled event to our handlers
2292
 
*/
2293
 
void FluxboxWindow::handleEvent(XEvent &event) {
2294
 
    switch (event.type) {
2295
 
    case ConfigureRequest:
2296
 
#ifdef DEBUG
2297
 
        cerr<<"ConfigureRequest("<<title()<<")"<<endl;
2298
 
#endif // DEBUG
2299
 
 
2300
 
        configureRequestEvent(event.xconfigurerequest);
2301
 
        break;
2302
 
    case MapNotify:
2303
 
        mapNotifyEvent(event.xmap);
2304
 
        break;
2305
 
        // This is already handled in Fluxbox::handleEvent
2306
 
        // case MapRequest:
2307
 
        //        mapRequestEvent(event.xmaprequest);
2308
 
        //break;
2309
 
    case PropertyNotify: {
2310
 
 
2311
 
#ifdef DEBUG
2312
 
        char *atomname = XGetAtomName(display, event.xproperty.atom);
2313
 
        cerr<<"PropertyNotify("<<title()<<"), property = "<<atomname<<endl;
2314
 
        if (atomname)
2315
 
            XFree(atomname);
2316
 
#endif // DEBUG
2317
 
        WinClient *client = findClient(event.xproperty.window);
2318
 
        if (client)
2319
 
            propertyNotifyEvent(*client, event.xproperty.atom);
2320
 
 
2321
 
    }
2322
 
        break;
2323
 
 
2324
 
    default:
2325
 
#ifdef SHAPE
2326
 
        if (Fluxbox::instance()->haveShape() &&
2327
 
            event.type == Fluxbox::instance()->shapeEventbase() + ShapeNotify) {
2328
 
#ifdef DEBUG
2329
 
            cerr<<"ShapeNotify("<<title()<<")"<<endl;
2330
 
#endif // DEBUG
2331
 
            XShapeEvent *shape_event = (XShapeEvent *)&event;
2332
 
 
2333
 
            if (shape_event->kind != ShapeBounding)
2334
 
                break;
2335
 
 
2336
 
            if (shape_event->shaped) {
2337
 
                m_shaped = true;
2338
 
                shape();
2339
 
            } else {
2340
 
                m_shaped = false;
2341
 
                // set no shape
2342
 
                XShapeCombineMask(display,
2343
 
                                  frame().window().window(), ShapeBounding,
2344
 
                                  0, 0,
2345
 
                                  None, ShapeSet);
2346
 
            }
2347
 
 
2348
 
            FbTk::App::instance()->sync(false);
2349
 
            break;
2350
 
        }
2351
 
#endif // SHAPE
2352
 
 
2353
 
        break;
2354
 
    }
2355
 
}
2356
 
 
2357
 
void FluxboxWindow::mapRequestEvent(XMapRequestEvent &re) {
2358
 
 
2359
 
    // we're only concerned about client window event
2360
 
    WinClient *client = findClient(re.window);
2361
 
    if (client == 0) {
2362
 
#ifdef DEBUG
2363
 
        cerr<<__FILE__<<"("<<__FUNCTION__<<"): Can't find client!"<<endl;
2364
 
#endif // DEBUG
2365
 
        return;
2366
 
    }
2367
 
 
2368
 
    // rest of current state checking is in initialisation
2369
 
    if (m_current_state == WithdrawnState)
2370
 
        withdraw(true);
2371
 
    else {
2372
 
 
2373
 
        // if this window was destroyed while autogrouping
2374
 
        bool destroyed = false;
2375
 
 
2376
 
        // check WM_CLASS only when we changed state to NormalState from
2377
 
        // WithdrawnState (ICCC 4.1.2.5)
2378
 
        client->updateWMClassHint();
2379
 
 
2380
 
        Workspace *wsp = screen().getWorkspace(m_workspace_number);
2381
 
        if (wsp != 0 && isGroupable())
2382
 
            destroyed = wsp->checkGrouping(*this);
2383
 
 
2384
 
        // if we weren't grouped with another window we deiconify ourself
2385
 
        if (!destroyed && !iconic)
2386
 
            deiconify(false);
2387
 
 
2388
 
    }
2389
 
}
2390
 
 
2391
 
 
2392
 
void FluxboxWindow::mapNotifyEvent(XMapEvent &ne) {
2393
 
    WinClient *client = findClient(ne.window);
2394
 
    if (client == 0)
2395
 
        return;
2396
 
#ifdef DEBUG
2397
 
    cerr<<"FluxboxWindow::mapNotifyEvent: "
2398
 
        <<"ne.override_redirect = "<<ne.override_redirect
2399
 
        <<" isVisible() = "<<isVisible()<<endl;
2400
 
#endif // DEBUG
2401
 
 
2402
 
    if (!ne.override_redirect && isVisible()) {
2403
 
#ifdef DEBUG
2404
 
        cerr<<"FluxboxWindow::mapNotify: not override redirect ans visible!"<<endl;
2405
 
#endif // DEBUG
2406
 
        Fluxbox *fluxbox = Fluxbox::instance();
2407
 
        fluxbox->grab();
2408
 
        if (! client->validateClient())
2409
 
            return;
2410
 
 
2411
 
        setState(NormalState, false);
2412
 
 
2413
 
        if (client->isTransient() || screen().doFocusNew())
2414
 
            setCurrentClient(*client, true);
2415
 
        else
2416
 
            setFocusFlag(false);
2417
 
 
2418
 
        iconic = false;
2419
 
 
2420
 
        // Auto-group from tab?
2421
 
        if (!client->isTransient()) {
2422
 
#ifdef DEBUG
2423
 
            cerr<<__FILE__<<"("<<__FUNCTION__<<") TODO check grouping here"<<endl;
2424
 
#endif // DEBUG
2425
 
        }
2426
 
 
2427
 
        fluxbox->ungrab();
2428
 
    }
2429
 
}
2430
 
 
2431
 
/**
2432
 
   Unmaps frame window and client window if
2433
 
   event.window == m_client->window
2434
 
   Returns true if *this should die
2435
 
   else false
2436
 
*/
2437
 
void FluxboxWindow::unmapNotifyEvent(XUnmapEvent &ue) {
2438
 
    WinClient *client = findClient(ue.window);
2439
 
    if (client == 0)
2440
 
        return;
2441
 
 
2442
 
#ifdef DEBUG
2443
 
    cerr<<__FILE__<<"("<<__FUNCTION__<<"): 0x"<<hex<<client->window()<<dec<<endl;
2444
 
    cerr<<__FILE__<<"("<<__FUNCTION__<<"): title="<<client->title()<<endl;
2445
 
#endif // DEBUG
2446
 
 
2447
 
    restore(client, false);
2448
 
 
2449
 
}
2450
 
 
2451
 
/**
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.
2455
 
*/
2456
 
void FluxboxWindow::destroyNotifyEvent(XDestroyWindowEvent &de) {
2457
 
    if (de.window == m_client->window()) {
2458
 
#ifdef DEBUG
2459
 
        cerr<<__FILE__<<"("<<__LINE__<<"): DestroyNotifyEvent this="<<this<<" title = "<<title()<<endl;
2460
 
#endif // DEBUG
2461
 
        if (numClients() == 1)
2462
 
            hide();
2463
 
    }
2464
 
 
2465
 
}
2466
 
 
2467
 
 
2468
 
void FluxboxWindow::propertyNotifyEvent(WinClient &client, Atom atom) {
2469
 
    switch(atom) {
2470
 
    case XA_WM_CLASS:
2471
 
    case XA_WM_CLIENT_MACHINE:
2472
 
    case XA_WM_COMMAND:
2473
 
        break;
2474
 
 
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());
2482
 
 
2483
 
    } break;
2484
 
 
2485
 
    case XA_WM_HINTS:
2486
 
        client.updateWMHints();
2487
 
        hintSig().notify(); // notify listeners
2488
 
        break;
2489
 
 
2490
 
    case XA_WM_ICON_NAME:
2491
 
        // update icon title and then do normal XA_WM_NAME stuff
2492
 
        client.updateIconTitle();
2493
 
    case XA_WM_NAME:
2494
 
        updateTitleFromClient(client);
2495
 
        titleSig().notify();
2496
 
        break;
2497
 
 
2498
 
    case XA_WM_NORMAL_HINTS: {
2499
 
#ifdef DEBUG
2500
 
        cerr<<"XA_WM_NORMAL_HINTS("<<title()<<")"<<endl;
2501
 
#endif // DEBUG
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();
2508
 
 
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 ||
2519
 
                    functions.resize ||
2520
 
                    functions.maximize)
2521
 
                    changed = true;
2522
 
                decorations.maximize = false;
2523
 
                decorations.handle = false;
2524
 
                functions.resize=false;
2525
 
                functions.maximize=false;
2526
 
            } else {
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)
2532
 
                        changed = true;
2533
 
                    decorations.maximize = true;
2534
 
                    decorations.handle = true;
2535
 
                    functions.maximize = true;
2536
 
                }
2537
 
                if (!functions.resize)
2538
 
                    changed = true;
2539
 
                functions.resize = true;
2540
 
            }
2541
 
 
2542
 
            if (changed)
2543
 
                setupWindow();
2544
 
        }
2545
 
 
2546
 
        moveResize(frame().x(), frame().y(),
2547
 
                   frame().width(), frame().height());
2548
 
 
2549
 
        break;
2550
 
    }
2551
 
 
2552
 
    default:
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
2568
 
            }
2569
 
        }
2570
 
        break;
2571
 
    }
2572
 
 
2573
 
}
2574
 
 
2575
 
 
2576
 
void FluxboxWindow::exposeEvent(XExposeEvent &ee) {
2577
 
    frame().exposeEvent(ee);
2578
 
}
2579
 
 
2580
 
void FluxboxWindow::configureRequestEvent(XConfigureRequestEvent &cr) {
2581
 
 
2582
 
    WinClient *client = findClient(cr.window);
2583
 
    if (client == 0 || isIconic())
2584
 
        return;
2585
 
 
2586
 
    int cx = frame().x(), cy = frame().y(), ignore = 0;
2587
 
    unsigned int cw = frame().width(), ch = frame().height();
2588
 
 
2589
 
    if (cr.value_mask & CWBorderWidth)
2590
 
        client->old_bw = cr.border_width;
2591
 
 
2592
 
    if ((cr.value_mask & CWX) &&
2593
 
        (cr.value_mask & CWY)) {
2594
 
        cx = cr.x;
2595
 
        cy = cr.y;
2596
 
        frame().gravityTranslate(cx, cy, client->gravity(), false);
2597
 
    } else if (cr.value_mask & CWX) {
2598
 
        cx = cr.x;
2599
 
        frame().gravityTranslate(cx, ignore, client->gravity(), false);
2600
 
    } else if (cr.value_mask & CWY) {
2601
 
        cy = cr.y;
2602
 
        frame().gravityTranslate(ignore, cy, client->gravity(), false);
2603
 
    }
2604
 
 
2605
 
    if (cr.value_mask & CWWidth)
2606
 
        cw = cr.width;
2607
 
 
2608
 
    if (cr.value_mask & CWHeight)
2609
 
        ch = cr.height;
2610
 
 
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);
2616
 
        else
2617
 
            frame().resizeForClient(cw, ch);
2618
 
    } else if (frame().x() != cx || frame().y() != cy) {
2619
 
        frame().move(cx, cy);
2620
 
    }
2621
 
 
2622
 
    if (cr.value_mask & CWStackMode) {
2623
 
        switch (cr.detail) {
2624
 
        case Above:
2625
 
        case TopIf:
2626
 
        default:
2627
 
            raise();
2628
 
            break;
2629
 
 
2630
 
        case Below:
2631
 
        case BottomIf:
2632
 
            lower();
2633
 
            break;
2634
 
        }
2635
 
    }
2636
 
 
2637
 
    sendConfigureNotify();
2638
 
 
2639
 
}
2640
 
 
2641
 
 
2642
 
void FluxboxWindow::buttonPressEvent(XButtonEvent &be) {
2643
 
    m_last_button_x = be.x_root;
2644
 
    m_last_button_y = be.y_root;
2645
 
 
2646
 
    // check frame events first
2647
 
    frame().buttonPressEvent(be);
2648
 
 
2649
 
    if (be.button == 1 || (be.button == 3 && be.state == Mod1Mask)) {
2650
 
        if ((! focused) && (! screen().isMouseFocus())) { //check focus
2651
 
            setInputFocus();
2652
 
        }
2653
 
 
2654
 
        if (frame().window().window() == be.window) {
2655
 
            if (screen().clickRaises())
2656
 
                raise();
2657
 
#ifdef DEBUG
2658
 
            cerr<<"FluxboxWindow::buttonPressEvent: AllowEvent"<<endl;
2659
 
#endif // DEBUG
2660
 
 
2661
 
            XAllowEvents(display, ReplayPointer, be.time);
2662
 
 
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)
2666
 
            raise();
2667
 
 
2668
 
        Fluxbox::instance()->hideExtraMenus(screen());
2669
 
        screen().hideWindowMenus(this);
2670
 
    }
2671
 
}
2672
 
 
2673
 
void FluxboxWindow::buttonReleaseEvent(XButtonEvent &re) {
2674
 
 
2675
 
    if ((re.button == 1) && (re.state & Mod1Mask) && !screen().clickRaises())
2676
 
        if (!isMoving())
2677
 
            raise();
2678
 
    
2679
 
    if (isMoving())
2680
 
        stopMoving();
2681
 
    else if (isResizing())
2682
 
        stopResizing();
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);
2688
 
        else
2689
 
            frame().buttonReleaseEvent(re);
2690
 
    } else {
2691
 
        frame().buttonReleaseEvent(re);
2692
 
    }
2693
 
}
2694
 
 
2695
 
 
2696
 
void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
2697
 
    if (isMoving() && me.window == parent()) {
2698
 
        me.window = frame().window().window();
2699
 
    }
2700
 
    bool inside_titlebar = (frame().titlebar() == me.window || frame().label() == me.window ||
2701
 
                            frame().handle() == me.window || frame().window() == me.window);
2702
 
 
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))
2711
 
            return;
2712
 
    }
2713
 
 
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;
2726
 
        }
2727
 
    }
2728
 
 
2729
 
    if ((me.state & Button1Mask) && functions.move &&
2730
 
        inside_titlebar &&
2731
 
        !isResizing()) {
2732
 
 
2733
 
        if (! isMoving()) {
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();
2740
 
        } else {
2741
 
            int dx = me.x_root - m_button_grab_x,
2742
 
                dy = me.y_root - m_button_grab_y;
2743
 
 
2744
 
            dx -= frame().window().borderWidth();
2745
 
            dy -= frame().window().borderWidth();
2746
 
 
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;
2752
 
 
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 &&
2760
 
                    moved_x > 0) {
2761
 
                    //warp right
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 &&
2765
 
                           moved_x < 0) {
2766
 
                    //warp left
2767
 
                    new_id = (cur_id + screen().numberOfWorkspaces() - 1) % screen().numberOfWorkspaces();
2768
 
                    dx = screen().width() - me.x_root-1; // move mouse to screen width - 1
2769
 
                }
2770
 
                if (new_id != cur_id) {
2771
 
 
2772
 
                    XWarpPointer(display, None, None, 0, 0, 0, 0, dx, 0);
2773
 
                    screen().changeWorkspaceID(new_id);
2774
 
 
2775
 
                    m_last_resize_x = me.x_root + dx;
2776
 
 
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;
2780
 
                }
2781
 
            }
2782
 
            // dx = current left side, dy = current top
2783
 
            doSnapping(dx, dy);
2784
 
 
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);
2790
 
 
2791
 
                parent().drawRectangle(screen().rootTheme().opGC(),
2792
 
                                       dx, dy,
2793
 
                                       frame().width() + 2*frame().window().borderWidth()-1,
2794
 
                                       frame().height() + 2*frame().window().borderWidth()-1);
2795
 
                m_last_move_x = dx;
2796
 
                m_last_move_y = dy;
2797
 
            } else {
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());
2801
 
            }
2802
 
 
2803
 
            screen().showPosition(dx, dy);
2804
 
        } // end if moving
2805
 
    } else if (functions.resize &&
2806
 
               (((me.state & Button1Mask) && (me.window == frame().gripRight() ||
2807
 
                                              me.window == frame().gripLeft())) ||
2808
 
                me.window == frame().window())) {
2809
 
 
2810
 
        if (! resizing) {
2811
 
 
2812
 
          int cx = frame().width() / 2;
2813
 
          int cy = frame().height() / 2;
2814
 
 
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;
2821
 
          else if (me.x < cx)
2822
 
              m_resize_corner = (me.y < cy) ? LEFTTOP : LEFTBOTTOM;
2823
 
          else
2824
 
              m_resize_corner = (me.y < cy) ? RIGHTTOP : RIGHTBOTTOM;
2825
 
 
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());
2833
 
 
2834
 
 
2835
 
            // move rectangle
2836
 
            int gx = 0, gy = 0;
2837
 
 
2838
 
            int dx = me.x - m_button_grab_x;
2839
 
            int dy = me.y - m_button_grab_y;
2840
 
 
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;
2844
 
            } else {
2845
 
                m_last_resize_h = frame().height() + dy;
2846
 
            }
2847
 
 
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;
2851
 
            } else {
2852
 
                 m_last_resize_w = frame().width() + dx;
2853
 
            }
2854
 
 
2855
 
            fixsize(&gx, &gy);
2856
 
 
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());
2862
 
 
2863
 
            screen().showGeometry(gx, gy);
2864
 
        }
2865
 
    } else if (functions.tabable &&
2866
 
               (me.state & Button2Mask) && inside_titlebar && (client != 0 || m_attaching_tab != 0)) {
2867
 
        //
2868
 
        // drag'n'drop code for tabs
2869
 
        //
2870
 
        FbTk::TextButton &active_button = *m_labelbuttons[(m_attaching_tab==0)?client:m_attaching_tab];
2871
 
 
2872
 
        if (m_attaching_tab == 0) {
2873
 
            if (s_num_grabs > 0)
2874
 
                return;
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;
2889
 
 
2890
 
            Fluxbox::instance()->grab();
2891
 
 
2892
 
            parent().drawRectangle(screen().rootTheme().opGC(),
2893
 
                                   m_last_move_x, m_last_move_y,
2894
 
                                   active_button.width(),
2895
 
                                   active_button.height());
2896
 
 
2897
 
            menu().hide();
2898
 
        } else {
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;
2902
 
 
2903
 
            //erase rectangle
2904
 
            parent().drawRectangle(screen().rootTheme().opGC(),
2905
 
                                   m_last_move_x, m_last_move_y,
2906
 
                                   active_button.width(),
2907
 
                                   active_button.height());
2908
 
 
2909
 
 
2910
 
            // redraw rectangle at new pos
2911
 
            m_last_move_x = dx;
2912
 
            m_last_move_y = dy;
2913
 
            parent().drawRectangle(screen().rootTheme().opGC(),
2914
 
                                   m_last_move_x, m_last_move_y,
2915
 
                                   active_button.width(),
2916
 
                                   active_button.height());
2917
 
 
2918
 
 
2919
 
        }
2920
 
    }
2921
 
 
2922
 
}
2923
 
 
2924
 
void FluxboxWindow::enterNotifyEvent(XCrossingEvent &ev) {
2925
 
 
2926
 
    // ignore grab activates, or if we're not visible
2927
 
    if (ev.mode == NotifyGrab ||
2928
 
        !isVisible()) {
2929
 
        return;
2930
 
    }
2931
 
 
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;
2943
 
                
2944
 
    }
2945
 
 
2946
 
    if (ev.window == frame().window() ||
2947
 
        ev.window == m_client->window() ||
2948
 
        client) {
2949
 
 
2950
 
        if (screen().isMouseFocus() && !isFocused()) {
2951
 
 
2952
 
            // check that there aren't any subsequent leave notify events in the
2953
 
            // X event queue
2954
 
            XEvent dummy;
2955
 
            scanargs sa;
2956
 
            sa.w = ev.window;
2957
 
            sa.enter = sa.leave = False;
2958
 
            XCheckIfEvent(display, &dummy, queueScanner, (char *) &sa);
2959
 
 
2960
 
            if ((!sa.leave || sa.inferior)) {
2961
 
                setInputFocus();
2962
 
            }
2963
 
        }
2964
 
    }
2965
 
 
2966
 
    if (screen().isMouseTabFocus() && client && client != m_client) {
2967
 
        setCurrentClient(*client, isFocused());
2968
 
    }
2969
 
 
2970
 
}
2971
 
 
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);
2976
 
}
2977
 
 
2978
 
// TODO: functions should not be affected by decoration
2979
 
void FluxboxWindow::setDecoration(Decoration decoration, bool apply) {
2980
 
    switch (decoration) {
2981
 
    case DECOR_NONE:
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
2989
 
        break;
2990
 
 
2991
 
    default:
2992
 
    case DECOR_NORMAL:
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;
2998
 
        break;
2999
 
 
3000
 
    case DECOR_TINY:
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;
3005
 
        break;
3006
 
 
3007
 
    case DECOR_TOOL:
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;
3012
 
        break;
3013
 
    }
3014
 
 
3015
 
    // we might want to wait with apply decorations
3016
 
    if (apply)
3017
 
        applyDecorations();
3018
 
 
3019
 
    //!! TODO: make sure this is correct
3020
 
    // is this reconfigure necessary???
3021
 
    //    reconfigure();
3022
 
 
3023
 
}
3024
 
 
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
3028
 
 
3029
 
    int grav_x=0, grav_y=0;
3030
 
    // negate gravity
3031
 
    frame().gravityTranslate(grav_x, grav_y, -m_client->gravity(), false);
3032
 
 
3033
 
    unsigned int border_width = 0;
3034
 
    if (decorations.border)
3035
 
        border_width = frame().theme().border().width();
3036
 
 
3037
 
    bool client_move = false;
3038
 
 
3039
 
    if (initial || frame().window().borderWidth() != border_width) {
3040
 
        client_move = true;
3041
 
        frame().setBorderWidth(border_width);
3042
 
    }
3043
 
 
3044
 
    // we rely on frame not doing anything if it is already shown/hidden
3045
 
    if (decorations.titlebar)
3046
 
        client_move |= frame().showTitlebar();
3047
 
    else
3048
 
        client_move |= frame().hideTitlebar();
3049
 
 
3050
 
    if (decorations.handle) {
3051
 
        client_move |= frame().showHandle();
3052
 
    } else
3053
 
        client_move |= frame().hideHandle();
3054
 
 
3055
 
    // apply gravity once more
3056
 
    frame().gravityTranslate(grav_x, grav_y, m_client->gravity(), false);
3057
 
 
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());
3061
 
        client_move = true;
3062
 
    }
3063
 
 
3064
 
    frame().reconfigure();
3065
 
    if (!initial && client_move)
3066
 
        sendConfigureNotify();
3067
 
 
3068
 
}
3069
 
 
3070
 
void FluxboxWindow::toggleDecoration() {
3071
 
    //don't toggle decor if the window is shaded
3072
 
    if (isShaded())
3073
 
        return;
3074
 
 
3075
 
    m_toggled_decos= true;
3076
 
 
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);
3084
 
        } else {
3085
 
            setDecoration(m_old_decoration);
3086
 
        }
3087
 
    }
3088
 
}
3089
 
 
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)
3105
 
        ret |= DECORM_MENU;
3106
 
    if (decorations.sticky)
3107
 
        ret |= DECORM_STICKY;
3108
 
    if (decorations.shade)
3109
 
        ret |= DECORM_SHADE;
3110
 
    if (decorations.tab)
3111
 
        ret |= DECORM_TAB;
3112
 
    if (decorations.enabled)
3113
 
        ret |= DECORM_ENABLED;
3114
 
    return ret;
3115
 
}
3116
 
 
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;
3129
 
    applyDecorations();
3130
 
}
3131
 
 
3132
 
void FluxboxWindow::startMoving(Window win) {
3133
 
    if (s_num_grabs > 0)
3134
 
        return;
3135
 
 
3136
 
    moving = true;
3137
 
    maximized = MAX_NONE;
3138
 
    
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);
3145
 
 
3146
 
    if (menu().isVisible())
3147
 
        menu().hide();
3148
 
 
3149
 
    fluxbox->maskWindowEvents(screen().rootWindow().window(), this);
3150
 
 
3151
 
    m_last_move_x = frame().x();
3152
 
    m_last_move_y = frame().y();
3153
 
    if (! screen().doOpaqueMove()) {
3154
 
        fluxbox->grab();
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());
3160
 
    }
3161
 
}
3162
 
 
3163
 
void FluxboxWindow::stopMoving(bool interrupted) {
3164
 
    moving = false;
3165
 
    Fluxbox *fluxbox = Fluxbox::instance();
3166
 
 
3167
 
    fluxbox->maskWindowEvents(0, 0);
3168
 
 
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);
3174
 
        if (!interrupted) {
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);
3178
 
                frame().show();
3179
 
            }
3180
 
        }
3181
 
        fluxbox->ungrab();
3182
 
    } else if (!interrupted) {
3183
 
        moveResize(frame().x(), frame().y(), frame().width(), frame().height(), ForgetGravity, true);
3184
 
        frame().notifyMoved(true);
3185
 
    }
3186
 
 
3187
 
 
3188
 
    screen().hidePosition();
3189
 
    ungrabPointer(CurrentTime);
3190
 
 
3191
 
    FbTk::App::instance()->sync(false); //make sure the redraw is made before we continue
3192
 
}
3193
 
 
3194
 
void FluxboxWindow::pauseMoving() {
3195
 
    if (screen().doOpaqueMove()) {
3196
 
        return;
3197
 
    }
3198
 
 
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);
3203
 
 
3204
 
}
3205
 
 
3206
 
 
3207
 
void FluxboxWindow::resumeMoving() {
3208
 
    if (screen().doOpaqueMove()) {
3209
 
        return;
3210
 
    }
3211
 
 
3212
 
    if (m_workspace_number == screen().currentWorkspaceID()) {
3213
 
        frame().show();
3214
 
        setInputFocus();
3215
 
    }
3216
 
 
3217
 
    FbTk::App::instance()->sync(false);
3218
 
 
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);
3223
 
 
3224
 
}
3225
 
 
3226
 
/**
3227
 
 * Helper function that snaps a window to another window
3228
 
 * We snap if we're closer than the x/ylimits.
3229
 
 */
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
3234
 
 
3235
 
    // for left + right, need to be in the right y range
3236
 
    if (top <= obottom && bottom >= otop) {
3237
 
        // left
3238
 
        if (abs(left-oleft)  < abs(xlimit)) xlimit = -(left-oleft);
3239
 
        if (abs(right-oleft) < abs(xlimit)) xlimit = -(right-oleft);
3240
 
 
3241
 
        // right
3242
 
        if (abs(left-oright)  < abs(xlimit)) xlimit = -(left-oright);
3243
 
        if (abs(right-oright) < abs(xlimit)) xlimit = -(right-oright);
3244
 
    }
3245
 
 
3246
 
    // for top + bottom, need to be in the right x range
3247
 
    if (left <= oright && right >= oleft) {
3248
 
        // top
3249
 
        if (abs(top-otop)    < abs(ylimit)) ylimit = -(top-otop);
3250
 
        if (abs(bottom-otop) < abs(ylimit)) ylimit = -(bottom-otop);
3251
 
 
3252
 
        // bottom
3253
 
        if (abs(top-obottom)    < abs(ylimit)) ylimit = -(top-obottom);
3254
 
        if (abs(bottom-obottom) < abs(ylimit)) ylimit = -(bottom-obottom);
3255
 
    }
3256
 
 
3257
 
}
3258
 
 
3259
 
/*
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
3262
 
 */
3263
 
void FluxboxWindow::doSnapping(int &orig_left, int &orig_top) {
3264
 
    /*
3265
 
     * Snap to screen/head edges
3266
 
     * Snap to windows
3267
 
     */
3268
 
 
3269
 
    if (screen().getEdgeSnapThreshold() == 0) return;
3270
 
 
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;
3275
 
 
3276
 
    // we only care about the left/top etc that includes borders
3277
 
    int borderW = 0;
3278
 
 
3279
 
    if (decorationMask() & (DECORM_ENABLED|DECORM_BORDER|DECORM_HANDLE))
3280
 
        borderW = frame().window().borderWidth();
3281
 
 
3282
 
    int top = orig_top; // orig include the borders
3283
 
    int left = orig_left;
3284
 
    
3285
 
    int right = orig_left + width() + 2 * borderW;
3286
 
    int bottom = orig_top + height() + 2 * borderW;
3287
 
 
3288
 
    /////////////////////////////////////
3289
 
    // begin by checking the screen (or Xinerama head) edges
3290
 
 
3291
 
    int h;
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),
3299
 
                         screen().maxTop(h),
3300
 
                         screen().maxBottom(h));
3301
 
        }
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));
3308
 
        }
3309
 
    } else {
3310
 
        snapToWindow(dx, dy, left, right, top, bottom,
3311
 
                     screen().maxLeft(0),
3312
 
                     screen().maxRight(0),
3313
 
                     screen().maxTop(0),
3314
 
                     screen().maxBottom(0));
3315
 
 
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));
3321
 
    }
3322
 
 
3323
 
 
3324
 
    /////////////////////////////////////
3325
 
    // now check window edges
3326
 
 
3327
 
    Workspace::Windows &wins =
3328
 
        screen().currentWorkspace()->windowList();
3329
 
 
3330
 
    Workspace::Windows::iterator it = wins.begin();
3331
 
    Workspace::Windows::iterator it_end = wins.end();
3332
 
 
3333
 
    unsigned int bw;
3334
 
    for (; it != it_end; it++) {
3335
 
        if ((*it) == this) 
3336
 
            continue; // skip myself
3337
 
 
3338
 
        bw = (*it)->decorationMask() & (DECORM_ENABLED|DECORM_BORDER|DECORM_HANDLE) ? 
3339
 
                (*it)->frame().window().borderWidth() : 0;
3340
 
 
3341
 
        snapToWindow(dx, dy, left, right, top, bottom,
3342
 
                     (*it)->x(),
3343
 
                     (*it)->x() + (*it)->width() + 2 * bw,
3344
 
                     (*it)->y(),
3345
 
                     (*it)->y() + (*it)->height() + 2 * bw);
3346
 
    }
3347
 
 
3348
 
    // commit
3349
 
    if (dx <= screen().getEdgeSnapThreshold())
3350
 
        orig_left += dx;
3351
 
    if (dy <= screen().getEdgeSnapThreshold())
3352
 
        orig_top  += dy;
3353
 
 
3354
 
}
3355
 
 
3356
 
 
3357
 
void FluxboxWindow::startResizing(Window win, int x, int y) {
3358
 
    if (s_num_grabs > 0 || isShaded() || isIconic() )
3359
 
        return;
3360
 
 
3361
 
    resizing = true;
3362
 
    maximized = MAX_NONE;
3363
 
 
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();
3368
 
 
3369
 
    grabPointer(win, false, ButtonMotionMask | ButtonReleaseMask,
3370
 
                GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
3371
 
 
3372
 
    int gx = 0, gy = 0;
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();
3379
 
 
3380
 
    fixsize(&gx, &gy);
3381
 
 
3382
 
 
3383
 
    screen().showGeometry(gx, gy);
3384
 
 
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());
3389
 
}
3390
 
 
3391
 
void FluxboxWindow::stopResizing(bool interrupted) {
3392
 
    resizing = false;
3393
 
 
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());
3398
 
 
3399
 
    screen().hideGeometry();
3400
 
 
3401
 
    if (!interrupted) {
3402
 
        fixsize();
3403
 
 
3404
 
        moveResize(m_last_resize_x, m_last_resize_y,
3405
 
                   m_last_resize_w, m_last_resize_h);
3406
 
    }
3407
 
 
3408
 
    ungrabPointer(CurrentTime);
3409
 
}
3410
 
 
3411
 
void FluxboxWindow::attachTo(int x, int y, bool interrupted) {
3412
 
    if (m_attaching_tab == 0)
3413
 
        return;
3414
 
 
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());
3419
 
 
3420
 
    ungrabPointer(CurrentTime);
3421
 
 
3422
 
    Fluxbox::instance()->ungrab();
3423
 
 
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;
3427
 
 
3428
 
    if (interrupted)
3429
 
        return;
3430
 
 
3431
 
    int dest_x = 0, dest_y = 0;
3432
 
    Window child = 0;
3433
 
    if (XTranslateCoordinates(display, parent().window(),
3434
 
                              parent().window(),
3435
 
                              x, y, &dest_x, &dest_y, &child)) {
3436
 
 
3437
 
        bool inside_titlebar = false;
3438
 
        // search for a fluxboxwindow
3439
 
        WinClient *client = Fluxbox::instance()->searchWindow(child);
3440
 
        FluxboxWindow *attach_to_win = 0;
3441
 
        if (client) {
3442
 
 
3443
 
            inside_titlebar = client->fbwindow()->hasTitlebar() &&
3444
 
                client->fbwindow()->y() + client->fbwindow()->titlebarHeight() > dest_y;
3445
 
            
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();
3451
 
            }
3452
 
        }
3453
 
 
3454
 
        if (attach_to_win != this &&
3455
 
            attach_to_win != 0 && attach_to_win->isTabable()) {
3456
 
 
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();
3468
 
            }
3469
 
        } else if( attach_to_win == this && attach_to_win->isTabable()) {
3470
 
            //reording of tabs within a frame
3471
 
            moveClientTo(*old_attached, x, y);
3472
 
        }
3473
 
    }
3474
 
}
3475
 
 
3476
 
void FluxboxWindow::restore(WinClient *client, bool remap) {
3477
 
    if (client->fbwindow() != this)
3478
 
        return;
3479
 
 
3480
 
    XChangeSaveSet(display, client->window(), SetModeDelete);
3481
 
    client->setEventMask(NoEventMask);
3482
 
 
3483
 
    int wx = frame().x(), wy = frame().y(); // not actually used here
3484
 
    frame().gravityTranslate(wx, wy, -client->gravity(), true); // negative to invert
3485
 
 
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
3490
 
    //client->hide();
3491
 
 
3492
 
    // restore old border width
3493
 
    client->setBorderWidth(client->old_bw);
3494
 
 
3495
 
    XEvent xev;
3496
 
    if (! XCheckTypedWindowEvent(display, client->window(), ReparentNotify,
3497
 
                                 &xev)) {
3498
 
#ifdef DEBUG
3499
 
        cerr<<"FluxboxWindow::restore: reparent 0x"<<hex<<client->window()<<dec<<" to root"<<endl;
3500
 
 
3501
 
#endif // DEBUG
3502
 
        // reparent to root window
3503
 
        client->reparent(screen().rootWindow(), frame().x(), frame().y(), false);
3504
 
 
3505
 
        if (!remap)
3506
 
            client->hide();
3507
 
    }
3508
 
 
3509
 
    if (remap)
3510
 
        client->show();
3511
 
 
3512
 
    installColormap(false);
3513
 
 
3514
 
    delete client;
3515
 
 
3516
 
 
3517
 
#ifdef DEBUG
3518
 
    cerr<<"FluxboxWindow::restore: remap = "<<remap<<endl;
3519
 
    cerr<<__FILE__<<"("<<__FUNCTION__<<"): numClients() = "<<numClients()<<endl;
3520
 
#endif // DEBUG
3521
 
    if (numClients() == 0) {
3522
 
        hide(true);
3523
 
    }
3524
 
 
3525
 
}
3526
 
 
3527
 
void FluxboxWindow::restore(bool remap) {
3528
 
    if (numClients() == 0)
3529
 
        return;
3530
 
#ifdef DEBUG
3531
 
    cerr<<"restore("<<remap<<")"<<endl;
3532
 
#endif // DEBUG
3533
 
    while (!clientList().empty()) {
3534
 
        restore(clientList().back(), remap);
3535
 
        // deleting winClient removes it from the clientList
3536
 
    }
3537
 
}
3538
 
 
3539
 
bool FluxboxWindow::isVisible() const {
3540
 
    return frame().isVisible();
3541
 
}
3542
 
 
3543
 
FbTk::FbWindow &FluxboxWindow::fbWindow() {
3544
 
    return frame().window();
3545
 
}
3546
 
 
3547
 
const FbTk::FbWindow &FluxboxWindow::fbWindow() const {
3548
 
    return frame().window();
3549
 
}
3550
 
 
3551
 
FbTk::Menu &FluxboxWindow::menu() {
3552
 
    return screen().windowMenu();
3553
 
}
3554
 
 
3555
 
const FbTk::Menu &FluxboxWindow::menu() const {
3556
 
    return screen().windowMenu();
3557
 
}
3558
 
 
3559
 
unsigned int FluxboxWindow::titlebarHeight() const {
3560
 
    return frame().titlebarHeight();
3561
 
}
3562
 
 
3563
 
Window FluxboxWindow::clientWindow() const  {
3564
 
    if (m_client == 0)
3565
 
        return 0;
3566
 
    return m_client->window();
3567
 
}
3568
 
 
3569
 
const std::string &FluxboxWindow::title() const {
3570
 
    static string empty_string("");
3571
 
    if (m_client == 0)
3572
 
        return empty_string;
3573
 
    return m_client->title();
3574
 
}
3575
 
 
3576
 
const std::string &FluxboxWindow::iconTitle() const {
3577
 
    static string empty_string("");
3578
 
    if (m_client == 0)
3579
 
        return empty_string;
3580
 
    return m_client->iconTitle();
3581
 
}
3582
 
 
3583
 
int FluxboxWindow::initialState() const { return m_client->initial_state; }
3584
 
 
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)))
3589
 
        shade();
3590
 
 
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)
3596
 
            iconify();
3597
 
        else if (iconic && !want_iconic)
3598
 
            deiconify();
3599
 
    }
3600
 
 
3601
 
    if (net.flags & (ATTRIB_MAXVERT | ATTRIB_MAXHORIZ)) {
3602
 
        // make maximise look like the net maximise flags
3603
 
        int want_max = MAX_NONE;
3604
 
 
3605
 
        if (net.flags & ATTRIB_MAXVERT)
3606
 
            want_max |= MAX_VERT;
3607
 
        if (net.flags & ATTRIB_MAXHORIZ)
3608
 
            want_max |= MAX_HORZ;
3609
 
 
3610
 
        if (want_max == MAX_NONE && maximized != MAX_NONE) {
3611
 
            maximize(MAX_NONE);
3612
 
        } else if (want_max == MAX_FULL && maximized != MAX_FULL) {
3613
 
            maximize(MAX_FULL);
3614
 
            // horz and vert are a little trickier to morph
3615
 
        }
3616
 
            // to toggle vert
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)) {
3621
 
            maximize(MAX_VERT);
3622
 
        }
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)) {
3626
 
            maximize(MAX_HORZ);
3627
 
        }
3628
 
    }
3629
 
 
3630
 
    if ((net.flags & ATTRIB_OMNIPRESENT) &&
3631
 
        ((m_blackbox_attrib.attrib & ATTRIB_OMNIPRESENT) !=
3632
 
         (net.attrib & ATTRIB_OMNIPRESENT)))
3633
 
        stick();
3634
 
 
3635
 
    if ((net.flags & ATTRIB_WORKSPACE) &&
3636
 
        (m_workspace_number !=  net.workspace)) {
3637
 
 
3638
 
        screen().reassociateWindow(this, net.workspace, true);
3639
 
 
3640
 
        if (screen().currentWorkspaceID() != net.workspace)
3641
 
            withdraw(true);
3642
 
        else
3643
 
            deiconify();
3644
 
    }
3645
 
 
3646
 
    if (net.flags & ATTRIB_STACK) {
3647
 
        if ((unsigned int) m_layernum != net.stack) {
3648
 
            moveToLayer(net.stack);
3649
 
        }
3650
 
    }
3651
 
 
3652
 
    if (net.flags & ATTRIB_DECORATION) {
3653
 
        m_old_decoration = static_cast<Decoration>(net.decoration);
3654
 
        setDecoration(m_old_decoration);
3655
 
    }
3656
 
 
3657
 
}
3658
 
 
3659
 
 
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;
3668
 
 
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;
3672
 
 
3673
 
    // dy = new height (w/o decorations), similarly
3674
 
    int dh = m_last_resize_h - decoration_height;
3675
 
 
3676
 
    m_client->applySizeHints(dw, dh, user_w, user_h);
3677
 
 
3678
 
    // update last resize
3679
 
    m_last_resize_w = dw;
3680
 
    m_last_resize_h = dh + decoration_height;
3681
 
 
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;
3685
 
    }
3686
 
 
3687
 
    if (m_resize_corner == LEFTTOP || m_resize_corner == RIGHTTOP) {
3688
 
        m_last_resize_y = frame().y() + frame().height() - m_last_resize_h;
3689
 
    }
3690
 
 
3691
 
}
3692
 
 
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());
3702
 
}
3703
 
 
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);
3709
 
        /*
3710
 
          Send event telling where the root position
3711
 
          of the client window is. (ie frame pos + client pos inside the frame = send pos)
3712
 
        */
3713
 
        //!!
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());
3721
 
 
3722
 
        if (send_to_netizens) {
3723
 
            XEvent event;
3724
 
            event.type = ConfigureNotify;
3725
 
 
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;
3736
 
 
3737
 
            screen().updateNetizenConfigNotify(event);
3738
 
        }
3739
 
    } // end for
3740
 
}
3741
 
 
3742
 
 
3743
 
void FluxboxWindow::close() {
3744
 
    if (m_client)
3745
 
        m_client->sendClose(false);
3746
 
}
3747
 
 
3748
 
void FluxboxWindow::kill() {
3749
 
    if (m_client)
3750
 
        m_client->sendClose(true);
3751
 
}
3752
 
 
3753
 
void FluxboxWindow::setupWindow() {
3754
 
    // sets up our window
3755
 
    // we allow both to be done at once to share the commands
3756
 
 
3757
 
    WinButtonTheme &winbutton_theme = screen().winButtonTheme();
3758
 
 
3759
 
    using namespace FbTk;
3760
 
    typedef RefCount<Command> CommandRef;
3761
 
    typedef SimpleCommand<FluxboxWindow> WindowCmd;
3762
 
 
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));
3778
 
 
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,
3791
 
                                          frame().titlebar(),
3792
 
                                          0, 0, 10, 10);
3793
 
                newbutton->setOnClick(iconify_cmd);
3794
 
 
3795
 
            } else if (isMaximizable() && (*dir)[i] == Fluxbox::MAXIMIZE) {
3796
 
                newbutton = new WinButton(*this, winbutton_theme,
3797
 
                                          WinButton::MAXIMIZE,
3798
 
                                          frame().titlebar(),
3799
 
                                          0, 0, 10, 10);
3800
 
 
3801
 
                newbutton->setOnClick(maximize_cmd, 1);
3802
 
                newbutton->setOnClick(maximize_horiz_cmd, 3);
3803
 
                newbutton->setOnClick(maximize_vert_cmd, 2);
3804
 
 
3805
 
            } else if (m_client->isClosable() && (*dir)[i] == Fluxbox::CLOSE) {
3806
 
                newbutton = new WinButton(*this, winbutton_theme,
3807
 
                                          WinButton::CLOSE,
3808
 
                                          frame().titlebar(),
3809
 
                                          0, 0, 10, 10);
3810
 
 
3811
 
                newbutton->setOnClick(close_cmd);
3812
 
 
3813
 
            } else if ((*dir)[i] == Fluxbox::STICK) {
3814
 
                WinButton *winbtn = new WinButton(*this, winbutton_theme,
3815
 
                                                  WinButton::STICK,
3816
 
                                                  frame().titlebar(),
3817
 
                                                  0, 0, 10, 10);
3818
 
                stateSig().attach(winbtn);
3819
 
                winbtn->setOnClick(stick_cmd);
3820
 
                newbutton = winbtn;
3821
 
            } else if ((*dir)[i] == Fluxbox::SHADE) {
3822
 
                WinButton *winbtn = new WinButton(*this, winbutton_theme,
3823
 
                                                  WinButton::SHADE,
3824
 
                                                  frame().titlebar(),
3825
 
                                                  0, 0, 10, 10);
3826
 
                stateSig().attach(winbtn);
3827
 
                winbtn->setOnClick(shade_cmd);
3828
 
                newbutton = winbtn;
3829
 
            } else if ((*dir)[i] == Fluxbox::MENUICON) {
3830
 
                WinButton* winbtn = new WinButton(*this, winbutton_theme,
3831
 
                                                  WinButton::MENUICON,
3832
 
                                                  frame().titlebar(),
3833
 
                                                  0, 0, 10, 10);
3834
 
                hintSig().attach(winbtn);
3835
 
                titleSig().attach(winbtn);
3836
 
                winbtn->setOnClick(show_menu_cmd);
3837
 
                newbutton = winbtn;
3838
 
            }
3839
 
 
3840
 
            if (newbutton != 0) {
3841
 
                newbutton->show();
3842
 
                if (c == 0)
3843
 
                    frame().addLeftButton(newbutton);
3844
 
                else
3845
 
                    frame().addRightButton(newbutton);
3846
 
            }
3847
 
        } //end for i
3848
 
        dir = &Fluxbox::instance()->getTitlebarRight();
3849
 
    } // end for c
3850
 
 
3851
 
    frame().reconfigure();
3852
 
 
3853
 
    // setup titlebar
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
3858
 
 
3859
 
    int reverse = 0;
3860
 
    if (screen().getScrollReverse())
3861
 
        reverse = 1;
3862
 
    
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
3869
 
    }
3870
 
 
3871
 
    frame().setDoubleClickTime(Fluxbox::instance()->getDoubleClickInterval());
3872
 
 
3873
 
    // end setup frame
3874
 
 
3875
 
}
3876
 
 
3877
 
 
3878
 
/**
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.
3882
 
 */
3883
 
void FluxboxWindow::reconfigTheme() {
3884
 
 
3885
 
    m_frame.setBorderWidth(decorations.border ?
3886
 
                           frame().theme().border().width() : 0);
3887
 
    if (decorations.handle && frame().theme().handleWidth() != 0)
3888
 
        frame().showHandle();
3889
 
    else
3890
 
        frame().hideHandle();
3891
 
 
3892
 
    ClientList::iterator it = clientList().begin();
3893
 
    ClientList::iterator it_end = clientList().end();
3894
 
 
3895
 
    int x = m_frame.clientArea().x(),
3896
 
        y = m_frame.clientArea().y();
3897
 
 
3898
 
    unsigned int width = m_frame.clientArea().width(),
3899
 
        height = m_frame.clientArea().height();
3900
 
 
3901
 
    for (; it != it_end; ++it) {
3902
 
        (*it)->moveResize(x, y, width, height);
3903
 
    }
3904
 
 
3905
 
    sendConfigureNotify();
3906
 
}
3907
 
 
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,
3915
 
                                Bool owner_events,
3916
 
                                unsigned int event_mask,
3917
 
                                int pointer_mode, int keyboard_mode,
3918
 
                                Window confine_to,
3919
 
                                Cursor cursor,
3920
 
                                Time time) {
3921
 
    XGrabPointer(FbTk::App::instance()->display(),
3922
 
                 grab_window,
3923
 
                 owner_events,
3924
 
                 event_mask,
3925
 
                 pointer_mode, keyboard_mode,
3926
 
                 confine_to,
3927
 
                 cursor,
3928
 
                 time);
3929
 
    s_num_grabs++;
3930
 
}
3931
 
 
3932
 
// ungrab and decrease counter
3933
 
void FluxboxWindow::ungrabPointer(Time time) {
3934
 
    XUngrabPointer(FbTk::App::instance()->display(), time);
3935
 
    s_num_grabs--;
3936
 
    if (s_num_grabs < 0)
3937
 
        s_num_grabs = 0;
3938
 
}
3939
 
 
3940
 
void FluxboxWindow::associateClient(WinClient &client) {
3941
 
 
3942
 
    FbWinFrame::ButtonId btn = frame().createTab(client.title(),
3943
 
                                                 new SetClientCmd(client));
3944
 
 
3945
 
    m_labelbuttons[&client] = btn;
3946
 
 
3947
 
 
3948
 
    FbTk::EventManager &evm = *FbTk::EventManager::instance();
3949
 
 
3950
 
    evm.add(*this, btn->window()); // we take care of button events for this
3951
 
    evm.add(*this, client.window());
3952
 
    client.setFluxboxWindow(this);
3953
 
}