[kwin] Use std::find_if and lambda functions for Workspace::findClient

Instead of passing the macro based Predicate to findClient it now
expects a function which can be passed to std::find_if.

Existing code like:
xcb_window_t window; // our test window
Client *c = findClient(WindowMatchPredicated(window));

becomes:
Client *c = findClient([window](const Client *c) {
    return c->window() == window;
});

The advantage is that it is way more flexible and has the logic what
to check for directly with the code and not hidden in the macro
definition.

In addition there is a simplified overload for the very common case of
matching a window id against one of Client's windows. This overloaded
method takes a Predicate and the window id.

Above example becomes:
Client *c = findClient(Predicate::WindowMatch, w);

Existing code is migrated to use the simplified method taking
MatchPredicate and window id. The very few cases where a more complex
condition is tested the lambda function is used. As these are very
local tests only used in one function it's not worthwhile to add further
overloads to the findClient method in Workspace.

With this change all the Predicate macro definitions are removed from
utils.h as they are now completely unused.

REVIEW: 116916
icc-effect-5.14.5
Martin Gräßlin 2014-03-20 09:19:53 +01:00
parent fe5f7fb2f6
commit bc0a9cb53a
16 changed files with 135 additions and 101 deletions

View File

@ -695,13 +695,6 @@ void Client::demandAttention(bool set)
emit demandsAttentionChanged();
}
// TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it
KWIN_COMPARE_PREDICATE(SameApplicationActiveHackPredicate, Client, const Client*,
// ignore already existing splashes, toolbars, utilities and menus,
// as the app may show those before the main window
!cl->isSplash() && !cl->isToolbar() && !cl->isUtility() && !cl->isMenu()
&& Client::belongToSameApplication(cl, value, true) && cl != value);
xcb_timestamp_t Client::readUserTimeMapTimestamp(const KStartupInfoId *asn_id, const KStartupInfoData *asn_data,
bool session) const
{
@ -733,17 +726,23 @@ xcb_timestamp_t Client::readUserTimeMapTimestamp(const KStartupInfoId *asn_id, c
Client* act = workspace()->mostRecentlyActivatedClient();
if (act != NULL && !belongToSameApplication(act, this, true)) {
bool first_window = true;
auto sameApplicationActiveHackPredicate = [this](const Client *cl) {
// ignore already existing splashes, toolbars, utilities and menus,
// as the app may show those before the main window
return !cl->isSplash() && !cl->isToolbar() && !cl->isUtility() && !cl->isMenu()
&& cl != this && Client::belongToSameApplication(cl, this, true);
};
if (isTransient()) {
if (act->hasTransient(this, true))
; // is transient for currently active window, even though it's not
// the same app (e.g. kcookiejar dialog) -> allow activation
else if (groupTransient() &&
findClientInList(mainClients(), SameApplicationActiveHackPredicate(this)) == NULL)
findInList<Client>(mainClients(), sameApplicationActiveHackPredicate) == NULL)
; // standalone transient
else
first_window = false;
} else {
if (workspace()->findClient(SameApplicationActiveHackPredicate(this)))
if (workspace()->findClient(sameApplicationActiveHackPredicate))
first_window = false;
}
// don't refuse if focus stealing prevention is turned off

View File

@ -50,13 +50,13 @@ bool ApplicationMenu::hasMenu(xcb_window_t window)
void ApplicationMenu::slotShowRequest(qulonglong wid)
{
if (Client *c = Workspace::self()->findClient(WindowMatchPredicate(wid)))
if (Client *c = Workspace::self()->findClient(Predicate::WindowMatch, wid))
c->emitShowRequest();
}
void ApplicationMenu::slotMenuAvailable(qulonglong wid)
{
if (Client *c = Workspace::self()->findClient(WindowMatchPredicate(wid)))
if (Client *c = Workspace::self()->findClient(Predicate::WindowMatch, wid))
c->setAppMenuAvailable();
else
m_windowsMenu.append(wid);
@ -64,7 +64,7 @@ void ApplicationMenu::slotMenuAvailable(qulonglong wid)
void ApplicationMenu::slotMenuHidden(qulonglong wid)
{
if (Client *c = Workspace::self()->findClient(WindowMatchPredicate(wid)))
if (Client *c = Workspace::self()->findClient(Predicate::WindowMatch, wid))
c->emitMenuHidden();
}

View File

@ -1800,8 +1800,6 @@ QString Client::readName() const
return KWindowSystem::readNameProperty(window(), XCB_ATOM_WM_NAME);
}
KWIN_COMPARE_PREDICATE(FetchNameInternalPredicate, Client, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
// The list is taken from http://www.unicode.org/reports/tr9/ (#154840)
QChar LRM(0x200E);
QChar RLM(0x200F);
@ -1856,12 +1854,16 @@ void Client::setCaption(const QString& _s, bool force)
}
QString shortcut_suffix = !shortcut().isEmpty() ? (QStringLiteral(" {") + shortcut().toString() + QStringLiteral("}")) : QString();
cap_suffix = machine_suffix + shortcut_suffix;
if ((!isSpecialWindow() || isToolbar()) && workspace()->findClient(FetchNameInternalPredicate(this))) {
auto fetchNameInternalPredicate = [this](const Client *cl) {
return (!cl->isSpecialWindow() || cl->isToolbar()) &&
cl != this && cl->caption() == caption();
};
if ((!isSpecialWindow() || isToolbar()) && workspace()->findClient(fetchNameInternalPredicate)) {
int i = 2;
do {
cap_suffix = machine_suffix + QStringLiteral(" <") + QString::number(i) + QStringLiteral(">") + LRM;
i++;
} while (workspace()->findClient(FetchNameInternalPredicate(this)));
} while (workspace()->findClient(fetchNameInternalPredicate));
info->setVisibleName(caption().toUtf8().constData());
reset_name = false;
}

View File

@ -55,6 +55,19 @@ class TabBoxClientImpl;
class Bridge;
class PaintRedirector;
/**
* @brief Defines Predicates on how to search for a Client.
*
* Used by Workspace::findClient.
*/
enum class Predicate {
WindowMatch,
WrapperIdMatch,
FrameIdMatch,
InputIdMatch
};
class Client
: public Toplevel
{
@ -978,7 +991,6 @@ private:
static bool check_active_modal; ///< \see Client::checkActiveModal()
QKeySequence _shortcut;
int sm_stacking_order;
friend struct FetchNameInternalPredicate;
friend struct ResetupRulesProcedure;
friend class GeometryUpdatesBlocker;
PaintRedirector* paintRedirector;
@ -1269,9 +1281,6 @@ inline void Client::print(T &stream) const
<< resourceName() << ";Caption:" << caption() << "\'";
}
KWIN_COMPARE_PREDICATE(WrapperIdMatchPredicate, Client, Window, cl->wrapperId() == value);
KWIN_COMPARE_PREDICATE(InputIdMatchPredicate, Client, Window, cl->inputId() == value);
} // namespace
Q_DECLARE_METATYPE(KWin::Client*)
Q_DECLARE_METATYPE(QList<KWin::Client*>)

View File

@ -1112,7 +1112,7 @@ WindowQuadType EffectsHandlerImpl::newWindowQuadType()
EffectWindow* EffectsHandlerImpl::findWindow(WId id) const
{
if (Client* w = Workspace::self()->findClient(WindowMatchPredicate(id)))
if (Client* w = Workspace::self()->findClient(Predicate::WindowMatch, id))
return w->effectWindow();
if (Unmanaged* w = Workspace::self()->findUnmanaged(id))
return w->effectWindow();

View File

@ -234,16 +234,16 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e)
const xcb_window_t eventWindow = findEventWindow(e);
if (eventWindow != XCB_WINDOW_NONE) {
if (Client* c = findClient(WindowMatchPredicate(eventWindow))) {
if (Client* c = findClient(Predicate::WindowMatch, eventWindow)) {
if (c->windowEvent(e))
return true;
} else if (Client* c = findClient(WrapperIdMatchPredicate(eventWindow))) {
} else if (Client* c = findClient(Predicate::WrapperIdMatch, eventWindow)) {
if (c->windowEvent(e))
return true;
} else if (Client* c = findClient(FrameIdMatchPredicate(eventWindow))) {
} else if (Client* c = findClient(Predicate::FrameIdMatch, eventWindow)) {
if (c->windowEvent(e))
return true;
} else if (Client *c = findClient(InputIdMatchPredicate(eventWindow))) {
} else if (Client *c = findClient(Predicate::InputIdMatch, eventWindow)) {
if (c->windowEvent(e))
return true;
} else if (Unmanaged* c = findUnmanaged(eventWindow)) {
@ -300,7 +300,7 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e)
updateXTime();
const auto *event = reinterpret_cast<xcb_map_request_event_t*>(e);
if (Client* c = findClient(WindowMatchPredicate(event->window))) {
if (Client* c = findClient(Predicate::WindowMatch, event->window)) {
// e->xmaprequest.window is different from e->xany.window
// TODO this shouldn't be necessary now
c->windowEvent(e);
@ -350,7 +350,7 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e)
break;
// TODO is this cliente ever found, given that client events are searched above?
const auto *event = reinterpret_cast<xcb_leave_notify_event_t*>(e);
Client* c = findClient(FrameIdMatchPredicate(event->event));
Client* c = findClient(Predicate::FrameIdMatch, event->event);
if (c && event->detail != XCB_NOTIFY_DETAIL_INFERIOR)
QWhatsThis::leaveWhatsThisMode();
break;

View File

@ -203,7 +203,7 @@ Group::Group(Window leader_P)
refcount(0)
{
if (leader_P != None) {
leader_client = workspace()->findClient(WindowMatchPredicate(leader_P));
leader_client = workspace()->findClient(Predicate::WindowMatch, leader_P);
leader_info = new NETWinInfo(connection(), leader_P, rootWindow(),
0, NET::WM2StartupId);
}
@ -583,7 +583,7 @@ void Client::setTransient(xcb_window_t new_transient_for_id)
transient_for = NULL;
m_transientForId = new_transient_for_id;
if (m_transientForId != XCB_WINDOW_NONE && !groupTransient()) {
transient_for = workspace()->findClient(WindowMatchPredicate(m_transientForId));
transient_for = workspace()->findClient(Predicate::WindowMatch, m_transientForId);
assert(transient_for != NULL); // verifyTransient() had to check this
transient_for->addTransient(this);
} // checkGroup() will check 'check_active_modal'
@ -755,14 +755,14 @@ xcb_window_t Client::verifyTransientFor(xcb_window_t new_transient_for, bool set
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))) {
&& !workspace()->findClient(Predicate::WindowMatch, new_transient_for)) {
Xcb::Tree tree(new_transient_for);
if (tree.isNull()) {
break;
}
new_transient_for = tree->parent;
}
if (Client* new_transient_for_client = workspace()->findClient(WindowMatchPredicate(new_transient_for))) {
if (Client* new_transient_for_client = workspace()->findClient(Predicate::WindowMatch, new_transient_for)) {
if (new_transient_for != before_search) {
qDebug() << "Client " << this << " has WM_TRANSIENT_FOR poiting to non-toplevel window "
<< before_search << ", child of " << new_transient_for_client << ", adjusting." << endl;
@ -776,7 +776,7 @@ xcb_window_t Client::verifyTransientFor(xcb_window_t new_transient_for, bool set
int count = 20;
xcb_window_t loop_pos = new_transient_for;
while (loop_pos != XCB_WINDOW_NONE && loop_pos != rootWindow()) {
Client* pos = workspace()->findClient(WindowMatchPredicate(loop_pos));
Client* pos = workspace()->findClient(Predicate::WindowMatch, loop_pos);
if (pos == NULL)
break;
loop_pos = pos->m_transientForId;
@ -786,7 +786,7 @@ xcb_window_t Client::verifyTransientFor(xcb_window_t new_transient_for, bool set
}
}
if (new_transient_for != rootWindow()
&& workspace()->findClient(WindowMatchPredicate(new_transient_for)) == NULL) {
&& workspace()->findClient(Predicate::WindowMatch, new_transient_for) == NULL) {
// it's transient for a specific window, but that window is not mapped
new_transient_for = rootWindow();
}

View File

@ -203,7 +203,7 @@ void KillWindow::killWindowId(xcb_window_t window_to_kill)
xcb_window_t window = window_to_kill;
Client* client = NULL;
while (true) {
client = Workspace::self()->findClient(FrameIdMatchPredicate(window));
client = Workspace::self()->findClient(Predicate::FrameIdMatch, window);
if (client) {
break; // Found the client
}

View File

@ -694,7 +694,7 @@ void Client::restackWindow(xcb_window_t above, int detail, NET::RequestSource sr
{
Client *other = 0;
if (detail == XCB_STACK_MODE_OPPOSITE) {
other = workspace()->findClient(WindowMatchPredicate(above));
other = workspace()->findClient(Predicate::WindowMatch, above);
if (!other) {
workspace()->raiseOrLowerClient(this);
return;
@ -713,20 +713,20 @@ void Client::restackWindow(xcb_window_t above, int detail, NET::RequestSource sr
}
}
else if (detail == XCB_STACK_MODE_TOP_IF) {
other = workspace()->findClient(WindowMatchPredicate(above));
other = workspace()->findClient(Predicate::WindowMatch, above);
if (other && other->geometry().intersects(geometry()))
workspace()->raiseClientRequest(this, src, timestamp);
return;
}
else if (detail == XCB_STACK_MODE_BOTTOM_IF) {
other = workspace()->findClient(WindowMatchPredicate(above));
other = workspace()->findClient(Predicate::WindowMatch, above);
if (other && other->geometry().intersects(geometry()))
workspace()->lowerClientRequest(this, src, timestamp);
return;
}
if (!other)
other = workspace()->findClient(WindowMatchPredicate(above));
other = workspace()->findClient(Predicate::WindowMatch, above);
if (other && detail == XCB_STACK_MODE_ABOVE) {
ToplevelList::const_iterator it = workspace()->stackingOrder().constEnd(),

View File

@ -157,7 +157,7 @@ void RootInfo::changeCurrentDesktop(int d)
void RootInfo::changeActiveWindow(xcb_window_t w, NET::RequestSource src, xcb_timestamp_t timestamp, xcb_window_t active_window)
{
Workspace *workspace = Workspace::self();
if (Client* c = workspace->findClient(WindowMatchPredicate(w))) {
if (Client* c = workspace->findClient(Predicate::WindowMatch, w)) {
if (timestamp == CurrentTime)
timestamp = c->userTime();
if (src != NET::FromApplication && src != FromTool)
@ -172,7 +172,7 @@ void RootInfo::changeActiveWindow(xcb_window_t w, NET::RequestSource src, xcb_ti
workspace->activateClient(c);
// if activation of the requestor's window would be allowed, allow activation too
else if (active_window != None
&& (c2 = workspace->findClient(WindowMatchPredicate(active_window))) != NULL
&& (c2 = workspace->findClient(Predicate::WindowMatch, active_window)) != NULL
&& workspace->allowClientActivation(c2,
timestampCompare(timestamp, c2->userTime() > 0 ? timestamp : c2->userTime()), false, true)) {
workspace->activateClient(c);
@ -184,7 +184,7 @@ void RootInfo::changeActiveWindow(xcb_window_t w, NET::RequestSource src, xcb_ti
void RootInfo::restackWindow(xcb_window_t w, RequestSource src, xcb_window_t above, int detail, xcb_timestamp_t timestamp)
{
if (Client* c = Workspace::self()->findClient(WindowMatchPredicate(w))) {
if (Client* c = Workspace::self()->findClient(Predicate::WindowMatch, w)) {
if (timestamp == CurrentTime)
timestamp = c->userTime();
if (src != NET::FromApplication && src != FromTool)
@ -195,14 +195,14 @@ void RootInfo::restackWindow(xcb_window_t w, RequestSource src, xcb_window_t abo
void RootInfo::closeWindow(xcb_window_t w)
{
Client* c = Workspace::self()->findClient(WindowMatchPredicate(w));
Client* c = Workspace::self()->findClient(Predicate::WindowMatch, w);
if (c)
c->closeWindow();
}
void RootInfo::moveResize(xcb_window_t w, int x_root, int y_root, unsigned long direction)
{
Client* c = Workspace::self()->findClient(WindowMatchPredicate(w));
Client* c = Workspace::self()->findClient(Predicate::WindowMatch, w);
if (c) {
updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp
c->NETMoveResize(x_root, y_root, (Direction)direction);
@ -211,14 +211,14 @@ void RootInfo::moveResize(xcb_window_t w, int x_root, int y_root, unsigned long
void RootInfo::moveResizeWindow(xcb_window_t w, int flags, int x, int y, int width, int height)
{
Client* c = Workspace::self()->findClient(WindowMatchPredicate(w));
Client* c = Workspace::self()->findClient(Predicate::WindowMatch, w);
if (c)
c->NETMoveResizeWindow(flags, x, y, width, height);
}
void RootInfo::gotPing(xcb_window_t w, xcb_timestamp_t timestamp)
{
if (Client* c = Workspace::self()->findClient(WindowMatchPredicate(w)))
if (Client* c = Workspace::self()->findClient(Predicate::WindowMatch, w))
c->gotPing(timestamp);
}

View File

@ -261,7 +261,7 @@ void WorkspaceWrapper::hideOutline()
Client *WorkspaceWrapper::getClient(qulonglong windowId)
{
return Workspace::self()->findClient(WindowMatchPredicate(windowId));
return Workspace::self()->findClient(Predicate::WindowMatch, windowId);
}
QSize WorkspaceWrapper::desktopGridSize() const

View File

@ -138,7 +138,7 @@ void WindowThumbnailItem::setWId(qulonglong wId)
}
m_wId = wId;
if (m_wId != 0) {
setClient(Workspace::self()->findClient(WindowMatchPredicate(m_wId)));
setClient(Workspace::self()->findClient(Predicate::WindowMatch, m_wId));
} else if (m_client) {
m_client = NULL;
emit clientChanged();
@ -165,7 +165,7 @@ void WindowThumbnailItem::paint(QPainter *painter)
if (effects) {
return;
}
Client *client = Workspace::self()->findClient(WindowMatchPredicate(m_wId));
Client *client = Workspace::self()->findClient(Predicate::WindowMatch, m_wId);
if (!client) {
return;
}

View File

@ -685,9 +685,6 @@ inline T *Toplevel::findInList(const QList<T*> &list, std::function<bool (const
QDebug& operator<<(QDebug& stream, const Toplevel*);
QDebug& operator<<(QDebug& stream, const ToplevelList&);
KWIN_COMPARE_PREDICATE(WindowMatchPredicate, Toplevel, Window, cl->window() == value);
KWIN_COMPARE_PREDICATE(FrameIdMatchPredicate, Toplevel, Window, cl->frameId() == value);
} // namespace
Q_DECLARE_METATYPE(KWin::Toplevel*)

34
utils.h
View File

@ -156,40 +156,6 @@ public:
#define UrgencyHint XUrgencyHint
#endif
// for STL-like algo's
#define KWIN_CHECK_PREDICATE( name, cls, check ) \
struct name \
{ \
inline bool operator()( const cls* cl ) { return check; } \
}
#define KWIN_COMPARE_PREDICATE( name, cls, type, check ) \
struct name \
{ \
typedef type type_helper; /* in order to work also with type being 'const Client*' etc. */ \
inline name( const type_helper& compare_value ) : value( compare_value ) {} \
inline bool operator()( const cls* cl ) { return check; } \
const type_helper& value; \
}
#define KWIN_PROCEDURE( name, cls, action ) \
struct name \
{ \
inline void operator()( cls* cl ) { action; } \
}
KWIN_CHECK_PREDICATE(TruePredicate, Client, cl == cl /*true, avoid warning about 'cl' */);
template< typename T >
Client* findClientInList(const ClientList& list, T predicate)
{
for (ClientList::ConstIterator it = list.begin(); it != list.end(); ++it) {
if (predicate(const_cast< const Client* >(*it)))
return *it;
}
return NULL;
}
QPoint cursorPos();
// converting between X11 mouse/keyboard state mask and Qt button/keyboard states

View File

@ -381,7 +381,7 @@ void Workspace::init()
Client* new_active_client = NULL;
if (!qApp->isSessionRestored()) {
--block_focus;
new_active_client = findClient(WindowMatchPredicate(client_info.activeWindow()));
new_active_client = findClient(Predicate::WindowMatch, client_info.activeWindow());
}
if (new_active_client == NULL
&& activeClient() == NULL && should_get_focus.count() == 0) {
@ -1527,6 +1527,17 @@ void Workspace::slotToggleCompositing()
}
}
Client *Workspace::findClient(std::function<bool (const Client*)> func) const
{
if (Client *ret = Toplevel::findInList(clients, func)) {
return ret;
}
if (Client *ret = Toplevel::findInList(desktops, func)) {
return ret;
}
return nullptr;
}
Unmanaged *Workspace::findUnmanaged(std::function<bool (const Unmanaged*)> func) const
{
return Toplevel::findInList(unmanaged, func);
@ -1539,6 +1550,29 @@ Unmanaged *Workspace::findUnmanaged(xcb_window_t w) const
});
}
Client *Workspace::findClient(Predicate predicate, xcb_window_t w) const
{
switch (predicate) {
case Predicate::WindowMatch:
return findClient([w](const Client *c) {
return c->window() == w;
});
case Predicate::WrapperIdMatch:
return findClient([w](const Client *c) {
return c->wrapperId() == w;
});
case Predicate::FrameIdMatch:
return findClient([w](const Client *c) {
return c->frameId() == w;
});
case Predicate::InputIdMatch:
return findClient([w](const Client *c) {
return c->inputId() == w;
});
}
return nullptr;
}
} // namespace
#include "workspace.moc"

View File

@ -55,6 +55,7 @@ class KillWindow;
class ShortcutDialog;
class UserActionsMenu;
class Compositor;
enum class Predicate;
class Workspace : public QObject, public KDecorationDefines
{
@ -72,7 +73,44 @@ public:
bool hasClient(const Client*);
template<typename T> Client* findClient(T predicate) const;
/**
* @brief Finds the first Client matching the condition expressed by passed in @p func.
*
* Internally findClient uses the std::find_if algorithm and that determines how the function
* needs to be implemented. An example usage for finding a Client with a matching windowId
* @code
* xcb_window_t w; // our test window
* Client *client = findClient([w](const Client *c) -> bool {
* return c->window() == w;
* });
* @endcode
*
* For the standard cases of matching the window id with one of the Client's windows use
* the simplified overload method findClient(Predicate, xcb_window_t). Above example
* can be simplified to:
* @code
* xcb_window_t w; // our test window
* Client *client = findClient(Predicate::WindowMatch, w);
* @endcode
*
* @param func Unary function that accepts a Client* as argument and
* returns a value convertible to bool. The value returned indicates whether the
* Client* is considered a match in the context of this function.
* The function shall not modify its argument.
* This can either be a function pointer or a function object.
* @return KWin::Client* The found Client or @c null
* @see findClient(Predicate, xcb_window_t)
*/
Client *findClient(std::function<bool (const Client*)> func) const;
/**
* @brief Finds the Client matching the given match @p predicate for the given window.
*
* @param predicate Which window should be compared
* @param w The window id to test against
* @return KWin::Client* The found Client or @c null
* @see findClient(std::function<bool (const Client*)>)
*/
Client *findClient(Predicate predicate, xcb_window_t w) const;
void forEachClient(std::function<void (Client*)> func);
Unmanaged *findUnmanaged(std::function<bool (const Unmanaged*)> func) const;
/**
@ -659,17 +697,6 @@ inline QPoint Workspace::focusMousePosition() const
return focusMousePos;
}
template< typename T >
inline Client* Workspace::findClient(T predicate) const
{
if (Client* ret = findClientInList(clients, predicate))
return ret;
if (Client* ret = findClientInList(desktops, predicate))
return ret;
return NULL;
}
inline
void Workspace::forEachClient(std::function< void (Client*) > func)
{
@ -683,11 +710,11 @@ void Workspace::forEachUnmanaged(std::function< void (Unmanaged*) > func)
std::for_each(unmanaged.constBegin(), unmanaged.constEnd(), func);
}
KWIN_COMPARE_PREDICATE(ClientMatchPredicate, Client, const Client*, cl == value);
inline bool Workspace::hasClient(const Client* c)
{
return findClient(ClientMatchPredicate(c));
return findClient([c](const Client *test) {
return test == c;
});
}
inline Workspace *workspace()