mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-17 17:39:20 +02:00
Gtk2: changed the way how main event loop iterates BUT ONLY VIA -dUSE_GTK_MAIN_CONTEXT_ITERATION until it's stable enough.
Now PostMessage() work correct when messages arrives from other threads. fixes #17548 and probably more issues with gtk2 threads usage. git-svn-id: trunk@27829 -
This commit is contained in:
parent
293f373040
commit
1c4a0cc726
@ -68,6 +68,9 @@ type
|
||||
|
||||
TGtk2WidgetSet = class(TWidgetSet)
|
||||
private
|
||||
{$IFDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
FMainPoll: PGPollFD;
|
||||
{$ENDIF}
|
||||
FMultiThreadingEnabled: boolean;
|
||||
FocusTimer: cardinal;
|
||||
FLastFocusIn: PGtkWidget;
|
||||
|
@ -26,7 +26,11 @@ unit Gtk2MsgQueue;
|
||||
|
||||
interface
|
||||
|
||||
uses LazLinkedList, LCLType, LMessages, Gtk2Globals, DynHashArray, Gtk2Proc;
|
||||
uses LazLinkedList, LCLType, LMessages, Gtk2Globals, DynHashArray, Gtk2Proc
|
||||
{$IFDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
, glib2
|
||||
{$ENDIF}
|
||||
;
|
||||
|
||||
type
|
||||
TFinalPaintMessageFlag=(FPMF_None,FPMF_Internal,FPMF_All);
|
||||
@ -47,7 +51,11 @@ type
|
||||
TGtkMessageQueue=class(TLinkList)
|
||||
private
|
||||
FPaintMessages: TDynHashArray; // Hash for paint messages
|
||||
{$IFDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
FMainContext: PGMainContext;
|
||||
{$ELSE}
|
||||
FCritSec: TRTLCriticalSection;
|
||||
{$ENDIF}
|
||||
fLock: integer;
|
||||
protected
|
||||
function CreateItem : TLinkListItem;override;
|
||||
@ -71,6 +79,9 @@ type
|
||||
function HasNonPaintMessages:boolean;
|
||||
function NumberOfPaintMessages:integer;
|
||||
function PopFirstMessage: PMsg;
|
||||
{$IFDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
property MainContext: PGMainContext read FMainContext;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
|
||||
@ -111,28 +122,46 @@ begin
|
||||
inherited Create;
|
||||
FPaintMessages := TDynHashArray.Create(-1);
|
||||
FPaintMessages.OwnerHashFunction := @HashPaintMessage;
|
||||
{$IFNDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
InitCriticalSection(FCritSec);
|
||||
{$ELSE}
|
||||
FMainContext := g_main_context_new;
|
||||
g_main_context_ref(FMainContext);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
destructor TGtkMessageQueue.destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
fPaintMessages.destroy;
|
||||
{$IFNDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
DoneCriticalsection(FCritSec);
|
||||
{$ELSE}
|
||||
g_main_context_unref(FMainContext);
|
||||
FMainContext := nil;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TGtkMessageQueue.Lock;
|
||||
begin
|
||||
inc(fLock);
|
||||
if fLock=1 then
|
||||
{$IFNDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
EnterCriticalsection(FCritSec);
|
||||
{$ELSE}
|
||||
g_main_context_acquire(FMainContext);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TGtkMessageQueue.UnLock;
|
||||
begin
|
||||
dec(fLock);
|
||||
if fLock=0 then
|
||||
{$IFNDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
LeaveCriticalsection(FCritSec);
|
||||
{$ELSE}
|
||||
g_main_context_release(FMainContext);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
{------------------------------------------------------------------------------
|
||||
@ -292,8 +321,12 @@ begin
|
||||
Lock;
|
||||
try
|
||||
vlItem := FirstMessageItem;
|
||||
Result := vlItem.Msg;
|
||||
RemoveMessage(vlItem,FPMF_none,false);
|
||||
if vlItem <> nil then
|
||||
begin
|
||||
Result := vlItem.Msg;
|
||||
RemoveMessage(vlItem,FPMF_none,false);
|
||||
end else
|
||||
Result := nil;
|
||||
finally
|
||||
UnLock;
|
||||
end;
|
||||
|
@ -23,6 +23,37 @@
|
||||
// {$DEFINE ASSERT_IS_ON}
|
||||
{$ENDIF}
|
||||
|
||||
{$IFDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
var
|
||||
Gtk2MPF: TGPollFunc;
|
||||
|
||||
function Gtk2PollFunction(ufds:PGPollFD; nfsd:guint; timeout:gint):gint;cdecl;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
Result := nfsd;
|
||||
if TimeOut = -1 then
|
||||
Gtk2WidgetSet.FMainPoll := ufds
|
||||
else
|
||||
Gtk2WidgetSet.FMainPoll := nil;
|
||||
if Gtk2MPF <> nil then
|
||||
begin
|
||||
if (glib_major_version = 2) and (glib_minor_version < 24) and
|
||||
(Gtk2WidgetSet.FMainPoll <> nil) then
|
||||
begin
|
||||
while (Gtk2WidgetSet.FMainPoll <> nil) and
|
||||
(Gtk2WidgetSet.FMainPoll^.revents = 0) do
|
||||
begin
|
||||
Gtk2MPF(ufds, nfsd, 1);
|
||||
if Gtk2WidgetSet.FMessageQueue.Count > 0 then
|
||||
break;
|
||||
end;
|
||||
end else
|
||||
Gtk2MPF(ufds, nfsd, timeout);
|
||||
end;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function GTK2FocusCB( widget: PGtkWidget; event:PGdkEventFocus;
|
||||
data: gPointer) : GBoolean; cdecl;
|
||||
var
|
||||
@ -1076,6 +1107,11 @@ constructor TGtk2WidgetSet.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
Gtk1Create;
|
||||
{$IFDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
FMainPoll := nil;
|
||||
Gtk2MPF := g_main_context_get_poll_func(g_main_context_default);
|
||||
g_main_context_set_poll_func(g_main_context_default, @Gtk2PollFunction);
|
||||
{$ENDIF}
|
||||
StayOnTopList := nil;
|
||||
im_context:=gtk_im_multicontext_new;
|
||||
g_signal_connect (G_OBJECT (im_context), 'commit',
|
||||
@ -2342,7 +2378,12 @@ procedure TGtk2WidgetSet.AppProcessMessages;
|
||||
|
||||
function PendingGtkMessagesExists: boolean;
|
||||
begin
|
||||
{$IFNDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
Result:=(gtk_events_pending<>0) or LCLtoGtkMessagePending;
|
||||
{$ELSE}
|
||||
Result := g_main_context_pending(g_main_context_default) or
|
||||
LCLtoGtkMessagePending;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
var
|
||||
@ -2357,10 +2398,20 @@ begin
|
||||
|
||||
// let gtk handle up to 100 messages and call our callbacks
|
||||
i:=100;
|
||||
while (gtk_events_pending<>0) and (i>0) do begin
|
||||
|
||||
{$IFNDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
while (gtk_events_pending<>0) and (i>0) do
|
||||
begin
|
||||
gtk_main_iteration_do(False);
|
||||
dec(i);
|
||||
end;
|
||||
{$ELSE}
|
||||
while g_main_context_pending(g_main_context_default) and (i>0) do
|
||||
begin
|
||||
g_main_context_iteration(g_main_context_default, False);
|
||||
dec(i);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
//DebugLn(['TGtk2WidgetSet.AppProcessMessages SendCachedGtkMessages']);
|
||||
// send cached gtk messages to the lcl
|
||||
@ -2404,10 +2455,13 @@ begin
|
||||
|
||||
//debugln(['TGtk2WidgetSet.AppProcessMessages ',vlMsg^.Message,' ',LM_CHAR,' ',dbgsname(GetLCLObject(Pointer(vlMsg^.hwnd)))]);
|
||||
// Send message
|
||||
try
|
||||
with vlMsg^ do SendMessage(hWND, Message, WParam, LParam);
|
||||
finally
|
||||
Dispose(vlMsg);
|
||||
if vlMsg <> nil then
|
||||
begin
|
||||
try
|
||||
with vlMsg^ do SendMessage(hWND, Message, WParam, LParam);
|
||||
finally
|
||||
Dispose(vlMsg);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -2425,11 +2479,14 @@ end;
|
||||
procedure TGtk2WidgetSet.AppWaitMessage;
|
||||
begin
|
||||
WaitingForMessages:=true;
|
||||
{$IFNDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
gtk_main_iteration_do(True);
|
||||
{$ELSE}
|
||||
g_main_context_iteration(g_main_context_default, True);
|
||||
{$ENDIF}
|
||||
WaitingForMessages:=false;
|
||||
end;
|
||||
|
||||
|
||||
procedure TGtk2WidgetSet.FreeStockItems;
|
||||
|
||||
procedure DeleteAndNilObject(var h: HGDIOBJ);
|
||||
|
@ -6799,7 +6799,7 @@ begin
|
||||
AMessage^.WParam := WParam;
|
||||
AMessage^.LParam := LParam;
|
||||
|
||||
fMessageQueue.Lock;
|
||||
FMessageQueue.Lock;
|
||||
try
|
||||
if (AMessage^.Message = LM_PAINT) or (AMessage^.Message = LM_GTKPAINT) then
|
||||
begin
|
||||
@ -6822,6 +6822,7 @@ begin
|
||||
|
||||
FMessageQueue.AddMessage(AMessage);
|
||||
|
||||
{$IFNDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
if GetCurrentThreadId <> MainThreadID then
|
||||
begin
|
||||
// awake gtk loop
|
||||
@ -6839,9 +6840,21 @@ begin
|
||||
DebugLn(['TGtk2WidgetSet.PostMessage ToDo: wake up gtk']);
|
||||
{$ENDIF}
|
||||
end;
|
||||
{$ENDIF}
|
||||
finally
|
||||
fMessageQueue.UnLock;
|
||||
FMessageQueue.UnLock;
|
||||
end;
|
||||
|
||||
{$IFDEF USE_GTK_MAIN_CONTEXT_ITERATION}
|
||||
if GetCurrentThreadId <> MainThreadID then
|
||||
begin
|
||||
// old glib versions needs another way to wake up.
|
||||
if (glib_major_version = 2) and
|
||||
(glib_minor_version < 24) and (FMainPoll <> nil) then
|
||||
FMainPoll^.revents := 1;
|
||||
g_main_context_wakeup(g_main_context_default);
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
{------------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user