mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-10-31 09:21:43 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			298 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			298 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {***************************************************************************
 | |
|                   GtkMsgQueue - Messagequeue for Gtk interface
 | |
|                   --------------------------------------------
 | |
| 
 | |
|                    Initial Revision  : Thu Aug 16, 2003
 | |
| 
 | |
| 
 | |
|  ***************************************************************************/
 | |
| 
 | |
|  *****************************************************************************
 | |
|   This file is part of the Lazarus Component Library (LCL)
 | |
| 
 | |
|   See the file COPYING.modifiedLGPL.txt, included in this distribution,
 | |
|   for details about the license.
 | |
|  *****************************************************************************
 | |
| }
 | |
| unit GtkMsgQueue;
 | |
| 
 | |
| {$mode objfpc}{$H+}
 | |
| 
 | |
| interface
 | |
| 
 | |
| uses LazLinkedList, LCLType, LMessages, GtkGlobals, DynHashArray, GtkProc;
 | |
| 
 | |
| type
 | |
|   TFinalPaintMessageFlag=(FPMF_None,FPMF_Internal,FPMF_All);
 | |
| 
 | |
|   TGtkMessageQueueItem=class(TLinkListitem)
 | |
|   private
 | |
|     fMsg : PMsg;
 | |
|   public
 | |
|     property Msg: PMsg read fMsg write fMsg;
 | |
|     function IsPaintMessage: Boolean;
 | |
|     procedure DestroyMessage(ParFinalInternalOnly: TFinalPaintMessageFlag;
 | |
|                              DisposeMessage: boolean);
 | |
|     constructor Create;
 | |
|   end;
 | |
| 
 | |
|   { TGtkMessageQueue }
 | |
| 
 | |
|   TGtkMessageQueue=class(TLinkList)
 | |
|   private
 | |
|     FPaintMessages: TDynHashArray; // Hash for paint messages
 | |
|     FCritSec: TRTLCriticalSection;
 | |
|     fLock: integer;
 | |
|   protected
 | |
|     function CreateItem : TLinkListItem;override;
 | |
|     function CalculateHash(ParWnd : Hwnd):integer;
 | |
|     function HashPaintMessage(p: pointer): integer;
 | |
|   public
 | |
|     constructor Create;
 | |
|     destructor destroy;override;
 | |
|     procedure  Lock;
 | |
|     procedure  UnLock;
 | |
|     function   FirstMessageItem: TGtkMessageQueueItem;
 | |
|     function   LastMessageItem: TGtkMessageQueueItem;
 | |
|     function   FirstMessage: PMsg;
 | |
|     function   LastMessage: PMsg;
 | |
|     procedure  AddMessage(ParMsg: PMsg);
 | |
|     procedure  RemoveMessage(ParItem: TGtkMessageQueueItem;
 | |
|                              ParFinalOnlyInternal: TFinalPaintMessageFlag;
 | |
|                              DisposeMessage: boolean);
 | |
|     function   FindPaintMessage(HandleWnd: HWnd): TGtkMessageQueueItem;
 | |
|     function   HasPaintMessages:boolean;
 | |
|     function   HasNonPaintMessages:boolean;
 | |
|     function   NumberOfPaintMessages:integer;
 | |
|     function   PopFirstMessage: PMsg;
 | |
|   end;
 | |
| 
 | |
| 
 | |
| implementation
 | |
| 
 | |
| {---(TGtkMessageQueueItem)----------------------}
 | |
| 
 | |
| function TGtkMessageQueueItem.IsPaintMessage: Boolean;
 | |
| begin
 | |
|   if fMsg <> nil then
 | |
|     Result := (Msg^.Message = LM_PAINT) or (Msg^.Message = LM_GTKPAINT)
 | |
|   else
 | |
|     Result := False;
 | |
| end;
 | |
| 
 | |
| constructor TGtkMessageQueueItem.Create;
 | |
| begin
 | |
|   inherited Create;
 | |
|   fMsg := nil;
 | |
| end;
 | |
| 
 | |
| procedure TGtkMessageQueueItem.DestroyMessage(
 | |
|   ParFinalInternalOnly: TFinalPaintMessageFlag; DisposeMessage: boolean);
 | |
| begin
 | |
|   if (ParFinalInternalOnly in [FPMF_All, FPMF_Internal])
 | |
|   and (fMsg^.message = LM_GTKPAINT)
 | |
|   then
 | |
|     FinalizePaintTagMsg(fMsg);
 | |
|   if DisposeMessage then
 | |
|     Dispose(fMsg);
 | |
|   fMsg := nil;
 | |
| end;
 | |
| 
 | |
| {---(TGtkMessageQueue )---------------------------}
 | |
| 
 | |
| constructor TGtkMessageQueue.Create;
 | |
| begin
 | |
|   inherited Create;
 | |
|   FPaintMessages := TDynHashArray.Create(-1);
 | |
|   FPaintMessages.OwnerHashFunction := @HashPaintMessage;
 | |
|   InitCriticalSection(FCritSec);
 | |
| end;
 | |
| 
 | |
| destructor TGtkMessageQueue.destroy;
 | |
| begin
 | |
|   inherited Destroy;
 | |
|   fPaintMessages.destroy;
 | |
|   DoneCriticalsection(FCritSec);
 | |
| end;
 | |
| 
 | |
| procedure TGtkMessageQueue.Lock;
 | |
| begin
 | |
|   inc(fLock);
 | |
|   if fLock=1 then
 | |
|     EnterCriticalsection(FCritSec);
 | |
| end;
 | |
| 
 | |
| procedure TGtkMessageQueue.UnLock;
 | |
| begin
 | |
|   dec(fLock);
 | |
|   if fLock=0 then
 | |
|     LeaveCriticalsection(FCritSec);
 | |
| end;
 | |
| 
 | |
| {------------------------------------------------------------------------------
 | |
|   Function: FindPaintMessage
 | |
|   Params: a window handle
 | |
|   Returns: nil or a Paint Message to the widget
 | |
| 
 | |
|   Searches in FPaintMessages for a LM_PAINT message with HandleWnd.
 | |
|  ------------------------------------------------------------------------------}
 | |
| function TGtkMessageQueue.FindPaintMessage(HandleWnd: HWnd): TGtkMessageQueueItem;
 | |
| var h: integer;
 | |
|   HashItem: PDynHashArrayItem;
 | |
| begin
 | |
|   h:= CalculateHash(HandleWnd);
 | |
|   HashItem:=FPaintMessages.GetHashItem(h);
 | |
|   if HashItem<>nil then begin
 | |
|     Result:=TGtkMessageQueueItem(HashItem^.Item);
 | |
|     if Result.Msg^.hWnd=HandleWnd then
 | |
|       exit;
 | |
|     HashItem:=HashItem^.Next;
 | |
|     while (HashItem<>nil) and (HashItem^.IsOverflow) do begin
 | |
| 
 | |
|       Result:=TGtkMessageQueueItem(HashItem^.Item);
 | |
|       if Result.Msg^.hWnd=HandleWnd then
 | |
|         exit;
 | |
|       HashItem:=HashItem^.Next;
 | |
| 
 | |
|     end;
 | |
|   end;
 | |
|   Result:=nil;
 | |
| end;
 | |
| 
 | |
| 
 | |
| function TGtkMessageQueue.HashPaintMessage(p: pointer): integer;
 | |
| begin
 | |
|   result := CalculateHash(TGtkMessageQueueItem(p).Msg^.Hwnd);
 | |
| end;
 | |
| 
 | |
| function TGtkMessageQueue.CalculateHash(ParWnd : Hwnd):integer;
 | |
| var
 | |
|   h:integer;
 | |
| begin
 | |
|   h :=ParWnd;
 | |
|   if h<0 then h:=-h;
 | |
|   Result:=((h mod 5364329)+(h mod 17)) mod FPaintMessages.Capacity;
 | |
| end;
 | |
| 
 | |
| function TGtkMessageQueue.CreateItem : TLinkListItem;
 | |
| begin
 | |
|   result := TGtkMessageQueueItem.Create;
 | |
|   result.ResetItem;
 | |
| end;
 | |
| 
 | |
| procedure TGtkMessageQueue.AddMessage(ParMsg : PMsg);
 | |
| var
 | |
|   vLItem : TGtkMessageQueueItem;
 | |
| begin
 | |
|   vlItem := TGtkMessageQueueItem(GetNewItem);
 | |
|   vlItem.fMsg := ParMsg;
 | |
|   AddAsLast(vlItem);
 | |
|   if vlItem.IsPaintMessage then fPaintMessages.Add(vlitem);
 | |
| end;
 | |
| 
 | |
| function TGtkMessageQueue.FirstMessageItem : TGtkMessageQueueItem;
 | |
| begin
 | |
|   Lock;
 | |
|   try
 | |
|     Result :=TGtkMessageQueueItem(First);
 | |
|   finally
 | |
|     UnLock;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TGtkMessageQueue.FirstMessage : PMsg;
 | |
| begin
 | |
|   Result := nil;
 | |
|   Lock;
 | |
|   try
 | |
|     if FirstMessageItem <> nil then  Result := FirstMessageItem.fMsg;
 | |
|   finally
 | |
|     UnLock;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TGtkMessageQueue.LastMessageItem : TGtkMessageQueueItem;
 | |
| begin
 | |
|   Lock;
 | |
|   try
 | |
|     Result:=TGtkMessageQueueItem(Last);
 | |
|   finally
 | |
|     UnLock;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TGtkMessageQueue.LastMessage : PMsg;
 | |
| begin
 | |
|   Lock;
 | |
|   try
 | |
|     Result := nil;
 | |
|     if LastMessageItem <> nil then   result := LastMessageItem.fMsg;
 | |
|   finally
 | |
|     UnLock;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| { Remove from queue and destroy message
 | |
|   ParItem         : Queue Item for removel
 | |
|   ParFinalOnlyInterl : finalyze message only for LM_GtkPaint }
 | |
| procedure  TGtkMessageQueue.RemoveMessage(ParItem: TGtkMessageQueueItem;
 | |
|   ParFinalOnlyInternal: TFinalPaintMessageFlag; DisposeMessage: boolean);
 | |
| begin
 | |
|   Lock;
 | |
|   try
 | |
|     if (ParItem.IsPaintMessage) then
 | |
|       fPaintMessages.Remove(ParItem);
 | |
|     ParItem.DestroyMessage(ParFinalOnlyInternal, DisposeMessage);
 | |
|     Delete(ParItem);
 | |
|   finally
 | |
|     UnLock;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TGtkMessageQueue.HasPaintMessages:boolean;
 | |
| begin
 | |
|   Lock;
 | |
|   try
 | |
|     Result := fPaintMessages.Count > 0;
 | |
|   finally
 | |
|     UnLock;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TGtkMessageQueue.NumberOfPaintMessages:integer;
 | |
| begin
 | |
|   Lock;
 | |
|   try
 | |
|     Result := fPaintMessages.Count;
 | |
|   finally
 | |
|     UnLock;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TGtkMessageQueue.HasNonPaintMessages:boolean;
 | |
| begin
 | |
|   Lock;
 | |
|   try
 | |
|     Result := fPaintMessages.Count <> count;
 | |
|   finally
 | |
|     UnLock;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TGtkMessageQueue.PopFirstMessage: PMsg;
 | |
| var
 | |
|   vlItem : TGtkMessageQueueItem;
 | |
| begin
 | |
|   Lock;
 | |
|   try
 | |
|     vlItem := FirstMessageItem;
 | |
|     Result := vlItem.Msg;
 | |
|     RemoveMessage(vlItem,FPMF_none,false);
 | |
|   finally
 | |
|     UnLock;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| end.
 | |
| 
 | 
