File indexing completed on 2024-04-28 08:50:59

0001 /*
0002     SPDX-FileCopyrightText: 2002-2003 Tim Jansen <tim@tjansen.de>
0003     SPDX-FileCopyrightText: 2007-2008 Urs Wolfer <uwolfer@kde.org>
0004     SPDX-FileCopyrightText: 2021 RafaƂ Lalik <rafallalik@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #ifndef REMOTEVIEW_H
0010 #define REMOTEVIEW_H
0011 
0012 #ifndef QTONLY
0013     #include <KWallet>
0014     #include "krdccore_export.h"
0015 #else
0016     #define KRDCCORE_EXPORT
0017 #endif
0018 
0019 #include <QUrl>
0020 #include <QWidget>
0021 
0022 class HostPreferences;
0023 
0024 /**
0025  * Generic widget that displays a remote framebuffer.
0026  * Implement this if you want to add another backend.
0027  *
0028  * Things to take care of:
0029  * @li The RemoteView is responsible for its size. In
0030  *     non-scaling mode, set the fixed size of the widget
0031  *     to the remote resolution. In scaling mode, set the
0032  *     maximum size to the remote size and minimum size to the
0033  *     smallest resolution that your scaler can handle.
0034  * @li if you override mouseMoveEvent()
0035  *     you must ignore the QEvent, because the KRDC widget will
0036  *     need it for stuff like toolbar auto-hide and bump
0037  *     scrolling. If you use x11Event(), make sure that
0038  *     MotionNotify events will be forwarded.
0039  *
0040  */
0041 class KRDCCORE_EXPORT RemoteView : public QWidget
0042 {
0043     Q_OBJECT
0044 
0045 public:
0046 
0047     enum Quality {
0048         Unknown,
0049         High,
0050         Medium,
0051         Low
0052     };
0053     Q_ENUM(Quality)
0054 
0055     /**
0056     * Describes the state of a local cursor, if there is such a concept in the backend.
0057     * With local cursors, there are two cursors: the cursor on the local machine (client),
0058     * and the cursor on the remote machine (server). Because there is usually some lag,
0059     * some backends show both cursors simultaneously. In the VNC backend the local cursor
0060     * is a dot and the remote cursor is the 'real' cursor, usually an arrow.
0061     */
0062 
0063     enum LocalCursorState {
0064         CursorOn,  ///< Always show local cursor based on remote one (or fallback to default).
0065         CursorOff, ///< Never show local cursor, only the remote one.
0066         /// Try to measure the lag and enable the local cursor if the latency is too high.
0067         CursorAuto
0068     };
0069     Q_ENUM(LocalCursorState)
0070 
0071     /**
0072     * State of the connection. The state of the connection is returned
0073     * by @ref RemoteView::status().
0074     *
0075     * Not every state transition is allowed. You are only allowed to transition
0076     * a state to the following state, with three exceptions:
0077     * @li You can move from every state directly to Disconnected
0078     * @li You can move from every state except Disconnected to
0079     *     Disconnecting
0080     * @li You can move from Disconnected to Connecting
0081     *
0082     * @ref RemoteView::setStatus() will follow this rules for you.
0083     * (If you add/remove a state here, you must adapt it)
0084     */
0085 
0086     enum RemoteStatus {
0087         Connecting     = 0,
0088         Authenticating = 1,
0089         Preparing      = 2,
0090         Connected      = 3,
0091         Disconnecting  = -1,
0092         Disconnected   = -2
0093     };
0094     Q_ENUM(RemoteStatus)
0095 
0096     enum ErrorCode {
0097         None = 0,
0098         Internal,
0099         Connection,
0100         Protocol,
0101         IO,
0102         Name,
0103         NoServer,
0104         ServerBlocked,
0105         Authentication
0106     };
0107     Q_ENUM(ErrorCode)
0108 
0109     ~RemoteView() override;
0110 
0111     /**
0112      * Checks whether the backend supports scaling. The
0113      * default implementation returns false.
0114      * @return true if scaling is supported
0115      * @see scaling()
0116      */
0117     virtual bool supportsScaling() const;
0118 
0119     /**
0120      * Checks whether the widget is in scale mode. The
0121      * default implementation always returns false.
0122      * @return true if scaling is activated. Must always be
0123      *         false if @ref supportsScaling() returns false
0124      * @see supportsScaling()
0125      */
0126     virtual bool scaling() const;
0127 
0128     /**
0129      * Checks whether the backend supports the concept of local cursors. The
0130      * default implementation returns false.
0131      * @return true if local cursors are supported/known
0132      * @see LocalCursorState
0133      * @see showLocalCursor()
0134      * @see localCursorState()
0135      */
0136     virtual bool supportsLocalCursor() const;
0137 
0138     /**
0139      * Sets the state of the dot cursor, if supported by the backend.
0140      * The default implementation does nothing.
0141      * @param state the new state (CursorOn, CursorOff or
0142      *        CursorAuto)
0143      * @see localCursorState()
0144      * @see supportsLocalCursor()
0145      */
0146     virtual void showLocalCursor(LocalCursorState state);
0147 
0148     /**
0149      * Returns the state of the local cursor. The default implementation returns
0150      * always CursorOff.
0151      * @return true if local cursors are supported/known
0152      * @see showLocalCursor()
0153      * @see supportsLocalCursor()
0154      */
0155     virtual LocalCursorState localCursorState() const;
0156 
0157     /**
0158      * Checks whether the backend supports the view only mode. The
0159      * default implementation returns false.
0160      * @return true if view-only mode is supported
0161      * @see LocalCursorState
0162      * @see showLocalCursor()
0163      * @see localCursorState()
0164      */
0165     virtual bool supportsViewOnly() const;
0166 
0167     /**
0168      * Checks whether the view is in view-only mode. This means
0169      * that all input is ignored.
0170      */
0171     virtual bool viewOnly();
0172 
0173     /**
0174      * Checks whether grabbing all possible keys is enabled.
0175      */
0176     virtual bool grabAllKeys();
0177 
0178     /**
0179      * Returns the resolution of the remote framebuffer.
0180      * It should return a null @ref QSize when the size
0181      * is not known.
0182      * The backend must also emit a @ref framebufferSizeChanged()
0183      * when the size of the framebuffer becomes available
0184      * for the first time or the size changed.
0185      * @return the remote framebuffer size, a null QSize
0186      *         if unknown
0187      */
0188     virtual QSize framebufferSize();
0189 
0190     /**
0191      * Initiate the disconnection. This doesn't need to happen
0192      * immediately. The call must not block.
0193      * @see isQuitting()
0194      */
0195     virtual void startQuitting();
0196 
0197     /**
0198      * Checks whether the view is currently quitting.
0199      * @return true if it is quitting
0200      * @see startQuitting()
0201      * @see setStatus()
0202      */
0203     virtual bool isQuitting();
0204 
0205     /**
0206      * @return the host the view is connected to
0207      */
0208     virtual QString host();
0209 
0210     /**
0211      * @return the port the view is connected to
0212      */
0213     virtual int port();
0214 
0215     /**
0216      * Initialize the view (for example by showing configuration
0217      * dialogs to the user) and start connecting. Should not block
0218      * without running the event loop (so displaying a dialog is ok).
0219      * When the view starts connecting the application must call
0220      * @ref setStatus() with the status Connecting.
0221      * @return true if successful (so far), false
0222      *         otherwise
0223      * @see connected()
0224      * @see disconnected()
0225      * @see disconnectedError()
0226      * @see statusChanged()
0227      */
0228     virtual bool start() = 0;
0229 
0230     /**
0231      * Called when the configuration is changed.
0232      * The default implementation does nothing.
0233      */
0234     virtual void updateConfiguration();
0235 
0236     /**
0237      * @return screenshot of the view
0238      */
0239     virtual QPixmap takeScreenshot();
0240 
0241 #ifndef QTONLY
0242     /**
0243      * Returns the current host preferences of this view.
0244      */
0245     virtual HostPreferences* hostPreferences() = 0;
0246 #endif
0247 
0248     /**
0249      * Returns the current status of the connection.
0250      * @return the status of the connection
0251      * @see setStatus()
0252      */
0253     RemoteStatus status();
0254 
0255     /**
0256      * @return the current url
0257      */
0258     QUrl url();
0259 
0260 public Q_SLOTS:
0261     /**
0262      * Called to enable or disable scaling.
0263      * Ignored if @ref supportsScaling() is false.
0264      * The default implementation does nothing.
0265      * @param scale true to enable, false to disable.
0266      * @see supportsScaling()
0267      * @see scaling()
0268      */
0269     virtual void enableScaling(bool scale);
0270 
0271     /**
0272      * Sets scaling factor for the view. If remote view has width R and
0273      * the window has width W, then scaling factor (float, range 0-1) set the
0274      * remote view width A to be: A = (R-W)*factor + W. For factor = 0, A=W,
0275      * so no scalling, for factor=1, A=R.
0276      *
0277      * @param factor scaling factor in the range 0-1
0278      */
0279     virtual void setScaleFactor(float factor);
0280 
0281     /**
0282      * Enables/disables the view-only mode.
0283      * Ignored if @ref supportsScaling() is false.
0284      * The default implementation does nothing.
0285      * @param viewOnly true to enable, false to disable.
0286      * @see supportsScaling()
0287      * @see viewOnly()
0288      */
0289     virtual void setViewOnly(bool viewOnly);
0290 
0291     /**
0292      * Enables/disables grabbing all possible keys.
0293      * @param grabAllKeys true to enable, false to disable.
0294      * Default is false.
0295      * @see grabAllKeys()
0296      */
0297     virtual void setGrabAllKeys(bool grabAllKeys);
0298 
0299     /**
0300      * Called to let the backend know it when
0301      * we switch from/to fullscreen.
0302      * @param on true when switching to fullscreen,
0303      *           false when switching from fullscreen.
0304      */
0305     virtual void switchFullscreen(bool on);
0306 
0307     /**
0308      * Sends a QKeyEvent to the remote server.
0309      * @param event the key to send
0310      */
0311     virtual void keyEvent(QKeyEvent *event);
0312 
0313     /**
0314      * Called when the visible place changed so remote
0315      * view can resize itself.
0316      *
0317      * @param w width of the remote view
0318      * @param h height of the remote view
0319      */
0320     virtual void scaleResize(int w, int h);
0321 
0322 Q_SIGNALS:
0323     /**
0324      * Emitted when the size of the remote screen changes. Also
0325      * called when the size is known for the first time.
0326      * @param w the width of the screen
0327      * @param h the height of the screen
0328      */
0329     void framebufferSizeChanged(int w, int h);
0330 
0331     /**
0332      * Emitted when the view connected successfully.
0333      */
0334     void connected();
0335 
0336     /**
0337      * Emitted when the view disconnected without error.
0338      */
0339     void disconnected();
0340 
0341     /**
0342      * Emitted when the view disconnected with error.
0343      */
0344     void disconnectedError();
0345 
0346     /**
0347      * Emitted when the view has a specific error.
0348      */
0349     void errorMessage(const QString &title, const QString &message);
0350 
0351     /**
0352      * Emitted when the status of the view changed.
0353      * @param s the new status
0354         */
0355     void statusChanged(RemoteView::RemoteStatus s);
0356 
0357     /**
0358      * Emitted when the password dialog is shown or hidden.
0359      * @param b true when the dialog is shown, false when it has been hidden
0360      */
0361     void showingPasswordDialog(bool b);
0362 
0363     /**
0364      * Emitted when the mouse on the remote side has been moved.
0365      * @param x the new x coordinate
0366      * @param y the new y coordinate
0367      * @param buttonMask the mask of mouse buttons (bit 0 for first mouse
0368      *                   button, 1 for second button etc)a
0369      */
0370     void mouseStateChanged(int x, int y, int buttonMask);
0371 
0372 protected:
0373     RemoteView(QWidget *parent = nullptr);
0374 
0375     void focusInEvent(QFocusEvent *event) override;
0376     void focusOutEvent(QFocusEvent *event) override;
0377 
0378     /**
0379      * The status of the remote view.
0380      */
0381     RemoteStatus m_status;
0382 
0383     /**
0384      * Set the status of the connection.
0385      * Emits a statusChanged() signal.
0386      * Note that the states need to be set in a certain order,
0387      * see @ref RemoteStatus. setStatus() will try to do this
0388      * transition automatically, so if you are in Connecting
0389      * and call setStatus(Preparing), setStatus() will
0390      * emit a Authenticating and then Preparing.
0391      * If you transition backwards, it will emit a
0392      * Disconnected before doing the transition.
0393      * @param s the new status
0394      */
0395     virtual void setStatus(RemoteStatus s);
0396 
0397     QCursor localDefaultCursor() const;
0398 
0399     QString m_host;
0400     int m_port;
0401     bool m_viewOnly;
0402     bool m_grabAllKeys;
0403     bool m_scale;
0404     bool m_keyboardIsGrabbed;
0405     QUrl m_url;
0406     qreal m_factor;
0407 
0408 #ifndef QTONLY
0409     QString readWalletPassword(bool fromUserNameOnly = false);
0410     void saveWalletPassword(const QString &password, bool fromUserNameOnly = false);
0411     QString readWalletPasswordForKey(const QString &key);
0412     void saveWalletPasswordForKey(const QString &key, const QString &password);
0413     KWallet::Wallet *m_wallet;
0414 #endif
0415 
0416     LocalCursorState m_localCursorState;
0417 };
0418 
0419 #endif