1{*************************************************************************** 2 GtkMsgQueue - Messagequeue for Gtk interface 3 -------------------------------------------- 4 5 Initial Revision : Thu Aug 16, 2003 6 7 8 ***************************************************************************/ 9 10 ***************************************************************************** 11 This file is part of the Lazarus Component Library (LCL) 12 13 See the file COPYING.modifiedLGPL.txt, included in this distribution, 14 for details about the license. 15 ***************************************************************************** 16} 17unit GtkMsgQueue; 18 19{$mode objfpc}{$H+} 20 21interface 22 23uses LazLinkedList, LCLType, LMessages, GtkGlobals, DynHashArray, GtkProc; 24 25type 26 TFinalPaintMessageFlag=(FPMF_None,FPMF_Internal,FPMF_All); 27 28 TGtkMessageQueueItem=class(TLinkListitem) 29 private 30 fMsg : PMsg; 31 public 32 property Msg: PMsg read fMsg write fMsg; 33 function IsPaintMessage: Boolean; 34 procedure DestroyMessage(ParFinalInternalOnly: TFinalPaintMessageFlag; 35 DisposeMessage: boolean); 36 constructor Create; 37 end; 38 39 { TGtkMessageQueue } 40 41 TGtkMessageQueue=class(TLinkList) 42 private 43 FPaintMessages: TDynHashArray; // Hash for paint messages 44 FCritSec: TRTLCriticalSection; 45 fLock: integer; 46 protected 47 function CreateItem : TLinkListItem;override; 48 function CalculateHash(ParWnd : Hwnd):integer; 49 function HashPaintMessage(p: pointer): integer; 50 public 51 constructor Create; 52 destructor destroy;override; 53 procedure Lock; 54 procedure UnLock; 55 function FirstMessageItem: TGtkMessageQueueItem; 56 function LastMessageItem: TGtkMessageQueueItem; 57 function FirstMessage: PMsg; 58 function LastMessage: PMsg; 59 procedure AddMessage(ParMsg: PMsg); 60 procedure RemoveMessage(ParItem: TGtkMessageQueueItem; 61 ParFinalOnlyInternal: TFinalPaintMessageFlag; 62 DisposeMessage: boolean); 63 function FindPaintMessage(HandleWnd: HWnd): TGtkMessageQueueItem; 64 function HasPaintMessages:boolean; 65 function HasNonPaintMessages:boolean; 66 function NumberOfPaintMessages:integer; 67 function PopFirstMessage: PMsg; 68 end; 69 70 71implementation 72 73{---(TGtkMessageQueueItem)----------------------} 74 75function TGtkMessageQueueItem.IsPaintMessage: Boolean; 76begin 77 if fMsg <> nil then 78 Result := (Msg^.Message = LM_PAINT) or (Msg^.Message = LM_GTKPAINT) 79 else 80 Result := False; 81end; 82 83constructor TGtkMessageQueueItem.Create; 84begin 85 inherited Create; 86 fMsg := nil; 87end; 88 89procedure TGtkMessageQueueItem.DestroyMessage( 90 ParFinalInternalOnly: TFinalPaintMessageFlag; DisposeMessage: boolean); 91begin 92 if (ParFinalInternalOnly in [FPMF_All, FPMF_Internal]) 93 and (fMsg^.message = LM_GTKPAINT) 94 then 95 FinalizePaintTagMsg(fMsg); 96 if DisposeMessage then 97 Dispose(fMsg); 98 fMsg := nil; 99end; 100 101{---(TGtkMessageQueue )---------------------------} 102 103constructor TGtkMessageQueue.Create; 104begin 105 inherited Create; 106 FPaintMessages := TDynHashArray.Create(-1); 107 FPaintMessages.OwnerHashFunction := @HashPaintMessage; 108 InitCriticalSection(FCritSec); 109end; 110 111destructor TGtkMessageQueue.destroy; 112begin 113 inherited Destroy; 114 fPaintMessages.destroy; 115 DoneCriticalsection(FCritSec); 116end; 117 118procedure TGtkMessageQueue.Lock; 119begin 120 inc(fLock); 121 if fLock=1 then 122 EnterCriticalsection(FCritSec); 123end; 124 125procedure TGtkMessageQueue.UnLock; 126begin 127 dec(fLock); 128 if fLock=0 then 129 LeaveCriticalsection(FCritSec); 130end; 131 132{------------------------------------------------------------------------------ 133 Function: FindPaintMessage 134 Params: a window handle 135 Returns: nil or a Paint Message to the widget 136 137 Searches in FPaintMessages for a LM_PAINT message with HandleWnd. 138 ------------------------------------------------------------------------------} 139function TGtkMessageQueue.FindPaintMessage(HandleWnd: HWnd): TGtkMessageQueueItem; 140var h: integer; 141 HashItem: PDynHashArrayItem; 142begin 143 h:= CalculateHash(HandleWnd); 144 HashItem:=FPaintMessages.GetHashItem(h); 145 if HashItem<>nil then begin 146 Result:=TGtkMessageQueueItem(HashItem^.Item); 147 if Result.Msg^.hWnd=HandleWnd then 148 exit; 149 HashItem:=HashItem^.Next; 150 while (HashItem<>nil) and (HashItem^.IsOverflow) do begin 151 152 Result:=TGtkMessageQueueItem(HashItem^.Item); 153 if Result.Msg^.hWnd=HandleWnd then 154 exit; 155 HashItem:=HashItem^.Next; 156 157 end; 158 end; 159 Result:=nil; 160end; 161 162 163function TGtkMessageQueue.HashPaintMessage(p: pointer): integer; 164begin 165 result := CalculateHash(TGtkMessageQueueItem(p).Msg^.Hwnd); 166end; 167 168function TGtkMessageQueue.CalculateHash(ParWnd : Hwnd):integer; 169var 170 h:integer; 171begin 172 h :=ParWnd; 173 if h<0 then h:=-h; 174 Result:=((h mod 5364329)+(h mod 17)) mod FPaintMessages.Capacity; 175end; 176 177function TGtkMessageQueue.CreateItem : TLinkListItem; 178begin 179 result := TGtkMessageQueueItem.Create; 180 result.ResetItem; 181end; 182 183procedure TGtkMessageQueue.AddMessage(ParMsg : PMsg); 184var 185 vLItem : TGtkMessageQueueItem; 186begin 187 vlItem := TGtkMessageQueueItem(GetNewItem); 188 vlItem.fMsg := ParMsg; 189 AddAsLast(vlItem); 190 if vlItem.IsPaintMessage then fPaintMessages.Add(vlitem); 191end; 192 193function TGtkMessageQueue.FirstMessageItem : TGtkMessageQueueItem; 194begin 195 Lock; 196 try 197 Result :=TGtkMessageQueueItem(First); 198 finally 199 UnLock; 200 end; 201end; 202 203function TGtkMessageQueue.FirstMessage : PMsg; 204begin 205 Result := nil; 206 Lock; 207 try 208 if FirstMessageItem <> nil then Result := FirstMessageItem.fMsg; 209 finally 210 UnLock; 211 end; 212end; 213 214function TGtkMessageQueue.LastMessageItem : TGtkMessageQueueItem; 215begin 216 Lock; 217 try 218 Result:=TGtkMessageQueueItem(Last); 219 finally 220 UnLock; 221 end; 222end; 223 224function TGtkMessageQueue.LastMessage : PMsg; 225begin 226 Lock; 227 try 228 Result := nil; 229 if LastMessageItem <> nil then result := LastMessageItem.fMsg; 230 finally 231 UnLock; 232 end; 233end; 234 235{ Remove from queue and destroy message 236 ParItem : Queue Item for removel 237 ParFinalOnlyInterl : finalyze message only for LM_GtkPaint } 238procedure TGtkMessageQueue.RemoveMessage(ParItem: TGtkMessageQueueItem; 239 ParFinalOnlyInternal: TFinalPaintMessageFlag; DisposeMessage: boolean); 240begin 241 Lock; 242 try 243 if (ParItem.IsPaintMessage) then 244 fPaintMessages.Remove(ParItem); 245 ParItem.DestroyMessage(ParFinalOnlyInternal, DisposeMessage); 246 Delete(ParItem); 247 finally 248 UnLock; 249 end; 250end; 251 252function TGtkMessageQueue.HasPaintMessages:boolean; 253begin 254 Lock; 255 try 256 Result := fPaintMessages.Count > 0; 257 finally 258 UnLock; 259 end; 260end; 261 262function TGtkMessageQueue.NumberOfPaintMessages:integer; 263begin 264 Lock; 265 try 266 Result := fPaintMessages.Count; 267 finally 268 UnLock; 269 end; 270end; 271 272function TGtkMessageQueue.HasNonPaintMessages:boolean; 273begin 274 Lock; 275 try 276 Result := fPaintMessages.Count <> count; 277 finally 278 UnLock; 279 end; 280end; 281 282function TGtkMessageQueue.PopFirstMessage: PMsg; 283var 284 vlItem : TGtkMessageQueueItem; 285begin 286 Lock; 287 try 288 vlItem := FirstMessageItem; 289 Result := vlItem.Msg; 290 RemoveMessage(vlItem,FPMF_none,false); 291 finally 292 UnLock; 293 end; 294end; 295 296end. 297 298