aboutsummaryrefslogtreecommitdiff
path: root/src/WinClient.cc
diff options
context:
space:
mode:
authorfluxgen <fluxgen>2005-04-29 02:52:36 (GMT)
committerfluxgen <fluxgen>2005-04-29 02:52:36 (GMT)
commitc7eb5b03323d3b1d4df30977ed69e59aad0a3392 (patch)
treeea91bb7b6fa787cc1d8c0a88c6ee4c5dfdc5d76d /src/WinClient.cc
parent40d026ff99bab25b7aa52e8e6c413277eb27006b (diff)
downloadfluxbox_pavel-c7eb5b03323d3b1d4df30977ed69e59aad0a3392.zip
fluxbox_pavel-c7eb5b03323d3b1d4df30977ed69e59aad0a3392.tar.bz2
transient window fix
Diffstat (limited to 'src/WinClient.cc')
-rw-r--r--src/WinClient.cc126
1 files changed, 98 insertions, 28 deletions
diff --git a/src/WinClient.cc b/src/WinClient.cc
index 42f8cae..df27621 100644
--- a/src/WinClient.cc
+++ b/src/WinClient.cc
@@ -27,14 +27,18 @@
27#include "fluxbox.hh" 27#include "fluxbox.hh"
28#include "Screen.hh" 28#include "Screen.hh"
29#include "FbAtoms.hh" 29#include "FbAtoms.hh"
30#include "EventManager.hh" 30
31#include "Xutil.hh" 31#include "Xutil.hh"
32 32
33#include "EventManager.hh"
33#include "FbTk/I18n.hh" 34#include "FbTk/I18n.hh"
35#include "FbTk/MultLayers.hh"
34 36
35#include <iostream> 37#include <iostream>
36#include <algorithm> 38#include <algorithm>
37#include <iterator> 39#include <iterator>
40#include <memory>
41
38#ifdef HAVE_CASSERT 42#ifdef HAVE_CASSERT
39 #include <cassert> 43 #include <cassert>
40#else 44#else
@@ -43,6 +47,9 @@
43 47
44using namespace std; 48using namespace std;
45 49
50
51WinClient::TransientWaitMap WinClient::s_transient_wait;
52
46WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::FbWindow(win), 53WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::FbWindow(win),
47 transient_for(0), 54 transient_for(0),
48 window_group(0), 55 window_group(0),
@@ -80,6 +87,16 @@ WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::Fb
80 if (window_group != None) 87 if (window_group != None)
81 Fluxbox::instance()->saveGroupSearch(window_group, this); 88 Fluxbox::instance()->saveGroupSearch(window_group, this);
82 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 }
83} 100}
84 101
85WinClient::~WinClient() { 102WinClient::~WinClient() {
@@ -99,16 +116,25 @@ WinClient::~WinClient() {
99 116
100 Fluxbox *fluxbox = Fluxbox::instance(); 117 Fluxbox *fluxbox = Fluxbox::instance();
101 118
119
120 //
121 // clear transients and transient_for
122 //
102 if (transient_for != 0) { 123 if (transient_for != 0) {
103 assert(transient_for != this); 124 assert(transient_for != this);
104 transient_for->transientList().remove(this); 125 transient_for->transientList().remove(this);
105 transient_for = 0; 126 transient_for = 0;
106 } 127 }
107 128
108 while (!transients.empty()) { 129 while (!transients.empty()) {
109 transients.back()->transient_for = 0; 130 transients.back()->transient_for = 0;
110 transients.pop_back(); 131 transients.pop_back();
111 } 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
112 138
113 screen().removeNetizen(window()); 139 screen().removeNetizen(window());
114 140
@@ -142,12 +168,12 @@ bool WinClient::sendFocus() {
142 cerr<<"WinClient::"<<__FUNCTION__<<": this = "<<this<< 168 cerr<<"WinClient::"<<__FUNCTION__<<": this = "<<this<<
143 " window = 0x"<<hex<<window()<<dec<<endl; 169 " window = 0x"<<hex<<window()<<dec<<endl;
144#endif // DEBUG 170#endif // DEBUG
145 Display *disp = FbTk::App::instance()->display(); 171
146 // setup focus msg 172 // setup focus msg
147 XEvent ce; 173 XEvent ce;
148 ce.xclient.type = ClientMessage; 174 ce.xclient.type = ClientMessage;
149 ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom(); 175 ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom();
150 ce.xclient.display = disp; 176 ce.xclient.display = display();
151 ce.xclient.window = window(); 177 ce.xclient.window = window();
152 ce.xclient.format = 32; 178 ce.xclient.format = 32;
153 ce.xclient.data.l[0] = FbAtoms::instance()->getWMTakeFocusAtom(); 179 ce.xclient.data.l[0] = FbAtoms::instance()->getWMTakeFocusAtom();
@@ -156,21 +182,20 @@ bool WinClient::sendFocus() {
156 ce.xclient.data.l[3] = 0l; 182 ce.xclient.data.l[3] = 0l;
157 ce.xclient.data.l[4] = 0l; 183 ce.xclient.data.l[4] = 0l;
158 // send focus msg 184 // send focus msg
159 XSendEvent(disp, window(), false, NoEventMask, &ce); 185 XSendEvent(display(), window(), false, NoEventMask, &ce);
160 return true; 186 return true;
161} 187}
162 188
163void WinClient::sendClose(bool forceful) { 189void WinClient::sendClose(bool forceful) {
164 if (forceful || !send_close_message) 190 if (forceful || !send_close_message)
165 XKillClient(FbTk::App::instance()->display(), window()); 191 XKillClient(display(), window());
166 else { 192 else {
167 // send WM_DELETE message 193 // send WM_DELETE message
168 Display *disp = FbTk::App::instance()->display();
169 // fill in XClientMessage structure for delete message 194 // fill in XClientMessage structure for delete message
170 XEvent ce; 195 XEvent ce;
171 ce.xclient.type = ClientMessage; 196 ce.xclient.type = ClientMessage;
172 ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom(); 197 ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom();
173 ce.xclient.display = disp; 198 ce.xclient.display = display();
174 ce.xclient.window = window(); 199 ce.xclient.window = window();
175 ce.xclient.format = 32; 200 ce.xclient.format = 32;
176 ce.xclient.data.l[0] = FbAtoms::instance()->getWMDeleteAtom(); 201 ce.xclient.data.l[0] = FbAtoms::instance()->getWMDeleteAtom();
@@ -179,20 +204,20 @@ void WinClient::sendClose(bool forceful) {
179 ce.xclient.data.l[3] = 0l; 204 ce.xclient.data.l[3] = 0l;
180 ce.xclient.data.l[4] = 0l; 205 ce.xclient.data.l[4] = 0l;
181 // send event delete message to client window 206 // send event delete message to client window
182 XSendEvent(disp, window(), false, NoEventMask, &ce); 207 XSendEvent(display(), window(), false, NoEventMask, &ce);
183 } 208 }
184} 209}
185 210
186bool WinClient::getAttrib(XWindowAttributes &attr) const { 211bool WinClient::getAttrib(XWindowAttributes &attr) const {
187 return XGetWindowAttributes(FbTk::App::instance()->display(), window(), &attr); 212 return XGetWindowAttributes(display(), window(), &attr);
188} 213}
189 214
190bool WinClient::getWMName(XTextProperty &textprop) const { 215bool WinClient::getWMName(XTextProperty &textprop) const {
191 return XGetWMName(FbTk::App::instance()->display(), window(), &textprop); 216 return XGetWMName(display(), window(), &textprop);
192} 217}
193 218
194bool WinClient::getWMIconName(XTextProperty &textprop) const { 219bool WinClient::getWMIconName(XTextProperty &textprop) const {
195 return XGetWMName(FbTk::App::instance()->display(), window(), &textprop); 220 return XGetWMName(display(), window(), &textprop);
196} 221}
197 222
198const std::string &WinClient::getWMClassName() const { 223const std::string &WinClient::getWMClassName() const {
@@ -205,7 +230,7 @@ const std::string &WinClient::getWMClassClass() const {
205 230
206void WinClient::updateWMClassHint() { 231void WinClient::updateWMClassHint() {
207 XClassHint ch; 232 XClassHint ch;
208 if (XGetClassHint(FbTk::App::instance()->display(), window(), &ch) == 0) { 233 if (XGetClassHint(display(), window(), &ch) == 0) {
209#ifdef DEBUG 234#ifdef DEBUG
210 cerr<<"WinClient: Failed to read class hint!"<<endl; 235 cerr<<"WinClient: Failed to read class hint!"<<endl;
211#endif //DEBUG 236#endif //DEBUG
@@ -234,16 +259,16 @@ void WinClient::updateTransientInfo() {
234 if (m_win == 0) 259 if (m_win == 0)
235 return; 260 return;
236 261
237 // remove us from parent 262
263 // remove this from parent
238 if (transientFor() != 0) { 264 if (transientFor() != 0) {
239 transientFor()->transientList().remove(this); 265 transientFor()->transientList().remove(this);
240 } 266 }
241 267
242 transient_for = 0; 268 transient_for = 0;
243 Display *disp = FbTk::App::instance()->display();
244 // determine if this is a transient window 269 // determine if this is a transient window
245 Window win = 0; 270 Window win = 0;
246 if (!XGetTransientForHint(disp, window(), &win)) { 271 if (!XGetTransientForHint(display(), window(), &win)) {
247#ifdef DEBUG 272#ifdef DEBUG
248 cerr<<__FUNCTION__<<": window() = 0x"<<hex<<window()<<dec<<"Failed to read transient for hint."<<endl; 273 cerr<<__FUNCTION__<<": window() = 0x"<<hex<<window()<<dec<<"Failed to read transient for hint."<<endl;
249#endif // DEBUG 274#endif // DEBUG
@@ -266,6 +291,22 @@ void WinClient::updateTransientInfo() {
266 291
267 292
268 transient_for = Fluxbox::instance()->searchWindow(win); 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
269 310
270#ifdef DEBUG 311#ifdef DEBUG
271 cerr<<__FUNCTION__<<": transient_for window = 0x"<<hex<<win<<dec<<endl; 312 cerr<<__FUNCTION__<<": transient_for window = 0x"<<hex<<win<<dec<<endl;
@@ -287,6 +328,7 @@ void WinClient::updateTransientInfo() {
287 if (transientFor()->fbwindow() && transientFor()->fbwindow()->isStuck()) 328 if (transientFor()->fbwindow() && transientFor()->fbwindow()->isStuck())
288 m_win->stick(); 329 m_win->stick();
289 } 330 }
331
290} 332}
291 333
292 334
@@ -301,7 +343,7 @@ void WinClient::updateTitle() {
301 // also influenced 343 // also influenced
302 // 344 //
303 // the limitation to 512 chars only avoids running in that trap 345 // the limitation to 512 chars only avoids running in that trap
304 m_title = string(Xutil::getWMName(window()) ,0 , 512); 346 m_title = string(Xutil::getWMName(window()), 0, 512);
305} 347}
306 348
307void WinClient::updateIconTitle() { 349void WinClient::updateIconTitle() {
@@ -314,7 +356,7 @@ void WinClient::updateIconTitle() {
314 if (text_prop.encoding != XA_STRING) { 356 if (text_prop.encoding != XA_STRING) {
315 text_prop.nitems = strlen((char *) text_prop.value); 357 text_prop.nitems = strlen((char *) text_prop.value);
316 358
317 if (XmbTextPropertyToTextList(FbTk::App::instance()->display(), &text_prop, 359 if (XmbTextPropertyToTextList(display(), &text_prop,
318 &list, &num) == Success && 360 &list, &num) == Success &&
319 num > 0 && *list) { 361 num > 0 && *list) {
320 m_icon_title = (char *)*list; 362 m_icon_title = (char *)*list;
@@ -341,6 +383,10 @@ void WinClient::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_
341 ); 383 );
342} 384}
343 385
386void WinClient::setFluxboxWindow(FluxboxWindow *win) {
387 m_win = win;
388}
389
344void WinClient::updateBlackboxHints() { 390void WinClient::updateBlackboxHints() {
345 int format; 391 int format;
346 Atom atom_return; 392 Atom atom_return;
@@ -392,7 +438,7 @@ void WinClient::updateMWMHints() {
392} 438}
393 439
394void WinClient::updateWMHints() { 440void WinClient::updateWMHints() {
395 XWMHints *wmhint = XGetWMHints(FbTk::App::instance()->display(), window()); 441 XWMHints *wmhint = XGetWMHints(display(), window());
396 if (! wmhint) { 442 if (! wmhint) {
397 m_focus_mode = F_PASSIVE; 443 m_focus_mode = F_PASSIVE;
398 window_group = None; 444 window_group = None;
@@ -447,7 +493,7 @@ void WinClient::updateWMHints() {
447void WinClient::updateWMNormalHints() { 493void WinClient::updateWMNormalHints() {
448 long icccm_mask; 494 long icccm_mask;
449 XSizeHints sizehint; 495 XSizeHints sizehint;
450 if (! XGetWMNormalHints(FbTk::App::instance()->display(), window(), &sizehint, &icccm_mask)) { 496 if (! XGetWMNormalHints(display(), window(), &sizehint, &icccm_mask)) {
451 min_width = min_height = 497 min_width = min_height =
452 base_width = base_height = 498 base_width = base_height =
453 width_inc = height_inc = 1; 499 width_inc = height_inc = 1;
@@ -515,7 +561,7 @@ Window WinClient::getGroupLeftWindow() const {
515 int format; 561 int format;
516 Atom atom_return; 562 Atom atom_return;
517 unsigned long num = 0, len = 0; 563 unsigned long num = 0, len = 0;
518 Atom group_left_hint = XInternAtom(FbTk::App::instance()->display(), "_FLUXBOX_GROUP_LEFT", False); 564 Atom group_left_hint = XInternAtom(display(), "_FLUXBOX_GROUP_LEFT", False);
519 565
520 Window *data = 0; 566 Window *data = 0;
521 if (property(group_left_hint, 0, 567 if (property(group_left_hint, 0,
@@ -538,7 +584,7 @@ Window WinClient::getGroupLeftWindow() const {
538 584
539 585
540void WinClient::setGroupLeftWindow(Window win) { 586void WinClient::setGroupLeftWindow(Window win) {
541 Atom group_left_hint = XInternAtom(FbTk::App::instance()->display(), "_FLUXBOX_GROUP_LEFT", False); 587 Atom group_left_hint = XInternAtom(display(), "_FLUXBOX_GROUP_LEFT", False);
542 changeProperty(group_left_hint, XA_WINDOW, 32, 588 changeProperty(group_left_hint, XA_WINDOW, 32,
543 PropModeReplace, (unsigned char *) &win, 1); 589 PropModeReplace, (unsigned char *) &win, 1);
544} 590}
@@ -549,7 +595,7 @@ bool WinClient::hasGroupLeftWindow() const {
549 int format; 595 int format;
550 Atom atom_return; 596 Atom atom_return;
551 unsigned long num = 0, len = 0; 597 unsigned long num = 0, len = 0;
552 Atom group_left_hint = XInternAtom(FbTk::App::instance()->display(), "_FLUXBOX_GROUP_LEFT", False); 598 Atom group_left_hint = XInternAtom(display(), "_FLUXBOX_GROUP_LEFT", False);
553 599
554 Window *data = 0; 600 Window *data = 0;
555 if (property(group_left_hint, 0, 601 if (property(group_left_hint, 0,
@@ -581,13 +627,12 @@ void WinClient::removeModal() {
581} 627}
582 628
583bool WinClient::validateClient() const { 629bool WinClient::validateClient() const {
584 Display *display = FbTk::App::instance()->display();
585 FbTk::App::instance()->sync(false); 630 FbTk::App::instance()->sync(false);
586 631
587 XEvent e; 632 XEvent e;
588 if (( XCheckTypedWindowEvent(display, window(), DestroyNotify, &e) || 633 if (( XCheckTypedWindowEvent(display(), window(), DestroyNotify, &e) ||
589 XCheckTypedWindowEvent(display, window(), UnmapNotify, &e)) 634 XCheckTypedWindowEvent(display(), window(), UnmapNotify, &e))
590 && XPutBackEvent(display, &e)) { 635 && XPutBackEvent(display(), &e)) {
591 Fluxbox::instance()->ungrab(); 636 Fluxbox::instance()->ungrab();
592 return false; 637 return false;
593 } 638 }
@@ -620,7 +665,7 @@ void WinClient::updateWMProtocols() {
620 int num_return = 0; 665 int num_return = 0;
621 FbAtoms *fbatoms = FbAtoms::instance(); 666 FbAtoms *fbatoms = FbAtoms::instance();
622 667
623 if (XGetWMProtocols(FbTk::App::instance()->display(), window(), &proto, &num_return)) { 668 if (XGetWMProtocols(display(), window(), &proto, &num_return)) {
624 669
625 // defaults 670 // defaults
626 send_focus_message = false; 671 send_focus_message = false;
@@ -762,3 +807,28 @@ void WinClient::applySizeHints(int &width, int &height,
762 if (display_height) 807 if (display_height)
763 *display_height = j; 808 *display_height = j;
764} 809}
810
811void 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}