abstract_client.h 42.8 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
    virtual MaximizeMode maximizeMode() const = 0;
460 461
    void maximize(MaximizeMode);
    void setMaximize(bool vertically, bool horizontally);
462 463
    virtual bool noBorder() const = 0;
    virtual void setNoBorder(bool set) = 0;
464
    virtual void blockActivityUpdates(bool b = true) = 0;
465 466
    QPalette palette() const;
    const Decoration::DecorationPalette *decorationPalette() const;
467 468 469
    virtual bool isResizable() const = 0;
    virtual bool isMovable() const = 0;
    virtual bool isMovableAcrossScreens() const = 0;
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
    /**
     * @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;
489 490
    virtual bool isMaximizable() const = 0;
    virtual bool isMinimizable() const = 0;
491
    virtual QRect iconGeometry() const;
492 493
    virtual bool userCanSetFullScreen() const = 0;
    virtual bool userCanSetNoBorder() const = 0;
494
    virtual void checkNoBorder();
495
    virtual void setOnActivities(QStringList newActivitiesList);
496
    virtual void setOnAllActivities(bool set) = 0;
497 498 499 500 501 502 503
    const WindowRules* rules() const {
        return &m_rules;
    }
    void removeRule(Rules* r);
    void setupWindowRules(bool ignore_temporary);
    void evaluateWindowRules();
    void applyWindowRules();
504 505
    virtual void takeFocus() = 0;
    virtual bool wantsInput() const = 0;
506 507 508 509 510 511 512 513 514 515 516 517
    /**
     * 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;
518
    void checkWorkspacePosition(QRect oldGeometry = QRect(), int oldDesktop = -2,  QRect oldClientGeometry = QRect());
519
    virtual xcb_timestamp_t userTime() const;
520
    virtual void updateWindowRules(Rules::Types selection);
521

522 523 524 525
    void growHorizontal();
    void shrinkHorizontal();
    void growVertical();
    void shrinkVertical();
526
    void updateMoveResize(const QPointF &currentGlobalCursor);
527 528 529 530
    /**
     * Ends move resize when all pointer buttons are up again.
     **/
    void endMoveResize();
531
    void keyPressEvent(uint key_code);
532

533
    void enterEvent(const QPoint &globalPos);
534
    void leaveEvent();
535

536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
    /**
     * 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
    };
551
    Position titlebarPosition() const;
552
    bool titlebarPositionUnderMouse() const;
553

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

557 558 559 560
    /** 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.
     */
561 562 563 564
    void setQuickTileMode(QuickTileMode mode, bool keyboard = false);
    QuickTileMode quickTileMode() const {
        return QuickTileMode(m_quickTileMode);
    }
565 566
    Layer layer() const override;
    void updateLayer();
567

568
    enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet };
569
    void move(int x, int y, ForceGeometry_t force = NormalGeometrySet);
570
    void move(const QPoint &p, ForceGeometry_t force = NormalGeometrySet);
571 572
    virtual void resizeWithChecks(int w, int h, ForceGeometry_t force = NormalGeometrySet) = 0;
    void resizeWithChecks(const QSize& s, ForceGeometry_t force = NormalGeometrySet);
573
    void keepInArea(QRect area, bool partial = false);
574 575
    virtual QSize minSize() const;
    virtual QSize maxSize() const;
576 577
    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);
578 579 580 581 582 583 584
    /// 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
    };
585 586 587 588 589 590 591 592
    /**
     *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;
593

594 595 596
    QSize adjustedSize(const QSize&, Sizemode mode = SizemodeAny) const;
    QSize adjustedSize() const;

597 598 599 600 601 602
    bool isMove() const {
        return isMoveResize() && moveResizePointerMode() == PositionCenter;
    }
    bool isResize() const {
        return isMoveResize() && moveResizePointerMode() != PositionCenter;
    }
603 604 605
    /**
     * Cursor shape for move/resize mode.
     **/
606
    CursorShape cursor() const {
607 608
        return m_moveResize.cursor;
    }
609

610
    virtual bool hasStrut() const;
611

612 613 614
    void setModal(bool modal);
    bool isModal() const;

615 616 617 618 619 620 621 622 623 624
    /**
     * 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;

625 626
    // decoration related
    KDecoration2::Decoration *decoration() {
627
        return m_decoration.decoration;
628 629
    }
    const KDecoration2::Decoration *decoration() const {
630
        return m_decoration.decoration;
631 632
    }
    bool isDecorated() const {
633
        return m_decoration.decoration != nullptr;
634
    }
635 636
    QPointer<Decoration::DecoratedClientImpl> decoratedClient() const;
    void setDecoratedClient(QPointer<Decoration::DecoratedClientImpl> client);
637
    bool decorationHasAlpha() const;
638
    void triggerDecorationRepaint();
639
    virtual void layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect &bottom) const;
640
    void processDecorationMove(const QPoint &localPos, const QPoint &globalPos);
641 642
    bool processDecorationButtonPress(QMouseEvent *event, bool ignoreMenu = false);
    void processDecorationButtonRelease(QMouseEvent *event);
643

644 645 646 647 648
    /**
     * TODO: fix boolean traps
     **/
    virtual void updateDecoration(bool check_workspace_pos, bool force = false) = 0;

649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
    /**
    * 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();

669 670
    QRect inputGeometry() const override;

671 672 673 674 675 676 677
    /**
     * 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;

678 679 680 681
    QByteArray desktopFileName() const {
        return m_desktopFileName;
    }

682 683 684 685 686 687 688
    /**
     * Tries to terminate the process of this AbstractClient.
     *
     * Implementing subclasses can perform a windowing system solution for terminating.
     **/
    virtual void killWindow() = 0;

689 690 691 692 693 694
    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());
695

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
    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);

715 716
    bool unresponsive() const;

Martin Flöser's avatar
Martin Flöser committed
717 718 719 720
    virtual bool isInitialPositionSet() const {
        return false;
    }

721 722 723
public Q_SLOTS:
    virtual void closeWindow() = 0;

724
Q_SIGNALS:
725
    void fullScreenChanged();
726
    void skipTaskbarChanged();
727
    void skipPagerChanged();
728
    void skipSwitcherChanged();
729
    void iconChanged();
730
    void activeChanged();
731 732
    void keepAboveChanged(bool);
    void keepBelowChanged(bool);
733 734 735 736
    /**
     * Emitted whenever the demands attention state changes.
     **/
    void demandsAttentionChanged();
737
    void desktopPresenceChanged(KWin::AbstractClient*, int); // to be forwarded by Workspace
738
    void desktopChanged();
739
    void shadeChanged();
740 741 742
    void minimizedChanged();
    void clientMinimized(KWin::AbstractClient* client, bool animate);
    void clientUnminimized(KWin::AbstractClient* client, bool animate);
743
    void paletteChanged(const QPalette &p);
744
    void captionChanged();
745 746
    void clientMaximizedStateChanged(KWin::AbstractClient*, MaximizeMode);
    void clientMaximizedStateChanged(KWin::AbstractClient* c, bool h, bool v);
747
    void transientChanged();
748
    void modalChanged();
749
    void quickTileModeChanged();
750
    void moveResizedChanged();
751
    void moveResizeCursorChanged(CursorShape);
752 753 754
    void clientStartUserMovedResized(KWin::AbstractClient*);
    void clientStepUserMovedResized(KWin::AbstractClient *, const QRect&);
    void clientFinishUserMovedResized(KWin::AbstractClient*);
755 756 757 758
    void closeableChanged(bool);
    void minimizeableChanged(bool);
    void shadeableChanged(bool);
    void maximizeableChanged(bool);
759
    void desktopFileNameChanged();
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
760 761
    void hasApplicationMenuChanged(bool);
    void applicationMenuActiveChanged(bool);
762
    void unresponsiveChanged(bool);
763 764 765 766 767
    /**
     * 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();
768

769 770
protected:
    AbstractClient();
771 772 773
    void setFirstInTabBox(bool enable) {
        m_firstInTabBox = enable;
    }
774
    void setIcon(const QIcon &icon);
775 776
    void startAutoRaise();
    void autoRaise();
777 778 779 780 781 782
    /**
     * 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;
783 784 785 786 787 788 789
    /**
     * Called from ::setActive once the active value got updated, but before the changed signal
     * is emitted.
     *
     * Default implementation does nothing.
     **/
    virtual void doSetActive();
790 791 792 793 794 795 796 797 798 799 800 801 802 803
    /**
     * 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();
804 805 806 807 808 809 810 811 812
    /**
     * 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);
813 814 815 816 817 818 819
    /**
     * 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();
820
    virtual bool belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const = 0;
821

822
    virtual void doSetSkipTaskbar();
823
    virtual void doSetSkipPager();
824
    virtual void doSetSkipSwitcher();
825

826 827 828
    void setupWindowManagementInterface();
    void destroyWindowManagementInterface();

829
    void updateColorScheme(QString path);
830
    virtual void updateColorScheme() = 0;
831

832
    void setTransientFor(AbstractClient *transientFor);
833 834 835 836 837
    virtual void addTransient(AbstractClient* cl);
    /**
     * Just removes the @p cl from the transients without any further checks.
     **/
    void removeTransientFromList(AbstractClient* cl);
838

839 840 841
    Layer belongsToLayer() const;
    virtual bool belongsToDesktop() const;
    void invalidateLayer();
842
    bool isActiveFullScreen() const;
843
    virtual Layer layerForDock() const;
844

845 846 847 848 849
    // electric border / quick tiling
    void setElectricBorderMode(QuickTileMode mode);
    QuickTileMode electricBorderMode() const {
        return m_electricMode;
    }
850 851 852 853
    void setElectricBorderMaximizing(bool maximizing);
    bool isElectricBorderMaximizing() const {
        return m_electricMaximizing;
    }
854
    QRect electricBorderMaximizeGeometry(QPoint pos, int desktop);
855 856 857
    void updateQuickTileMode(QuickTileMode newMode) {
        m_quickTileMode = newMode;
    }
858

859 860 861 862
    KWayland::Server::PlasmaWindowInterface *windowManagementInterface() const {
        return m_windowManagementInterface;
    }

863 864
    // geometry handling
    void checkOffscreenPosition(QRect *geom, const QRect &screenArea);
865 866 867 868
    int borderLeft() const;
    int borderRight() const;
    int borderTop() const;
    int borderBottom() const;
869
    virtual void changeMaximize(bool horizontal, bool vertical, bool adjust) = 0;
870
    virtual void setGeometryRestore(const QRect &geo) = 0;
871 872 873 874 875
    /**
     * 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);
876 877 878 879 880 881 882 883 884 885 886
    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);
887 888 889 890
    QRect geometryBeforeUpdateBlocking() const {
        return m_geometryBeforeUpdateBlocking;
    }
    void updateGeometryBeforeUpdateBlocking();
891 892 893 894 895 896
    /**
     * 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();
897

898 899 900 901 902 903 904
    /**
     * 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);

905 906 907 908 909 910 911 912 913 914 915 916
    /**
     * @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;
    }
917 918 919 920 921 922 923 924 925 926 927 928
    /**
     * @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;
    }
929 930 931 932 933 934 935 936 937 938 939 940
    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;
    }
941 942 943 944 945 946 947
    QRect initialMoveResizeGeometry() const {
        return m_moveResize.initialGeometry;
    }
    /**
     * Sets the initial move resize geometry to the current geometry.
     **/
    void updateInitialMoveResizeGeometry();
948 949 950 951 952 953
    QRect moveResizeGeometry() const {
        return m_moveResize.geometry;
    }
    void setMoveResizeGeometry(const QRect &geo) {
        m_moveResize.geometry = geo;
    }
954 955 956 957 958 959
    Position moveResizePointerMode() const {
        return m_moveResize.pointer;
    }
    void setMoveResizePointerMode(Position mode) {
        m_moveResize.pointer = mode;
    }
960 961 962 963 964 965
    bool isMoveResizePointerButtonDown() const {
        return m_moveResize.buttonDown;
    }
    void setMoveResizePointerButtonDown(bool down) {
        m_moveResize.buttonDown = down;
    }
966 967 968
    int moveResizeStartScreen() const {
        return m_moveResize.startScreen;
    }
969
    void checkUnrestrictedMoveResize();
970 971 972 973
    /**
    * Sets an appropriate cursor shape for the logical mouse position.
    */
    void updateCursor();
974 975
    void startDelayedMoveResize();
    void stopDelayedMoveResize();
976 977 978 979 980 981 982 983 984 985
    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();
986
    void finishMoveResize(bool cancel);
987 988 989 990 991 992 993
    /**
     * Leaves the move resize mode.
     *
     * Inheriting classes must invoke the base implementation which
     * ensures that the internal mode is properly ended.
     **/
    virtual void leaveMoveResize();
994
    virtual void positionGeometryTip();
995 996 997 998 999 1000 1001 1002
    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();
1003 1004 1005 1006 1007
    /*
     * 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);
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
    /**
     * 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);
1022
    void dontMoveResize();
1023

1024 1025
    virtual QSize resizeIncrements() const;

1026
    /**
1027 1028
     * Returns the position depending on the Decoration's section under mouse.
     * If no decoration it returns PositionCenter.
1029
     **/
1030
    Position mousePosition() const;
1031

1032 1033 1034 1035 1036 1037 1038 1039
    static bool haveResizeEffect() {
        return s_haveResizeEffect;
    }
    static void updateHaveResizeEffect();
    static void resetHaveResizeEffect() {
        s_haveResizeEffect = false;
    }

1040
    void setDecoration(KDecoration2::Decoration *decoration) {
1041
        m_decoration.decoration = decoration;
1042 1043
    }
    virtual void destroyDecoration();
1044
    void startDecorationDoubleClickTimer();
1045
    void invalidateDecorationDoubleClickTimer();
1046

1047
    void setDesktopFileName(QByteArray name);
1048 1049
    QString iconFromDesktopFile() const;

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
1050 1051 1052
    void updateApplicationMenuServiceName(const QString &serviceName);
    void updateApplicationMenuObjectPath(const QString &objectPath);

1053 1054
    void setUnresponsive(bool unresponsive);

1055
    virtual void setShortcutInternal();
1056 1057
    QString shortcutCaptionSuffix() const;
    virtual void updateCaption() = 0;
1058

1059 1060 1061 1062 1063 1064
    /**
     * Looks for another AbstractClient with same @link{captionNormal} and @link{captionSuffix}.
     * If no such AbstractClient exists @c nullptr is returned.
     **/
    AbstractClient *findClientWithSameCaption() const;

1065 1066 1067
    void finishWindowRules();
    void discardTemporaryRules();

1068 1069
    bool tabTo(AbstractClient *other, bool behind, bool activate);

1070
private:
1071
    void handlePaletteChange();
1072
    QSharedPointer<TabBox::TabBoxClientImpl> m_tabBoxClient;
1073
    bool m_firstInTabBox = false;
1074 1075 1076 1077 1078
    bool m_skipTaskbar = false;
    /**
     * Unaffected by KWin
     **/
    bool m_originalSkipTaskbar = false;
1079
    bool m_skipPager = false;
1080
    bool m_skipSwitcher = false;
1081
    QIcon m_icon;
1082
    bool m_active = false;
1083 1084
    bool m_keepAbove = false;
    bool m_keepBelow = false;
1085
    bool m_demandsAttention = false;
1086
    bool m_minimized = false;
1087
    QTimer *m_autoRaiseTimer = nullptr;
1088
    int m_desktop = 0; // 0 means not on any desktop yet
1089 1090 1091 1092 1093

    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;
1094 1095

    KWayland::Server::PlasmaWindowInterface *m_windowManagementInterface = nullptr;
1096 1097

    AbstractClient *m_transientFor = nullptr;
1098
    QList<AbstractClient*> m_transients;
1099
    bool m_modal = false;
1100
    Layer m_layer = UnknownLayer;
1101 1102

    // electric border/quick tiling
1103
    QuickTileMode m_electricMode = QuickTileFlag::None;
1104
    bool m_electricMaximizing = false;
1105 1106
    /** The quick tile mode of this window.
     */
1107
    int m_quickTileMode = int(QuickTileFlag::None);
1108
    QTimer *m_electricMaximizingDelay = nullptr;
1109 1110 1111 1112 1113

    // geometry
    int m_blockGeometryUpdates = 0; // > 0 = New geometry is remembered, but not actually set
    PendingGeometry_t m_pendingGeometryUpdate = PendingGeometryNone;
    friend class GeometryUpdatesBlocker;
1114
    QRect m_visibleRectBeforeGeometryUpdate;
1115
    QRect m_geometryBeforeUpdateBlocking;
1116 1117 1118

    struct {
        bool enabled = false;
1119
        bool unrestricted = false;
1120 1121
        QPoint offset;
        QPoint invertedOffset;
1122
        QRect initialGeometry;
1123
        QRect geometry;
1124
        Position pointer = PositionCenter;
1125
        bool buttonDown = false;
1126
        CursorShape cursor = Qt::ArrowCursor;
1127
        int startScreen = 0;
1128
        QTimer *delayedTimer = nullptr;
1129
    } m_moveResize;
1130

1131 1132 1133 1134 1135
    struct {
        KDecoration2::Decoration *decoration = nullptr;
        QPointer<Decoration::DecoratedClientImpl> client;
        QElapsedTimer doubleClickTimer;
    } m_decoration;
1136 1137
    QByteArray m_desktopFileName;

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
1138 1139 1140
    bool m_applicationMenuActive = false;
    QString m_applicationMenuServiceName;
    QString m_applicationMenuObjectPath;
1141

1142 1143
    bool m_unresponsive = false;

1144 1145
    QKeySequence _shortcut;

1146
    WindowRules m_rules;
1147
    TabGroup* tab_group = nullptr;
1148

1149
    static bool s_haveResizeEffect;
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
};

/**
 * 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;
1168 1169
};

1170 1171 1172 1173 1174
inline void AbstractClient::move(const QPoint& p, ForceGeometry_t force)
{
    move(p.x(), p.y(), force);
}

1175 1176 1177 1178 1179
inline void AbstractClient::resizeWithChecks(const QSize& s, AbstractClient::ForceGeometry_t force)
{
    resizeWithChecks(s.width(), s.height(), force);
}

1180 1181 1182 1183 1184
inline void AbstractClient::setGeometry(const QRect& r, ForceGeometry_t force)
{
    setGeometry(r.x(), r.y(), r.width(), r.height(), force);
}

1185 1186 1187 1188 1189
inline const QList<AbstractClient*>& AbstractClient::transients() const
{
    return m_transients;
}

1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
inline bool AbstractClient::areGeometryUpdatesBlocked() const
{
    return m_blockGeometryUpdates != 0;
}

inline void AbstractClient::blockGeometryUpdates()
{
    m_blockGeometryUpdates++;
}

inline void AbstractClient::unblockGeometryUpdates()
{
    m_blockGeometryUpdates--;
}

inline AbstractClient::PendingGeometry_t AbstractClient::pendingGeometryUpdate() const
{
    return m_pendingGeometryUpdate;
}

inline void AbstractClient::setPendingGeometryUpdate(PendingGeometry_t update)
{
    m_pendingGeometryUpdate = update;
}

1215