1 /*************************************************************************** 2 rkrbackendprotocol - description 3 ------------------- 4 begin : Thu Nov 04 2010 5 copyright : (C) 2010-2018 by Thomas Friedrichsmeier 6 email : thomas.friedrichsmeier@kdemail.net 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 18 #ifndef RKRBACKENDPROTOCOL_SHARED_H 19 #define RKRBACKENDPROTOCOL_SHARED_H 20 21 #include <QVariantMap> 22 #include <QMutex> 23 #include "rcommand.h" 24 25 class RCommandProxy; 26 27 class RBackendRequest { 28 public: 29 enum RCallbackType { 30 BackendExit, 31 ShowMessage, 32 ShowFiles, 33 ChooseFile, 34 EditFiles, 35 ReadLine, // 5 36 CommandOut, 37 Started, 38 EvalRequest, 39 CallbackRequest, 40 HistoricalSubstackRequest, // 10 41 PlainGenericRequest, 42 SetParamsFromBackend, 43 Debugger, 44 CommandLineIn, /**< The next line of the current user command has been submitted in the backend. */ 45 Output, /**< A piece of output. Note: If the backend runs in a single process, output is handled in a pull fashion, instead of using requests. */ //15 46 Interrupt, /**< Interrupt evaluation. This request type originates in the frontend, not the backend. */ 47 PriorityCommand, /**< Send a command to be run during R's event processing. This request type originates in the frontend, not the backend. */ 48 OutputStartedNotification, /**< Only used in the frontend: Notification that a new bit of output has arrived. Used to trigger flushing after a timeout. */ 49 OtherRequest /**< Any other type of request. Note: which requests are in the enum, and which are not has mostly historical reasons. @see params */ 50 }; 51 52 RBackendRequest (bool synchronous, RCallbackType type); 53 ~RBackendRequest (); 54 takeCommand()55 RCommandProxy *takeCommand () { 56 RCommandProxy* ret = command; 57 command = 0; 58 return ret; 59 } 60 takeOutput()61 ROutputList *takeOutput () { 62 ROutputList* ret = output; 63 output = 0; 64 return ret; 65 } 66 67 /** Should this request be handled synchronously? False by default. */ 68 bool synchronous; 69 /** For synchronous requests, only: The frontend-thread will set this to true (using completed()), once the request has been "completed". Important: The backend thread MUST NOT touch a request after it has been sent, and before "done" has been set to true. */ 70 bool volatile done; 71 int id; 72 static int _id; 73 RCallbackType type; 74 /** For synchronous requests, only: If the frontend wants any commands to be executed, it will place the next one in this slot. The backend thread should keep executing commands (in a sub-eventloop) while this is non-zero. Also, the backend-thread may place here any command that has just finished. */ 75 RCommandProxy *command; 76 /** Any other parameters, esp. for RCallbackType::OtherRequest. Can be used in both directions. */ 77 QVariantMap params; 78 /** NOTE: only used for separate process backend. See RCallbackType::Output */ 79 ROutputList *output; 80 /** NOTE: this does @em not copy merge the "done" flag. Do that manually, @em after merging (and don't touch the request from the transmitter thread, after that). */ 81 void mergeReply (RBackendRequest *reply); 82 protected: 83 friend class RKRBackendProtocolFrontend; 84 friend class RKRBackendProtocolBackend; 85 completed()86 void completed () { 87 if (!synchronous) delete this; 88 else done = true; 89 } 90 91 /** duplicates the request. NOTE: The command, and output, if any are @em taken from the original, and transferred to the copy, not really duplicated. */ 92 RBackendRequest *duplicate (); 93 }; 94 95 #include <QEvent> 96 /** Simple event class to relay information from the RKRBackend to the main thread. This is basically like QCustomEvent in Qt3*/ 97 class RKRBackendEvent : public QEvent { 98 public: 99 enum EventType { 100 RKWardEvent = QEvent::User + 1 101 }; 102 explicit RKRBackendEvent (RBackendRequest* data=0) : QEvent ((QEvent::Type) RKWardEvent) { _data = data; }; 103 RKRBackendEvent (); 104 data()105 RBackendRequest* data () { return _data; }; 106 private: 107 RBackendRequest* _data; 108 }; 109 110 /** This is a reduced version of an RCommand, intended for use in the R backend. */ 111 class RCommandProxy : public RData { 112 protected: 113 friend class RCommand; 114 friend class RKRBackend; 115 friend class RKRBackendSerializer; 116 friend class RBackendRequest; 117 RCommandProxy (); 118 ~RCommandProxy (); 119 RCommandProxy (const QString &command, int type); 120 public: // all these are public for technical reasons, only. 121 QString command; 122 int type; 123 int id; 124 int status; 125 int has_been_run_up_to; 126 }; 127 128 class RKROutputBuffer { 129 public: 130 RKROutputBuffer (); 131 virtual ~RKROutputBuffer (); 132 133 /** This gets called on normal R output (R_WriteConsole). Used to get at output. 134 returns true, if a *new* piece of output started, i.e. the buffer was empty before this. */ 135 bool handleOutput (const QString &output, int len, ROutput::ROutputType type, bool allow_blocking=true); 136 137 enum CaptureMode { 138 RecordMessages = 1, 139 RecordOutput = 2, 140 SuppressMessages = 4, 141 SuppressOutput = 8 142 }; 143 void pushOutputCapture (int capture_mode); 144 QString popOutputCapture (bool highlighted); 145 146 /** Flushes current output buffer. Meant to be called from RInterface::flushOutput, only. 147 @param forcibly: if true, will always flush the output. If false, will flush the output only if the mutex can be locked without waiting. */ 148 ROutputList flushOutput (bool forcibly=false); 149 protected: 150 /** Function to be called while waiting for downstream threads to catch up. Return false to make the buffer continue, immediately (e.g. to prevent lockups after a crash) */ 151 virtual bool doMSleep (int msecs) = 0; 152 private: 153 /** current output */ 154 ROutputList output_buffer; 155 /** Provides thread-safety for the output_buffer */ 156 QMutex output_buffer_mutex; 157 /** current length of output. If the backlog of output which has not yet been processed by the frontend becomes too long, output will be paused, automatically */ 158 int out_buf_len; 159 160 struct OutputCapture { 161 ROutputList recorded; 162 int mode; 163 }; 164 QList<OutputCapture> output_captures; 165 }; 166 167 namespace RKRSharedFunctionality { 168 QString quote (const QString &string); 169 }; 170 171 #endif 172