File indexing completed on 2024-04-21 04:58:34

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