diff --git a/Test/X2LogTest.dpr b/Test/X2LogTest.dpr
index ff3104f..0a4af8d 100644
--- a/Test/X2LogTest.dpr
+++ b/Test/X2LogTest.dpr
@@ -12,7 +12,9 @@ uses
X2Log.Observer.LogFile in '..\X2Log.Observer.LogFile.pas',
X2Log.Constants in '..\X2Log.Constants.pas',
X2Log.Observer.NamedPipe in '..\X2Log.Observer.NamedPipe.pas',
- X2Log.Observer.CustomThreaded in '..\X2Log.Observer.CustomThreaded.pas';
+ X2Log.Observer.CustomThreaded in '..\X2Log.Observer.CustomThreaded.pas',
+ X2Log.Observer.MonitorForm in '..\X2Log.Observer.MonitorForm.pas' {X2LogObserverMonitorForm},
+ X2Log.Global in '..\X2Log.Global.pas';
{$R *.res}
diff --git a/Test/X2LogTest.dproj b/Test/X2LogTest.dproj
index b34f1bf..35a1f50 100644
--- a/Test/X2LogTest.dproj
+++ b/Test/X2LogTest.dproj
@@ -183,6 +183,11 @@
+
+
+ dfm
+
+
Cfg_2
Base
diff --git a/X2Log.Global.pas b/X2Log.Global.pas
new file mode 100644
index 0000000..2c1faca
--- /dev/null
+++ b/X2Log.Global.pas
@@ -0,0 +1,102 @@
+unit X2Log.Global;
+
+interface
+uses
+ System.SysUtils,
+
+ X2Log.Intf;
+
+
+type
+ TX2GlobalLog = class(TObject)
+ private
+ class var FInstance: IX2Log;
+ public
+ class function Instance: IX2Log;
+
+ { Facade for IX2Log }
+ class procedure Attach(AObserver: IX2LogObserver);
+ class procedure Detach(AObserver: IX2LogObserver);
+
+ class procedure SetExceptionStrategy(AStrategy: IX2LogExceptionStrategy);
+
+ { Facade for IX2LogMethods }
+ class procedure Log(ALevel: TX2LogLevel; const AMessage: string; const ADetails: string = '');
+
+ class procedure Verbose(const AMessage: string; const ADetails: string = '');
+ class procedure Info(const AMessage: string; const ADetails: string = '');
+ class procedure Warning(const AMessage: string; const ADetails: string = '');
+ class procedure Error(const AMessage: string; const ADetails: string = '');
+ class procedure Exception(AException: Exception; const AMessage: string = ''; const ADetails: string = '');
+ end;
+
+
+implementation
+uses
+ X2Log;
+
+
+{ TX2GlobalLog }
+class function TX2GlobalLog.Instance: IX2Log;
+begin
+ if not Assigned(FInstance) then
+ FInstance := TX2Log.Create;
+
+ Result := FInstance;
+end;
+
+
+class procedure TX2GlobalLog.Attach(AObserver: IX2LogObserver);
+begin
+ Instance.Attach(AObserver);
+end;
+
+
+class procedure TX2GlobalLog.Detach(AObserver: IX2LogObserver);
+begin
+ instance.Detach(AObserver);
+end;
+
+
+class procedure TX2GlobalLog.SetExceptionStrategy(AStrategy: IX2LogExceptionStrategy);
+begin
+ Instance.SetExceptionStrategy(AStrategy);
+end;
+
+
+class procedure TX2GlobalLog.Log(ALevel: TX2LogLevel; const AMessage, ADetails: string);
+begin
+ Instance.Log(ALevel, AMessage, ADetails);
+end;
+
+
+class procedure TX2GlobalLog.Verbose(const AMessage, ADetails: string);
+begin
+ Instance.Verbose(AMessage, ADetails);
+end;
+
+
+class procedure TX2GlobalLog.Info(const AMessage, ADetails: string);
+begin
+ Instance.Info(AMessage, ADetails);
+end;
+
+
+class procedure TX2GlobalLog.Warning(const AMessage, ADetails: string);
+begin
+ Instance.Warning(AMessage, ADetails);
+end;
+
+
+class procedure TX2GlobalLog.Error(const AMessage, ADetails: string);
+begin
+ Instance.Error(AMessage, ADetails);
+end;
+
+
+class procedure TX2GlobalLog.Exception(AException: Exception; const AMessage, ADetails: string);
+begin
+ Instance.Exception(AException, AMessage, ADetails);
+end;
+
+end.
diff --git a/X2Log.Observer.MonitorForm.dfm b/X2Log.Observer.MonitorForm.dfm
new file mode 100644
index 0000000..994b316
--- /dev/null
+++ b/X2Log.Observer.MonitorForm.dfm
@@ -0,0 +1,16 @@
+object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
+ Left = 0
+ Top = 0
+ Caption = 'Log'
+ ClientHeight = 519
+ ClientWidth = 658
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ OldCreateOrder = False
+ PixelsPerInch = 96
+ TextHeight = 13
+end
diff --git a/X2Log.Observer.MonitorForm.pas b/X2Log.Observer.MonitorForm.pas
new file mode 100644
index 0000000..9167aac
--- /dev/null
+++ b/X2Log.Observer.MonitorForm.pas
@@ -0,0 +1,65 @@
+unit X2Log.Observer.MonitorForm;
+
+interface
+uses
+ Vcl.Controls,
+ Vcl.Forms,
+ Winapi.Messages,
+
+ X2Log.Intf;
+
+
+const
+ CM_REENABLE = WM_APP + 1;
+
+
+type
+ TX2LogObserverMonitorForm = class(TForm, IX2LogObserver)
+ protected
+ procedure CreateParams(var Params: TCreateParams); override;
+
+ procedure WMEnable(var Msg: TWMEnable); message WM_ENABLE;
+ procedure CMReenable(var Msg: TMessage); message CM_REENABLE;
+ public
+ { IX2LogObserver }
+ procedure Log(ALevel: TX2LogLevel; const AMessage: string; const ADetails: string = '');
+ end;
+
+
+implementation
+uses
+ Winapi.Windows;
+
+
+{$R *.dfm}
+
+
+{ TX2LogObserverMonitorForm }
+procedure TX2LogObserverMonitorForm.CreateParams(var Params: TCreateParams);
+begin
+ inherited CreateParams(Params);
+
+ Params.WndParent := 0;
+end;
+
+
+procedure TX2LogObserverMonitorForm.Log(ALevel: TX2LogLevel; const AMessage, ADetails: string);
+begin
+ //
+end;
+
+
+procedure TX2LogObserverMonitorForm.WMEnable(var Msg: TWMEnable);
+begin
+ if not Msg.Enabled then
+ { Modal forms disable all other forms, ensure we're still accessible }
+ PostMessage(Self.Handle, CM_REENABLE, 0, 0);
+end;
+
+
+procedure TX2LogObserverMonitorForm.CMReenable(var Msg: TMessage);
+begin
+ EnableWindow(Self.Handle, True);
+end;
+
+end.