transient window fix

This commit is contained in:
fluxgen 2005-04-29 02:52:36 +00:00
parent 40d026ff99
commit c7eb5b0332
3 changed files with 123 additions and 36 deletions

View file

@ -1177,10 +1177,8 @@ FluxboxWindow *BScreen::createWindow(Window client) {
FbTk::App::instance()->sync(false); FbTk::App::instance()->sync(false);
if (isKdeDockapp(client)) { if (isKdeDockapp(client) && addKdeDockapp(client)) {
if (addKdeDockapp(client)) { return 0; // dont create a FluxboxWindow for this one
return 0; // dont create a FluxboxWindow for this one
}
} }
WinClient *winclient = new WinClient(client, *this); WinClient *winclient = new WinClient(client, *this);
@ -1387,7 +1385,7 @@ void BScreen::nextFocus(int opts) {
break; break;
} }
FluxboxWindow *fbwin = (*it)->m_win; FluxboxWindow *fbwin = (*it)->fbwindow();
if (fbwin && !fbwin->isIconic() && if (fbwin && !fbwin->isIconic() &&
(fbwin->isStuck() (fbwin->isStuck()
|| fbwin->workspaceNumber() == currentWorkspaceID())) { || fbwin->workspaceNumber() == currentWorkspaceID())) {
@ -1482,7 +1480,7 @@ void BScreen::prevFocus(int opts) {
break; break;
} }
FluxboxWindow *fbwin = (*it)->m_win; FluxboxWindow *fbwin = (*it)->fbwindow();
if (fbwin && !fbwin->isIconic() && if (fbwin && !fbwin->isIconic() &&
(fbwin->isStuck() (fbwin->isStuck()
|| fbwin->workspaceNumber() == currentWorkspaceID())) { || fbwin->workspaceNumber() == currentWorkspaceID())) {
@ -2220,7 +2218,7 @@ FluxboxWindow *BScreen::findGroupRight(WinClient &winclient) {
other->getGroupLeftWindow() != None) other->getGroupLeftWindow() != None)
return 0; return 0;
return other->m_win; return other->fbwindow();
} }
void BScreen::initXinerama() { void BScreen::initXinerama() {
#ifdef XINERAMA #ifdef XINERAMA

View file

@ -27,14 +27,18 @@
#include "fluxbox.hh" #include "fluxbox.hh"
#include "Screen.hh" #include "Screen.hh"
#include "FbAtoms.hh" #include "FbAtoms.hh"
#include "EventManager.hh"
#include "Xutil.hh" #include "Xutil.hh"
#include "EventManager.hh"
#include "FbTk/I18n.hh" #include "FbTk/I18n.hh"
#include "FbTk/MultLayers.hh"
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include <memory>
#ifdef HAVE_CASSERT #ifdef HAVE_CASSERT
#include <cassert> #include <cassert>
#else #else
@ -43,6 +47,9 @@
using namespace std; using namespace std;
WinClient::TransientWaitMap WinClient::s_transient_wait;
WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::FbWindow(win), WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::FbWindow(win),
transient_for(0), transient_for(0),
window_group(0), window_group(0),
@ -80,6 +87,16 @@ WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::Fb
if (window_group != None) if (window_group != None)
Fluxbox::instance()->saveGroupSearch(window_group, this); 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() { WinClient::~WinClient() {
@ -99,6 +116,10 @@ WinClient::~WinClient() {
Fluxbox *fluxbox = Fluxbox::instance(); Fluxbox *fluxbox = Fluxbox::instance();
//
// clear transients and transient_for
//
if (transient_for != 0) { if (transient_for != 0) {
assert(transient_for != this); assert(transient_for != this);
transient_for->transientList().remove(this); transient_for->transientList().remove(this);
@ -109,6 +130,11 @@ WinClient::~WinClient() {
transients.back()->transient_for = 0; transients.back()->transient_for = 0;
transients.pop_back(); 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()); screen().removeNetizen(window());
@ -142,12 +168,12 @@ bool WinClient::sendFocus() {
cerr<<"WinClient::"<<__FUNCTION__<<": this = "<<this<< cerr<<"WinClient::"<<__FUNCTION__<<": this = "<<this<<
" window = 0x"<<hex<<window()<<dec<<endl; " window = 0x"<<hex<<window()<<dec<<endl;
#endif // DEBUG #endif // DEBUG
Display *disp = FbTk::App::instance()->display();
// setup focus msg // setup focus msg
XEvent ce; XEvent ce;
ce.xclient.type = ClientMessage; ce.xclient.type = ClientMessage;
ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom(); ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom();
ce.xclient.display = disp; ce.xclient.display = display();
ce.xclient.window = window(); ce.xclient.window = window();
ce.xclient.format = 32; ce.xclient.format = 32;
ce.xclient.data.l[0] = FbAtoms::instance()->getWMTakeFocusAtom(); 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[3] = 0l;
ce.xclient.data.l[4] = 0l; ce.xclient.data.l[4] = 0l;
// send focus msg // send focus msg
XSendEvent(disp, window(), false, NoEventMask, &ce); XSendEvent(display(), window(), false, NoEventMask, &ce);
return true; return true;
} }
void WinClient::sendClose(bool forceful) { void WinClient::sendClose(bool forceful) {
if (forceful || !send_close_message) if (forceful || !send_close_message)
XKillClient(FbTk::App::instance()->display(), window()); XKillClient(display(), window());
else { else {
// send WM_DELETE message // send WM_DELETE message
Display *disp = FbTk::App::instance()->display();
// fill in XClientMessage structure for delete message // fill in XClientMessage structure for delete message
XEvent ce; XEvent ce;
ce.xclient.type = ClientMessage; ce.xclient.type = ClientMessage;
ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom(); ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom();
ce.xclient.display = disp; ce.xclient.display = display();
ce.xclient.window = window(); ce.xclient.window = window();
ce.xclient.format = 32; ce.xclient.format = 32;
ce.xclient.data.l[0] = FbAtoms::instance()->getWMDeleteAtom(); 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[3] = 0l;
ce.xclient.data.l[4] = 0l; ce.xclient.data.l[4] = 0l;
// send event delete message to client window // 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 { 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 { 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 { 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 { const std::string &WinClient::getWMClassName() const {
@ -205,7 +230,7 @@ const std::string &WinClient::getWMClassClass() const {
void WinClient::updateWMClassHint() { void WinClient::updateWMClassHint() {
XClassHint ch; XClassHint ch;
if (XGetClassHint(FbTk::App::instance()->display(), window(), &ch) == 0) { if (XGetClassHint(display(), window(), &ch) == 0) {
#ifdef DEBUG #ifdef DEBUG
cerr<<"WinClient: Failed to read class hint!"<<endl; cerr<<"WinClient: Failed to read class hint!"<<endl;
#endif //DEBUG #endif //DEBUG
@ -234,16 +259,16 @@ void WinClient::updateTransientInfo() {
if (m_win == 0) if (m_win == 0)
return; return;
// remove us from parent
// remove this from parent
if (transientFor() != 0) { if (transientFor() != 0) {
transientFor()->transientList().remove(this); transientFor()->transientList().remove(this);
} }
transient_for = 0; transient_for = 0;
Display *disp = FbTk::App::instance()->display();
// determine if this is a transient window // determine if this is a transient window
Window win = 0; Window win = 0;
if (!XGetTransientForHint(disp, window(), &win)) { if (!XGetTransientForHint(display(), window(), &win)) {
#ifdef DEBUG #ifdef DEBUG
cerr<<__FUNCTION__<<": window() = 0x"<<hex<<window()<<dec<<"Failed to read transient for hint."<<endl; cerr<<__FUNCTION__<<": window() = 0x"<<hex<<window()<<dec<<"Failed to read transient for hint."<<endl;
#endif // DEBUG #endif // DEBUG
@ -266,6 +291,22 @@ void WinClient::updateTransientInfo() {
transient_for = Fluxbox::instance()->searchWindow(win); transient_for = Fluxbox::instance()->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 #ifdef DEBUG
cerr<<__FUNCTION__<<": transient_for window = 0x"<<hex<<win<<dec<<endl; cerr<<__FUNCTION__<<": transient_for window = 0x"<<hex<<win<<dec<<endl;
@ -287,6 +328,7 @@ void WinClient::updateTransientInfo() {
if (transientFor()->fbwindow() && transientFor()->fbwindow()->isStuck()) if (transientFor()->fbwindow() && transientFor()->fbwindow()->isStuck())
m_win->stick(); m_win->stick();
} }
} }
@ -301,7 +343,7 @@ void WinClient::updateTitle() {
// also influenced // also influenced
// //
// the limitation to 512 chars only avoids running in that trap // 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() { void WinClient::updateIconTitle() {
@ -314,7 +356,7 @@ void WinClient::updateIconTitle() {
if (text_prop.encoding != XA_STRING) { if (text_prop.encoding != XA_STRING) {
text_prop.nitems = strlen((char *) text_prop.value); text_prop.nitems = strlen((char *) text_prop.value);
if (XmbTextPropertyToTextList(FbTk::App::instance()->display(), &text_prop, if (XmbTextPropertyToTextList(display(), &text_prop,
&list, &num) == Success && &list, &num) == Success &&
num > 0 && *list) { num > 0 && *list) {
m_icon_title = (char *)*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() { void WinClient::updateBlackboxHints() {
int format; int format;
Atom atom_return; Atom atom_return;
@ -392,7 +438,7 @@ void WinClient::updateMWMHints() {
} }
void WinClient::updateWMHints() { void WinClient::updateWMHints() {
XWMHints *wmhint = XGetWMHints(FbTk::App::instance()->display(), window()); XWMHints *wmhint = XGetWMHints(display(), window());
if (! wmhint) { if (! wmhint) {
m_focus_mode = F_PASSIVE; m_focus_mode = F_PASSIVE;
window_group = None; window_group = None;
@ -447,7 +493,7 @@ void WinClient::updateWMHints() {
void WinClient::updateWMNormalHints() { void WinClient::updateWMNormalHints() {
long icccm_mask; long icccm_mask;
XSizeHints sizehint; XSizeHints sizehint;
if (! XGetWMNormalHints(FbTk::App::instance()->display(), window(), &sizehint, &icccm_mask)) { if (! XGetWMNormalHints(display(), window(), &sizehint, &icccm_mask)) {
min_width = min_height = min_width = min_height =
base_width = base_height = base_width = base_height =
width_inc = height_inc = 1; width_inc = height_inc = 1;
@ -515,7 +561,7 @@ Window WinClient::getGroupLeftWindow() const {
int format; int format;
Atom atom_return; Atom atom_return;
unsigned long num = 0, len = 0; 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; Window *data = 0;
if (property(group_left_hint, 0, if (property(group_left_hint, 0,
@ -538,7 +584,7 @@ Window WinClient::getGroupLeftWindow() const {
void WinClient::setGroupLeftWindow(Window win) { 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, changeProperty(group_left_hint, XA_WINDOW, 32,
PropModeReplace, (unsigned char *) &win, 1); PropModeReplace, (unsigned char *) &win, 1);
} }
@ -549,7 +595,7 @@ bool WinClient::hasGroupLeftWindow() const {
int format; int format;
Atom atom_return; Atom atom_return;
unsigned long num = 0, len = 0; 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; Window *data = 0;
if (property(group_left_hint, 0, if (property(group_left_hint, 0,
@ -581,13 +627,12 @@ void WinClient::removeModal() {
} }
bool WinClient::validateClient() const { bool WinClient::validateClient() const {
Display *display = FbTk::App::instance()->display();
FbTk::App::instance()->sync(false); FbTk::App::instance()->sync(false);
XEvent e; XEvent e;
if (( XCheckTypedWindowEvent(display, window(), DestroyNotify, &e) || if (( XCheckTypedWindowEvent(display(), window(), DestroyNotify, &e) ||
XCheckTypedWindowEvent(display, window(), UnmapNotify, &e)) XCheckTypedWindowEvent(display(), window(), UnmapNotify, &e))
&& XPutBackEvent(display, &e)) { && XPutBackEvent(display(), &e)) {
Fluxbox::instance()->ungrab(); Fluxbox::instance()->ungrab();
return false; return false;
} }
@ -620,7 +665,7 @@ void WinClient::updateWMProtocols() {
int num_return = 0; int num_return = 0;
FbAtoms *fbatoms = FbAtoms::instance(); FbAtoms *fbatoms = FbAtoms::instance();
if (XGetWMProtocols(FbTk::App::instance()->display(), window(), &proto, &num_return)) { if (XGetWMProtocols(display(), window(), &proto, &num_return)) {
// defaults // defaults
send_focus_message = false; send_focus_message = false;
@ -762,3 +807,28 @@ void WinClient::applySizeHints(int &width, int &height,
if (display_height) if (display_height)
*display_height = j; *display_height = j;
} }
void WinClient::removeTransientFromWaitingList() {
// holds the windows that dont have empty
// transient waiting list
std::list<Window> 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<Window>::iterator it = remove_list.begin();
std::list<Window>::iterator it_end = remove_list.end();
for (; it != it_end; ++it)
s_transient_wait.erase(*it);
}

View file

@ -94,6 +94,7 @@ public:
void setGroupLeftWindow(Window win); void setGroupLeftWindow(Window win);
void saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs); void saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs);
void setFluxboxWindow(FluxboxWindow *win);
// does this client have a pending unmap or destroy event? // does this client have a pending unmap or destroy event?
bool validateClient() const; bool validateClient() const;
@ -164,7 +165,7 @@ public:
unsigned long initial_state, normal_hint_flags, wm_hint_flags; unsigned long initial_state, normal_hint_flags, wm_hint_flags;
FluxboxWindow *m_win;
class WinClientSubj: public FbTk::Subject { class WinClientSubj: public FbTk::Subject {
public: public:
explicit WinClientSubj(WinClient &client):m_winclient(client) { } explicit WinClientSubj(WinClient &client):m_winclient(client) { }
@ -176,6 +177,11 @@ public:
enum FocusMode { F_NOINPUT = 0, F_PASSIVE, F_LOCALLYACTIVE, F_GLOBALLYACTIVE }; enum FocusMode { F_NOINPUT = 0, F_PASSIVE, F_LOCALLYACTIVE, F_GLOBALLYACTIVE };
private: 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 // number of transients which we are modal for
// or indicates that we are modal if don't have any transients // or indicates that we are modal if don't have any transients
int m_modal; int m_modal;
@ -195,6 +201,19 @@ private:
BScreen &m_screen; BScreen &m_screen;
Strut *m_strut; 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<Window, TransientList> TransientWaitMap;
static TransientWaitMap s_transient_wait;
}; };