Files
lazarus-ccr/applications/cactusjukebox/source/MGSignals.pas
sekelsenmat 6f8c048343 Adds the cactus jukebox to the lazarus ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1748 8e941d3f-bd1b-0410-a28a-d453659cc2b4
2011-07-21 09:39:48 +00:00

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.