5cd223f051
Most windows use the hostname in WM_CLIENT_MACHINE, but there are windows using the FQDN (for example libreoffice). So instead of "foo" it is "foo.local.net" or similar. The logic so far has been unable to properly determine whether windows with FQDN are on the local system. In order to solve this problem the handling is split out into an own class which stores the information of hostname and whether it is a local machine. This is to not query multiple times. To determine whether the Client is on the local system getaddrinfo is used for the own hostname and the FQDN provided in WM_CLIENT_MACHINE. If one of the queried names matches, we know that it is on the local machine. The old logic to compare the hostname is still used and getaddrinfo is only a fallback in case hostname does not match. The problem with getaddrinfo is, that it accesses the network and by that could block. To circumvent this problem the calls are moved into threads by using QtConcurrent::run. Obviously this brings disadvantages. When trying to resolve whether a Client is on the local machine and a FQDN is used, the information is initially wrong. The new ClientMachine class emits a signal when the information that the system is local becomes available, but for some things this is just too late: * window rules are already gathered * Session Management has already taken place In both cases this is an acceptable loss. For window rules it just needs a proper matching of the machine in case of localhost (remote hosts are not affected). And the case of session management is very academic as it is unlikely that a restoring session contains remote windows. BUG: 308391 FIXED-IN: 4.11 REVIEW: 108235
406 lines
12 KiB
C++
406 lines
12 KiB
C++
/********************************************************************
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
|
|
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*********************************************************************/
|
|
|
|
#ifndef KWIN_UTILS_H
|
|
#define KWIN_UTILS_H
|
|
|
|
class QLabel;
|
|
|
|
#include <config-X11.h>
|
|
#include <config-kwin.h>
|
|
|
|
#include <kwinconfig.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <fixx11h.h>
|
|
|
|
#include <QWidget>
|
|
#include <kmanagerselection.h>
|
|
#include <netwm_def.h>
|
|
#include <kkeysequencewidget.h>
|
|
#include <limits.h>
|
|
#include <QX11Info>
|
|
#include <kdialog.h>
|
|
|
|
#include <kwinglobals.h>
|
|
|
|
// needed by the DBUS interface
|
|
Q_DECLARE_METATYPE(QList<int>)
|
|
|
|
namespace KWin
|
|
{
|
|
|
|
// window types that are supported as normal windows (i.e. KWin actually manages them)
|
|
const int SUPPORTED_MANAGED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
|
|
| NET::ToolbarMask | NET::MenuMask | NET::DialogMask /*| NET::OverrideMask*/ | NET::TopMenuMask
|
|
| NET::UtilityMask | NET::SplashMask;
|
|
// window types that are supported as unmanaged (mainly for compositing)
|
|
const int SUPPORTED_UNMANAGED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
|
|
| NET::ToolbarMask | NET::MenuMask | NET::DialogMask /*| NET::OverrideMask*/ | NET::TopMenuMask
|
|
| NET::UtilityMask | NET::SplashMask | NET::DropdownMenuMask | NET::PopupMenuMask
|
|
| NET::TooltipMask | NET::NotificationMask | NET::ComboBoxMask | NET::DNDIconMask;
|
|
|
|
const long ClientWinMask = KeyPressMask | KeyReleaseMask |
|
|
ButtonPressMask | ButtonReleaseMask |
|
|
KeymapStateMask |
|
|
ButtonMotionMask |
|
|
PointerMotionMask | // need this, too!
|
|
EnterWindowMask | LeaveWindowMask |
|
|
FocusChangeMask |
|
|
ExposureMask |
|
|
StructureNotifyMask |
|
|
SubstructureRedirectMask;
|
|
|
|
const QPoint invalidPoint(INT_MIN, INT_MIN);
|
|
|
|
class Toplevel;
|
|
class Client;
|
|
class Unmanaged;
|
|
class Deleted;
|
|
class Group;
|
|
class Options;
|
|
|
|
typedef QList< Toplevel* > ToplevelList;
|
|
typedef QList< const Toplevel* > ConstToplevelList;
|
|
typedef QList< Client* > ClientList;
|
|
typedef QList< const Client* > ConstClientList;
|
|
typedef QList< Unmanaged* > UnmanagedList;
|
|
typedef QList< const Unmanaged* > ConstUnmanagedList;
|
|
typedef QList< Deleted* > DeletedList;
|
|
typedef QList< const Deleted* > ConstDeletedList;
|
|
|
|
typedef QList< Group* > GroupList;
|
|
typedef QList< const Group* > ConstGroupList;
|
|
|
|
extern Options* options;
|
|
extern bool initting; // whether kwin is starting up
|
|
|
|
enum Layer {
|
|
UnknownLayer = -1,
|
|
FirstLayer = 0,
|
|
DesktopLayer = FirstLayer,
|
|
BelowLayer,
|
|
NormalLayer,
|
|
DockLayer,
|
|
AboveLayer,
|
|
ActiveLayer, // active fullscreen, or active dialog
|
|
UnmanagedLayer, // layer for override redirect windows.
|
|
NumLayers // number of layers, must be last
|
|
};
|
|
|
|
// yes, I know this is not 100% like standard operator++
|
|
inline void operator++(Layer& lay)
|
|
{
|
|
lay = static_cast< Layer >(lay + 1);
|
|
}
|
|
|
|
// for Client::takeActivity()
|
|
enum ActivityFlags {
|
|
ActivityFocus = 1 << 0, // focus the window
|
|
ActivityFocusForce = 1 << 1, // focus even if Dock etc.
|
|
ActivityRaise = 1 << 2 // raise the window
|
|
};
|
|
|
|
enum StrutArea {
|
|
StrutAreaInvalid = 0, // Null
|
|
StrutAreaTop = 1 << 0,
|
|
StrutAreaRight = 1 << 1,
|
|
StrutAreaBottom = 1 << 2,
|
|
StrutAreaLeft = 1 << 3,
|
|
StrutAreaAll = StrutAreaTop | StrutAreaRight | StrutAreaBottom | StrutAreaLeft
|
|
};
|
|
Q_DECLARE_FLAGS(StrutAreas, StrutArea)
|
|
|
|
class StrutRect : public QRect
|
|
{
|
|
public:
|
|
explicit StrutRect(QRect rect = QRect(), StrutArea area = StrutAreaInvalid);
|
|
StrutRect(const StrutRect& other);
|
|
inline StrutArea area() const {
|
|
return m_area;
|
|
};
|
|
private:
|
|
StrutArea m_area;
|
|
};
|
|
typedef QVector<StrutRect> StrutRects;
|
|
|
|
// Some KWin classes, mainly Client and Workspace, are very tighly coupled,
|
|
// and some of the methods of one class may be called only from speficic places.
|
|
// Those methods have additional allowed_t argument. If you pass Allowed
|
|
// as an argument to any function, make sure you really know what you're doing.
|
|
enum allowed_t { Allowed };
|
|
|
|
// some enums to have more readable code, instead of using bools
|
|
enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet };
|
|
|
|
|
|
|
|
enum ShadeMode {
|
|
ShadeNone, // not shaded
|
|
ShadeNormal, // normally shaded - isShade() is true only here
|
|
ShadeHover, // "shaded", but visible due to hover unshade
|
|
ShadeActivated // "shaded", but visible due to alt+tab to the window
|
|
};
|
|
|
|
// Whether to keep all windows mapped when compositing (i.e. whether to have
|
|
// actively updated window pixmaps).
|
|
enum HiddenPreviews {
|
|
// The normal mode with regard to mapped windows. Hidden (minimized, etc.)
|
|
// and windows on inactive virtual desktops are not mapped, their pixmaps
|
|
// are only their icons.
|
|
HiddenPreviewsNever,
|
|
// Like normal mode, but shown windows (i.e. on inactive virtual desktops)
|
|
// are kept mapped, only hidden windows are unmapped.
|
|
HiddenPreviewsShown,
|
|
// All windows are kept mapped regardless of their state.
|
|
HiddenPreviewsAlways
|
|
};
|
|
|
|
// compile with XShape older than 1.0
|
|
#ifndef ShapeInput
|
|
const int ShapeInput = 2;
|
|
#endif
|
|
|
|
class Motif
|
|
{
|
|
public:
|
|
// Read a window's current settings from its _MOTIF_WM_HINTS
|
|
// property. If it explicitly requests that decorations be shown
|
|
// or hidden, 'got_noborder' is set to true and 'noborder' is set
|
|
// appropriately.
|
|
static void readFlags(WId w, bool& got_noborder, bool& noborder,
|
|
bool& resize, bool& move, bool& minimize, bool& maximize,
|
|
bool& close);
|
|
struct MwmHints {
|
|
ulong flags;
|
|
ulong functions;
|
|
ulong decorations;
|
|
long input_mode;
|
|
ulong status;
|
|
};
|
|
enum {
|
|
MWM_HINTS_FUNCTIONS = (1L << 0),
|
|
MWM_HINTS_DECORATIONS = (1L << 1),
|
|
|
|
MWM_FUNC_ALL = (1L << 0),
|
|
MWM_FUNC_RESIZE = (1L << 1),
|
|
MWM_FUNC_MOVE = (1L << 2),
|
|
MWM_FUNC_MINIMIZE = (1L << 3),
|
|
MWM_FUNC_MAXIMIZE = (1L << 4),
|
|
MWM_FUNC_CLOSE = (1L << 5)
|
|
};
|
|
};
|
|
|
|
class KWinSelectionOwner
|
|
: public KSelectionOwner
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit KWinSelectionOwner(int screen);
|
|
protected:
|
|
virtual bool genericReply(Atom target, Atom property, Window requestor);
|
|
virtual void replyTargets(Atom property, Window requestor);
|
|
virtual void getAtoms();
|
|
private:
|
|
Atom make_selection_atom(int screen);
|
|
static Atom xa_version;
|
|
};
|
|
|
|
// Class which saves original value of the variable, assigns the new value
|
|
// to it, and in the destructor restores the value.
|
|
// Used in Client::isMaximizable() and so on.
|
|
// It also casts away contness and generally this looks like a hack.
|
|
template< typename T >
|
|
class TemporaryAssign
|
|
{
|
|
public:
|
|
TemporaryAssign(const T& var, const T& value)
|
|
: variable(var), orig(var) {
|
|
const_cast< T& >(variable) = value;
|
|
}
|
|
~TemporaryAssign() {
|
|
const_cast< T& >(variable) = orig;
|
|
}
|
|
private:
|
|
const T& variable;
|
|
T orig;
|
|
};
|
|
|
|
// Light weight scoped pointer class that stores a pointer to a
|
|
// dynamically allocated object and automatically free()'s it
|
|
// upon destruction.
|
|
//
|
|
// This class works the same way as QScopedPointer, but uses
|
|
// free() instead of delete.
|
|
template <typename T>
|
|
class ScopedCPointer
|
|
{
|
|
public:
|
|
ScopedCPointer() : m_ptr(0) {}
|
|
ScopedCPointer(T *ptr) : m_ptr(ptr) {}
|
|
~ScopedCPointer() { if (m_ptr) free(m_ptr); }
|
|
|
|
T *data() const { return m_ptr; }
|
|
bool isNull() const { return !m_ptr; }
|
|
void reset(T *other = 0) { m_ptr = other; }
|
|
T *take() { T *ret = m_ptr; m_ptr = 0; return ret; }
|
|
|
|
T ** operator & () { return &m_ptr; }
|
|
operator bool () const { return bool(m_ptr); }
|
|
bool operator ! () const { return !m_ptr; }
|
|
operator T * () const { return m_ptr; }
|
|
T * operator -> () const { return m_ptr; }
|
|
ScopedCPointer & operator = (T *ptr) { m_ptr = ptr; }
|
|
|
|
private:
|
|
ScopedCPointer & operator = (const ScopedCPointer &);
|
|
|
|
private:
|
|
T *m_ptr;
|
|
};
|
|
|
|
QByteArray getStringProperty(WId w, Atom prop, char separator = 0);
|
|
void updateXTime();
|
|
void grabXServer();
|
|
void ungrabXServer();
|
|
bool grabbedXServer();
|
|
bool grabXKeyboard(Window w = rootWindow());
|
|
void ungrabXKeyboard();
|
|
|
|
/**
|
|
* Small helper class which performs @link grabXServer in the ctor and
|
|
* @link ungrabXServer in the dtor. Use this class to ensure that grab and
|
|
* ungrab are matched.
|
|
**/
|
|
class XServerGrabber
|
|
{
|
|
public:
|
|
XServerGrabber() {
|
|
grabXServer();
|
|
}
|
|
~XServerGrabber() {
|
|
ungrabXServer();
|
|
}
|
|
};
|
|
|
|
// the docs say it's UrgencyHint, but it's often #defined as XUrgencyHint
|
|
#ifndef UrgencyHint
|
|
#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;
|
|
}
|
|
|
|
template< typename T >
|
|
Unmanaged* findUnmanagedInList(const UnmanagedList& list, T predicate)
|
|
{
|
|
for (UnmanagedList::ConstIterator it = list.begin(); it != list.end(); ++it) {
|
|
if (predicate(const_cast< const Unmanaged* >(*it)))
|
|
return *it;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
inline
|
|
int timestampCompare(Time time1, Time time2) // like strcmp()
|
|
{
|
|
return NET::timestampCompare(time1, time2);
|
|
}
|
|
|
|
inline
|
|
Time timestampDiff(Time time1, Time time2) // returns time2 - time1
|
|
{
|
|
return NET::timestampDiff(time1, time2);
|
|
}
|
|
|
|
QPoint cursorPos();
|
|
|
|
// converting between X11 mouse/keyboard state mask and Qt button/keyboard states
|
|
int qtToX11Button(Qt::MouseButton button);
|
|
Qt::MouseButton x11ToQtMouseButton(int button);
|
|
int qtToX11State(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers);
|
|
Qt::MouseButtons x11ToQtMouseButtons(int state);
|
|
Qt::KeyboardModifiers x11ToQtKeyboardModifiers(int state);
|
|
|
|
void checkNonExistentClients();
|
|
|
|
#ifndef KCMRULES
|
|
// Qt dialogs emit no signal when closed :(
|
|
class ShortcutDialog
|
|
: public KDialog
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit ShortcutDialog(const QKeySequence& cut);
|
|
virtual void accept();
|
|
QKeySequence shortcut() const;
|
|
public Q_SLOTS:
|
|
void keySequenceChanged(const QKeySequence &seq);
|
|
signals:
|
|
void dialogDone(bool ok);
|
|
protected:
|
|
virtual void done(int r);
|
|
private:
|
|
KKeySequenceWidget* widget;
|
|
QKeySequence _shortcut;
|
|
QLabel *warning;
|
|
};
|
|
|
|
#endif //KCMRULES
|
|
|
|
} // namespace
|
|
|
|
// Must be outside namespace
|
|
Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::StrutAreas)
|
|
|
|
#endif
|