You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1748 8e941d3f-bd1b-0410-a28a-d453659cc2b4
500 lines
14 KiB
ObjectPascal
Executable File
500 lines
14 KiB
ObjectPascal
Executable File
//******************************************************************************
|
|
//*** COMMON DELPHI FUNCTIONS ***
|
|
//*** ***
|
|
//*** (c) Massimo Magnano 11-11-2004. ***
|
|
//*** ***
|
|
//*** ***
|
|
//******************************************************************************
|
|
//
|
|
// File : MGSignals.pas REV. 1.1 (22-06-2005)
|
|
//
|
|
// Description : Implementazione di un dispatcher di messaggi (svincolato dalla VCL)
|
|
// verso delle classi registrate.
|
|
// Implements a message dispatcher (disengaged from VCL)
|
|
// to registered classes.
|
|
//
|
|
//******************************************************************************
|
|
// WARNING -TO TEST IN ExtFind (compare of method is different under Lazarus?)
|
|
|
|
|
|
unit MGSignals;
|
|
{$mode delphi}{$H+}
|
|
|
|
interface
|
|
uses MGTree16, MGList,
|
|
{$ifdef WINDOWS}
|
|
Windows,
|
|
{$endif}
|
|
Messages, Forms, Classes;
|
|
|
|
Type
|
|
TSignalMethod = function (var aMessage: TMessage):Boolean of object;
|
|
//necessario xchè TSignalMethod è una coppia di puntatori...
|
|
//necessary because TSignalMethod is a pair of pointers
|
|
PSignalMethod =^TSignalMethod;
|
|
|
|
{ TMGSignalsManager }
|
|
|
|
TMGSignalsManager = class
|
|
protected
|
|
rClients : TMGTree16;
|
|
|
|
procedure FreeClassOnList(Tag :Integer; wMessageID :Integer; wMessageList :TObject);
|
|
procedure FreeLists(Tag :Integer; wMessageID :Integer; wMessageList :TObject);
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Connect(ClassMethod :TSignalMethod; MessageID :Integer);
|
|
procedure Disconnect(ClassMethod :TSignalMethod; MessageID :Integer); overload;
|
|
procedure Disconnect(ClassPointer :TObject); overload;
|
|
function Signal(MessageID :Cardinal; WParam, LParam :Integer; var Handled :Boolean) :Integer; overload;
|
|
function Signal(var aMessage: TMessage) :Boolean; overload;
|
|
end;
|
|
|
|
{ TMessagesList }
|
|
|
|
PMessage =^TMessage;
|
|
|
|
TMessagesList = class (TMGList)
|
|
protected
|
|
function allocData :Pointer; override;
|
|
procedure deallocData(pData :Pointer); override;
|
|
public
|
|
function Add(aMessage :TMessage) :PMessage; overload;
|
|
end;
|
|
|
|
{ TSignalsAsyncThread }
|
|
|
|
TSignalsAsyncThread = class(TThread)
|
|
private
|
|
curMsg :PMessage;
|
|
protected
|
|
msgSignals : TMGSignalsManager;
|
|
msgList : TMessagesList;
|
|
|
|
procedure _Signal;
|
|
procedure Execute; override;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Connect(ClassMethod :TSignalMethod; MessageID :Integer; Priority :Integer=0); //Priority for future use
|
|
procedure Disconnect(ClassMethod :TSignalMethod; MessageID :Integer); overload;
|
|
procedure Disconnect(ClassPointer :TObject); overload;
|
|
procedure Signal(MessageID :Cardinal; WParam, LParam :Integer); overload;
|
|
procedure Signal(aMessage: TMessage); overload;
|
|
end;
|
|
|
|
{ TMGSignals }
|
|
|
|
TMGSignals = class
|
|
protected
|
|
signals_async :TSignalsAsyncThread;
|
|
signals_sync :TMGSignalsManager;
|
|
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Connect(ClassMethod :TSignalMethod; MessageID :Integer);
|
|
procedure Disconnect(ClassMethod :TSignalMethod; MessageID :Integer); overload;
|
|
procedure Disconnect(ClassPointer :TObject); overload;
|
|
procedure ConnectAsync(ClassMethod :TSignalMethod; MessageID :Integer; Priority :Integer=0); //Priority for future use
|
|
procedure DisconnectAsync(ClassMethod :TSignalMethod; MessageID :Integer); overload;
|
|
procedure DisconnectAsync(ClassPointer :TObject); overload;
|
|
function Signal(MessageID :Cardinal; WParam, LParam :Integer; var Handled :Boolean) :Integer; overload;
|
|
function Signal(var aMessage: TMessage) :Boolean; overload;
|
|
end;
|
|
|
|
implementation
|
|
|
|
Type
|
|
TSignalMethodsList = class (TMGList)
|
|
protected
|
|
function allocData :Pointer; override;
|
|
procedure deallocData(pData :Pointer); override;
|
|
function CompBySignalMethod(xTag :Pointer; ptData1, ptData2 :Pointer) :Boolean;
|
|
public
|
|
function Add(AMethod :TSignalMethod) :PSignalMethod; overload;
|
|
function Find(AMethod :TSignalMethod) : Integer; overload;
|
|
function ExtFind(AMethod :TSignalMethod) : Pointer; overload;
|
|
function Delete(AMethod :TSignalMethod) :Boolean; overload;
|
|
function DeleteByClassMethod(AMethod :TSignalMethod) :Boolean;
|
|
procedure DeleteByClass(ClassPointer :TObject);
|
|
function CallAllMethods(var aMessage: TMessage) :Boolean;
|
|
end;
|
|
|
|
|
|
|
|
{ TMessagesList }
|
|
|
|
function TMessagesList.allocData: Pointer;
|
|
begin
|
|
GetMem(Result, sizeOf(TSignalMethod));
|
|
end;
|
|
|
|
procedure TMessagesList.deallocData(pData: Pointer);
|
|
begin
|
|
FreeMem(pData, sizeOf(TSignalMethod));
|
|
end;
|
|
|
|
function TMessagesList.Add(aMessage: TMessage): PMessage;
|
|
begin
|
|
Result :=Add;
|
|
Result^ :=aMessage;
|
|
end;
|
|
|
|
|
|
{ TSignalsAsyncThread }
|
|
|
|
procedure TSignalsAsyncThread._Signal;
|
|
begin
|
|
Self.msgSignals.Signal(curMsg^);
|
|
end;
|
|
|
|
procedure TSignalsAsyncThread.Execute;
|
|
begin
|
|
//Get the Message from the First Position (Head)
|
|
curMsg :=msgList.GetFirst;
|
|
while (curMsg<>Nil) do
|
|
begin
|
|
//Process the Message
|
|
//maxm: For Future use may be 3 msgSignals owned by priority
|
|
Synchronize(_Signal);
|
|
|
|
msgList.DeleteFirst;
|
|
curMsg :=msgList.GetFirst;
|
|
end;
|
|
end;
|
|
|
|
constructor TSignalsAsyncThread.Create;
|
|
begin
|
|
inherited Create(true);
|
|
msgList :=TMessagesList.Create;
|
|
end;
|
|
|
|
destructor TSignalsAsyncThread.Destroy;
|
|
begin
|
|
msgList.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSignalsAsyncThread.Connect(ClassMethod: TSignalMethod; MessageID: Integer; Priority :Integer=0);
|
|
begin
|
|
Self.msgSignals.Connect(ClassMethod, MessageID);
|
|
end;
|
|
|
|
procedure TSignalsAsyncThread.Disconnect(ClassMethod: TSignalMethod; MessageID: Integer);
|
|
begin
|
|
Self.msgSignals.Disconnect(ClassMethod, MessageID);
|
|
end;
|
|
|
|
procedure TSignalsAsyncThread.Disconnect(ClassPointer: TObject);
|
|
begin
|
|
Self.msgSignals.Disconnect(ClassPointer);
|
|
end;
|
|
|
|
procedure TSignalsAsyncThread.Signal(MessageID: Cardinal; WParam, LParam: Integer);
|
|
Var
|
|
aMessage :TMessage;
|
|
|
|
begin
|
|
aMessage.Msg :=MessageID;
|
|
aMessage.WParam :=WParam;
|
|
aMessage.LParam :=LParam;
|
|
Signal(aMessage);
|
|
end;
|
|
|
|
procedure TSignalsAsyncThread.Signal(aMessage: TMessage);
|
|
begin
|
|
//Add the Message to Last Position (Tail)
|
|
msgList.Add(aMessage);
|
|
//Wakeup
|
|
Self.Resume;
|
|
end;
|
|
|
|
|
|
// =============================================================================
|
|
|
|
function TSignalMethodsList.allocData :Pointer;
|
|
begin
|
|
GetMem(Result, sizeOf(TSignalMethod));
|
|
end;
|
|
|
|
procedure TSignalMethodsList.deallocData(pData :Pointer);
|
|
begin
|
|
FreeMem(pData, sizeOf(TSignalMethod));
|
|
end;
|
|
|
|
function TSignalMethodsList.CompBySignalMethod(xTag :Pointer; ptData1, ptData2 :Pointer) :Boolean;
|
|
Var
|
|
m1,
|
|
m2 :TSignalMethod;
|
|
Message1: TMessage;
|
|
|
|
begin
|
|
m1 :=PSignalMethod(ptData1)^;
|
|
m2 :=PSignalMethod(ptData2)^;
|
|
|
|
Result := (TMethod(m1).Data = TMethod(m2).Data) and //Stessa Classe (Instanza) Same Instance
|
|
(TMethod(m1).Code = TMethod(m2).Code); //Stesso Metodo Same Method
|
|
|
|
|
|
//(@m1 = @m2); dovrebbe essere così, ma un metodo di due classi
|
|
//dello stesso tipo viene sempre considerato uguale...
|
|
//EN
|
|
//(@m1 = @m2); should be so, but a method of the same class type
|
|
//is always considered the same...
|
|
//esempio (example):
|
|
// Classe1, Classe2 :TForm;
|
|
// Classe1.func = Classe2.func because
|
|
// TForm.func = TForm.func but Classe1 is not the same of Class2
|
|
end;
|
|
|
|
function TSignalMethodsList.Add(AMethod :TSignalMethod) :PSignalMethod;
|
|
begin
|
|
Result :=ExtFind(AMethod);
|
|
if (Result=Nil)
|
|
then begin
|
|
Result :=Add;
|
|
Result^ :=AMethod;
|
|
end;
|
|
end;
|
|
|
|
function TSignalMethodsList.Find(AMethod :TSignalMethod) : Integer;
|
|
Var
|
|
auxPointer :PSignalMethod;
|
|
|
|
begin
|
|
GetMem(auxPointer, sizeOf(TSignalMethod));
|
|
auxPointer^ :=AMethod;
|
|
Result :=Find(auxPointer, 0, CompBySignalMethod);
|
|
FreeMem(auxPointer);
|
|
end;
|
|
|
|
function TSignalMethodsList.ExtFind(AMethod :TSignalMethod) : Pointer;
|
|
Var
|
|
auxPointer :PSignalMethod;
|
|
|
|
begin
|
|
GetMem(auxPointer, sizeOf(TSignalMethod));
|
|
auxPointer^ :=AMethod;
|
|
Result :=ExtFind(auxPointer, 0, CompBySignalMethod);
|
|
FreeMem(auxPointer);
|
|
end;
|
|
|
|
|
|
function TSignalMethodsList.Delete(AMethod :TSignalMethod) :Boolean;
|
|
begin
|
|
Result :=DeleteByClassMethod(AMethod);
|
|
end;
|
|
|
|
function TSignalMethodsList.DeleteByClassMethod(AMethod :TSignalMethod) :Boolean;
|
|
Var
|
|
auxPointer :PSignalMethod;
|
|
|
|
begin
|
|
GetMem(auxPointer, sizeOf(TSignalMethod));
|
|
auxPointer^ :=AMethod;
|
|
Result :=Delete(auxPointer, 0, CompBySignalMethod);
|
|
FreeMem(auxPointer);
|
|
end;
|
|
|
|
procedure TSignalMethodsList.DeleteByClass(ClassPointer :TObject);
|
|
Var
|
|
Pt :PSignalMethod;
|
|
|
|
begin
|
|
Pt :=FindFirst;
|
|
while (Pt<>Nil) do
|
|
begin
|
|
if (TMethod(Pt^).Data = ClassPointer)
|
|
then DeleteCurrent;
|
|
|
|
Pt :=FindNext;
|
|
end;
|
|
FindClose;
|
|
end;
|
|
|
|
function TSignalMethodsList.CallAllMethods(var aMessage: TMessage) :Boolean;
|
|
Var
|
|
Pt :PSignalMethod;
|
|
|
|
begin
|
|
Result :=False;
|
|
|
|
Pt :=FindFirst;
|
|
while (Pt<>Nil) do
|
|
begin
|
|
if Assigned(Pt^)
|
|
then Result :=Pt^(aMessage)
|
|
else Result :=False;
|
|
|
|
if Result
|
|
then Pt :=FindNext
|
|
else Pt :=Nil;
|
|
end;
|
|
FindClose;
|
|
end;
|
|
|
|
|
|
// =============================================================================
|
|
|
|
constructor TMGSignalsManager.Create;
|
|
begin
|
|
inherited Create;
|
|
rClients :=TMGTree16.Create;
|
|
end;
|
|
|
|
|
|
procedure TMGSignalsManager.FreeLists(Tag :Integer; wMessageID :Integer; wMessageList :TObject);
|
|
begin
|
|
if (wMessageList<>Nil)
|
|
then TSignalMethodsList(wMessageList).Free;
|
|
end;
|
|
|
|
destructor TMGSignalsManager.Destroy;
|
|
begin
|
|
rClients.Clear(0, FreeLists);
|
|
rClients.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
|
|
procedure TMGSignalsManager.Connect(ClassMethod :TSignalMethod; MessageID :Integer);
|
|
Var
|
|
TreeData :PMGTree16Data;
|
|
theList :TSignalMethodsList;
|
|
|
|
begin
|
|
TreeData :=rClients.Add(MessageID);
|
|
if (TreeData<>Nil) then
|
|
begin
|
|
theList :=TSignalMethodsList(TreeData^.UData);
|
|
if (theList=nil) //La Lista non esiste...
|
|
then begin
|
|
theList :=TSignalMethodsList.Create;
|
|
TreeData^.UData :=theList;
|
|
end;
|
|
theList.Add(ClassMethod);
|
|
end;
|
|
end;
|
|
|
|
procedure TMGSignalsManager.Disconnect(ClassMethod :TSignalMethod; MessageID :Integer);
|
|
Var
|
|
uMessageID :Integer;
|
|
uMessageList :TObject;
|
|
|
|
begin
|
|
if Assigned(ClassMethod) then
|
|
begin
|
|
if rClients.Find(MessageID, uMessageID, uMessageList)
|
|
then if (uMessageList<>Nil)
|
|
then begin
|
|
TSignalMethodsList(uMessageList).DeleteByClassMethod(ClassMethod);
|
|
if (TSignalMethodsList(uMessageList).Count=0)
|
|
then rClients.Del(MessageID);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMGSignalsManager.FreeClassOnList(Tag :Integer; wMessageID :Integer; wMessageList :TObject);
|
|
Var
|
|
ClassPointer :TObject;
|
|
|
|
begin
|
|
ClassPointer :=TObject(Tag);
|
|
if (ClassPointer<>Nil) and (wMessageList<>Nil) then
|
|
begin
|
|
TSignalMethodsList(wMessageList).DeleteByClass(ClassPointer);
|
|
end;
|
|
end;
|
|
|
|
procedure TMGSignalsManager.Disconnect(ClassPointer :TObject);
|
|
begin
|
|
rClients.WalkOnTree(Integer(ClassPointer), FreeClassOnList);
|
|
end;
|
|
|
|
function TMGSignalsManager.Signal(MessageID :Cardinal; WParam, LParam :Integer; var Handled :Boolean) :Integer;
|
|
Var
|
|
aMessage :TMessage;
|
|
|
|
begin
|
|
aMessage.Msg :=MessageID;
|
|
aMessage.WParam :=WParam;
|
|
aMessage.LParam :=LParam;
|
|
Handled :=Signal(aMessage);
|
|
Result :=aMessage.Result;
|
|
end;
|
|
|
|
function TMGSignalsManager.Signal(var aMessage: TMessage):Boolean;
|
|
Var
|
|
uMessageID :Integer;
|
|
uMessageList :TObject;
|
|
|
|
begin
|
|
Result :=False;
|
|
|
|
if rClients.Find(aMessage.Msg, uMessageID, uMessageList)
|
|
then if (uMessageList<>Nil)
|
|
then Result :=TSignalMethodsList(uMessageList).CallAllMethods(aMessage);
|
|
end;
|
|
|
|
{ TMGSignals }
|
|
|
|
constructor TMGSignals.Create;
|
|
begin
|
|
signals_async :=TSignalsAsyncThread.Create;
|
|
signals_sync :=TMGSignalsManager.Create;
|
|
end;
|
|
|
|
destructor TMGSignals.Destroy;
|
|
begin
|
|
signals_async.Free;
|
|
signals_sync.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TMGSignals.Connect(ClassMethod: TSignalMethod; MessageID: Integer);
|
|
begin
|
|
signals_sync.Connect(ClassMethod, MessageID);
|
|
end;
|
|
|
|
procedure TMGSignals.Disconnect(ClassMethod: TSignalMethod; MessageID: Integer);
|
|
begin
|
|
signals_sync.Disconnect(ClassMethod, MessageID);
|
|
end;
|
|
|
|
procedure TMGSignals.Disconnect(ClassPointer: TObject);
|
|
begin
|
|
signals_sync.Disconnect(ClassPointer);
|
|
end;
|
|
|
|
procedure TMGSignals.ConnectAsync(ClassMethod: TSignalMethod; MessageID: Integer; Priority :Integer=0);
|
|
begin
|
|
signals_async.Connect(ClassMethod, MessageID, Priority);
|
|
end;
|
|
|
|
procedure TMGSignals.DisconnectAsync(ClassMethod: TSignalMethod; MessageID: Integer);
|
|
begin
|
|
signals_async.Disconnect(ClassMethod, MessageID);
|
|
end;
|
|
|
|
procedure TMGSignals.DisconnectAsync(ClassPointer: TObject);
|
|
begin
|
|
signals_async.Disconnect(ClassPointer);
|
|
end;
|
|
|
|
function TMGSignals.Signal(MessageID: Cardinal; WParam, LParam: Integer;
|
|
var Handled: Boolean): Integer;
|
|
begin
|
|
Result :=signals_sync.Signal(MessageID, WParam, LParam, Handled);
|
|
signals_async.Signal(MessageID, WParam, LParam);
|
|
end;
|
|
|
|
function TMGSignals.Signal(var aMessage: TMessage): Boolean;
|
|
begin
|
|
Result :=signals_sync.Signal(aMessage);
|
|
signals_async.Signal(aMessage);
|
|
end;
|
|
|
|
end.
|