diff options
author | fluxgen <fluxgen> | 2005-04-29 02:52:36 (GMT) |
---|---|---|
committer | fluxgen <fluxgen> | 2005-04-29 02:52:36 (GMT) |
commit | c7eb5b03323d3b1d4df30977ed69e59aad0a3392 (patch) | |
tree | ea91bb7b6fa787cc1d8c0a88c6ee4c5dfdc5d76d /src/WinClient.cc | |
parent | 40d026ff99bab25b7aa52e8e6c413277eb27006b (diff) | |
download | fluxbox-c7eb5b03323d3b1d4df30977ed69e59aad0a3392.zip fluxbox-c7eb5b03323d3b1d4df30977ed69e59aad0a3392.tar.bz2 |
transient window fix
Diffstat (limited to 'src/WinClient.cc')
-rw-r--r-- | src/WinClient.cc | 126 |
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 | ||
44 | using namespace std; | 48 | using namespace std; |
45 | 49 | ||
50 | |||
51 | WinClient::TransientWaitMap WinClient::s_transient_wait; | ||
52 | |||
46 | WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::FbWindow(win), | 53 | WinClient::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 | ||
85 | WinClient::~WinClient() { | 102 | WinClient::~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 | ||
163 | void WinClient::sendClose(bool forceful) { | 189 | void 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 | ||
186 | bool WinClient::getAttrib(XWindowAttributes &attr) const { | 211 | bool WinClient::getAttrib(XWindowAttributes &attr) const { |
187 | return XGetWindowAttributes(FbTk::App::instance()->display(), window(), &attr); | 212 | return XGetWindowAttributes(display(), window(), &attr); |
188 | } | 213 | } |
189 | 214 | ||
190 | bool WinClient::getWMName(XTextProperty &textprop) const { | 215 | bool WinClient::getWMName(XTextProperty &textprop) const { |
191 | return XGetWMName(FbTk::App::instance()->display(), window(), &textprop); | 216 | return XGetWMName(display(), window(), &textprop); |
192 | } | 217 | } |
193 | 218 | ||
194 | bool WinClient::getWMIconName(XTextProperty &textprop) const { | 219 | bool WinClient::getWMIconName(XTextProperty &textprop) const { |
195 | return XGetWMName(FbTk::App::instance()->display(), window(), &textprop); | 220 | return XGetWMName(display(), window(), &textprop); |
196 | } | 221 | } |
197 | 222 | ||
198 | const std::string &WinClient::getWMClassName() const { | 223 | const std::string &WinClient::getWMClassName() const { |
@@ -205,7 +230,7 @@ const std::string &WinClient::getWMClassClass() const { | |||
205 | 230 | ||
206 | void WinClient::updateWMClassHint() { | 231 | void 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 | ||
307 | void WinClient::updateIconTitle() { | 349 | void 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 | ||
386 | void WinClient::setFluxboxWindow(FluxboxWindow *win) { | ||
387 | m_win = win; | ||
388 | } | ||
389 | |||
344 | void WinClient::updateBlackboxHints() { | 390 | void 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 | ||
394 | void WinClient::updateWMHints() { | 440 | void 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() { | |||
447 | void WinClient::updateWMNormalHints() { | 493 | void 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 | ||
540 | void WinClient::setGroupLeftWindow(Window win) { | 586 | void 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 | ||
583 | bool WinClient::validateClient() const { | 629 | bool 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 | |||
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 | } | ||