From f32b44aa31908f523c079007486e5f8356a93c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Salvador=20D=C3=ADaz=20Fau?= Date: Tue, 26 Aug 2025 17:02:21 +0200 Subject: [PATCH] Fixed IME in GTK3 for Lazarus Only for browsers in OSR mode. --- source/uCEFBufferPanel.pas | 17 ++++- source/uceflinuxosrimehandler.pas | 106 ++++++++++++++++++++++-------- update_CEF4Delphi.json | 2 +- 3 files changed, 96 insertions(+), 29 deletions(-) diff --git a/source/uCEFBufferPanel.pas b/source/uCEFBufferPanel.pas index 8d00460a..759c429c 100644 --- a/source/uCEFBufferPanel.pas +++ b/source/uCEFBufferPanel.pas @@ -207,6 +207,12 @@ type /// function ConnectSignals: boolean; {$ENDIF} + {$IFDEF LCLGTK3} + /// + /// This is just a workaround for the missing implementation of SendMessage in GTK3. Don't use! + /// + procedure SendMessage(var aMessage : TMessage); + {$ENDIF} /// /// Returns the scanline size. @@ -675,6 +681,15 @@ begin end; {$ENDIF} +{$IFDEF LCLGTK3} +// This is just a workaround for the missing implementation of SendMessage in GTK3. +procedure TBufferPanel.SendMessage(var aMessage : TMessage); +begin + if (aMessage.Msg = LM_IM_COMPOSITION) and Focused then + WMIMEComposition(aMessage); +end; +{$ENDIF} + procedure TBufferPanel.CreateIMEHandler; begin {$IFDEF MSWINDOWS} @@ -1162,7 +1177,7 @@ procedure TBufferPanel.WMIMEComposition(var aMessage : TMessage); var TempText : ustring; TempCommit : string; -begin +begin case aMessage.WPARAM of GTK_IM_FLAG_START : if assigned(FOnIMEPreEditStart) then diff --git a/source/uceflinuxosrimehandler.pas b/source/uceflinuxosrimehandler.pas index 5c5de1e6..7e2539e0 100644 --- a/source/uceflinuxosrimehandler.pas +++ b/source/uceflinuxosrimehandler.pas @@ -25,11 +25,11 @@ type public constructor Create(aPanel : TCustomPanel); destructor Destroy; override; - procedure CreateContext; + function CreateContext : boolean; procedure DestroyContext; procedure SetClientWindow; procedure ResetClientWindow; - procedure ConnectSignals; + function ConnectSignals : boolean; procedure Focus; procedure Blur; procedure Reset; @@ -51,7 +51,29 @@ implementation uses {$IF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)}pango,{$ENDIF} {$IFDEF FPC}LCLType, LCLIntf, LMessages,{$ENDIF} - SysUtils; + {$IFDEF LCLGTK3}uCEFBufferPanel,{$ENDIF} + SysUtils, uCEFMiscFunctions; + +{$IFDEF LCLGTK3} +// This is just a workaround for the missing implementation of SendMessage in GTK3. +function SendMessage(HandleWnd: HWND; Msg: Cardinal; wParam: WParam; lParam: LParam): LResult; +var + LMessage : TLMessage; + LPanel : TBufferPanel; +begin + LMessage.Msg := Msg; + LMessage.WParam := WParam; + LMessage.LParam := LParam; + LMessage.Result := 0; + + LPanel := TBufferPanel(HandleWnd); + + if (LPanel <> nil) then + LPanel.SendMessage(LMessage); + + Result := LMessage.Result; +end; +{$ENDIF} {$IF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)} procedure gtk_commit_cb({%H-}context: PGtkIMContext; const Str: Pgchar; {%H-}Data: Pointer); cdecl; @@ -126,14 +148,19 @@ begin FForm := nil; end; -procedure TCEFLinuxOSRIMEHandler.CreateContext; +function TCEFLinuxOSRIMEHandler.CreateContext : boolean; begin + Result := False; {$IF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)} if not(assigned(FIMContext)) then begin FIMContext := gtk_im_multicontext_new(); - SetClientWindow; - ConnectSignals; + + if assigned(FIMContext) then + begin + SetClientWindow; + Result := ConnectSignals; + end; end; {$ENDIF} end; @@ -152,18 +179,18 @@ end; procedure TCEFLinuxOSRIMEHandler.SetClientWindow; {$IF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)} var - TempWidget : PGtkWidget; + TempWindow : PGdkWindow; {$ENDIF} begin if Initialized then begin {$IFDEF LCLGTK2} - TempWidget := PGtkWidget(FForm.Handle); - gtk_im_context_set_client_window(FIMContext, TempWidget^.window); + TempWindow := PGtkWidget(FForm.Handle)^.window; + gtk_im_context_set_client_window(FIMContext, TempWindow); {$ENDIF} {$IFDEF LCLGTK3} - TempWidget := TGtk3Widget(FForm.Handle).Widget; - gtk_im_context_set_client_window(FIMContext, TempWidget^.window); + TempWindow := TGtk3Widget(FForm.Handle).Widget^.window; + gtk_im_context_set_client_window(FIMContext, TempWindow); {$ENDIF} end; end; @@ -179,23 +206,48 @@ begin end; end; -procedure TCEFLinuxOSRIMEHandler.ConnectSignals; -begin - if Initialized then - begin - {$IFDEF LCLGTK3} - g_signal_connect_data(PGObject(@FIMContext), 'commit', TGCallback(@gtk_commit_cb), GPointer(FPanel.Handle), nil, G_CONNECT_DEFAULT); - g_signal_connect_data(PGObject(@FIMContext), 'preedit-start', TGCallback(@gtk_preedit_start_cb), GPointer(FPanel.Handle), nil, G_CONNECT_DEFAULT); - g_signal_connect_data(PGObject(@FIMContext), 'preedit-end', TGCallback(@gtk_preedit_end_cb), GPointer(FPanel.Handle), nil, G_CONNECT_DEFAULT); - g_signal_connect_data(PGObject(@FIMContext), 'preedit-changed', TGCallback(@gtk_preedit_changed_cb), GPointer(FPanel.Handle), nil, G_CONNECT_DEFAULT); - {$ENDIF} - {$IFDEF LCLGTK2} - g_signal_connect(G_OBJECT(FIMContext), 'commit', G_CALLBACK(@gtk_commit_cb), GPointer(FPanel.Handle)); - g_signal_connect(G_OBJECT(FIMContext), 'preedit-start', G_CALLBACK(@gtk_preedit_start_cb), GPointer(FPanel.Handle)); - g_signal_connect(G_OBJECT(FIMContext), 'preedit-end', G_CALLBACK(@gtk_preedit_end_cb), GPointer(FPanel.Handle)); - g_signal_connect(G_OBJECT(FIMContext), 'preedit-changed', G_CALLBACK(@gtk_preedit_changed_cb), GPointer(FPanel.Handle)); - {$ENDIF} +function TCEFLinuxOSRIMEHandler.ConnectSignals: boolean; +var + TempHandlerID1, TempHandlerID2, TempHandlerID3, TempHandlerID4 : gulong; + {$IF DEFINED(LCLGTK2) or DEFINED(LCLGTK3)} + TempData : GPointer; + {$ENDIF} +begin + TempHandlerID1 := 0; + TempHandlerID2 := 0; + TempHandlerID3 := 0; + TempHandlerID4 := 0; + + try + try + if Initialized then + begin + {$IFDEF LCLGTK3} + // This should be the data passed to the callback. We'll enable this line as soon as Lazarus implements SendMessage in GTK3. + //TempData := GPointer(TGtk3Widget(FPanel.Handle).Widget); + TempData := GPointer(FPanel); + + TempHandlerID1 := g_signal_connect_data(PGObject(FIMContext), 'commit', TGCallback(@gtk_commit_cb), TempData, nil, G_CONNECT_DEFAULT); + TempHandlerID2 := g_signal_connect_data(PGObject(FIMContext), 'preedit-start', TGCallback(@gtk_preedit_start_cb), TempData, nil, G_CONNECT_DEFAULT); + TempHandlerID3 := g_signal_connect_data(PGObject(FIMContext), 'preedit-end', TGCallback(@gtk_preedit_end_cb), TempData, nil, G_CONNECT_DEFAULT); + TempHandlerID4 := g_signal_connect_data(PGObject(FIMContext), 'preedit-changed', TGCallback(@gtk_preedit_changed_cb), TempData, nil, G_CONNECT_DEFAULT); + {$ENDIF} + {$IFDEF LCLGTK2} + TempData := GPointer(FPanel.Handle); + + TempHandlerID1 := g_signal_connect(G_OBJECT(FIMContext), 'commit', G_CALLBACK(@gtk_commit_cb), TempData); + TempHandlerID2 := g_signal_connect(G_OBJECT(FIMContext), 'preedit-start', G_CALLBACK(@gtk_preedit_start_cb), TempData); + TempHandlerID3 := g_signal_connect(G_OBJECT(FIMContext), 'preedit-end', G_CALLBACK(@gtk_preedit_end_cb), TempData); + TempHandlerID4 := g_signal_connect(G_OBJECT(FIMContext), 'preedit-changed', G_CALLBACK(@gtk_preedit_changed_cb), TempData); + {$ENDIF} + end; + except + on e : exception do + if CustomExceptionHandler('TCEFLinuxOSRIMEHandler.ConnectSignals', e) then raise; end; + finally + Result := (TempHandlerID1 > 0) and (TempHandlerID2 > 0) and (TempHandlerID3 > 0) and (TempHandlerID4 > 0); + end; end; procedure TCEFLinuxOSRIMEHandler.Focus; diff --git a/update_CEF4Delphi.json b/update_CEF4Delphi.json index 13534d52..05bc37fa 100644 --- a/update_CEF4Delphi.json +++ b/update_CEF4Delphi.json @@ -2,7 +2,7 @@ "UpdateLazPackages" : [ { "ForceNotify" : true, - "InternalVersion" : 772, + "InternalVersion" : 773, "Name" : "cef4delphi_lazarus.lpk", "Version" : "139.0.28" }