diff --git a/ide/environmentopts.pp b/ide/environmentopts.pp index 1a18f2b4cd..57823e8dee 100644 --- a/ide/environmentopts.pp +++ b/ide/environmentopts.pp @@ -184,6 +184,16 @@ const 'Never' ); +type + TIDEMultipleInstancesOption = (mioAlwaysStartNew, mioOpenFilesInRunning, mioForceSingleInstance); +const + IDEMultipleInstancesOptionNames: array[TIDEMultipleInstancesOption] of string = ( + 'AlwaysStartNew', // mioAlwaysStartNew + 'OpenFilesInRunning', // mioOpenFilesInRunning + 'ForceSingleInstance' // mioForceSingleInstance + ); + DefaultIDEMultipleInstancesOption = mioOpenFilesInRunning; + { Messages window } type TMsgWndFileNameStyle = ( @@ -485,6 +495,7 @@ type FRecentPackageFiles: TStringList; FMaxRecentPackageFiles: integer; FOpenLastProjectAtStart: boolean; + FMultipleInstances: TIDEMultipleInstancesOption; // Prevent repopulating Recent project files menu with example projects if it was already cleared up. FAlreadyPopulatedRecentFiles : Boolean; @@ -737,6 +748,8 @@ type property LastOpenPackages: TLastOpenPackagesList read FLastOpenPackages; property OpenLastProjectAtStart: boolean read FOpenLastProjectAtStart write FOpenLastProjectAtStart; + property MultipleInstances: TIDEMultipleInstancesOption read FMultipleInstances + write FMultipleInstances; property FileDialogFilter: string read FFileDialogFilter write FFileDialogFilter; // backup @@ -812,6 +825,7 @@ function AmbiguousFileActionNameToType(const Action: string): TAmbiguousFileActi function CharCaseFileActionNameToType(const Action: string): TCharCaseFileAction; function UnitRenameReferencesActionNameToType(const Action: string): TUnitRenameReferencesAction; function StrToMsgWndFilenameStyle(const s: string): TMsgWndFileNameStyle; +function StrToIDEMultipleInstancesOption(const s: string): TIDEMultipleInstancesOption; function SimpleDirectoryCheck(const OldDir, NewDir, NotFoundErrMsg: string; out StopChecking: boolean): boolean; @@ -881,6 +895,13 @@ begin Result:=mwfsShort; end; +function StrToIDEMultipleInstancesOption(const s: string): TIDEMultipleInstancesOption; +begin + for Result in TIDEMultipleInstancesOption do + if CompareText(s,IDEMultipleInstancesOptionNames[Result])=0 then exit; + Result:=DefaultIDEMultipleInstancesOption; +end; + function SimpleDirectoryCheck(const OldDir, NewDir, NotFoundErrMsg: string; out StopChecking: boolean): boolean; var @@ -1324,6 +1345,7 @@ begin FRecentPackageFiles:=TStringList.Create; FMaxRecentPackageFiles:=DefaultMaxRecentPackageFiles; FOpenLastProjectAtStart:=true; + FMultipleInstances:=DefaultIDEMultipleInstancesOption; // backup with FBackupInfoProjectFiles do begin @@ -1761,6 +1783,7 @@ begin Path+'UnitRenameReferencesAction/Value',UnitRenameReferencesActionNames[urraAsk])); FAskForFilenameOnNewFile:=FXMLCfg.GetValue(Path+'AskForFilenameOnNewFile/Value',false); FLowercaseDefaultFilename:=FXMLCfg.GetValue(Path+'LowercaseDefaultFilename/Value',true); + FMultipleInstances:=StrToIDEMultipleInstancesOption(FXMLCfg.GetValue(Path+'MultipleInstances/Value','')); // fpdoc FPDocPaths := FXMLCfg.GetValue(Path+'LazDoc/Paths',''); @@ -2070,6 +2093,11 @@ begin FAskForFilenameOnNewFile,false); FXMLCfg.SetDeleteValue(Path+'LowercaseDefaultFilename/Value', FLowercaseDefaultFilename,true); + if FMultipleInstances = DefaultIDEMultipleInstancesOption then + FXMLCfg.DeletePath(Path+'MultipleInstances') + else + FXMLCfg.SetValue(Path+'MultipleInstances/Value',IDEMultipleInstancesOptionNames[FMultipleInstances]); + // fpdoc FXMLCfg.SetDeleteValue(Path+'LazDoc/Paths',FPDocPaths,''); diff --git a/ide/frames/files_options.lfm b/ide/frames/files_options.lfm index 18aa3db512..c605025bcd 100644 --- a/ide/frames/files_options.lfm +++ b/ide/frames/files_options.lfm @@ -47,12 +47,12 @@ object FilesOptionsFrame: TFilesOptionsFrame end object ShowCompileDialogCheckBox: TCheckBox AnchorSideLeft.Control = Owner - AnchorSideTop.Control = OpenLastProjectAtStartCheckBox + AnchorSideTop.Control = MultipleInstancesComboBox AnchorSideTop.Side = asrBottom AnchorSideRight.Side = asrBottom Left = 2 Height = 19 - Top = 69 + Top = 94 Width = 180 BorderSpacing.Top = 2 Caption = 'ShowCompileDialogCheckBox' @@ -65,7 +65,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideTop.Side = asrBottom Left = 2 Height = 15 - Top = 117 + Top = 142 Width = 82 BorderSpacing.Top = 10 Caption = 'LazarusDirLabel' @@ -80,7 +80,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideBottom.Side = asrBottom Left = 542 Height = 23 - Top = 132 + Top = 157 Width = 25 Anchors = [akTop, akRight, akBottom] Caption = '...' @@ -94,7 +94,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideRight.Control = LazarusDirButton Left = 2 Height = 23 - Top = 132 + Top = 157 Width = 540 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 @@ -108,7 +108,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideRight.Control = CompilerPathButton Left = 2 Height = 23 - Top = 176 + Top = 201 Width = 540 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 @@ -123,7 +123,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideBottom.Side = asrBottom Left = 542 Height = 23 - Top = 176 + Top = 201 Width = 25 Anchors = [akTop, akRight, akBottom] Caption = '...' @@ -136,7 +136,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideTop.Side = asrBottom Left = 2 Height = 15 - Top = 161 + Top = 186 Width = 101 BorderSpacing.Top = 6 Caption = 'CompilerPathLabel' @@ -149,7 +149,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideRight.Control = FPCSourceDirButton Left = 2 Height = 23 - Top = 220 + Top = 245 Width = 540 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 @@ -164,7 +164,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideBottom.Side = asrBottom Left = 542 Height = 23 - Top = 220 + Top = 245 Width = 25 Anchors = [akTop, akRight, akBottom] Caption = '...' @@ -177,7 +177,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideTop.Side = asrBottom Left = 2 Height = 15 - Top = 205 + Top = 230 Width = 100 BorderSpacing.Top = 6 Caption = 'FPCSourceDirLabel' @@ -189,7 +189,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideTop.Side = asrBottom Left = 2 Height = 15 - Top = 249 + Top = 274 Width = 81 BorderSpacing.Top = 6 Caption = 'MakePathLabel' @@ -201,7 +201,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideTop.Side = asrBottom Left = 2 Height = 15 - Top = 293 + Top = 318 Width = 91 BorderSpacing.Top = 6 Caption = 'TestBuildDirLabel' @@ -214,7 +214,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideRight.Control = MakePathButton Left = 2 Height = 23 - Top = 264 + Top = 289 Width = 540 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 @@ -229,7 +229,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideBottom.Side = asrBottom Left = 542 Height = 23 - Top = 264 + Top = 289 Width = 25 Anchors = [akTop, akRight, akBottom] Caption = '...' @@ -243,7 +243,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideRight.Control = TestBuildDirButton Left = 2 Height = 23 - Top = 308 + Top = 333 Width = 540 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 @@ -258,7 +258,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideBottom.Side = asrBottom Left = 542 Height = 23 - Top = 308 + Top = 333 Width = 25 Anchors = [akTop, akRight, akBottom] Caption = '...' @@ -272,7 +272,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideRight.Side = asrBottom Left = 32 Height = 19 - Top = 88 + Top = 113 Width = 206 BorderSpacing.Left = 30 Caption = 'AutoCloseCompileDialogCheckBox' @@ -284,7 +284,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideTop.Side = asrBottom Left = 2 Height = 15 - Top = 337 + Top = 362 Width = 153 Alignment = taRightJustify BorderSpacing.Top = 6 @@ -301,7 +301,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideBottom.Side = asrBottom Left = 542 Height = 23 - Top = 352 + Top = 377 Width = 25 Anchors = [akTop, akRight, akBottom] Caption = '...' @@ -317,7 +317,7 @@ object FilesOptionsFrame: TFilesOptionsFrame AnchorSideRight.Control = CompilerTranslationFileButton Left = 2 Height = 23 - Top = 352 + Top = 377 Width = 540 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 @@ -365,4 +365,27 @@ object FilesOptionsFrame: TFilesOptionsFrame BorderSpacing.Around = 2 TabOrder = 16 end + object MultipleInstancesLabel: TLabel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = MultipleInstancesComboBox + AnchorSideTop.Side = asrCenter + Left = 2 + Height = 15 + Top = 73 + Width = 121 + Caption = 'MultipleInstancesLabel' + ParentColor = False + end + object MultipleInstancesComboBox: TComboBox + AnchorSideLeft.Control = MultipleInstancesLabel + AnchorSideLeft.Side = asrBottom + Left = 131 + Height = 23 + Top = 69 + Width = 238 + BorderSpacing.Left = 8 + ItemHeight = 15 + Style = csDropDownList + TabOrder = 17 + end end diff --git a/ide/frames/files_options.pas b/ide/frames/files_options.pas index 14485f722a..d5881f5c8d 100644 --- a/ide/frames/files_options.pas +++ b/ide/frames/files_options.pas @@ -40,6 +40,7 @@ type TFilesOptionsFrame = class(TAbstractIDEOptionsEditor) AutoCloseCompileDialogCheckBox: TCheckBox; + MultipleInstancesComboBox: TComboBox; CompilerTranslationFileButton:TButton; CompilerTranslationFileComboBox:TComboBox; CompilerTranslationFileLabel:TLabel; @@ -49,6 +50,7 @@ type FPCSourceDirButton:TButton; FPCSourceDirComboBox:TComboBox; FPCSourceDirLabel:TLabel; + MultipleInstancesLabel: TLabel; lblCenter: TLabel; LazarusDirButton:TButton; LazarusDirComboBox:TComboBox; @@ -229,6 +231,16 @@ begin Add(ProgramDirectory(true)); EndUpdate; end; + MultipleInstancesLabel.Caption := dlgMultipleInstances; + with MultipleInstancesComboBox.Items do + begin + BeginUpdate; + Add(dlgMultipleInstances_AlwaysStartNew); + Add(dlgMultipleInstances_OpenFilesInRunning); + Add(dlgMultipleInstances_ForceSingleInstance); + EndUpdate; + end; + Assert(MultipleInstancesComboBox.Items.Count = Ord(High(TIDEMultipleInstancesOption))+1); CompilerPathLabel.Caption:=Format(dlgFpcExecutable,[GetDefaultCompilerFilename]); FPCSourceDirLabel.Caption:=dlgFpcSrcPath; @@ -361,6 +373,8 @@ begin // open last project at start OpenLastProjectAtStartCheckBox.Checked:=OpenLastProjectAtStart; + MultipleInstancesComboBox.ItemIndex := Ord(MultipleInstances); + // compile dialog fOldShowCompileDialog:=ShowCompileDialog; ShowCompileDialogCheckBox.Checked:=ShowCompileDialog; @@ -391,6 +405,7 @@ begin MaxRecentOpenFiles := MaxRecentOpenFilesSpin.Value; MaxRecentProjectFiles := MaxRecentProjectFilesSpin.Value; OpenLastProjectAtStart:=OpenLastProjectAtStartCheckBox.Checked; + MultipleInstances := TIDEMultipleInstancesOption(MultipleInstancesComboBox.ItemIndex); ShowCompileDialog := ShowCompileDialogCheckBox.Checked; AutoCloseCompileDialog := AutoCloseCompileDialogCheckBox.Checked; end; diff --git a/ide/idecmdline.pas b/ide/idecmdline.pas index cfdd6f7ff0..cb796d3f2d 100644 --- a/ide/idecmdline.pas +++ b/ide/idecmdline.pas @@ -50,6 +50,7 @@ const NoSplashScreenOptLong='--no-splash-screen'; NoSplashScreenOptShort='--nsc'; StartedByStartLazarusOpt='--started-by-startlazarus'; + ForceNewInstanceOpt='--force-new-instance'; SkipLastProjectOpt='--skip-last-project'; DebugLogOpt='--debug-log='; DebugLogOptEnable='--debug-enable='; diff --git a/ide/lazarus.pp b/ide/lazarus.pp index 0b6b7fd0de..d7d3772855 100644 --- a/ide/lazarus.pp +++ b/ide/lazarus.pp @@ -52,6 +52,7 @@ uses {$IFEND} SysUtils, Interfaces, + IDEInstances,//keep IDEInstances up so that it will be initialized soon Forms, LCLProc, IDEOptionsIntf, LazConf, IDEGuiCmdLine, @@ -104,6 +105,10 @@ begin {$ENDIF} Application.Initialize; + LazIDEInstances.PerformCheck; + if not LazIDEInstances.StartIDE then + Exit; + LazIDEInstances.StartServer; TMainIDE.ParseCmdLineOptions; if not SetupMainIDEInstance then exit; if Application.Terminated then exit; diff --git a/ide/lazarusidestrconsts.pas b/ide/lazarusidestrconsts.pas index 887c9d5d11..09634e2cbc 100644 --- a/ide/lazarusidestrconsts.pas +++ b/ide/lazarusidestrconsts.pas @@ -142,6 +142,14 @@ resourcestring lisMoveFiles2 = 'Move files?'; lrsPLDDeleteSelected = 'Delete selected'; + dlgMultipleInstances = 'Multiple Lazarus instances'; + dlgMultipleInstances_AlwaysStartNew = 'always start a new instance'; + dlgMultipleInstances_OpenFilesInRunning = 'open files in a running instance'; + dlgMultipleInstances_ForceSingleInstance = 'do not allow multiple instances'; + dlgRunningInstanceModalError = 'The running Lazarus instance cannot accept any files.'+sLineBreak+'Do you want to open them in a new IDE instance?'+sLineBreak+sLineBreak+'%s'; + dlgForceUniqueInstanceModalError = 'The running Lazarus instance cannot accept any files.'; + dlgRunningInstanceNotRespondingError = 'Lazarus instance is running but not responding.'; + // *** Rest of the resource strings *** lisImportPackageListXml = 'Import package list (*.xml)'; diff --git a/ide/lazarusmanager.pas b/ide/lazarusmanager.pas index b9fe26fe18..e26bd77202 100644 --- a/ide/lazarusmanager.pas +++ b/ide/lazarusmanager.pas @@ -92,8 +92,8 @@ uses BaseUnix, {$ENDIF} Classes, SysUtils, Process, Forms, Controls, Dialogs, LCLProc, - UTF8Process, FileUtil, LazFileUtils, LazUTF8, FileProcs, - IDECmdLine, LazConf, Splash, BaseIDEIntf; + UTF8Process, FileUtil, FileProcs, LazUTF8, LazFileUtils, + IDECmdLine, LazConf, Splash, BaseIDEIntf, IDEInstances; type @@ -244,13 +244,22 @@ begin if FShowSplashOption then ShowSplash; + // we already handled IDEInstances, ignore it in lazarus EXE + if (FCmdLineParams.IndexOf(ForceNewInstanceOpt) = -1) then + FCmdLineParams.Add(ForceNewInstanceOpt); + // pass the AllowOpenLastProject parameter to lazarus EXE + if not LazIDEInstances.AllowOpenLastProject and + (FCmdLineParams.IndexOf(SkipLastProjectOpt) = -1) + then + FCmdLineParams.Add(SkipLastProjectOpt); + // set primary config path PCP:=ExtractPrimaryConfigPath(FCmdLineParams); if PCP<>'' then SetPrimaryConfigPath(PCP); // get command line files - CmdLineFiles := ExtractCmdLineFilenames; + CmdLineFiles := LazIDEInstances.FilesToOpen; if CmdLineFiles<>nil then begin for i := 0 to CmdLineFiles.Count-1 do diff --git a/ide/main.pp b/ide/main.pp index 812c3fb809..3691a6eb4c 100644 --- a/ide/main.pp +++ b/ide/main.pp @@ -157,6 +157,7 @@ uses CleanDirDlg, CodeContextForm, AboutFrm, CompatibilityRestrictions, RestrictionBrowser, ProjectWizardDlg, IDECmdLine, IDEGuiCmdLine, CodeExplOpts, EditorMacroListViewer, SourceFileManager, EditorToolbarStatic, + IDEInstances, // main ide MainBar, MainIntf, MainBase; @@ -187,6 +188,8 @@ type procedure HandleRemoteControlTimer(Sender: TObject); procedure HandleSelectFrame(Sender: TObject; var AComponentClass: TComponentClass); procedure OIChangedTimerTimer(Sender: TObject); + procedure LazInstancesStartNewInstance(const aFiles: TStrings; + var Result: TStartNewInstanceResult); public // file menu procedure mnuNewUnitClicked(Sender: TObject); @@ -637,6 +640,7 @@ type OldCompilerFilename, OldLanguage: String; OIChangedTimer: TIdleTimer; + procedure DoDropFilesAsync(Data: PtrInt); procedure RenameInheritedMethods(AnUnitInfo: TUnitInfo; List: TStrings); function OIHelpProvider: TAbstractIDEHTMLProvider; // form editor and designer @@ -950,6 +954,14 @@ var StartedByStartLazarus: boolean = false; ShowSetupDialog: boolean = false; +type + TDoDropFilesAsyncParams = class(TComponent) + public + FileNames: array of string; + WindowIndex: Integer; + BringToFront: Boolean; + end; + function FindDesignComponent(const aName: string): TComponent; var AnUnitInfo: TUnitInfo; @@ -1556,6 +1568,7 @@ begin DoShowMessagesView(false); // reopen extra windows fUserInputSinceLastIdle:=true; // Idle work gets done initially before user action. MainIDEBar.ApplicationIsActivate:=true; + LazIDEInstances.StartListening(@LazInstancesStartNewInstance); FIDEStarted:=true; {$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.StartIDE END');{$ENDIF} end; @@ -1946,6 +1959,7 @@ end; procedure TMainIDE.MainIDEFormClose(Sender: TObject; var CloseAction: TCloseAction); begin + LazIDEInstances.StopServer; DoCallNotifyHandler(lihtIDEClose); SaveEnvironment(true); if IDEDockMaster<>nil then @@ -2182,119 +2196,116 @@ begin {$ENDIF} {$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.SetupStartProject A');{$ENDIF} // load command line project or last project or create a new project - CmdLineFiles:=ExtractCmdLineFilenames; - try - ProjectLoaded:=false; + CmdLineFiles:=LazIDEInstances.FilesToOpen; + ProjectLoaded:=false; - // try command line project - if (CmdLineFiles<>nil) and (CmdLineFiles.Count>0) then begin - AProjectFilename:=CmdLineFiles[0]; - if (CompareFileExt(AProjectFilename,'.lpr',false)=0) then - AProjectFilename:=ChangeFileExt(AProjectFilename,'.lpi'); - // only try to load .lpi files, other files are loaded later - if (CompareFileExt(AProjectFilename,'.lpi',false)=0) then begin - AProjectFilename:=CleanAndExpandFilename(AProjectFilename); - if FileExistsUTF8(AProjectFilename) then begin - CmdLineFiles.Delete(0); - ProjectLoaded:=(DoOpenProjectFile(AProjectFilename,[])=mrOk); - end; + // try command line project + if (CmdLineFiles<>nil) and (CmdLineFiles.Count>0) then begin + AProjectFilename:=CmdLineFiles[0]; + if (CompareFileExt(AProjectFilename,'.lpr',false)=0) then + AProjectFilename:=ChangeFileExt(AProjectFilename,'.lpi'); + // only try to load .lpi files, other files are loaded later + if (CompareFileExt(AProjectFilename,'.lpi',false)=0) then begin + AProjectFilename:=CleanAndExpandFilename(AProjectFilename); + if FileExistsUTF8(AProjectFilename) then begin + CmdLineFiles.Delete(0); + ProjectLoaded:=(DoOpenProjectFile(AProjectFilename,[ofAddToRecent])=mrOk); end; end; - - // try loading last project if lazarus didn't fail last time - if (not ProjectLoaded) - and (not SkipAutoLoadingLastProject) - and (EnvironmentOptions.OpenLastProjectAtStart) - and (EnvironmentOptions.LastSavedProjectFile<>'') - and (EnvironmentOptions.LastSavedProjectFile<>RestoreProjectClosed) - and (FileExistsCached(EnvironmentOptions.LastSavedProjectFile)) - then begin - if (not IDEProtocolOpts.LastProjectLoadingCrashed) - or AskIfLoadLastFailingProject then begin - // protocol that the IDE is trying to load the last project and did not - // yet succeed - IDEProtocolOpts.LastProjectLoadingCrashed := True; - IDEProtocolOpts.Save; - // try loading the project - ProjectLoaded:= - (DoOpenProjectFile(EnvironmentOptions.LastSavedProjectFile,[])=mrOk); - // protocol that the IDE was able to open the project without crashing - IDEProtocolOpts.LastProjectLoadingCrashed := false; - IDEProtocolOpts.Save; - if ProjectLoaded then - begin - PkgOpenFlags:=[pofAddToRecent]; - for I := 0 to EnvironmentOptions.LastOpenPackages.Count-1 do - begin - AFilename:=EnvironmentOptions.LastOpenPackages[I]; - if AFilename='' then - continue; - if i restore that state - end else begin - // create new project - DoNewProject(ProjectDescriptorApplication); - end; - end; - - // load the cmd line files - if CmdLineFiles<>nil then begin - for i:=0 to CmdLineFiles.Count-1 do - Begin - AFilename:=CleanAndExpandFilename(CmdLineFiles.Strings[i]); - if not FileExistsCached(AFilename) then begin - debugln(['WARNING: command line file not found: "',AFilename,'"']); - continue; - end; - if Project1=nil then begin - // to open a file a project is needed - // => create a project - DoNewProject(ProjectDescriptorEmptyProject); - end; - if CompareFileExt(AFilename,'.lpk',false)=0 then begin - if PkgBoss.DoOpenPackageFile(AFilename,[pofAddToRecent,pofMultiOpen],true)=mrAbort - then - break; - end else begin - OpenFlags:=[ofAddToRecent,ofRegularFile]; - if i'') + and (EnvironmentOptions.LastSavedProjectFile<>RestoreProjectClosed) + and (FileExistsCached(EnvironmentOptions.LastSavedProjectFile)) + then begin + if (not IDEProtocolOpts.LastProjectLoadingCrashed) + or AskIfLoadLastFailingProject then begin + // protocol that the IDE is trying to load the last project and did not + // yet succeed + IDEProtocolOpts.LastProjectLoadingCrashed := True; + IDEProtocolOpts.Save; + // try loading the project + ProjectLoaded:= + (DoOpenProjectFile(EnvironmentOptions.LastSavedProjectFile,[])=mrOk); + // protocol that the IDE was able to open the project without crashing + IDEProtocolOpts.LastProjectLoadingCrashed := false; + IDEProtocolOpts.Save; + if ProjectLoaded then + begin + PkgOpenFlags:=[pofAddToRecent]; + for I := 0 to EnvironmentOptions.LastOpenPackages.Count-1 do + begin + AFilename:=EnvironmentOptions.LastOpenPackages[I]; + if AFilename='' then + continue; + if i restore that state + end else begin + // create new project + DoNewProject(ProjectDescriptorApplication); + end; + end; + + // load the cmd line files + if CmdLineFiles<>nil then begin + for i:=0 to CmdLineFiles.Count-1 do + Begin + AFilename:=CleanAndExpandFilename(CmdLineFiles.Strings[i]); + if not FileExistsCached(AFilename) then begin + debugln(['WARNING: command line file not found: "',AFilename,'"']); + continue; + end; + if Project1=nil then begin + // to open a file a project is needed + // => create a project + DoNewProject(ProjectDescriptorEmptyProject); + end; + if CompareFileExt(AFilename,'.lpk',false)=0 then begin + if PkgBoss.DoOpenPackageFile(AFilename,[pofAddToRecent,pofMultiOpen],true)=mrAbort + then + break; + end else begin + OpenFlags:=[ofAddToRecent,ofRegularFile]; + if i 0 then + DoDropFiles(Self, xParams.FileNames, xParams.WindowIndex); + if xParams.BringToFront then + begin + if Application.MainForm.WindowState = wsMinimized then + UnhideIDE; + Application.BringToFront; + if SourceEditorManager.ActiveSourceWindow <> nil then + SourceEditorManager.ActiveSourceWindow.BringToFront; + end; + finally + xParams.Free; + end; +end; + function TMainIDE.DoSelectFrame: TComponentClass; var UnitList: TStringList; @@ -9112,6 +9144,51 @@ begin Result:=false; end; +procedure TMainIDE.LazInstancesStartNewInstance(const aFiles: TStrings; + var Result: TStartNewInstanceResult); +var + xParams: TDoDropFilesAsyncParams; + I: Integer; +begin + if aFiles.Count > 0 then + begin + //there are files to open + if EnvironmentOptions.MultipleInstances = mioAlwaysStartNew then + begin//the user wants to open them in new instance! + Result := ofrStartNewInstance; + end else + if (not IsWindowEnabled(Application.MainForm.Handle) or//check that main is active + (Application.ModalLevel > 0))//check that no modal window is opened + then + begin + if EnvironmentOptions.MultipleInstances = mioForceSingleInstance then + Result := ofrForceSingleInstanceModalError + else + Result := ofrModalError; + end else + Result := ofrDoNotStart; + end else + begin + //no files to open + if EnvironmentOptions.MultipleInstances = mioForceSingleInstance then + Result := ofrDoNotStart + else + Result := ofrStartNewInstance; + end; + + if Result in [ofrStartNewInstance, ofrModalError, ofrForceSingleInstanceModalError] then + Exit; + + //show up the current IDE and open files (if there are any) + xParams := TDoDropFilesAsyncParams.Create(Self);//we need direct response, do not wait to get the files opened! + SetLength(xParams.FileNames, aFiles.Count); + for I := 0 to aFiles.Count-1 do + xParams.FileNames[I] := aFiles[I]; + xParams.WindowIndex := -1; + xParams.BringToFront := True; + Application.QueueAsyncCall(@DoDropFilesAsync, PtrInt(xParams)); +end; + procedure TMainIDE.ApplyCodeToolChanges; begin // all changes were handled automatically by events, just clear the logs diff --git a/ide/startlazarus.lpi b/ide/startlazarus.lpi index d997f5b55e..6d5bfb59ba 100644 --- a/ide/startlazarus.lpi +++ b/ide/startlazarus.lpi @@ -8,6 +8,7 @@ + diff --git a/ide/startlazarus.lpr b/ide/startlazarus.lpr index 890e3efaaf..773a747eb9 100644 --- a/ide/startlazarus.lpr +++ b/ide/startlazarus.lpr @@ -34,6 +34,7 @@ uses redirect_stderr, Interfaces, SysUtils, Forms, + IDEInstances, LazarusManager; {$R *.res} @@ -44,6 +45,9 @@ var begin redirect_stderr.DoShowWindow := False; Application.Initialize; + LazIDEInstances.PerformCheck; + if not LazIDEInstances.StartIDE then + Exit; ALazarusManager := TLazarusManager.Create(nil); ALazarusManager.Initialize; ALazarusManager.Run;