Port Client::transient_for handling to XCB

The type of the transient_for related variables are changed to
xcb_window_t. They cannot be Xcb::Window as we don't take ownership over
the transient for window.

Variables are renamed to m_camelCase to follow naming scheme.

A wrapper for retrieving the TransientFor hint is added to the Xcb
Wrappers.
icc-effect-5.14.5
Martin Gräßlin 2013-05-03 08:53:35 +02:00
parent 9d1fb072d4
commit 5afe5f810e
4 changed files with 64 additions and 45 deletions

View File

@ -99,8 +99,8 @@ Client::Client()
, move_resize_has_keyboard_grab(false)
, m_managed(false)
, transient_for (NULL)
, transient_for_id(None)
, original_transient_for_id(None)
, m_transientForId(XCB_WINDOW_NONE)
, m_originalTransientForId(XCB_WINDOW_NONE)
, shade_below(NULL)
, skip_switcher(false)
, blocks_compositing(false)

View File

@ -283,7 +283,7 @@ public:
ClientList allMainClients() const; // Call once before loop , is indirect
bool hasTransient(const Client* c, bool indirect) const;
const ClientList& transients() const; // Is not indirect
void checkTransient(Window w);
void checkTransient(xcb_window_t w);
Client* findModal(bool allow_itself = false);
const Group* group() const;
Group* group();
@ -869,16 +869,16 @@ private:
int quick_tile_mode;
void readTransient();
Window verifyTransientFor(Window transient_for, bool set);
xcb_window_t verifyTransientFor(xcb_window_t transient_for, bool set);
void addTransient(Client* cl);
void removeTransient(Client* cl);
void removeFromMainClients();
void cleanGrouping();
void checkGroupTransients();
void setTransient(Window new_transient_for_id);
void setTransient(xcb_window_t new_transient_for_id);
Client* transient_for;
Window transient_for_id;
Window original_transient_for_id;
xcb_window_t m_transientForId;
xcb_window_t m_originalTransientForId;
ClientList transients_list; // SELI TODO: Make this ordered in stacking order?
ShadeMode shade_mode;
Client *shade_below;
@ -1033,19 +1033,19 @@ inline Client* Client::transientFor()
inline bool Client::groupTransient() const
{
return transient_for_id == rootWindow();
return m_transientForId == rootWindow();
}
// Needed because verifyTransientFor() may set transient_for_id to root window,
// if the original value has a problem (window doesn't exist, etc.)
inline bool Client::wasOriginallyGroupTransient() const
{
return original_transient_for_id == rootWindow();
return m_originalTransientForId == rootWindow();
}
inline bool Client::isTransient() const
{
return transient_for_id != None;
return m_transientForId != XCB_WINDOW_NONE;
}
inline const ClientList& Client::transients() const

View File

@ -588,26 +588,27 @@ bool Client::sameAppWindowRoleMatch(const Client* c1, const Client* c2, bool act
void Client::readTransient()
{
TRANSIENCY_CHECK(this);
Window new_transient_for_id;
if (XGetTransientForHint(display(), window(), &new_transient_for_id)) {
original_transient_for_id = new_transient_for_id;
Xcb::TransientFor transientFor(window());
xcb_window_t new_transient_for_id = XCB_WINDOW_NONE;
if (transientFor.getTransientFor(&new_transient_for_id)) {
m_originalTransientForId = new_transient_for_id;
new_transient_for_id = verifyTransientFor(new_transient_for_id, true);
} else {
original_transient_for_id = None;
new_transient_for_id = verifyTransientFor(None, false);
m_originalTransientForId = XCB_WINDOW_NONE;
new_transient_for_id = verifyTransientFor(XCB_WINDOW_NONE, false);
}
setTransient(new_transient_for_id);
}
void Client::setTransient(Window new_transient_for_id)
void Client::setTransient(xcb_window_t new_transient_for_id)
{
TRANSIENCY_CHECK(this);
if (new_transient_for_id != transient_for_id) {
if (new_transient_for_id != m_transientForId) {
removeFromMainClients();
transient_for = NULL;
transient_for_id = new_transient_for_id;
if (transient_for_id != None && !groupTransient()) {
transient_for = workspace()->findClient(WindowMatchPredicate(transient_for_id));
m_transientForId = new_transient_for_id;
if (m_transientForId != XCB_WINDOW_NONE && !groupTransient()) {
transient_for = workspace()->findClient(WindowMatchPredicate(m_transientForId));
assert(transient_for != NULL); // verifyTransient() had to check this
transient_for->addTransient(this);
} // checkGroup() will check 'check_active_modal'
@ -755,18 +756,18 @@ void Client::checkGroupTransients()
/*!
Check that the window is not transient for itself, and similar nonsense.
*/
Window Client::verifyTransientFor(Window new_transient_for, bool defined)
xcb_window_t Client::verifyTransientFor(xcb_window_t new_transient_for, bool set)
{
Window new_property_value = new_transient_for;
xcb_window_t new_property_value = new_transient_for;
// make sure splashscreens are shown above all their app's windows, even though
// they're in Normal layer
if (isSplash() && new_transient_for == None)
if (isSplash() && new_transient_for == XCB_WINDOW_NONE)
new_transient_for = rootWindow();
if (new_transient_for == None) {
if (defined) // sometimes WM_TRANSIENT_FOR is set to None, instead of root window
if (new_transient_for == XCB_WINDOW_NONE) {
if (set) // sometimes WM_TRANSIENT_FOR is set to None, instead of root window
new_property_value = new_transient_for = rootWindow();
else
return None;
return XCB_WINDOW_NONE;
}
if (new_transient_for == window()) { // pointing to self
// also fix the property itself
@ -776,19 +777,15 @@ Window Client::verifyTransientFor(Window new_transient_for, bool defined)
// The transient_for window may be embedded in another application,
// so kwin cannot see it. Try to find the managed client for the
// window and fix the transient_for property if possible.
WId before_search = new_transient_for;
while (new_transient_for != None
xcb_window_t before_search = new_transient_for;
while (new_transient_for != XCB_WINDOW_NONE
&& new_transient_for != rootWindow()
&& !workspace()->findClient(WindowMatchPredicate(new_transient_for))) {
Window root_return, parent_return;
Window* wins = NULL;
unsigned int nwins;
int r = XQueryTree(display(), new_transient_for, &root_return, &parent_return, &wins, &nwins);
if (wins)
XFree((void *) wins);
if (r == 0)
Xcb::Tree tree(new_transient_for);
if (tree.isNull()) {
break;
new_transient_for = parent_return;
}
new_transient_for = tree->parent;
}
if (Client* new_transient_for_client = workspace()->findClient(WindowMatchPredicate(new_transient_for))) {
if (new_transient_for != before_search) {
@ -802,12 +799,12 @@ Window Client::verifyTransientFor(Window new_transient_for, bool defined)
// group transients cannot cause loops, because they're considered transient only for non-transient
// windows in the group
int count = 20;
Window loop_pos = new_transient_for;
while (loop_pos != None && loop_pos != rootWindow()) {
xcb_window_t loop_pos = new_transient_for;
while (loop_pos != XCB_WINDOW_NONE && loop_pos != rootWindow()) {
Client* pos = workspace()->findClient(WindowMatchPredicate(loop_pos));
if (pos == NULL)
break;
loop_pos = pos->transient_for_id;
loop_pos = pos->m_transientForId;
if (--count == 0 || pos == this) {
kWarning(1216) << "Client " << this << " caused WM_TRANSIENT_FOR loop." ;
new_transient_for = rootWindow();
@ -818,8 +815,8 @@ Window Client::verifyTransientFor(Window new_transient_for, bool defined)
// it's transient for a specific window, but that window is not mapped
new_transient_for = rootWindow();
}
if (new_property_value != original_transient_for_id)
XSetTransientForHint(display(), window(), new_property_value);
if (new_property_value != m_originalTransientForId)
xcb_icccm_set_wm_transient_for(connection(), window(), new_property_value);
return new_transient_for;
}
@ -849,18 +846,18 @@ void Client::removeTransient(Client* cl)
// cl is transient for this, but this is going away
// make cl group transient
if (cl->transientFor() == this) {
cl->transient_for_id = None;
cl->m_transientForId = XCB_WINDOW_NONE;
cl->transient_for = NULL; // SELI
// SELI cl->setTransient( rootWindow());
cl->setTransient(None);
cl->setTransient(XCB_WINDOW_NONE);
}
}
// A new window has been mapped. Check if it's not a mainwindow for this already existing window.
void Client::checkTransient(Window w)
void Client::checkTransient(xcb_window_t w)
{
TRANSIENCY_CHECK(this);
if (original_transient_for_id != w)
if (m_originalTransientForId != w)
return;
w = verifyTransientFor(w, true);
setTransient(w);

View File

@ -29,6 +29,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <xcb/xcb.h>
#include <xcb/composite.h>
#include <xcb/xcb_icccm.h>
namespace KWin {
@ -206,6 +207,27 @@ public:
}
};
class TransientFor : public Wrapper<xcb_get_property_reply_t, xcb_get_property_cookie_t, &xcb_get_property_reply, &xcb_icccm_get_wm_transient_for_unchecked>
{
public:
explicit TransientFor(WindowId window) : Wrapper<xcb_get_property_reply_t, xcb_get_property_cookie_t, &xcb_get_property_reply, &xcb_icccm_get_wm_transient_for_unchecked>(window) {}
/**
* @brief Fill given window pointer with the WM_TRANSIENT_FOR property of a window.
* @param prop WM_TRANSIENT_FOR property value.
* @returns @c true on success, @c false otherwise
**/
inline bool getTransientFor(WindowId *prop) {
if (isNull()) {
return false;
}
if (xcb_icccm_get_wm_transient_for_from_reply(prop, const_cast<xcb_get_property_reply_t*>(data()))) {
return true;
}
return false;
}
};
class ExtensionData
{
public: