| 1 | unit UKernel;
|
|---|
| 2 |
|
|---|
| 3 | {$mode delphi}
|
|---|
| 4 |
|
|---|
| 5 | interface
|
|---|
| 6 |
|
|---|
| 7 | uses
|
|---|
| 8 | Classes, SysUtils, Forms, Generics.Collections, UApp, UApi, UTextBuffer;
|
|---|
| 9 |
|
|---|
| 10 | type
|
|---|
| 11 | TKernel = class;
|
|---|
| 12 | TAppContext = class;
|
|---|
| 13 |
|
|---|
| 14 | { TKernelApi }
|
|---|
| 15 |
|
|---|
| 16 | TKernelApi = class(TApi)
|
|---|
| 17 | Kernel: TKernel;
|
|---|
| 18 | AppContext: TAppContext;
|
|---|
| 19 | procedure Sleep(Time: TDateTime); override;
|
|---|
| 20 | function GetMessage: TApiMessage; override;
|
|---|
| 21 | function InputText: string; override;
|
|---|
| 22 | procedure OutputText(Text: string); override;
|
|---|
| 23 | procedure Terminate; override;
|
|---|
| 24 | procedure ExecuteApp(Name: string); override;
|
|---|
| 25 | end;
|
|---|
| 26 |
|
|---|
| 27 | { TAppThread }
|
|---|
| 28 |
|
|---|
| 29 | TAppThread = class(TThread)
|
|---|
| 30 | AppContext: TAppContext;
|
|---|
| 31 | procedure Execute; override;
|
|---|
| 32 | end;
|
|---|
| 33 |
|
|---|
| 34 | TAppState = (asSleep, asRunning, asTerminated);
|
|---|
| 35 |
|
|---|
| 36 | { TAppContext }
|
|---|
| 37 |
|
|---|
| 38 | TAppContext = class
|
|---|
| 39 | AppState: TAppState;
|
|---|
| 40 | App: TApp;
|
|---|
| 41 | AppDescription: TAppDescription;
|
|---|
| 42 | InputBuffer: TTextBuffer;
|
|---|
| 43 | OutputBuffer: TTextBuffer;
|
|---|
| 44 | Messages: TList<TApiMessage>;
|
|---|
| 45 | Thread: TAppThread;
|
|---|
| 46 | procedure Start;
|
|---|
| 47 | procedure Stop;
|
|---|
| 48 | constructor Create;
|
|---|
| 49 | destructor Destroy; override;
|
|---|
| 50 | end;
|
|---|
| 51 |
|
|---|
| 52 | TOutputTextEvent = procedure (Text: string) of object;
|
|---|
| 53 |
|
|---|
| 54 | { TKernel }
|
|---|
| 55 |
|
|---|
| 56 | TKernel = class
|
|---|
| 57 | private
|
|---|
| 58 | FOnOutputText: TOutputTextEvent;
|
|---|
| 59 | FAppContexts: TObjectList<TAppContext>;
|
|---|
| 60 | FCurrentApp: TAppContext;
|
|---|
| 61 | FAppDescriptions: TAppDescriptions;
|
|---|
| 62 | procedure Schedule;
|
|---|
| 63 | function AddAppContext(AppDescription: TAppDescription): TAppContext;
|
|---|
| 64 | procedure DoOutputText(Text: string);
|
|---|
| 65 | procedure RemoveTerminated;
|
|---|
| 66 | public
|
|---|
| 67 | Terminated: Boolean;
|
|---|
| 68 | function AddApp(Name: string; AppClass: TAppClass): TAppDescription;
|
|---|
| 69 | procedure Start;
|
|---|
| 70 | procedure Input(Text: string);
|
|---|
| 71 | procedure InputKey(Key: Word);
|
|---|
| 72 | constructor Create;
|
|---|
| 73 | destructor Destroy; override;
|
|---|
| 74 | property OnOutputText: TOutputTextEvent read FOnOutputText write FOnOutputText;
|
|---|
| 75 | end;
|
|---|
| 76 |
|
|---|
| 77 |
|
|---|
| 78 | implementation
|
|---|
| 79 |
|
|---|
| 80 | { TAppThread }
|
|---|
| 81 |
|
|---|
| 82 | procedure TAppThread.Execute;
|
|---|
| 83 | begin
|
|---|
| 84 | while not Terminated do begin
|
|---|
| 85 | AppContext.App.Run;
|
|---|
| 86 | end;
|
|---|
| 87 | AppContext.AppState := asTerminated;
|
|---|
| 88 | end;
|
|---|
| 89 |
|
|---|
| 90 | { TAppContext }
|
|---|
| 91 |
|
|---|
| 92 | procedure TAppContext.Start;
|
|---|
| 93 | begin
|
|---|
| 94 | Thread.Resume;
|
|---|
| 95 | end;
|
|---|
| 96 |
|
|---|
| 97 | procedure TAppContext.Stop;
|
|---|
| 98 | begin
|
|---|
| 99 | Thread.Terminate;
|
|---|
| 100 | end;
|
|---|
| 101 |
|
|---|
| 102 | constructor TAppContext.Create;
|
|---|
| 103 | begin
|
|---|
| 104 | InputBuffer := TTextBuffer.Create;
|
|---|
| 105 | OutputBuffer := TTextBuffer.Create;
|
|---|
| 106 | Messages := TList<TApiMessage>.Create;
|
|---|
| 107 | Thread := TAppThread.Create(True);
|
|---|
| 108 | Thread.AppContext := Self;
|
|---|
| 109 | end;
|
|---|
| 110 |
|
|---|
| 111 | destructor TAppContext.Destroy;
|
|---|
| 112 | begin
|
|---|
| 113 | FreeAndNil(Thread);
|
|---|
| 114 | FreeAndNil(Messages);
|
|---|
| 115 | FreeAndNil(InputBuffer);
|
|---|
| 116 | FreeAndNil(OutputBuffer);
|
|---|
| 117 | inherited;
|
|---|
| 118 | end;
|
|---|
| 119 |
|
|---|
| 120 | { TKernelApi }
|
|---|
| 121 |
|
|---|
| 122 | procedure TKernelApi.Sleep(Time: TDateTime);
|
|---|
| 123 | begin
|
|---|
| 124 |
|
|---|
| 125 | end;
|
|---|
| 126 |
|
|---|
| 127 | function TKernelApi.GetMessage: TApiMessage;
|
|---|
| 128 | begin
|
|---|
| 129 | while AppContext.AppState <> asTerminated do begin
|
|---|
| 130 | if AppContext.AppState = asTerminated then begin
|
|---|
| 131 | Result := amTerminate;
|
|---|
| 132 | Break;
|
|---|
| 133 | end else begin
|
|---|
| 134 | if AppContext.InputBuffer.Size > 0 then begin
|
|---|
| 135 | Result := amInputText;
|
|---|
| 136 | Break;
|
|---|
| 137 | end;
|
|---|
| 138 | end;
|
|---|
| 139 | Sleep(1);
|
|---|
| 140 | end;
|
|---|
| 141 | end;
|
|---|
| 142 |
|
|---|
| 143 | function TKernelApi.InputText: string;
|
|---|
| 144 | begin
|
|---|
| 145 | Result := AppContext.InputBuffer.Read;
|
|---|
| 146 | end;
|
|---|
| 147 |
|
|---|
| 148 | procedure TKernelApi.OutputText(Text: string);
|
|---|
| 149 | begin
|
|---|
| 150 | AppContext.OutputBuffer.Write(Text);
|
|---|
| 151 | end;
|
|---|
| 152 |
|
|---|
| 153 | procedure TKernelApi.Terminate;
|
|---|
| 154 | begin
|
|---|
| 155 | AppContext.AppState := asTerminated;
|
|---|
| 156 | AppContext.Thread.Terminate;
|
|---|
| 157 | end;
|
|---|
| 158 |
|
|---|
| 159 | procedure TKernelApi.ExecuteApp(Name: string);
|
|---|
| 160 | var
|
|---|
| 161 | AppDescription: TAppDescription;
|
|---|
| 162 | AppContext: TAppContext;
|
|---|
| 163 | begin
|
|---|
| 164 | AppDescription := Kernel.FAppDescriptions.SearchByName(Name);
|
|---|
| 165 | if Assigned(AppDescription) then begin
|
|---|
| 166 | AppContext := Kernel.AddAppContext(AppDescription);
|
|---|
| 167 | AppContext.Start;
|
|---|
| 168 | Kernel.FCurrentApp := Kernel.FAppContexts[Kernel.FAppContexts.Count - 1];
|
|---|
| 169 | end;
|
|---|
| 170 | end;
|
|---|
| 171 |
|
|---|
| 172 | { TKernel }
|
|---|
| 173 |
|
|---|
| 174 | procedure TKernel.Schedule;
|
|---|
| 175 | var
|
|---|
| 176 | I: Integer;
|
|---|
| 177 | begin
|
|---|
| 178 | I := FAppContexts.IndexOf(FCurrentApp);
|
|---|
| 179 | if FAppContexts.Count > 0 then begin
|
|---|
| 180 | I := (I + 1) mod FAppContexts.Count;
|
|---|
| 181 | FCurrentApp := FAppContexts[I];
|
|---|
| 182 | end else FCurrentApp := nil;
|
|---|
| 183 | end;
|
|---|
| 184 |
|
|---|
| 185 | function TKernel.AddAppContext(AppDescription: TAppDescription): TAppContext;
|
|---|
| 186 | var
|
|---|
| 187 | App: TApp;
|
|---|
| 188 | begin
|
|---|
| 189 | App := AppDescription.AppClass.Create;
|
|---|
| 190 | Result := TAppContext.Create;
|
|---|
| 191 | Result.App := App;
|
|---|
| 192 | Result.AppDescription := AppDescription;
|
|---|
| 193 | App.Api.Parent := TKernelApi.Create;
|
|---|
| 194 | TKernelApi(App.Api.Parent).AppContext := Result;
|
|---|
| 195 | TKernelApi(App.Api.Parent).Kernel := Self;
|
|---|
| 196 | FAppContexts.Add(Result);
|
|---|
| 197 | end;
|
|---|
| 198 |
|
|---|
| 199 | procedure TKernel.DoOutputText(Text: string);
|
|---|
| 200 | begin
|
|---|
| 201 | if Assigned(FOnOutputText) then FOnOutputText(Text);
|
|---|
| 202 | end;
|
|---|
| 203 |
|
|---|
| 204 | procedure TKernel.RemoveTerminated;
|
|---|
| 205 | var
|
|---|
| 206 | I: Integer;
|
|---|
| 207 | begin
|
|---|
| 208 | for I := FAppContexts.Count - 1 downto 0 do begin
|
|---|
| 209 | if FAppContexts[I].AppState = asTerminated then begin
|
|---|
| 210 | FAppContexts.Delete(I);
|
|---|
| 211 | if FAppContexts.Count > 0 then
|
|---|
| 212 | FCurrentApp := FAppContexts[I mod FAppContexts.Count]
|
|---|
| 213 | else FCurrentApp := nil;
|
|---|
| 214 | end;
|
|---|
| 215 | end;
|
|---|
| 216 | if FAppContexts.Count = 0 then Terminated := True;
|
|---|
| 217 | end;
|
|---|
| 218 |
|
|---|
| 219 | function TKernel.AddApp(Name: string; AppClass: TAppClass): TAppDescription;
|
|---|
| 220 | begin
|
|---|
| 221 | Result := TAppDescription.Create;
|
|---|
| 222 | Result.Name := Name;
|
|---|
| 223 | Result.AppClass := AppClass;
|
|---|
| 224 | FAppDescriptions.Add(Result);
|
|---|
| 225 | end;
|
|---|
| 226 |
|
|---|
| 227 | procedure TKernel.Start;
|
|---|
| 228 | var
|
|---|
| 229 | Text: string;
|
|---|
| 230 | begin
|
|---|
| 231 | if FAppDescriptions.Count > 0 then begin
|
|---|
| 232 | FCurrentApp := AddAppContext(FAppDescriptions[0]);
|
|---|
| 233 | FCurrentApp.Start;
|
|---|
| 234 | repeat
|
|---|
| 235 | RemoveTerminated;
|
|---|
| 236 | Application.ProcessMessages;
|
|---|
| 237 | Sleep(1);
|
|---|
| 238 |
|
|---|
| 239 | if Assigned(FCurrentApp) then begin
|
|---|
| 240 | Text := FCurrentApp.OutputBuffer.Read;
|
|---|
| 241 | if Text <> '' then begin
|
|---|
| 242 | DoOutputText(Text);
|
|---|
| 243 | end;
|
|---|
| 244 | end;
|
|---|
| 245 | until Terminated;
|
|---|
| 246 | end;
|
|---|
| 247 | end;
|
|---|
| 248 |
|
|---|
| 249 | procedure TKernel.Input(Text: string);
|
|---|
| 250 | begin
|
|---|
| 251 | if Assigned(FCurrentApp) then begin
|
|---|
| 252 | FCurrentApp.InputBuffer.Write(Text);
|
|---|
| 253 | end;
|
|---|
| 254 | end;
|
|---|
| 255 |
|
|---|
| 256 | procedure TKernel.InputKey(Key: Word);
|
|---|
| 257 | begin
|
|---|
| 258 | if Key = 9 then begin
|
|---|
| 259 | if FAppContexts.Count > 1 then begin
|
|---|
| 260 | FCurrentApp := FAppContexts[(FAppContexts.IndexOf(FCurrentApp) + 1 ) mod FAppContexts.Count];
|
|---|
| 261 | DoOutputText('Switched to ' + FCurrentApp.AppDescription.Name + LineEnding);
|
|---|
| 262 | end;
|
|---|
| 263 | end;
|
|---|
| 264 | end;
|
|---|
| 265 |
|
|---|
| 266 | constructor TKernel.Create;
|
|---|
| 267 | begin
|
|---|
| 268 | FAppContexts := TObjectList<TAppContext>.Create;
|
|---|
| 269 | FAppDescriptions := TAppDescriptions.Create;
|
|---|
| 270 | end;
|
|---|
| 271 |
|
|---|
| 272 | destructor TKernel.Destroy;
|
|---|
| 273 | begin
|
|---|
| 274 | FreeAndNil(FAppContexts);
|
|---|
| 275 | FreeAndNil(FAppDescriptions);
|
|---|
| 276 | inherited;
|
|---|
| 277 | end;
|
|---|
| 278 |
|
|---|
| 279 | end.
|
|---|
| 280 |
|
|---|