abstract_client.h 43.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/********************************************************************
 KWin - the KDE window manager
 This file is part of the KDE project.

Copyright (C) 2015 Martin Gräßlin <mgraesslin@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_ABSTRACT_CLIENT_H
#define KWIN_ABSTRACT_CLIENT_H

#include "toplevel.h"
24
#include "options.h"
25
#include "rules.h"
26
#include "tabgroup.h"
27
#include "cursor.h"
28

29 30
#include <memory>

31
#include <QElapsedTimer>
32
#include <QPointer>
33

34 35 36 37 38 39 40 41
namespace KWayland
{
namespace Server
{
class PlasmaWindowInterface;
}
}

42 43 44 45 46
namespace KDecoration2
{
class Decoration;
}

47 48 49 50 51 52 53 54
namespace KWin
{

namespace TabBox
{
class TabBoxClientImpl;
}

55 56
namespace Decoration
{
57
class DecoratedClientImpl;
58 59 60
class DecorationPalette;
}

61
class KWIN_EXPORT AbstractClient : public Toplevel
62 63
{
    Q_OBJECT
64 65 66 67 68 69 70 71 72 73 74
    /**
     * Whether this Client is fullScreen. A Client might either be fullScreen due to the _NET_WM property
     * or through a legacy support hack. The fullScreen state can only be changed if the Client does not
     * use the legacy hack. To be sure whether the state changed, connect to the notify signal.
     **/
    Q_PROPERTY(bool fullScreen READ isFullScreen WRITE setFullScreen NOTIFY fullScreenChanged)
    /**
     * Whether the Client can be set to fullScreen. The property is evaluated each time it is invoked.
     * Because of that there is no notify signal.
     **/
    Q_PROPERTY(bool fullScreenable READ isFullScreenable)
75 76 77 78 79
    /**
     * Whether this Client is the currently visible Client in its Client Group (Window Tabs).
     * For change connect to the visibleChanged signal on the Client's Group.
     **/
    Q_PROPERTY(bool isCurrentTab READ isCurrentTab)
80 81 82 83 84
    /**
     * Whether this Client is active or not. Use Workspace::activateClient() to activate a Client.
     * @see Workspace::activateClient
     **/
    Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
85 86 87 88 89 90 91 92
    /**
     * The desktop this Client is on. If the Client is on all desktops the property has value -1.
     **/
    Q_PROPERTY(int desktop READ desktop WRITE setDesktop NOTIFY desktopChanged)
    /**
     * Whether the Client is on all desktops. That is desktop is -1.
     **/
    Q_PROPERTY(bool onAllDesktops READ isOnAllDesktops WRITE setOnAllDesktops NOTIFY desktopChanged)
93 94 95 96
    /**
     * Indicates that the window should not be included on a taskbar.
     **/
    Q_PROPERTY(bool skipTaskbar READ skipTaskbar WRITE setSkipTaskbar NOTIFY skipTaskbarChanged)
97 98 99 100
    /**
     * Indicates that the window should not be included on a Pager.
     **/
    Q_PROPERTY(bool skipPager READ skipPager WRITE setSkipPager NOTIFY skipPagerChanged)
101 102 103 104
    /**
     * Whether the Client should be excluded from window switching effects.
     **/
    Q_PROPERTY(bool skipSwitcher READ skipSwitcher WRITE setSkipSwitcher NOTIFY skipSwitcherChanged)
105 106 107 108 109
    /**
     * Whether the window can be closed by the user. The value is evaluated each time the getter is called.
     * Because of that no changed signal is provided.
     **/
    Q_PROPERTY(bool closeable READ isCloseable)
110
    Q_PROPERTY(QIcon icon READ icon NOTIFY iconChanged)
111 112 113 114 115 116 117 118
    /**
     * Whether the Client is set to be kept above other windows.
     **/
    Q_PROPERTY(bool keepAbove READ keepAbove WRITE setKeepAbove NOTIFY keepAboveChanged)
    /**
     * Whether the Client is set to be kept below other windows.
     **/
    Q_PROPERTY(bool keepBelow READ keepBelow WRITE setKeepBelow NOTIFY keepBelowChanged)
119 120 121 122 123 124 125 126 127
    /**
     * Whether the Client can be shaded. The property is evaluated each time it is invoked.
     * Because of that there is no notify signal.
     **/
    Q_PROPERTY(bool shadeable READ isShadeable)
    /**
     * Whether the Client is shaded.
     **/
    Q_PROPERTY(bool shade READ isShade WRITE setShade NOTIFY shadeChanged)
128 129 130 131 132 133 134 135 136
    /**
     * Whether the Client can be minimized. The property is evaluated each time it is invoked.
     * Because of that there is no notify signal.
     **/
    Q_PROPERTY(bool minimizable READ isMinimizable)
    /**
     * Whether the Client is minimized.
     **/
    Q_PROPERTY(bool minimized READ isMinimized WRITE setMinimized NOTIFY minimizedChanged)
137 138 139 140 141 142 143
    /**
     * The optional geometry representing the minimized Client in e.g a taskbar.
     * See _NET_WM_ICON_GEOMETRY at http://standards.freedesktop.org/wm-spec/wm-spec-latest.html .
     * The value is evaluated each time the getter is called.
     * Because of that no changed signal is provided.
     **/
    Q_PROPERTY(QRect iconGeometry READ iconGeometry)
144 145 146 147 148 149 150 151
    /**
     * Returns whether the window is any of special windows types (desktop, dock, splash, ...),
     * i.e. window types that usually don't have a window frame and the user does not use window
     * management (moving, raising,...) on them.
     * The value is evaluated each time the getter is called.
     * Because of that no changed signal is provided.
     **/
    Q_PROPERTY(bool specialWindow READ isSpecialWindow)
152 153 154 155 156 157 158 159 160
    /**
     * Whether window state _NET_WM_STATE_DEMANDS_ATTENTION is set. This state indicates that some
     * action in or with the window happened. For example, it may be set by the Window Manager if
     * the window requested activation but the Window Manager refused it, or the application may set
     * it if it finished some work. This state may be set by both the Client and the Window Manager.
     * It should be unset by the Window Manager when it decides the window got the required attention
     * (usually, that it got activated).
     **/
    Q_PROPERTY(bool demandsAttention READ isDemandingAttention WRITE demandAttention NOTIFY demandsAttentionChanged)
161 162 163 164 165
    /**
     * The Caption of the Client. Read from WM_NAME property together with a suffix for hostname and shortcut.
     * To read only the caption as provided by WM_NAME, use the getter with an additional @c false value.
     **/
    Q_PROPERTY(QString caption READ caption NOTIFY captionChanged)
166 167 168 169 170 171 172 173
    /**
     * Minimum size as specified in WM_NORMAL_HINTS
     **/
    Q_PROPERTY(QSize minSize READ minSize)
    /**
     * Maximum size as specified in WM_NORMAL_HINTS
     **/
    Q_PROPERTY(QSize maxSize READ maxSize)
174 175 176 177 178 179
    /**
     * Whether the Client can accept keyboard focus.
     * The value is evaluated each time the getter is called.
     * Because of that no changed signal is provided.
     **/
    Q_PROPERTY(bool wantsInput READ wantsInput)
180 181 182 183 184
    /**
     * Whether the Client is a transient Window to another Window.
     * @see transientFor
     **/
    Q_PROPERTY(bool transient READ isTransient NOTIFY transientChanged)
185 186 187 188
    /**
     * The Client to which this Client is a transient if any.
     **/
    Q_PROPERTY(KWin::AbstractClient *transientFor READ transientFor NOTIFY transientChanged)
189 190 191 192
    /**
     * Whether the Client represents a modal window.
     **/
    Q_PROPERTY(bool modal READ isModal NOTIFY modalChanged)
193 194 195 196 197
    /**
     * The geometry of this Client. Be aware that depending on resize mode the geometryChanged signal
     * might be emitted at each resize step or only at the end of the resize operation.
     **/
    Q_PROPERTY(QRect geometry READ geometry WRITE setGeometry)
198 199 200 201 202 203 204 205 206 207
    /**
     * Whether the Client is currently being moved by the user.
     * Notify signal is emitted when the Client starts or ends move/resize mode.
     **/
    Q_PROPERTY(bool move READ isMove NOTIFY moveResizedChanged)
    /**
     * Whether the Client is currently being resized by the user.
     * Notify signal is emitted when the Client starts or ends move/resize mode.
     **/
    Q_PROPERTY(bool resize READ isResize NOTIFY moveResizedChanged)
208 209 210 211
    /**
     * Whether the decoration is currently using an alpha channel.
     **/
    Q_PROPERTY(bool decorationHasAlpha READ decorationHasAlpha)
212 213 214 215 216 217 218
    /**
     * Whether the window has a decoration or not.
     * This property is not allowed to be set by applications themselves.
     * The decision whether a window has a border or not belongs to the window manager.
     * If this property gets abused by application developers, it will be removed again.
     **/
    Q_PROPERTY(bool noBorder READ noBorder WRITE setNoBorder)
219 220 221 222 223
    /**
     * Whether the Client provides context help. Mostly needed by decorations to decide whether to
     * show the help button or not.
     **/
    Q_PROPERTY(bool providesContextHelp READ providesContextHelp CONSTANT)
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    /**
     * Whether the Client can be maximized both horizontally and vertically.
     * The property is evaluated each time it is invoked.
     * Because of that there is no notify signal.
     **/
    Q_PROPERTY(bool maximizable READ isMaximizable)
    /**
     * Whether the Client is moveable. Even if it is not moveable, it might be possible to move
     * it to another screen. The property is evaluated each time it is invoked.
     * Because of that there is no notify signal.
     * @see moveableAcrossScreens
     **/
    Q_PROPERTY(bool moveable READ isMovable)
    /**
     * Whether the Client can be moved to another screen. The property is evaluated each time it is invoked.
     * Because of that there is no notify signal.
     * @see moveable
     **/
    Q_PROPERTY(bool moveableAcrossScreens READ isMovableAcrossScreens)
    /**
     * Whether the Client can be resized. The property is evaluated each time it is invoked.
     * Because of that there is no notify signal.
     **/
    Q_PROPERTY(bool resizeable READ isResizable)
248 249 250 251 252 253 254 255 256 257 258

    /**
     * The desktop file name of the application this AbstractClient belongs to.
     *
     * This is either the base name without full path and without file extension of the
     * desktop file for the window's application (e.g. "org.kde.foo").
     *
     * The application's desktop file name can also be the full path to the desktop file
     * (e.g. "/opt/kde/share/org.kde.foo.desktop") in case it's not in a standard location.
     **/
    Q_PROPERTY(QByteArray desktopFileName READ desktopFileName NOTIFY desktopFileNameChanged)
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
259 260 261 262 263 264 265 266 267 268

    /**
     * Whether an application menu is available for this Client
     */
    Q_PROPERTY(bool hasApplicationMenu READ hasApplicationMenu NOTIFY hasApplicationMenuChanged)
    /**
     * Whether the application menu for this Client is currently opened
     */
    Q_PROPERTY(bool applicationMenuActive READ applicationMenuActive NOTIFY applicationMenuActiveChanged)

269 270 271 272 273 274 275
    /**
     * Whether this client is unresponsive.
     *
     * When an application failed to react on a ping request in time, it is
     * considered unresponsive. This usually indicates that the application froze or crashed.
     */
    Q_PROPERTY(bool unresponsive READ unresponsive NOTIFY unresponsiveChanged)
276 277 278 279
    /**
     * The "Window Tabs" Group this Client belongs to.
     **/
    Q_PROPERTY(KWin::TabGroup* tabGroup READ tabGroup NOTIFY tabGroupChanged SCRIPTABLE false)
280

281 282 283
public:
    virtual ~AbstractClient();

284 285 286
    QWeakPointer<TabBox::TabBoxClientImpl> tabBoxClient() const {
        return m_tabBoxClient.toWeakRef();
    }
287 288 289
    bool isFirstInTabBox() const {
        return m_firstInTabBox;
    }
290 291 292 293
    bool skipSwitcher() const {
        return m_skipSwitcher;
    }
    void setSkipSwitcher(bool set);
294

295 296 297 298 299 300 301 302 303
    bool skipTaskbar() const {
        return m_skipTaskbar;
    }
    void setSkipTaskbar(bool set);
    void setOriginalSkipTaskbar(bool set);
    bool originalSkipTaskbar() const {
        return m_originalSkipTaskbar;
    }

304 305 306 307 308
    bool skipPager() const {
        return m_skipPager;
    }
    void setSkipPager(bool set);

309 310 311 312
    const QIcon &icon() const {
        return m_icon;
    }

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    bool isActive() const {
        return m_active;
    }
    /**
     * Sets the client's active state to \a act.
     *
     * This function does only change the visual appearance of the client,
     * it does not change the focus setting. Use
     * Workspace::activateClient() or Workspace::requestFocus() instead.
     *
     * If a client receives or looses the focus, it calls setActive() on
     * its own.
     **/
    void setActive(bool);

328 329 330 331 332 333 334 335 336
    bool keepAbove() const {
        return m_keepAbove;
    }
    void setKeepAbove(bool);
    bool keepBelow() const {
        return m_keepBelow;
    }
    void setKeepBelow(bool);

337 338 339 340 341
    void demandAttention(bool set = true);
    bool isDemandingAttention() const {
        return m_demandsAttention;
    }

342 343
    void cancelAutoRaise();

344 345
    bool wantsTabFocus() const;

346 347 348 349
    QPoint clientPos() const override {
        return QPoint(borderLeft(), borderTop());
    }

350
    virtual void updateMouseGrab();
351 352 353 354 355
    /**
     * @returns The caption consisting of @link{captionNormal} and @link{captionSuffix}
     * @see captionNormal
     * @see captionSuffix
     **/
356
    QString caption() const;
357 358 359 360 361 362 363 364 365 366 367 368
    /**
     * @returns The caption as set by the AbstractClient without any suffix.
     * @see caption
     * @see captionSuffix
     **/
    virtual QString captionNormal() const = 0;
    /**
     * @returns The suffix added to the caption (e.g. shortcut, machine name, etc.)
     * @see caption
     * @see captionNormal
     **/
    virtual QString captionSuffix() const = 0;
369 370 371
    virtual bool isCloseable() const = 0;
    // TODO: remove boolean trap
    virtual bool isShown(bool shaded_is_shown) const = 0;
372
    virtual bool isHiddenInternal() const = 0;
373 374
    // TODO: remove boolean trap
    virtual void hideClient(bool hide) = 0;
375 376
    bool isFullScreenable() const;
    bool isFullScreenable(bool fullscreen_hack) const;
377
    virtual bool isFullScreen() const = 0;
378 379
    // TODO: remove boolean trap
    virtual AbstractClient *findModal(bool allow_itself = false) = 0;
380
    virtual bool isTransient() const;
381 382 383 384 385 386 387 388 389
    /**
     * @returns Whether there is a hint available to place the AbstractClient on it's parent, default @c false.
     * @see transientPlacementHint
     **/
    virtual bool hasTransientPlacementHint() const;
    /**
     * @returns The recommended position of the transient in parent coordinates
     **/
    virtual QPoint transientPlacementHint() const;
390 391
    const AbstractClient* transientFor() const;
    AbstractClient* transientFor();
392 393 394 395 396 397
    /**
     * @returns @c true if c is the transient_for window for this client,
     *  or recursively the transient_for window
     * @todo: remove boolean trap
     **/
    virtual bool hasTransient(const AbstractClient* c, bool indirect) const;
398
    const QList<AbstractClient*>& transients() const; // Is not indirect
Martin Flöser's avatar
Martin Flöser committed
399
    virtual void removeTransient(AbstractClient* cl);
400 401
    virtual QList<AbstractClient*> mainClients() const; // Call once before loop , is not indirect
    QList<AbstractClient*> allMainClients() const; // Call once before loop , is indirect
402 403 404 405 406 407
    /**
     * Returns true for "special" windows and false for windows which are "normal"
     * (normal=window which has a border, can be moved by the user, can be closed, etc.)
     * true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now)
     * false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO
     */
408
    bool isSpecialWindow() const;
409
    void sendToScreen(int screen);
410 411 412 413
    const QKeySequence &shortcut() const {
        return _shortcut;
    }
    void setShortcut(const QString &cut);
414
    virtual bool performMouseCommand(Options::MouseCommand, const QPoint &globalPos);
415 416 417 418 419
    void setOnAllDesktops(bool set);
    void setDesktop(int);
    int desktop() const override {
        return m_desktop;
    }
420 421 422 423 424 425 426 427 428
    void setMinimized(bool set);
    /**
    * Minimizes this client plus its transients
    */
    void minimize(bool avoid_animation = false);
    void unminimize(bool avoid_animation = false);
    bool isMinimized() const {
        return m_minimized;
    }
429
    virtual void setFullScreen(bool set, bool user = true) = 0;
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
    // Tabbing functions
    Q_INVOKABLE inline bool tabBefore(AbstractClient *other, bool activate) { return tabTo(other, false, activate); }
    Q_INVOKABLE inline bool tabBehind(AbstractClient *other, bool activate) { return tabTo(other, true, activate); }
    /**
     * Syncs the *dynamic* @param property @param fromThisClient or the @link currentTab() to
     * all members of the @link tabGroup() (if there is one)
     *
     * eg. if you call:
     * client->setProperty("kwin_tiling_floats", true);
     * client->syncTabGroupFor("kwin_tiling_floats", true)
     * all clients in this tabGroup will have ::property("kwin_tiling_floats").toBool() == true
     *
     * WARNING: non dynamic properties are ignored - you're not supposed to alter/update such explicitly
     */
    Q_INVOKABLE void syncTabGroupFor(QString property, bool fromThisClient = false);
    TabGroup *tabGroup() const;
    /**
     * Set tab group - this is to be invoked by TabGroup::add/remove(client) and NO ONE ELSE
     */
    void setTabGroup(TabGroup* group);
450
    virtual void setClientShown(bool shown);
451 452 453 454 455 456 457
    Q_INVOKABLE bool untab(const QRect &toGeometry = QRect(), bool clientRemoved = false);
    /*
    *   When a click is done in the decoration and it calls the group
    *   to change the visible client it starts to move-resize the new
    *   client, this function stops it.
    */
    bool isCurrentTab() const;
458
    virtual QRect geometryRestore() const = 0;
459 460 461
    /**
     * The currently applied maximize mode
     */
462
    virtual MaximizeMode maximizeMode() const = 0;
463 464 465 466 467 468
    /**
     * The maximise mode requested by the server.
     * For X this always matches maximizeMode, for wayland clients it
     * is asyncronous
     */
    virtual MaximizeMode requestedMaximizeMode() const;
469 470
    void maximize(MaximizeMode);
    void setMaximize(bool vertically, bool horizontally);
471 472
    virtual bool noBorder() const = 0;
    virtual void setNoBorder(bool set) = 0;
473
    virtual void blockActivityUpdates(bool b = true) = 0;
474 475
    QPalette palette() const;
    const Decoration::DecorationPalette *decorationPalette() const;
476 477 478
    virtual bool isResizable() const = 0;
    virtual bool isMovable() const = 0;
    virtual bool isMovableAcrossScreens() const = 0;
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
    /**
     * @c true only for @c ShadeNormal
     **/
    bool isShade() const {
        return shadeMode() == ShadeNormal;
    }
    /**
     * Default implementation returns @c ShadeNone
     **/
    virtual ShadeMode shadeMode() const; // Prefer isShade()
    void setShade(bool set);
    /**
     * Default implementation does nothing
     **/
    virtual void setShade(ShadeMode mode);
    /**
     * Whether the Client can be shaded. Default implementation returns @c false.
     **/
    virtual bool isShadeable() const;
498 499
    virtual bool isMaximizable() const = 0;
    virtual bool isMinimizable() const = 0;
500
    virtual QRect iconGeometry() const;
501 502
    virtual bool userCanSetFullScreen() const = 0;
    virtual bool userCanSetNoBorder() const = 0;
503
    virtual void checkNoBorder();
504
    virtual void setOnActivities(QStringList newActivitiesList);
505
    virtual void setOnAllActivities(bool set) = 0;
506 507 508 509 510 511 512
    const WindowRules* rules() const {
        return &m_rules;
    }
    void removeRule(Rules* r);
    void setupWindowRules(bool ignore_temporary);
    void evaluateWindowRules();
    void applyWindowRules();
513 514
    virtual void takeFocus() = 0;
    virtual bool wantsInput() const = 0;
515 516 517 518 519 520 521 522 523 524 525 526
    /**
     * Whether a dock window wants input.
     *
     * By default KWin doesn't pass focus to a dock window unless a force activate
     * request is provided.
     *
     * This method allows to have dock windows take focus also through flags set on
     * the window.
     *
     * The default implementation returns @c false.
     **/
    virtual bool dockWantsInput() const;
527
    void checkWorkspacePosition(QRect oldGeometry = QRect(), int oldDesktop = -2,  QRect oldClientGeometry = QRect());
528
    virtual xcb_timestamp_t userTime() const;
529
    virtual void updateWindowRules(Rules::Types selection);
530

531 532 533 534
    void growHorizontal();
    void shrinkHorizontal();
    void growVertical();
    void shrinkVertical();
535
    void updateMoveResize(const QPointF &currentGlobalCursor);
536 537 538 539
    /**
     * Ends move resize when all pointer buttons are up again.
     **/
    void endMoveResize();
540
    void keyPressEvent(uint key_code);
541

542
    void enterEvent(const QPoint &globalPos);
543
    void leaveEvent();
544

545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
    /**
     * These values represent positions inside an area
     */
    enum Position {
        // without prefix, they'd conflict with Qt::TopLeftCorner etc. :(
        PositionCenter         = 0x00,
        PositionLeft           = 0x01,
        PositionRight          = 0x02,
        PositionTop            = 0x04,
        PositionBottom         = 0x08,
        PositionTopLeft        = PositionLeft | PositionTop,
        PositionTopRight       = PositionRight | PositionTop,
        PositionBottomLeft     = PositionLeft | PositionBottom,
        PositionBottomRight    = PositionRight | PositionBottom
    };
560
    Position titlebarPosition() const;
561
    bool titlebarPositionUnderMouse() const;
562

563
    // a helper for the workspace window packing. tests for screen validity and updates since in maximization case as with normal moving
564
    void packTo(int left, int top);
565

566 567 568 569
    /** Set the quick tile mode ("snap") of this window.
     * This will also handle preserving and restoring of window geometry as necessary.
     * @param mode The tile mode (left/right) to give this window.
     */
570 571 572 573
    void setQuickTileMode(QuickTileMode mode, bool keyboard = false);
    QuickTileMode quickTileMode() const {
        return QuickTileMode(m_quickTileMode);
    }
574 575
    Layer layer() const override;
    void updateLayer();
576

577
    enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet };
578
    void move(int x, int y, ForceGeometry_t force = NormalGeometrySet);
579
    void move(const QPoint &p, ForceGeometry_t force = NormalGeometrySet);
580 581
    virtual void resizeWithChecks(int w, int h, ForceGeometry_t force = NormalGeometrySet) = 0;
    void resizeWithChecks(const QSize& s, ForceGeometry_t force = NormalGeometrySet);
582
    void keepInArea(QRect area, bool partial = false);
583 584
    virtual QSize minSize() const;
    virtual QSize maxSize() const;
585 586
    virtual void setGeometry(int x, int y, int w, int h, ForceGeometry_t force = NormalGeometrySet) = 0;
    void setGeometry(const QRect& r, ForceGeometry_t force = NormalGeometrySet);
587 588 589 590 591 592 593
    /// How to resize the window in order to obey constains (mainly aspect ratios)
    enum Sizemode {
        SizemodeAny,
        SizemodeFixedW, ///< Try not to affect width
        SizemodeFixedH, ///< Try not to affect height
        SizemodeMax ///< Try not to make it larger in either direction
    };
594 595 596 597 598 599 600 601
    /**
     *Calculate the appropriate frame size for the given client size @p wsize.
     *
     * @p wsize is adapted according to the window's size hints (minimum, maximum and incremental size changes).
     *
     * Default implementation returns the passed in @p wsize.
     */
    virtual QSize sizeForClientSize(const QSize &wsize, Sizemode mode = SizemodeAny, bool noframe = false) const;
602

603 604 605
    QSize adjustedSize(const QSize&, Sizemode mode = SizemodeAny) const;
    QSize adjustedSize() const;

606 607 608 609 610 611
    bool isMove() const {
        return isMoveResize() && moveResizePointerMode() == PositionCenter;
    }
    bool isResize() const {
        return isMoveResize() && moveResizePointerMode() != PositionCenter;
    }
612 613 614
    /**
     * Cursor shape for move/resize mode.
     **/
615
    CursorShape cursor() const {
616 617
        return m_moveResize.cursor;
    }
618

619
    virtual bool hasStrut() const;
620

621 622 623
    void setModal(bool modal);
    bool isModal() const;

624 625 626 627 628 629 630 631 632 633
    /**
     * Determines the mouse command for the given @p button in the current state.
     *
     * The @p handled argument specifies whether the button was handled or not.
     * This value should be used to determine whether the mouse button should be
     * passed to the AbstractClient or being filtered out.
     **/
    Options::MouseCommand getMouseCommand(Qt::MouseButton button, bool *handled) const;
    Options::MouseCommand getWheelCommand(Qt::Orientation orientation, bool *handled) const;

634 635
    // decoration related
    KDecoration2::Decoration *decoration() {
636
        return m_decoration.decoration;
637 638
    }
    const KDecoration2::Decoration *decoration() const {
639
        return m_decoration.decoration;
640 641
    }
    bool isDecorated() const {
642
        return m_decoration.decoration != nullptr;
643
    }
644 645
    QPointer<Decoration::DecoratedClientImpl> decoratedClient() const;
    void setDecoratedClient(QPointer<Decoration::DecoratedClientImpl> client);
646
    bool decorationHasAlpha() const;
647
    void triggerDecorationRepaint();
648
    virtual void layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect &bottom) const;
649
    void processDecorationMove(const QPoint &localPos, const QPoint &globalPos);
650 651
    bool processDecorationButtonPress(QMouseEvent *event, bool ignoreMenu = false);
    void processDecorationButtonRelease(QMouseEvent *event);
652

653 654 655 656 657
    /**
     * TODO: fix boolean traps
     **/
    virtual void updateDecoration(bool check_workspace_pos, bool force = false) = 0;

658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
    /**
    * Returns whether the window provides context help or not. If it does,
    * you should show a help menu item or a help button like '?' and call
    * contextHelp() if this is invoked.
    *
    * Default implementation returns @c false.
    * @see showContextHelp;
    */
    virtual bool providesContextHelp() const;

    /**
    * Invokes context help on the window. Only works if the window
    * actually provides context help.
    *
    * Default implementation does nothing.
    *
    * @see providesContextHelp()
    */
    virtual void showContextHelp();

678 679
    QRect inputGeometry() const override;

680 681 682 683 684 685 686
    /**
     * Restores the AbstractClient after it had been hidden due to show on screen edge functionality.
     * The AbstractClient also gets raised (e.g. Panel mode windows can cover) and the AbstractClient
     * gets informed in a window specific way that it is shown and raised again.
     **/
    virtual void showOnScreenEdge() = 0;

687 688 689 690
    QByteArray desktopFileName() const {
        return m_desktopFileName;
    }

691 692 693 694 695 696 697
    /**
     * Tries to terminate the process of this AbstractClient.
     *
     * Implementing subclasses can perform a windowing system solution for terminating.
     **/
    virtual void killWindow() = 0;

698 699 700 701 702 703
    enum class SameApplicationCheck {
        RelaxedForActive = 1 << 0,
        AllowCrossProcesses = 1 << 1
    };
    Q_DECLARE_FLAGS(SameApplicationChecks, SameApplicationCheck)
    static bool belongToSameApplication(const AbstractClient* c1, const AbstractClient* c2, SameApplicationChecks checks = SameApplicationChecks());
704

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
    bool hasApplicationMenu() const;
    bool applicationMenuActive() const {
        return m_applicationMenuActive;
    }
    void setApplicationMenuActive(bool applicationMenuActive);

    QString applicationMenuServiceName() const {
        return m_applicationMenuServiceName;
    }
    QString applicationMenuObjectPath() const {
        return m_applicationMenuObjectPath;
    }

    /**
     * Request showing the application menu bar
     * @param actionId The DBus menu ID of the action that should be highlighted, 0 for the root menu
     */
    void showApplicationMenu(int actionId);

724 725
    bool unresponsive() const;

Martin Flöser's avatar
Martin Flöser committed
726 727 728 729
    virtual bool isInitialPositionSet() const {
        return false;
    }

730 731 732
public Q_SLOTS:
    virtual void closeWindow() = 0;

733
Q_SIGNALS:
734
    void fullScreenChanged();
735
    void skipTaskbarChanged();
736
    void skipPagerChanged();
737
    void skipSwitcherChanged();
738
    void iconChanged();
739
    void activeChanged();
740 741
    void keepAboveChanged(bool);
    void keepBelowChanged(bool);
742 743 744 745
    /**
     * Emitted whenever the demands attention state changes.
     **/
    void demandsAttentionChanged();
746
    void desktopPresenceChanged(KWin::AbstractClient*, int); // to be forwarded by Workspace
747
    void desktopChanged();
748
    void shadeChanged();
749 750 751
    void minimizedChanged();
    void clientMinimized(KWin::AbstractClient* client, bool animate);
    void clientUnminimized(KWin::AbstractClient* client, bool animate);
752
    void paletteChanged(const QPalette &p);
753
    void captionChanged();
754 755
    void clientMaximizedStateChanged(KWin::AbstractClient*, MaximizeMode);
    void clientMaximizedStateChanged(KWin::AbstractClient* c, bool h, bool v);
756
    void transientChanged();
757
    void modalChanged();
758
    void quickTileModeChanged();
759
    void moveResizedChanged();
760
    void moveResizeCursorChanged(CursorShape);
761 762 763
    void clientStartUserMovedResized(KWin::AbstractClient*);
    void clientStepUserMovedResized(KWin::AbstractClient *, const QRect&);
    void clientFinishUserMovedResized(KWin::AbstractClient*);
764 765 766 767
    void closeableChanged(bool);
    void minimizeableChanged(bool);
    void shadeableChanged(bool);
    void maximizeableChanged(bool);
768
    void desktopFileNameChanged();
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
769 770
    void hasApplicationMenuChanged(bool);
    void applicationMenuActiveChanged(bool);
771
    void unresponsiveChanged(bool);
772 773 774 775 776
    /**
     * Emitted whenever the Client's TabGroup changed. That is whenever the Client is moved to
     * another group, but not when a Client gets added or removed to the Client's ClientGroup.
     **/
    void tabGroupChanged();
777

778 779
protected:
    AbstractClient();
780 781 782
    void setFirstInTabBox(bool enable) {
        m_firstInTabBox = enable;
    }
783
    void setIcon(const QIcon &icon);
784 785
    void startAutoRaise();
    void autoRaise();
786 787 788 789 790 791
    /**
     * Whether the window accepts focus.
     * The difference to wantsInput is that the implementation should not check rules and return
     * what the window effectively supports.
     **/
    virtual bool acceptsFocus() const = 0;
792 793 794 795 796 797 798
    /**
     * Called from ::setActive once the active value got updated, but before the changed signal
     * is emitted.
     *
     * Default implementation does nothing.
     **/
    virtual void doSetActive();
799 800 801 802 803 804 805 806 807 808 809 810 811 812
    /**
     * Called from ::setKeepAbove once the keepBelow value got updated, but before the changed signal
     * is emitted.
     *
     * Default implementation does nothing.
     **/
    virtual void doSetKeepAbove();
    /**
     * Called from ::setKeepBelow once the keepBelow value got updated, but before the changed signal
     * is emitted.
     *
     * Default implementation does nothing.
     **/
    virtual void doSetKeepBelow();
813 814 815 816 817 818 819 820 821
    /**
     * Called from ::setDeskop once the desktop value got updated, but before the changed signal
     * is emitted.
     *
     * Default implementation does nothing.
     * @param desktop The new desktop the Client is on
     * @param was_desk The desktop the Client was on before
     **/
    virtual void doSetDesktop(int desktop, int was_desk);
822 823 824 825 826 827 828
    /**
     * Called from ::minimize and ::unminimize once the minimized value got updated, but before the
     * changed signal is emitted.
     *
     * Default implementation does nothig.
     **/
    virtual void doMinimize();
829
    virtual bool belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const = 0;
830

831
    virtual void doSetSkipTaskbar();
832
    virtual void doSetSkipPager();
833
    virtual void doSetSkipSwitcher();
834

835 836 837
    void setupWindowManagementInterface();
    void destroyWindowManagementInterface();

838
    void updateColorScheme(QString path);
839
    virtual void updateColorScheme() = 0;
840

841
    void setTransientFor(AbstractClient *transientFor);
842 843 844 845 846
    virtual void addTransient(AbstractClient* cl);
    /**
     * Just removes the @p cl from the transients without any further checks.
     **/
    void removeTransientFromList(AbstractClient* cl);
847

848 849 850
    Layer belongsToLayer() const;
    virtual bool belongsToDesktop() const;
    void invalidateLayer();
851
    bool isActiveFullScreen() const;
852
    virtual Layer layerForDock() const;
853

854 855 856 857 858
    // electric border / quick tiling
    void setElectricBorderMode(QuickTileMode mode);
    QuickTileMode electricBorderMode() const {
        return m_electricMode;
    }
859 860 861 862
    void setElectricBorderMaximizing(bool maximizing);
    bool isElectricBorderMaximizing() const {
        return m_electricMaximizing;
    }
863
    QRect electricBorderMaximizeGeometry(QPoint pos, int desktop);
864 865 866
    void updateQuickTileMode(QuickTileMode newMode) {
        m_quickTileMode = newMode;
    }
867

868 869 870 871
    KWayland::Server::PlasmaWindowInterface *windowManagementInterface() const {
        return m_windowManagementInterface;
    }

872 873
    // geometry handling
    void checkOffscreenPosition(QRect *geom, const QRect &screenArea);
874 875 876 877
    int borderLeft() const;
    int borderRight() const;
    int borderTop() const;
    int borderBottom() const;
878
    virtual void changeMaximize(bool horizontal, bool vertical, bool adjust) = 0;
879
    virtual void setGeometryRestore(const QRect &geo) = 0;
880 881 882 883 884
    /**
     * Called from move after updating the geometry. Can be reimplemented to perform specific tasks.
     * The base implementation does nothing.
     **/
    virtual void doMove(int x, int y);
885 886 887 888 889 890 891 892 893 894 895
    void blockGeometryUpdates(bool block);
    void blockGeometryUpdates();
    void unblockGeometryUpdates();
    bool areGeometryUpdatesBlocked() const;
    enum PendingGeometry_t {
        PendingGeometryNone,
        PendingGeometryNormal,
        PendingGeometryForced
    };
    PendingGeometry_t pendingGeometryUpdate() const;
    void setPendingGeometryUpdate(PendingGeometry_t update);
896 897 898 899
    QRect geometryBeforeUpdateBlocking() const {
        return m_geometryBeforeUpdateBlocking;
    }
    void updateGeometryBeforeUpdateBlocking();
900 901 902 903 904 905
    /**
     * Schedules a repaint for the visibleRect before and after a
     * geometry update. The current visibleRect is stored for the
     * next time this method is called as the before geometry.
     **/
    void addRepaintDuringGeometryUpdates();
906

907 908 909 910 911 912 913
    /**
     * Convenient method to update the TabGroup states if there is one present.
     * Marked as virtual as TabGroup does not yet handle AbstractClient, but only
     * subclasses of AbstractClient. Given that the default implementation does nothing.
     **/
    virtual void updateTabGroupStates(TabGroup::States states);

914 915 916 917 918 919 920 921 922 923 924 925
    /**
     * @returns whether the Client is currently in move resize mode
     **/
    bool isMoveResize() const {
        return m_moveResize.enabled;
    }
    /**
     * Sets whether the Client is in move resize mode to @p enabled.
     **/
    void setMoveResize(bool enabled) {
        m_moveResize.enabled = enabled;
    }
926 927 928 929 930 931 932 933 934 935 936 937
    /**
     * @returns whether the move resize mode is unrestricted.
     **/
    bool isUnrestrictedMoveResize() const {
        return m_moveResize.unrestricted;
    }
    /**
     * Sets whether move resize mode is unrestricted to @p set.
     **/
    void setUnrestrictedMoveResize(bool set) {
        m_moveResize.unrestricted = set;
    }
938 939 940 941 942 943 944 945 946 947 948 949
    QPoint moveOffset() const {
        return m_moveResize.offset;
    }
    void setMoveOffset(const QPoint &offset) {
        m_moveResize.offset = offset;
    }
    QPoint invertedMoveOffset() const {
        return m_moveResize.invertedOffset;
    }
    void setInvertedMoveOffset(const QPoint &offset) {
        m_moveResize.invertedOffset = offset;
    }
950 951 952 953 954 955 956
    QRect initialMoveResizeGeometry() const {
        return m_moveResize.initialGeometry;
    }
    /**
     * Sets the initial move resize geometry to the current geometry.
     **/
    void updateInitialMoveResizeGeometry();
957 958 959 960 961 962
    QRect moveResizeGeometry() const {
        return m_moveResize.geometry;
    }
    void setMoveResizeGeometry(const QRect &geo) {
        m_moveResize.geometry = geo;
    }
963 964 965 966 967 968
    Position moveResizePointerMode() const {
        return m_moveResize.pointer;
    }
    void setMoveResizePointerMode(Position mode) {
        m_moveResize.pointer = mode;
    }
969 970 971 972 973 974
    bool isMoveResizePointerButtonDown() const {
        return m_moveResize.buttonDown;
    }
    void setMoveResizePointerButtonDown(bool down) {
        m_moveResize.buttonDown = down;
    }
975 976 977
    int moveResizeStartScreen() const {
        return m_moveResize.startScreen;
    }
978
    void checkUnrestrictedMoveResize();
979 980 981 982
    /**
    * Sets an appropriate cursor shape for the logical mouse position.
    */
    void updateCursor();
983 984
    void startDelayedMoveResize();
    void stopDelayedMoveResize();
985 986 987 988 989 990 991 992 993 994
    bool startMoveResize();
    /**
     * Called from @link startMoveResize.
     *
     * Implementing classes should return @c false if starting move resize should
     * get aborted. In that case @link startMoveResize will also return @c false.
     *
     * Base implementation returns @c true.
     **/
    virtual bool doStartMoveResize();
995
    void finishMoveResize(bool cancel);
996 997 998 999 1000 1001 1002
    /**
     * Leaves the move resize mode.
     *
     * Inheriting classes must invoke the base implementation which
     * ensures that the internal mode is properly ended.
     **/
    virtual void leaveMoveResize();
1003
    virtual void positionGeometryTip();
1004 1005 1006 1007 1008 1009 1010 1011
    void performMoveResize();
    /**
     * Called from performMoveResize() after actually performing the change of geometry.
     * Implementing subclasses can perform windowing system specific handling here.
     *
     * Default implementation does nothing.
     **/
    virtual void doPerformMoveResize();
1012 1013 1014 1015 1016
    /*
     * Checks if the mouse cursor is near the edge of the screen and if so
     * activates quick tiling or maximization
     */
    void checkQuickTilingMaximizationZones(int xroot, int yroot);
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
    /**
     * Whether a sync request is still pending.
     * Default implementation returns @c false.
     **/
    virtual bool isWaitingForMoveResizeSync() const;
    /**
     * Called during handling a resize. Implementing subclasses can use this
     * method to perform windowing system specific syncing.
     *
     * Default implementation does nothing.
     **/
    virtual void doResizeSync();
    void handleMoveResize(int x, int y, int x_root, int y_root);
    void handleMoveResize(const QPoint &local, const QPoint &global);
1031
    void dontMoveResize();
1032

1033 1034
    virtual QSize resizeIncrements() const;

1035
    /**
1036 1037
     * Returns the position depending on the Decoration's section under mouse.
     * If no decoration it returns PositionCenter.
1038
     **/
1039
    Position mousePosition() const;
1040

1041 1042 1043 1044 1045 1046 1047 1048
    static bool haveResizeEffect() {
        return s_haveResizeEffect;
    }
    static void updateHaveResizeEffect();
    static void resetHaveResizeEffect() {
        s_haveResizeEffect = false;
    }

1049
    void setDecoration(KDecoration2::Decoration *decoration) {
1050
        m_decoration.decoration = decoration;
1051 1052
    }
    virtual void destroyDecoration();
1053
    void startDecorationDoubleClickTimer();
1054
    void invalidateDecorationDoubleClickTimer();
1055

1056
    void setDesktopFileName(QByteArray name);
1057 1058
    QString iconFromDesktopFile() const;

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
1059 1060 1061
    void updateApplicationMenuServiceName(const QString &serviceName);
    void updateApplicationMenuObjectPath(const QString &objectPath);

1062 1063
    void setUnresponsive(bool unresponsive);

1064
    virtual void setShortcutInternal();
1065 1066
    QString shortcutCaptionSuffix() const;
    virtual void updateCaption() = 0;
1067

1068 1069 1070 1071 1072 1073
    /**
     * Looks for another AbstractClient with same @link{captionNormal} and @link{captionSuffix}.
     * If no such AbstractClient exists @c nullptr is returned.
     **/
    AbstractClient *findClientWithSameCaption() const;

1074 1075 1076
    void finishWindowRules();
    void discardTemporaryRules();

1077 1078
    bool tabTo(AbstractClient *other, bool behind, bool activate);

1079
private:
1080
    void handlePaletteChange();
1081
    QSharedPointer<TabBox::TabBoxClientImpl> m_tabBoxClient;
1082
    bool m_firstInTabBox = false;
1083 1084 1085 1086 1087
    bool m_skipTaskbar = false;
    /**
     * Unaffected by KWin
     **/
    bool m_originalSkipTaskbar = false;
1088
    bool m_skipPager = false;
1089
    bool m_skipSwitcher = false;
1090
    QIcon m_icon;
1091
    bool m_active = false;
1092 1093
    bool m_keepAbove = false;
    bool m_keepBelow = false;
1094
    bool m_demandsAttention = false;
1095
    bool m_minimized = false;
1096
    QTimer *m_autoRaiseTimer = nullptr;
1097
    int m_desktop = 0; // 0 means not on any desktop yet
1098 1099 1100 1101 1102

    QString m_colorScheme;
    std::shared_ptr<Decoration::DecorationPalette> m_palette;
    static QHash<QString, std::weak_ptr<Decoration::DecorationPalette>> s_palettes;
    static std::shared_ptr<Decoration::DecorationPalette> s_defaultPalette;
1103 1104

    KWayland::Server::PlasmaWindowInterface *m_windowManagementInterface = nullptr;
1105 1106

    AbstractClient *m_transientFor = nullptr;
1107
    QList<AbstractClient*> m_transients;
1108
    bool m_modal = false;
1109
    Layer m_layer = UnknownLayer;
1110 1111

    // electric border/quick tiling
1112
    QuickTileMode m_electricMode = QuickTileFlag::None;
1113
    bool m_electricMaximizing = false;
1114 1115
    /** The quick tile mode of this window.
     */
1116
    int m_quickTileMode = int(QuickTileFlag::None);
1117
    QTimer *m_electricMaximizingDelay = nullptr;
1118 1119 1120 1121 1122

    // geometry
    int m_blockGeometryUpdates = 0; // > 0 = New geometry is remembered, but not actually set
    PendingGeometry_t m_pendingGeometryUpdate = PendingGeometryNone;
    friend class GeometryUpdatesBlocker;
1123
    QRect m_visibleRectBeforeGeometryUpdate;
1124
    QRect m_geometryBeforeUpdateBlocking;
1125 1126 1127

    struct {
        bool enabled = false;
1128
        bool unrestricted = false;
1129 1130
        QPoint offset;
        QPoint invertedOffset;
1131
        QRect initialGeometry;
1132
        QRect geometry;
1133
        Position pointer = PositionCenter;
1134
        bool buttonDown = false;
1135
        CursorShape cursor = Qt::ArrowCursor;
1136
        int startScreen = 0;
1137
        QTimer *delayedTimer = nullptr;
1138
    } m_moveResize;
1139

1140 1141 1142 1143 1144
    struct {
        KDecoration2::Decoration *decoration = nullptr;
        QPointer<Decoration::DecoratedClientImpl> client;
        QElapsedTimer doubleClickTimer;
    } m_decoration;
1145 1146
    QByteArray m_desktopFileName;

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
1147 1148 1149
    bool m_applicationMenuActive = false;
    QString m_applicationMenuServiceName;
    QString m_applicationMenuObjectPath;
1150

1151 1152
    bool m_unresponsive = false;

1153 1154
    QKeySequence _shortcut;

1155
    WindowRules m_rules;
1156
    TabGroup* tab_group = nullptr;
1157

1158
    static bool s_haveResizeEffect;
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
};

/**
 * Helper for AbstractClient::blockGeometryUpdates() being called in pairs (true/false)
 */
class GeometryUpdatesBlocker
{
public:
    explicit GeometryUpdatesBlocker(AbstractClient* c)
        : cl(c) {
        cl->blockGeometryUpdates(true);
    }
    ~GeometryUpdatesBlocker() {
        cl->blockGeometryUpdates(false);
    }

private:
    AbstractClient* cl;
1177 1178
};

1179 1180 1181 1182 1183
inline void AbstractClient::move(const QPoint& p, ForceGeometry_t force)
{
    move(p.x(), p.y(), force);
}

1184 1185 1186 1187 1188
inline void AbstractClient::resizeWithChecks(const QSize& s, AbstractClient::ForceGeometry_t force)
{
    resizeWithChecks(s.width(), s.height(), force);
}

1189 1190 1191 1192 1193
inline void AbstractClient::setGeometry(const QRect& r, ForceGeometry_t force)
{
    setGeometry(r.x(), r.y(), r.width(), r.height(), force);
}

1194 1195 1196 1197 1198
inline const QList<AbstractClient*>& AbstractClient::transients() const
{
    return m_transients;
}

1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222