~ubuntu-branches/ubuntu/trusty/fluxbox/trusty-proposed

« back to all changes in this revision

Viewing changes to src/WinClient.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
 
// WinClient.cc for Fluxbox - an X11 Window manager
2
 
// Copyright (c) 2003 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
3
 
//
4
 
// Permission is hereby granted, free of charge, to any person obtaining a
5
 
// copy of this software and associated documentation files (the "Software"),
6
 
// to deal in the Software without restriction, including without limitation
7
 
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
 
// and/or sell copies of the Software, and to permit persons to whom the
9
 
// Software is furnished to do so, subject to the following conditions:
10
 
//
11
 
// The above copyright notice and this permission notice shall be included in
12
 
// all copies or substantial portions of the Software.
13
 
//
14
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17
 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
 
// DEALINGS IN THE SOFTWARE.
21
 
 
22
 
// $Id: WinClient.cc 3967 2005-04-29 02:52:36Z fluxgen $
23
 
 
24
 
#include "WinClient.hh"
25
 
 
26
 
#include "Window.hh"
27
 
#include "fluxbox.hh"
28
 
#include "Screen.hh"
29
 
#include "FbAtoms.hh"
30
 
 
31
 
#include "Xutil.hh"
32
 
 
33
 
#include "EventManager.hh"
34
 
#include "FbTk/I18n.hh"
35
 
#include "FbTk/MultLayers.hh"
36
 
 
37
 
#include <iostream>
38
 
#include <algorithm>
39
 
#include <iterator>
40
 
#include <memory>
41
 
 
42
 
#ifdef HAVE_CASSERT
43
 
  #include <cassert>
44
 
#else
45
 
  #include <assert.h>
46
 
#endif
47
 
 
48
 
using namespace std;
49
 
 
50
 
 
51
 
WinClient::TransientWaitMap WinClient::s_transient_wait;
52
 
 
53
 
WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::FbWindow(win),
54
 
                     transient_for(0),
55
 
                     window_group(0),
56
 
                     x(0), y(0), old_bw(0),
57
 
                     min_width(1), min_height(1),
58
 
                     max_width(0), max_height(0),
59
 
                     width_inc(1), height_inc(1),
60
 
                     min_aspect_x(0), min_aspect_y(0),
61
 
                     max_aspect_x(0), max_aspect_y(0),
62
 
                     base_width(1), base_height(1),
63
 
                     initial_state(0),
64
 
                     normal_hint_flags(0),
65
 
                     wm_hint_flags(0),
66
 
                     m_win(fbwin),
67
 
                     m_modal(0),
68
 
                     send_focus_message(false),
69
 
                     send_close_message(false),
70
 
                     m_win_gravity(0),
71
 
                     m_title(""), m_icon_title(""),
72
 
                     m_class_name(""), m_instance_name(""),
73
 
                     m_blackbox_hint(0),
74
 
                     m_mwm_hint(0),
75
 
                     m_focus_mode(F_PASSIVE),
76
 
                     m_diesig(*this), m_screen(screen), 
77
 
                     m_strut(0) {
78
 
    updateWMProtocols();
79
 
    updateBlackboxHints();
80
 
    updateMWMHints();
81
 
    updateWMHints();
82
 
    updateWMNormalHints();
83
 
    updateWMClassHint();
84
 
    updateTitle();
85
 
    updateIconTitle();
86
 
    Fluxbox::instance()->saveWindowSearch(win, this);
87
 
    if (window_group != None) 
88
 
        Fluxbox::instance()->saveGroupSearch(window_group, this);
89
 
 
90
 
    // search for this in transient waiting list
91
 
    if (s_transient_wait.find(win) != s_transient_wait.end()) {
92
 
        // Found transients that are waiting for this.
93
 
        // For each transient that waits call updateTransientInfo
94
 
        for_each(s_transient_wait[win].begin(),
95
 
                 s_transient_wait[win].end(),
96
 
                 mem_fun(&WinClient::updateTransientInfo));
97
 
        // clear transient waiting list for this window
98
 
        s_transient_wait.erase(win);
99
 
    }
100
 
}
101
 
 
102
 
WinClient::~WinClient() {
103
 
#ifdef DEBUG
104
 
    cerr<<__FILE__<<"(~"<<__FUNCTION__<<")[this="<<this<<"]"<<endl;
105
 
#endif // DEBUG
106
 
 
107
 
    FbTk::EventManager::instance()->remove(window());
108
 
 
109
 
    clearStrut();
110
 
 
111
 
    if (m_win != 0)
112
 
        m_win->removeClient(*this);
113
 
 
114
 
    // this takes care of any focus issues
115
 
    m_diesig.notify();
116
 
 
117
 
    Fluxbox *fluxbox = Fluxbox::instance();
118
 
 
119
 
 
120
 
    //
121
 
    // clear transients and transient_for
122
 
    //
123
 
    if (transient_for != 0) {
124
 
        assert(transient_for != this);
125
 
        transient_for->transientList().remove(this);
126
 
        transient_for = 0;
127
 
    }
128
 
    
129
 
    while (!transients.empty()) {
130
 
        transients.back()->transient_for = 0;
131
 
        transients.pop_back();
132
 
    }
133
 
    // This fixes issue 1 (see WinClient.hh):
134
 
    // If transients die before the transient_for is created
135
 
    removeTransientFromWaitingList();
136
 
    s_transient_wait.erase(window());
137
 
 
138
 
 
139
 
    screen().removeNetizen(window());
140
 
 
141
 
    if (window_group != 0) {
142
 
        fluxbox->removeGroupSearch(window_group);
143
 
        window_group = 0;
144
 
    }
145
 
 
146
 
    if (m_mwm_hint != 0)
147
 
        XFree(m_mwm_hint);
148
 
 
149
 
    if (m_blackbox_hint != 0)
150
 
        XFree(m_blackbox_hint);
151
 
 
152
 
    if (window())
153
 
        fluxbox->removeWindowSearch(window());
154
 
 
155
 
    m_win = 0;
156
 
}
157
 
 
158
 
bool WinClient::acceptsFocus() const {
159
 
    return (m_focus_mode == F_LOCALLYACTIVE || 
160
 
            m_focus_mode == F_PASSIVE || 
161
 
            m_focus_mode == F_GLOBALLYACTIVE && send_focus_message);
162
 
}
163
 
 
164
 
bool WinClient::sendFocus() {
165
 
    if (!send_focus_message)
166
 
        return false;
167
 
#ifdef DEBUG
168
 
    cerr<<"WinClient::"<<__FUNCTION__<<": this = "<<this<<
169
 
        " window = 0x"<<hex<<window()<<dec<<endl;
170
 
#endif // DEBUG
171
 
 
172
 
    // setup focus msg
173
 
    XEvent ce;
174
 
    ce.xclient.type = ClientMessage;
175
 
    ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom();
176
 
    ce.xclient.display = display();
177
 
    ce.xclient.window = window();
178
 
    ce.xclient.format = 32;
179
 
    ce.xclient.data.l[0] = FbAtoms::instance()->getWMTakeFocusAtom();
180
 
    ce.xclient.data.l[1] = Fluxbox::instance()->getLastTime();
181
 
    ce.xclient.data.l[2] = 0l;
182
 
    ce.xclient.data.l[3] = 0l;
183
 
    ce.xclient.data.l[4] = 0l;
184
 
    // send focus msg
185
 
    XSendEvent(display(), window(), false, NoEventMask, &ce);
186
 
    return true;
187
 
}
188
 
 
189
 
void WinClient::sendClose(bool forceful) {
190
 
    if (forceful || !send_close_message)
191
 
        XKillClient(display(), window());
192
 
    else {
193
 
        // send WM_DELETE message
194
 
        // fill in XClientMessage structure for delete message
195
 
        XEvent ce;
196
 
        ce.xclient.type = ClientMessage;
197
 
        ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom();
198
 
        ce.xclient.display = display();
199
 
        ce.xclient.window = window();
200
 
        ce.xclient.format = 32;
201
 
        ce.xclient.data.l[0] = FbAtoms::instance()->getWMDeleteAtom();
202
 
        ce.xclient.data.l[1] = CurrentTime;
203
 
        ce.xclient.data.l[2] = 0l;
204
 
        ce.xclient.data.l[3] = 0l;
205
 
        ce.xclient.data.l[4] = 0l;
206
 
        // send event delete message to client window
207
 
        XSendEvent(display(), window(), false, NoEventMask, &ce);
208
 
    }
209
 
}
210
 
 
211
 
bool WinClient::getAttrib(XWindowAttributes &attr) const {
212
 
    return XGetWindowAttributes(display(), window(), &attr);
213
 
}
214
 
 
215
 
bool WinClient::getWMName(XTextProperty &textprop) const {
216
 
    return XGetWMName(display(), window(), &textprop);
217
 
}
218
 
 
219
 
bool WinClient::getWMIconName(XTextProperty &textprop) const {
220
 
    return XGetWMName(display(), window(), &textprop);
221
 
}
222
 
 
223
 
const std::string &WinClient::getWMClassName() const {
224
 
    return m_instance_name;
225
 
}
226
 
 
227
 
const std::string &WinClient::getWMClassClass() const {
228
 
    return m_class_name;
229
 
}
230
 
 
231
 
void WinClient::updateWMClassHint() {
232
 
    XClassHint ch;
233
 
    if (XGetClassHint(display(), window(), &ch) == 0) {
234
 
#ifdef DEBUG
235
 
        cerr<<"WinClient: Failed to read class hint!"<<endl;
236
 
#endif //DEBUG
237
 
    } else {        
238
 
 
239
 
        if (ch.res_name != 0) {
240
 
            m_instance_name = const_cast<char *>(ch.res_name);
241
 
            XFree(ch.res_name);
242
 
            ch.res_name = 0;
243
 
        } else 
244
 
            m_instance_name = "";
245
 
        
246
 
        if (ch.res_class != 0) {
247
 
            m_class_name = const_cast<char *>(ch.res_class);
248
 
            XFree(ch.res_class);
249
 
            ch.res_class = 0;
250
 
        } else
251
 
            m_class_name = "";
252
 
    }
253
 
}
254
 
 
255
 
void WinClient::updateTransientInfo() {
256
 
#ifdef DEBUG
257
 
    cerr<<__FUNCTION__<<": m_win = "<<m_win<<endl;
258
 
#endif // DEBUG
259
 
    if (m_win == 0)
260
 
        return;
261
 
 
262
 
 
263
 
    // remove this from parent
264
 
    if (transientFor() != 0) {
265
 
        transientFor()->transientList().remove(this);
266
 
    }
267
 
    
268
 
    transient_for = 0;
269
 
    // determine if this is a transient window
270
 
    Window win = 0;
271
 
    if (!XGetTransientForHint(display(), window(), &win)) {
272
 
#ifdef DEBUG
273
 
        cerr<<__FUNCTION__<<": window() = 0x"<<hex<<window()<<dec<<"Failed to read transient for hint."<<endl;
274
 
#endif // DEBUG
275
 
        return;
276
 
    }
277
 
 
278
 
    // we can't be transient to ourself
279
 
    if (win == window()) {
280
 
#ifdef DEBUG
281
 
        cerr<<__FUNCTION__<<": transient to ourself"<<endl;
282
 
#endif // DEBUG
283
 
        return;
284
 
    }
285
 
        
286
 
    if (win != None && m_win->screen().rootWindow() == win) {
287
 
        // transient for root window... =  transient for group
288
 
        // I don't think we are group-aware yet
289
 
        return; 
290
 
    }
291
 
 
292
 
 
293
 
    transient_for = Fluxbox::instance()->searchWindow(win);
294
 
    // if we did not find a transient WinClient but still
295
 
    // have a transient X window, then we have to put the 
296
 
    // X transient_for window in a waiting list and update this clients transient
297
 
    // list later when the transient_for has a Winclient
298
 
    if (!transient_for) {
299
 
        // We might also already waiting for an old transient_for;
300
 
        // 
301
 
        // this call fixes issue 2:
302
 
        // If transients changes to new transient_for before the old transient_for is created. 
303
 
        // (see comment in WinClient.hh)
304
 
        //
305
 
        removeTransientFromWaitingList();
306
 
 
307
 
        s_transient_wait[win].push_back(this);
308
 
    }
309
 
 
310
 
 
311
 
#ifdef DEBUG
312
 
    cerr<<__FUNCTION__<<": transient_for window = 0x"<<hex<<win<<dec<<endl;
313
 
    cerr<<__FUNCTION__<<": transient_for = "<<transient_for<<endl;
314
 
#endif // DEBUG
315
 
    // make sure we don't have deadlock loop in transient chain
316
 
    for (WinClient *w = this; w != 0; w = w->transient_for) {
317
 
        if (w == w->transient_for) {
318
 
            w->transient_for = 0;
319
 
            break;
320
 
        }
321
 
    }
322
 
 
323
 
    if (transientFor() != 0) {
324
 
        // we need to add ourself to the right client in
325
 
        // the transientFor() window so we search client
326
 
        transient_for->transientList().push_back(this);
327
 
 
328
 
        if (transientFor()->fbwindow() && transientFor()->fbwindow()->isStuck())
329
 
            m_win->stick();
330
 
    }
331
 
 
332
 
}
333
 
 
334
 
 
335
 
void WinClient::updateTitle() {
336
 
    // why 512? very very long wmnames seem to either 
337
 
    // crash fluxbox or to make it have high cpuload
338
 
    // see also: 
339
 
    //    http://www.securityfocus.com/archive/1/382398/2004-11-24/2004-11-30/2
340
 
    // 
341
 
    // TODO: - find out why this mostly happens when using xft-fonts
342
 
    //       - why other windowmanagers (pekwm/pwm3/openbox etc) are
343
 
    //         also influenced
344
 
    //
345
 
    // the limitation to 512 chars only avoids running in that trap
346
 
    m_title = string(Xutil::getWMName(window()), 0, 512);
347
 
}
348
 
 
349
 
void WinClient::updateIconTitle() {
350
 
    XTextProperty text_prop;
351
 
    char **list = 0;
352
 
    int num = 0;
353
 
 
354
 
    if (getWMIconName(text_prop)) {
355
 
        if (text_prop.value && text_prop.nitems > 0) {
356
 
            if (text_prop.encoding != XA_STRING) {
357
 
                text_prop.nitems = strlen((char *) text_prop.value);
358
 
 
359
 
                if (XmbTextPropertyToTextList(display(), &text_prop,
360
 
                                               &list, &num) == Success &&
361
 
                    num > 0 && *list) {
362
 
                    m_icon_title = (char *)*list;
363
 
                    XFreeStringList(list);
364
 
                } else
365
 
                    m_icon_title = text_prop.value ? (char *)text_prop.value : "";
366
 
            } else
367
 
                m_icon_title = text_prop.value ? (char *)text_prop.value : "";
368
 
 
369
 
            if (text_prop.value)
370
 
                XFree((char *) text_prop.value);
371
 
        } else
372
 
            m_icon_title = title();
373
 
    } else
374
 
        m_icon_title = title();
375
 
 
376
 
}
377
 
 
378
 
void WinClient::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs) {
379
 
    changeProperty(FbAtoms::instance()->getFluxboxAttributesAtom(),
380
 
                   XA_CARDINAL, 32, PropModeReplace,
381
 
                   (unsigned char *)&blackbox_attribs,
382
 
                   FluxboxWindow::PropBlackboxAttributesElements
383
 
        );
384
 
}
385
 
 
386
 
void WinClient::setFluxboxWindow(FluxboxWindow *win) {
387
 
    m_win = win;
388
 
}
389
 
 
390
 
void WinClient::updateBlackboxHints() {
391
 
    int format;
392
 
    Atom atom_return;
393
 
    unsigned long num, len;
394
 
    FbAtoms *atoms = FbAtoms::instance();
395
 
 
396
 
    if (m_blackbox_hint) {
397
 
        XFree(m_blackbox_hint);
398
 
        m_blackbox_hint = 0;
399
 
    }
400
 
 
401
 
    if (property(atoms->getFluxboxHintsAtom(), 0,
402
 
                 PropBlackboxHintsElements, False,
403
 
                 atoms->getFluxboxHintsAtom(), &atom_return,
404
 
                 &format, &num, &len,
405
 
                 (unsigned char **) &m_blackbox_hint) &&
406
 
        m_blackbox_hint) {
407
 
 
408
 
        if (num != (unsigned)PropBlackboxHintsElements) {
409
 
            XFree(m_blackbox_hint);
410
 
            m_blackbox_hint = 0;
411
 
        }
412
 
    }
413
 
}
414
 
 
415
 
void WinClient::updateMWMHints() {
416
 
    int format;
417
 
    Atom atom_return;
418
 
    unsigned long num = 0, len = 0;
419
 
 
420
 
    if (m_mwm_hint) {
421
 
        XFree(m_mwm_hint);
422
 
        m_mwm_hint = 0;
423
 
    }
424
 
    Atom motif_wm_hints = FbAtoms::instance()->getMWMHintsAtom();
425
 
 
426
 
    if (!(property(motif_wm_hints, 0,
427
 
                   PropMwmHintsElements, false,
428
 
                   motif_wm_hints, &atom_return,
429
 
                   &format, &num, &len,
430
 
                   (unsigned char **) &m_mwm_hint) &&
431
 
          m_mwm_hint)) {
432
 
        if (num != static_cast<unsigned int>(PropMwmHintsElements)) {
433
 
            XFree(m_mwm_hint);
434
 
            m_mwm_hint = 0;
435
 
            return;
436
 
        }
437
 
    }
438
 
}
439
 
 
440
 
void WinClient::updateWMHints() {
441
 
    XWMHints *wmhint = XGetWMHints(display(), window());
442
 
    if (! wmhint) {
443
 
        m_focus_mode = F_PASSIVE;
444
 
        window_group = None;
445
 
        initial_state = NormalState;
446
 
    } else {
447
 
        wm_hint_flags = wmhint->flags;
448
 
        /*
449
 
         * ICCCM 4.1.7
450
 
         *---------------------------------------------
451
 
         * Input Model      Input Field   WM_TAKE_FOCUS
452
 
         *---------------------------------------------
453
 
         * No Input          False         Absent
454
 
         * Passive           True          Absent
455
 
         * Locally Active    True          Present
456
 
         * Globally Active   False         Present
457
 
         *---------------------------------------------
458
 
         * Here: WM_TAKE_FOCUS = send_focus_message
459
 
         *       Input Field   = wmhint->input
460
 
         *       Input Model   = m_focus_mode
461
 
         */
462
 
        if (wmhint->flags & InputHint) {
463
 
            if (wmhint->input) {
464
 
                if (send_focus_message)
465
 
                    m_focus_mode = F_LOCALLYACTIVE;
466
 
                else
467
 
                    m_focus_mode = F_PASSIVE;
468
 
            } else {
469
 
                if (send_focus_message)
470
 
                    m_focus_mode = F_GLOBALLYACTIVE;
471
 
                else
472
 
                    m_focus_mode = F_NOINPUT;
473
 
            }
474
 
        } else // InputHint not present: ignoring send_focus_message and assuming F_PASSIVE
475
 
            m_focus_mode = F_PASSIVE; 
476
 
 
477
 
        if (wmhint->flags & StateHint)
478
 
            initial_state = wmhint->initial_state;
479
 
        else
480
 
            initial_state = NormalState;
481
 
 
482
 
        if (wmhint->flags & WindowGroupHint) {
483
 
            if (! window_group)
484
 
                window_group = wmhint->window_group;
485
 
        } else
486
 
            window_group = None;
487
 
 
488
 
        XFree(wmhint);
489
 
    }
490
 
}
491
 
 
492
 
 
493
 
void WinClient::updateWMNormalHints() {
494
 
    long icccm_mask;
495
 
    XSizeHints sizehint;
496
 
    if (! XGetWMNormalHints(display(), window(), &sizehint, &icccm_mask)) {
497
 
        min_width = min_height =
498
 
            base_width = base_height =
499
 
            width_inc = height_inc = 1;
500
 
        max_width = 0; // unbounded
501
 
        max_height = 0;
502
 
        min_aspect_x = min_aspect_y =
503
 
            max_aspect_x = max_aspect_y = 0;
504
 
        m_win_gravity = NorthWestGravity;
505
 
    } else {
506
 
        normal_hint_flags = sizehint.flags;
507
 
 
508
 
        if (sizehint.flags & PMinSize) {
509
 
            min_width = sizehint.min_width;
510
 
            min_height = sizehint.min_height;
511
 
            if (!(sizehint.flags & PBaseSize)) {
512
 
                base_width = min_width;
513
 
                base_height = min_height;
514
 
            }
515
 
        } else {
516
 
            min_width = min_height = 1;
517
 
            base_width = base_height = 0;
518
 
        }
519
 
 
520
 
        if (sizehint.flags & PBaseSize) {
521
 
            base_width = sizehint.base_width;
522
 
            base_height = sizehint.base_height;
523
 
            if (!(sizehint.flags & PMinSize)) {
524
 
                min_width = base_width;
525
 
                min_height = base_height;
526
 
            }
527
 
        } // default set in PMinSize
528
 
 
529
 
        if (sizehint.flags & PMaxSize) {
530
 
            max_width = sizehint.max_width;
531
 
            max_height = sizehint.max_height;
532
 
        } else {
533
 
            max_width = 0; // unbounded
534
 
            max_height = 0;
535
 
        }
536
 
 
537
 
        if (sizehint.flags & PResizeInc) {
538
 
            width_inc = sizehint.width_inc;
539
 
            height_inc = sizehint.height_inc;
540
 
        } else
541
 
            width_inc = height_inc = 1;
542
 
 
543
 
        if (sizehint.flags & PAspect) {
544
 
            min_aspect_x = sizehint.min_aspect.x;
545
 
            min_aspect_y = sizehint.min_aspect.y;
546
 
            max_aspect_x = sizehint.max_aspect.x;
547
 
            max_aspect_y = sizehint.max_aspect.y;
548
 
        } else
549
 
            min_aspect_x = min_aspect_y =
550
 
                max_aspect_x = max_aspect_y = 0;
551
 
 
552
 
        if (sizehint.flags & PWinGravity)
553
 
            m_win_gravity = sizehint.win_gravity;
554
 
        else
555
 
            m_win_gravity = NorthWestGravity;
556
 
 
557
 
    }
558
 
}
559
 
 
560
 
Window WinClient::getGroupLeftWindow() const {
561
 
    int format;
562
 
    Atom atom_return;
563
 
    unsigned long num = 0, len = 0;
564
 
    Atom group_left_hint = XInternAtom(display(), "_FLUXBOX_GROUP_LEFT", False);
565
 
 
566
 
    Window *data = 0;
567
 
    if (property(group_left_hint, 0,
568
 
                   1, false,
569
 
                   XA_WINDOW, &atom_return,
570
 
                   &format, &num, &len,
571
 
                   (unsigned char **) &data) &&
572
 
        data) {
573
 
        if (num != 1) {
574
 
            XFree(data);
575
 
            return None;
576
 
        } else {
577
 
            Window ret = *data;
578
 
            XFree(data);
579
 
            return ret;
580
 
        }
581
 
    }
582
 
    return None;
583
 
}
584
 
 
585
 
 
586
 
void WinClient::setGroupLeftWindow(Window win) {
587
 
    Atom group_left_hint = XInternAtom(display(), "_FLUXBOX_GROUP_LEFT", False);
588
 
    changeProperty(group_left_hint, XA_WINDOW, 32, 
589
 
                   PropModeReplace, (unsigned char *) &win, 1);
590
 
}
591
 
 
592
 
bool WinClient::hasGroupLeftWindow() const {
593
 
    // try to find _FLUXBOX_GROUP_LEFT atom in window
594
 
    // if we have one then we have a group left window
595
 
    int format;
596
 
    Atom atom_return;
597
 
    unsigned long num = 0, len = 0;
598
 
    Atom group_left_hint = XInternAtom(display(), "_FLUXBOX_GROUP_LEFT", False);
599
 
 
600
 
    Window *data = 0;
601
 
    if (property(group_left_hint, 0,
602
 
                   1, false,
603
 
                   XA_WINDOW, &atom_return,
604
 
                   &format, &num, &len,
605
 
                   (unsigned char **) &data) &&
606
 
        data) {
607
 
            XFree(data);
608
 
            if (num != 1)
609
 
                return false;
610
 
            else
611
 
                return true;
612
 
    }
613
 
 
614
 
    return false;
615
 
}
616
 
 
617
 
void WinClient::addModal() {
618
 
    ++m_modal;
619
 
    if (transient_for)
620
 
        transient_for->addModal();
621
 
}
622
 
 
623
 
void WinClient::removeModal() {
624
 
    --m_modal;
625
 
    if (transient_for)
626
 
        transient_for->removeModal();
627
 
}
628
 
 
629
 
bool WinClient::validateClient() const {
630
 
    FbTk::App::instance()->sync(false);
631
 
 
632
 
    XEvent e;
633
 
    if (( XCheckTypedWindowEvent(display(), window(), DestroyNotify, &e) ||
634
 
          XCheckTypedWindowEvent(display(), window(), UnmapNotify, &e)) 
635
 
        && XPutBackEvent(display(), &e)) {
636
 
        Fluxbox::instance()->ungrab();
637
 
        return false;
638
 
    }
639
 
 
640
 
    return true;
641
 
}
642
 
 
643
 
void WinClient::setStrut(Strut *strut) {    
644
 
    clearStrut();
645
 
    m_strut = strut;
646
 
}
647
 
 
648
 
void WinClient::clearStrut() {
649
 
    if (m_strut != 0) {
650
 
        screen().clearStrut(m_strut);
651
 
        screen().updateAvailableWorkspaceArea();
652
 
        m_strut = 0;
653
 
    }
654
 
}
655
 
 
656
 
bool WinClient::focus() {
657
 
    if (m_win == 0)
658
 
        return false;
659
 
    else
660
 
        return m_win->setCurrentClient(*this, true);
661
 
}
662
 
 
663
 
void WinClient::updateWMProtocols() {
664
 
    Atom *proto = 0;
665
 
    int num_return = 0;
666
 
    FbAtoms *fbatoms = FbAtoms::instance();
667
 
 
668
 
    if (XGetWMProtocols(display(), window(), &proto, &num_return)) {
669
 
 
670
 
        // defaults
671
 
        send_focus_message = false;
672
 
        send_close_message = false;
673
 
        // could be added to netizens twice...
674
 
        for (int i = 0; i < num_return; ++i) {
675
 
            if (proto[i] == fbatoms->getWMDeleteAtom())
676
 
                send_close_message = true;
677
 
            else if (proto[i] == fbatoms->getWMTakeFocusAtom())
678
 
                send_focus_message = true;
679
 
            else if (proto[i] == fbatoms->getFluxboxStructureMessagesAtom())
680
 
                screen().addNetizen(window());
681
 
        }
682
 
 
683
 
        XFree(proto);
684
 
        if (m_win)
685
 
            m_win->updateFunctions();
686
 
#ifdef DEBUG
687
 
    } else {
688
 
        cerr<<"Warning: Failed to read WM Protocols. "<<endl;
689
 
#endif // DEBUG
690
 
    }
691
 
 
692
 
}
693
 
 
694
 
/* For aspect ratios
695
 
   Note that its slightly simplified in that only the
696
 
   line gradient is given - this is because for aspect
697
 
   ratios, we always have the line going through the origin
698
 
   
699
 
   * Based on this formula:
700
 
   http://astronomy.swin.edu.au/~pbourke/geometry/pointline/
701
 
 
702
 
   Note that a gradient from origin goes through ( grad , 1 )
703
 
 */
704
 
 
705
 
void closestPointToLine(double &ret_x, double &ret_y, 
706
 
                        double point_x, double point_y,
707
 
                        double gradient) {
708
 
    double u = (point_x * gradient + point_y) /
709
 
        (gradient*gradient + 1);
710
 
 
711
 
    ret_x = u*gradient;
712
 
    ret_y = u;
713
 
}
714
 
 
715
 
/**
716
 
 * Changes width and height to the nearest (lower) value
717
 
 * that conforms to it's size hints.
718
 
 *
719
 
 * display_* give the values that would be displayed
720
 
 * to the user when resizing.
721
 
 * We use pointers for display_* since they are optional.
722
 
 *
723
 
 * See ICCCM section 4.1.2.3
724
 
 */
725
 
void WinClient::applySizeHints(int &width, int &height, 
726
 
                               int *display_width, int *display_height) {
727
 
 
728
 
    int i = width, j = height;
729
 
 
730
 
    // Check minimum size
731
 
    if (width < 0 || width < static_cast<signed>(min_width)) 
732
 
        width = min_width;
733
 
 
734
 
    if (height < 0 || height < static_cast<signed>(min_height))
735
 
        height = min_height;
736
 
 
737
 
    // Check maximum size
738
 
    if (max_width > 0 && width > static_cast<signed>(max_width))
739
 
        width = max_width;
740
 
 
741
 
    if (max_height > 0 && height > static_cast<signed>(max_height))
742
 
        height = max_height;
743
 
 
744
 
    // we apply aspect ratios before incrementals
745
 
    // Too difficult to exactly satisfy both incremental+aspect 
746
 
    // in most situations 
747
 
    // (they really shouldn't happen at the same time anyway).
748
 
 
749
 
    /* aspect ratios are applied exclusive to the base_width
750
 
     *
751
 
     * min_aspect_x      width      max_aspect_x
752
 
     * ------------  <  -------  <  ------------
753
 
     * min_aspect_y      height     max_aspect_y
754
 
     *
755
 
     * beware of integer maximum (so I'll use doubles instead and divide)
756
 
     *
757
 
     * The trick is how to get back to the aspect ratio with minimal
758
 
     * change - do we modify x, y or both?
759
 
     * A: we minimise the distance between the current point, and
760
 
     *    the target aspect ratio (consider them as x,y coordinates)
761
 
     *  Consider that the aspect ratio is a line, and the current
762
 
     *  w/h is a point, so we're just using the formula for
763
 
     *  shortest distance from a point to a line!
764
 
     */
765
 
 
766
 
    if (min_aspect_y > 0 && max_aspect_y > 0 &&
767
 
        (height - base_height) > 0) {
768
 
        double widthd = static_cast<double>(width - base_width);
769
 
        double heightd = static_cast<double>(height - base_height);
770
 
 
771
 
        double min = static_cast<double>(min_aspect_x) / 
772
 
            static_cast<double>(min_aspect_y); 
773
 
 
774
 
        double max = static_cast<double>(max_aspect_x) / 
775
 
            static_cast<double>(max_aspect_y); 
776
 
 
777
 
        double actual = widthd / heightd;
778
 
 
779
 
        if (max > 0 && min > 0 && actual > 0) { // don't even try otherwise
780
 
            bool changed = false;
781
 
            if (actual < min) {
782
 
                changed = true;
783
 
                closestPointToLine(widthd, heightd, widthd, heightd, min);
784
 
            } else if (actual > max) {
785
 
                changed = true;
786
 
                closestPointToLine(widthd, heightd, widthd, heightd, max);
787
 
            }
788
 
 
789
 
            if (changed) {
790
 
                width = static_cast<int>(widthd) + base_width;
791
 
                height = static_cast<int>(heightd) + base_height;
792
 
            }
793
 
        }
794
 
    }
795
 
 
796
 
    // enforce incremental size limits, wrt base size
797
 
    // only calculate this if we really need to
798
 
    i = (width - base_width) / width_inc;
799
 
    width = i*width_inc + base_width;
800
 
 
801
 
    j = (height - base_height) / height_inc;
802
 
    height = j*height_inc + base_height;
803
 
 
804
 
    if (display_width)
805
 
        *display_width = i;
806
 
 
807
 
    if (display_height)
808
 
        *display_height = j;
809
 
}
810
 
 
811
 
void WinClient::removeTransientFromWaitingList() {
812
 
 
813
 
    // holds the windows that dont have empty
814
 
    // transient waiting list
815
 
    std::list<Window> remove_list;
816
 
 
817
 
    // The worst case complexity is huge, but since we usually do not (virtualy never) 
818
 
    // have a large transient waiting list the time spent here is neglectable
819
 
    TransientWaitMap::iterator t_it = s_transient_wait.begin();
820
 
    TransientWaitMap::iterator t_it_end = s_transient_wait.end();
821
 
    for (; t_it != t_it_end; ++t_it) {
822
 
        (*t_it).second.remove(this);
823
 
        // if the list is empty, add it to remove list
824
 
        // so we can erase it later
825
 
        if ((*t_it).second.empty())
826
 
            remove_list.push_back((*t_it).first);
827
 
    }
828
 
 
829
 
    // erase empty waiting lists
830
 
    std::list<Window>::iterator it = remove_list.begin();
831
 
    std::list<Window>::iterator it_end = remove_list.end();
832
 
    for (; it != it_end; ++it)
833
 
        s_transient_wait.erase(*it);
834
 
}