From c7eb5b03323d3b1d4df30977ed69e59aad0a3392 Mon Sep 17 00:00:00 2001 From: fluxgen Date: Fri, 29 Apr 2005 02:52:36 +0000 Subject: transient window fix --- src/Screen.cc | 12 +++--- src/WinClient.cc | 126 ++++++++++++++++++++++++++++++++++++++++++------------- src/WinClient.hh | 21 +++++++++- 3 files changed, 123 insertions(+), 36 deletions(-) diff --git a/src/Screen.cc b/src/Screen.cc index 45f9693..73acb3a 100644 --- a/src/Screen.cc +++ b/src/Screen.cc @@ -1177,10 +1177,8 @@ FluxboxWindow *BScreen::createWindow(Window client) { FbTk::App::instance()->sync(false); - if (isKdeDockapp(client)) { - if (addKdeDockapp(client)) { - return 0; // dont create a FluxboxWindow for this one - } + if (isKdeDockapp(client) && addKdeDockapp(client)) { + return 0; // dont create a FluxboxWindow for this one } WinClient *winclient = new WinClient(client, *this); @@ -1387,7 +1385,7 @@ void BScreen::nextFocus(int opts) { break; } - FluxboxWindow *fbwin = (*it)->m_win; + FluxboxWindow *fbwin = (*it)->fbwindow(); if (fbwin && !fbwin->isIconic() && (fbwin->isStuck() || fbwin->workspaceNumber() == currentWorkspaceID())) { @@ -1482,7 +1480,7 @@ void BScreen::prevFocus(int opts) { break; } - FluxboxWindow *fbwin = (*it)->m_win; + FluxboxWindow *fbwin = (*it)->fbwindow(); if (fbwin && !fbwin->isIconic() && (fbwin->isStuck() || fbwin->workspaceNumber() == currentWorkspaceID())) { @@ -2220,7 +2218,7 @@ FluxboxWindow *BScreen::findGroupRight(WinClient &winclient) { other->getGroupLeftWindow() != None) return 0; - return other->m_win; + return other->fbwindow(); } void BScreen::initXinerama() { #ifdef XINERAMA 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 @@ #include "fluxbox.hh" #include "Screen.hh" #include "FbAtoms.hh" -#include "EventManager.hh" + #include "Xutil.hh" +#include "EventManager.hh" #include "FbTk/I18n.hh" +#include "FbTk/MultLayers.hh" #include #include #include +#include + #ifdef HAVE_CASSERT #include #else @@ -43,6 +47,9 @@ using namespace std; + +WinClient::TransientWaitMap WinClient::s_transient_wait; + WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::FbWindow(win), transient_for(0), window_group(0), @@ -80,6 +87,16 @@ WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::Fb if (window_group != None) Fluxbox::instance()->saveGroupSearch(window_group, this); + // search for this in transient waiting list + if (s_transient_wait.find(win) != s_transient_wait.end()) { + // Found transients that are waiting for this. + // For each transient that waits call updateTransientInfo + for_each(s_transient_wait[win].begin(), + s_transient_wait[win].end(), + mem_fun(&WinClient::updateTransientInfo)); + // clear transient waiting list for this window + s_transient_wait.erase(win); + } } WinClient::~WinClient() { @@ -99,16 +116,25 @@ WinClient::~WinClient() { Fluxbox *fluxbox = Fluxbox::instance(); + + // + // clear transients and transient_for + // if (transient_for != 0) { assert(transient_for != this); transient_for->transientList().remove(this); transient_for = 0; } - + while (!transients.empty()) { transients.back()->transient_for = 0; transients.pop_back(); } + // This fixes issue 1 (see WinClient.hh): + // If transients die before the transient_for is created + removeTransientFromWaitingList(); + s_transient_wait.erase(window()); + screen().removeNetizen(window()); @@ -142,12 +168,12 @@ bool WinClient::sendFocus() { cerr<<"WinClient::"<<__FUNCTION__<<": this = "<display(); + // setup focus msg XEvent ce; ce.xclient.type = ClientMessage; ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom(); - ce.xclient.display = disp; + ce.xclient.display = display(); ce.xclient.window = window(); ce.xclient.format = 32; ce.xclient.data.l[0] = FbAtoms::instance()->getWMTakeFocusAtom(); @@ -156,21 +182,20 @@ bool WinClient::sendFocus() { ce.xclient.data.l[3] = 0l; ce.xclient.data.l[4] = 0l; // send focus msg - XSendEvent(disp, window(), false, NoEventMask, &ce); + XSendEvent(display(), window(), false, NoEventMask, &ce); return true; } void WinClient::sendClose(bool forceful) { if (forceful || !send_close_message) - XKillClient(FbTk::App::instance()->display(), window()); + XKillClient(display(), window()); else { // send WM_DELETE message - Display *disp = FbTk::App::instance()->display(); // fill in XClientMessage structure for delete message XEvent ce; ce.xclient.type = ClientMessage; ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom(); - ce.xclient.display = disp; + ce.xclient.display = display(); ce.xclient.window = window(); ce.xclient.format = 32; ce.xclient.data.l[0] = FbAtoms::instance()->getWMDeleteAtom(); @@ -179,20 +204,20 @@ void WinClient::sendClose(bool forceful) { ce.xclient.data.l[3] = 0l; ce.xclient.data.l[4] = 0l; // send event delete message to client window - XSendEvent(disp, window(), false, NoEventMask, &ce); + XSendEvent(display(), window(), false, NoEventMask, &ce); } } bool WinClient::getAttrib(XWindowAttributes &attr) const { - return XGetWindowAttributes(FbTk::App::instance()->display(), window(), &attr); + return XGetWindowAttributes(display(), window(), &attr); } bool WinClient::getWMName(XTextProperty &textprop) const { - return XGetWMName(FbTk::App::instance()->display(), window(), &textprop); + return XGetWMName(display(), window(), &textprop); } bool WinClient::getWMIconName(XTextProperty &textprop) const { - return XGetWMName(FbTk::App::instance()->display(), window(), &textprop); + return XGetWMName(display(), window(), &textprop); } const std::string &WinClient::getWMClassName() const { @@ -205,7 +230,7 @@ const std::string &WinClient::getWMClassClass() const { void WinClient::updateWMClassHint() { XClassHint ch; - if (XGetClassHint(FbTk::App::instance()->display(), window(), &ch) == 0) { + if (XGetClassHint(display(), window(), &ch) == 0) { #ifdef DEBUG cerr<<"WinClient: Failed to read class hint!"<transientList().remove(this); } transient_for = 0; - Display *disp = FbTk::App::instance()->display(); // determine if this is a transient window Window win = 0; - if (!XGetTransientForHint(disp, window(), &win)) { + if (!XGetTransientForHint(display(), window(), &win)) { #ifdef DEBUG cerr<<__FUNCTION__<<": window() = 0x"<searchWindow(win); + // if we did not find a transient WinClient but still + // have a transient X window, then we have to put the + // X transient_for window in a waiting list and update this clients transient + // list later when the transient_for has a Winclient + if (!transient_for) { + // We might also already waiting for an old transient_for; + // + // this call fixes issue 2: + // If transients changes to new transient_for before the old transient_for is created. + // (see comment in WinClient.hh) + // + removeTransientFromWaitingList(); + + s_transient_wait[win].push_back(this); + } + #ifdef DEBUG cerr<<__FUNCTION__<<": transient_for window = 0x"<fbwindow() && transientFor()->fbwindow()->isStuck()) m_win->stick(); } + } @@ -301,7 +343,7 @@ void WinClient::updateTitle() { // also influenced // // the limitation to 512 chars only avoids running in that trap - m_title = string(Xutil::getWMName(window()) ,0 , 512); + m_title = string(Xutil::getWMName(window()), 0, 512); } void WinClient::updateIconTitle() { @@ -314,7 +356,7 @@ void WinClient::updateIconTitle() { if (text_prop.encoding != XA_STRING) { text_prop.nitems = strlen((char *) text_prop.value); - if (XmbTextPropertyToTextList(FbTk::App::instance()->display(), &text_prop, + if (XmbTextPropertyToTextList(display(), &text_prop, &list, &num) == Success && num > 0 && *list) { m_icon_title = (char *)*list; @@ -341,6 +383,10 @@ void WinClient::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_ ); } +void WinClient::setFluxboxWindow(FluxboxWindow *win) { + m_win = win; +} + void WinClient::updateBlackboxHints() { int format; Atom atom_return; @@ -392,7 +438,7 @@ void WinClient::updateMWMHints() { } void WinClient::updateWMHints() { - XWMHints *wmhint = XGetWMHints(FbTk::App::instance()->display(), window()); + XWMHints *wmhint = XGetWMHints(display(), window()); if (! wmhint) { m_focus_mode = F_PASSIVE; window_group = None; @@ -447,7 +493,7 @@ void WinClient::updateWMHints() { void WinClient::updateWMNormalHints() { long icccm_mask; XSizeHints sizehint; - if (! XGetWMNormalHints(FbTk::App::instance()->display(), window(), &sizehint, &icccm_mask)) { + if (! XGetWMNormalHints(display(), window(), &sizehint, &icccm_mask)) { min_width = min_height = base_width = base_height = width_inc = height_inc = 1; @@ -515,7 +561,7 @@ Window WinClient::getGroupLeftWindow() const { int format; Atom atom_return; unsigned long num = 0, len = 0; - Atom group_left_hint = XInternAtom(FbTk::App::instance()->display(), "_FLUXBOX_GROUP_LEFT", False); + Atom group_left_hint = XInternAtom(display(), "_FLUXBOX_GROUP_LEFT", False); Window *data = 0; if (property(group_left_hint, 0, @@ -538,7 +584,7 @@ Window WinClient::getGroupLeftWindow() const { void WinClient::setGroupLeftWindow(Window win) { - Atom group_left_hint = XInternAtom(FbTk::App::instance()->display(), "_FLUXBOX_GROUP_LEFT", False); + Atom group_left_hint = XInternAtom(display(), "_FLUXBOX_GROUP_LEFT", False); changeProperty(group_left_hint, XA_WINDOW, 32, PropModeReplace, (unsigned char *) &win, 1); } @@ -549,7 +595,7 @@ bool WinClient::hasGroupLeftWindow() const { int format; Atom atom_return; unsigned long num = 0, len = 0; - Atom group_left_hint = XInternAtom(FbTk::App::instance()->display(), "_FLUXBOX_GROUP_LEFT", False); + Atom group_left_hint = XInternAtom(display(), "_FLUXBOX_GROUP_LEFT", False); Window *data = 0; if (property(group_left_hint, 0, @@ -581,13 +627,12 @@ void WinClient::removeModal() { } bool WinClient::validateClient() const { - Display *display = FbTk::App::instance()->display(); FbTk::App::instance()->sync(false); XEvent e; - if (( XCheckTypedWindowEvent(display, window(), DestroyNotify, &e) || - XCheckTypedWindowEvent(display, window(), UnmapNotify, &e)) - && XPutBackEvent(display, &e)) { + if (( XCheckTypedWindowEvent(display(), window(), DestroyNotify, &e) || + XCheckTypedWindowEvent(display(), window(), UnmapNotify, &e)) + && XPutBackEvent(display(), &e)) { Fluxbox::instance()->ungrab(); return false; } @@ -620,7 +665,7 @@ void WinClient::updateWMProtocols() { int num_return = 0; FbAtoms *fbatoms = FbAtoms::instance(); - if (XGetWMProtocols(FbTk::App::instance()->display(), window(), &proto, &num_return)) { + if (XGetWMProtocols(display(), window(), &proto, &num_return)) { // defaults send_focus_message = false; @@ -762,3 +807,28 @@ void WinClient::applySizeHints(int &width, int &height, if (display_height) *display_height = j; } + +void WinClient::removeTransientFromWaitingList() { + + // holds the windows that dont have empty + // transient waiting list + std::list remove_list; + + // The worst case complexity is huge, but since we usually do not (virtualy never) + // have a large transient waiting list the time spent here is neglectable + TransientWaitMap::iterator t_it = s_transient_wait.begin(); + TransientWaitMap::iterator t_it_end = s_transient_wait.end(); + for (; t_it != t_it_end; ++t_it) { + (*t_it).second.remove(this); + // if the list is empty, add it to remove list + // so we can erase it later + if ((*t_it).second.empty()) + remove_list.push_back((*t_it).first); + } + + // erase empty waiting lists + std::list::iterator it = remove_list.begin(); + std::list::iterator it_end = remove_list.end(); + for (; it != it_end; ++it) + s_transient_wait.erase(*it); +} diff --git a/src/WinClient.hh b/src/WinClient.hh index 49e1931..deeffd5 100644 --- a/src/WinClient.hh +++ b/src/WinClient.hh @@ -94,6 +94,7 @@ public: void setGroupLeftWindow(Window win); void saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs); + void setFluxboxWindow(FluxboxWindow *win); // does this client have a pending unmap or destroy event? bool validateClient() const; @@ -164,7 +165,7 @@ public: unsigned long initial_state, normal_hint_flags, wm_hint_flags; - FluxboxWindow *m_win; + class WinClientSubj: public FbTk::Subject { public: explicit WinClientSubj(WinClient &client):m_winclient(client) { } @@ -176,6 +177,11 @@ public: enum FocusMode { F_NOINPUT = 0, F_PASSIVE, F_LOCALLYACTIVE, F_GLOBALLYACTIVE }; private: + /// removes client from any waiting list and clears empty waiting lists + void removeTransientFromWaitingList(); + + FluxboxWindow *m_win; + // number of transients which we are modal for // or indicates that we are modal if don't have any transients int m_modal; @@ -195,6 +201,19 @@ private: BScreen &m_screen; Strut *m_strut; + // map transient_for X window to winclient transient + // (used if transient_for FbWindow was created after transient) + // Since a lot of transients can be created before transient_for + // we need to map transient_for window to a list of transients + // + // Stuff to worry about: + // 1) If transients die before the transient_for is created + // 2) If transients changes to a new transient_for before old transient_for is created + // ( 3) Transient_for is never created + // This is not a big deal since the key value will be cleared + // once the list is empty ) + typedef std::map TransientWaitMap; + static TransientWaitMap s_transient_wait; }; -- cgit v0.11.2