gtk2 intf: using a gtk_im_multicontext_new to use the gtk input method handling - e.g. dead keys for UTF8KeyPress

git-svn-id: trunk@11687 -
This commit is contained in:
mattias 2007-07-31 13:49:36 +00:00
parent d707f64709
commit 95f4b69572
12 changed files with 140 additions and 68 deletions

View File

@ -319,7 +319,9 @@ begin
{$IFDEF EventTrace}
EventTrace('activate', data);
{$ENDIF}
ResetDefaultIMContext;
if LockOnChange(PgtkObject(Widget),0) > 0 then Exit;
FillChar(Mess,SizeOf(Mess),#0);
@ -595,6 +597,10 @@ begin
EventTrace('activate after', data);
{$ENDIF}
if (Widget=nil) or (Event=nil) then ;
ResetDefaultIMContext;
UpdateMouseCaptureControl;
FillChar(Mess,SizeOf(Mess),#0);
{$IFDEF VerboseFocus}
write('gtkfrmactivateAfter Widget=',DbgS(Widget),' Event^.theIn=',Event^.theIn);
@ -626,7 +632,6 @@ begin
DebugLn('');
{$ENDIF}
UpdateMouseCaptureControl;
Mess.Msg := LM_ACTIVATE;
Mess.Active:=true;
Mess.Minimized:=false;
@ -660,6 +665,7 @@ begin
else
DebugLn(' LCLObject=nil');
{$ENDIF}
ResetDefaultIMContext;
UpdateMouseCaptureControl;
Mess.Msg := LM_DEACTIVATE;
@ -785,7 +791,9 @@ begin
DebugLn('');
{$ENDIF}
ResetDefaultIMContext;
UpdateMouseCaptureControl;
//TODO: fill in old focus
FillChar(Mess,SizeOf(Mess),0);
Mess.msg := LM_SETFOCUS;
@ -884,6 +892,7 @@ begin
DebugLn('');
{$ENDIF}
ResetDefaultIMContext;
UpdateMouseCaptureControl;
FillChar(Mess,SizeOf(Mess),0);
@ -1516,6 +1525,7 @@ begin
EventTrace('Mouse button Press', data);
{$ENDIF}
ResetDefaultIMContext;
UpdateMouseCaptureControl;
if not (csDesigning in TComponent(Data).ComponentState) then begin
@ -1568,6 +1578,7 @@ begin
' ',dbgs(TruncToInt(Event^.X)),',',dbgs(TruncToInt(Event^.Y)));
{$ENDIF}
ResetDefaultIMContext;
UpdateMouseCaptureControl;
// stop the signal, so that it is not sent to the parent widgets
@ -1738,6 +1749,7 @@ begin
//' EventMask=',DbgS(gdk_window_get_events(Widget^.Window)),
//' GDK_BUTTON_RELEASE_MASK=',DbgS(GDK_BUTTON_RELEASE_MASK));
ResetDefaultIMContext;
UpdateMouseCaptureControl;
if not (csDesigning in TComponent(Data).ComponentState) then begin
@ -1783,6 +1795,7 @@ begin
// stop the signal, so that it is not sent to the parent widgets
g_signal_stop_emission_by_name(PGTKObject(Widget),'button-release-event');
ResetDefaultIMContext;
UpdateMouseCaptureControl;
if (csDesigning in TComponent(Data).ComponentState) then exit;
@ -2584,7 +2597,7 @@ begin
Mess.Msg := LM_NOTIFY;
FillChar(NMHdr,SizeOf(NMHdr),0);
NMHdr.code := TCN_SELCHANGING;
NMHdr.hwndfrom := PtrInt(widget);
NMHdr.hwndfrom := PtrUInt(widget);
NMHdr.idfrom := pagenum; //use this to set pageindex to the correct page.
Mess.NMHdr := @NMHdr;
Mess.Result := 0;
@ -2599,7 +2612,7 @@ begin
Mess.Msg := LM_NOTIFY;
FillChar(NMHdr,SizeOf(NMHdr),0);
NMHdr.code := TCN_SELCHANGE;
NMHdr.hwndfrom := ptrint(widget);
NMHdr.hwndfrom := PtrUInt(widget);
NMHdr.idfrom := pagenum; //use this to set pageindex to the correct page.
Mess.NMHdr := @NMHdr;
DeliverMessage(Data, Mess);

View File

@ -91,6 +91,15 @@ var
// Map a TCursor (<= 0 = HCursor) or a HCursor to a PGDKCursor
MMouseCursorMap: TMap;
{$IFDEF Gtk2}
var
im_context: PGtkIMContext = nil;
im_context_widget: PGtkWidget = nil;
im_context_string: string = '';
{$ENDIF}
procedure ResetDefaultIMContext;
var
LastFileSelectRow : gint;
@ -382,7 +391,7 @@ var
// each widget that should be to the LCL bounds is stored here
// (hasharray of PGtkWidget)
FWidgetsWithResizeRequest: TDynHashArray; // hasharray of PGtkWidget
const
aGtkJustification: array[TAlignment] of TGTKJustification =
(GTK_JUSTIFY_LEFT,GTK_JUSTIFY_RIGHT,GTK_JUSTIFY_CENTER);
@ -491,6 +500,18 @@ begin
CurrentSentPaintMessageTarget:=nil;
end;
procedure ResetDefaultIMContext;
begin
{$IFDEF Gtk2}
if (im_context<>nil) and (im_context_widget<>nil) then begin
gtk_im_context_reset(im_context);
gtk_im_context_set_client_window(im_context,nil);
end;
im_context_widget:=nil;
im_context_string:='';
{$ENDIF}
end;
procedure AddCharsetEncoding(CharSet: Byte; CharSetReg, CharSetCod: CharSetStr;
ToEnum:boolean=true; CrPart:boolean=false; CcPart:boolean=false);
var
@ -574,7 +595,6 @@ begin
AddCharsetEncoding(FCS_ISO_8859_9, 'iso8859', '9');
AddCharsetEncoding(FCS_ISO_8859_10, 'iso8859', '10');
AddCharsetEncoding(FCS_ISO_8859_15, 'iso8859', '15');
end;
initialization

View File

@ -1517,8 +1517,6 @@ end;
------------------------------------------------------------------------------}
procedure TGtkWidgetSet.AppInit(var ScreenInfo: TScreenInfo);
begin
// MG: TODO: call FillScreenFonts on demand, not for every application
//FillScreenFonts(Screen.Fonts);
InitKeyboardTables;
{ Compute pixels per inch variable }
ScreenInfo.PixelsPerInchX :=
@ -4854,7 +4852,6 @@ var
Box : Pointer; // currently only used for MainMenu
ParentForm: TCustomForm;
AWindow: PGdkWindow;
Adjustment: PGtkAdjustment;
LabelWidget: PGtkLabel;
begin
@ -5311,9 +5308,6 @@ var
Decor, Func : Longint;
AWindow: PGdkWindow;
ACustomForm: TCustomForm;
{$IFDEF Gtk1}
AWindowPrivate: PGdkWindowPrivate;
{$ENDIF}
begin
if not (Sender is TWinControl) then
RaiseWrongClass;
@ -6824,8 +6818,8 @@ begin
// set the pointer to the start of the current line
CurLineEntry[i shr 1]:=CurLineStart;
// copy the line
LineStart:=PtrInt(LinesList[i]);
LineEnd:=PtrInt(LinesList[i+1]);
LineStart:=integer(PtrUInt(LinesList[i]));
LineEnd:=integer(PtrUInt(LinesList[i+1]));
LineLen:=LineEnd-LineStart;
if LineLen>0 then
Move(AText[LineStart],CurLineStart^,LineLen);
@ -6836,7 +6830,7 @@ begin
// next line
inc(i,2);
end;
if PtrInt(Lines)+TotalSize<>PtrInt(CurLineStart) then
if PtrUInt(Lines)+TotalSize<>PtrUInt(CurLineStart) then
RaiseGDBException('TGtkWidgetSet.WordWrap Consistency Error:'
+' Lines+TotalSize<>CurLineStart');
CurLineEntry[i shr 1]:=nil;

View File

@ -1974,6 +1974,7 @@ var
AEvent^.length := 0;
end;
{MWE:.$EndIf}
ResetDefaultIMContext;
AEvent^.KeyVal := 0;
end;
@ -2177,6 +2178,24 @@ var
{$ENDIF}
end;
procedure CheckDeadKey;
begin
if ABeforeEvent then begin
{$IFDEF Gtk2}
if im_context_widget<>TargetWidget then begin
//DebugLn(['CheckDeadKey init im_context ',GetWidgetDebugReport(TargetWidget)]);
ResetDefaultIMContext;
im_context_widget:=TargetWidget;
gtk_im_context_set_client_window(im_context,GetControlWindow(TargetWidget));
//DebugLn(['CheckDeadKey im_context initialized']);
end;
// Note: gtk_im_context_filter_keypress understands keypress and keyrelease
gtk_im_context_filter_keypress (im_context, AEvent);
//DebugLn(['CheckDeadKey DeadKey=',DeadKey,' str="',im_context_string,'"']);
{$ENDIF}
end;
end;
begin
Result := CallBackDefaultReturn;
@ -2184,9 +2203,9 @@ begin
HandledByLCL := KeyEventWasHandledByLCL(AEvent, ABeforeEvent);
{$IFDEF VerboseKeyboard}
DebugLn('[HandleGTKKeyUpDown] ',DbgSName(TControl(AData)),
' ',dbgs(AEvent^.{$IFDEF GTK1}theType{$ELSE}_Type{$ENDIF}),' Widget=',GetWidgetClassName(AWidget),
' Before=',dbgs(ABeforeEvent),' HandledByLCL=',dbgs(AHandledByLCL));
DebugLn(['[HandleGTKKeyUpDown] ',DbgSName(TControl(AData)),
' ',(AEvent^.{$IFDEF GTK1}theType{$ELSE}_Type{$ENDIF}),' Widget=',GetWidgetClassName(AWidget),
' Before=',ABeforeEvent,' Down=',AHandleDown,' HandledByLCL=',HandledByLCL]);
{$ENDIF}
// handle every key event only once
@ -2195,6 +2214,7 @@ begin
TargetWidget := AWidget;
TargetObj := AData;
FocusedWinControl := nil;
FocusedWidget := nil;
// The gtk sends keys first to the gtkwindow and then to the focused control.
// The LCL expects only once to the focused control.
@ -2232,16 +2252,14 @@ begin
//DebugLn(['HandleGTKKeyUpDown TargetWidget=',GetWidgetDebugReport(TargetWidget)]);
gdk_event_key_get_string(AEvent, EventString);
//DebugLn(['HandleGTKKeyUpDown TargetWidget=',GetWidgetDebugReport(TargetWidget),' ',DbgStr(EventString),' state=',AEvent^.state,' keyval=',AEvent^.keyval]);
FillChar(Msg, SizeOf(Msg), 0);
gdk_event_key_get_string(AEvent, EventString);
//DebugLn(['HandleGTKKeyUpDown TargetWidget=',GetWidgetDebugReport(TargetWidget),' ',DbgStr(EventString),' state=',AEvent^.state,' keyval=',AEvent^.keyval]);
CheckDeadKey;
Flags := 0;
SysKey := False;
ShiftState := GTKEventStateToShiftState(AEvent^.state);
{$ifdef gtk1}
KeyCode := XKeysymToKeycode(gdk_display, AEvent^.keyval);
{$else}
@ -2342,14 +2360,16 @@ begin
if ABeforeEvent then begin
// try to get the UTF8 representation of the key
{$IFDEF GTK1}
Character := '';
if (AEvent^.length > 0) and (AEvent^.length <= 8) //max composed UTF8 char has lenght 8
then begin
SetLength(Character, AEvent^.length);
System.Move(AEvent^.thestring^, Character[1], length(Character));
end;
Character := '';
if (AEvent^.length > 0) and (AEvent^.length <= 8) //max composed UTF8 char has lenght 8
then begin
SetLength(Character, AEvent^.length);
System.Move(AEvent^.thestring^, Character[1], length(Character));
end;
{$ELSE GTK2}
Character := UnicodeToUTF8(gdk_keyval_to_unicode(AEvent^.KeyVal));
Character := UTF8Copy(im_context_string,1,1);
im_context_string:='';// clear, to avoid sending again
// Character := UnicodeToUTF8(gdk_keyval_to_unicode(AEvent^.KeyVal));
{$ENDIF GTK2}
{$IFDEF VerboseKeyboard}
@ -2381,15 +2401,7 @@ begin
then begin
// ASCII key was pressed
KeyPressesChar := EventString^;
end
else
if AEvent^.KeyVal < 128
then begin
// non ASCII key was pressed
// MWE: imo this is impossible since when eventlength > 1 it contains
// a UTF char and that case keyval is never < 128
KeyPressesChar := chr(byte(AEvent^.KeyVal));
end;
end;
if KeyPressesChar <> #0
then begin
@ -4026,7 +4038,7 @@ begin
Result^.CoreWidget := AWidget;
Result^.Style := AParams.Style;
Result^.ExStyle := AParams.ExStyle;
Result^.WndProc := PtrInt(AParams.WindowClass.lpfnWndProc);
Result^.WndProc := PtrUInt(AParams.WindowClass.lpfnWndProc);
end;
function GetWidgetInfo(const AWidget: Pointer {; const Create: Boolean = False}): PWidgetInfo;
@ -4824,7 +4836,7 @@ end;
function GetDesignSignalMask(Widget: PGtkWidget): TDesignSignalMask;
begin
Result:=TDesignSignalMask(PtrInt(gtk_object_get_data(PGtkObject(Widget),
Result:=TDesignSignalMask(PtrUInt(gtk_object_get_data(PGtkObject(Widget),
'LCLDesignMask')));
end;
@ -4850,7 +4862,7 @@ var
begin
Handler := gtk_object_get_data_by_id (AnObject, gtk_handler_quark);
SignalID := g_signal_lookup(ASignal, GTK_OBJECT_TYPE(AnObject));
if SignalID<0 then
if (SignalID<0) or (SignalID>$ffffff) then
RaiseGDBException('SignalConnected');
while (Handler <> nil) do begin

View File

@ -42,7 +42,7 @@ uses
{$ELSE}
glib, gdk, gtk, {$Ifndef NoGdkPixbufLib}gdkpixbuf,{$EndIf}
{$ENDIF}
Math, // after gtk to get the correct Float type
Math, // Math after gtk to get the correct Float type
LMessages, LCLProc, LCLStrConsts, LCLIntf, LCLType, DynHashArray, Maps, Masks,
GraphType, GraphMath, Graphics, GTKWinApiWindow, LResources, Controls, Forms,
Buttons, Menus, StdCtrls, ComCtrls, CommCtrl, ExtCtrls, Dialogs, ExtDlgs,

View File

@ -740,7 +740,7 @@ var
GdiObject: PGdiObject;
DefGdkWindow: PGdkWindow;
begin
Assert(False, Format('Trace:> [TGtkWidgetSet.CreateBitmap] Width: %d, Height: %d, Planes: %d, BitCount: %d, BitmapBits: 0x%x', [Width, Height, Planes, BitCount, PtrInt(BitmapBits)]));
Assert(False, Format('Trace:> [TGtkWidgetSet.CreateBitmap] Width: %d, Height: %d, Planes: %d, BitCount: %d, BitmapBits: 0x%x', [Width, Height, Planes, BitCount, PtrUInt(BitmapBits)]));
if (BitCount < 1) or (Bitcount > 32)
then begin
@ -6346,9 +6346,12 @@ end;
Returns: Nothing
------------------------------------------------------------------------------}
Function TGtkWidgetSet.GetWindowLong(Handle : hwnd; int : Integer): PtrInt;
var
//Data : Tobject;
P : Pointer;
function GetObjectData(Name: PChar): PtrInt;
begin
Result := PtrInt(PtrUInt(gtk_object_get_data(pgtkobject(Handle),Name)));
end;
begin
//TODO:Started but not finished
Assert(False, Format('Trace:> [TGtkWidgetSet.GETWINDOWLONG] HWND: 0x%x, int: 0x%x (%d)', [Handle, int, int]));
@ -6356,16 +6359,15 @@ begin
case int of
GWL_WNDPROC :
begin
Result := PtrInt(gtk_object_get_data(pgtkobject(Handle),'WNDPROC'));
Result := GetObjectData('WNDPROC');
end;
GWL_HINSTANCE :
begin
Result := PtrInt(gtk_object_get_data(pgtkobject(Handle),'HINSTANCE'));
Result := GetObjectData('HINSTANCE');
end;
GWL_HWNDPARENT :
begin
P := gtk_object_get_data(pgtkobject(Handle),'HWNDPARENT');
if P = nil then Result := 0 else Result := PtrInt(p);
Result := GetObjectData('HWNDPARENT');
end;
{ GWL_WNDPROC :
@ -6386,19 +6388,19 @@ begin
}
GWL_STYLE :
begin
Result := PtrInt(gtk_object_get_data(pgtkobject(Handle),'Style'));
Result := GetObjectData('Style');
end;
GWL_EXSTYLE :
begin
Result := PtrInt(gtk_object_get_data(pgtkobject(Handle),'ExStyle'));
Result := GetObjectData('ExStyle');
end;
GWL_USERDATA :
begin
Result := PtrInt(gtk_object_get_data(pgtkobject(Handle),'Userdata'));
Result := GetObjectData('Userdata');
end;
GWL_ID :
begin
Result := PtrInt(gtk_object_get_data(pgtkobject(Handle),'ID'));
Result := GetObjectData('ID');
end;
else Result := 0;
end; //case
@ -7503,7 +7505,7 @@ const
begin
if (Item^.Data <> Pointer(hndMenu)) // exclude ourself
and gtk_is_radio_menu_item(Item^.Data)
and (GroupIndex = PtrInt(gtk_object_get_data(Item^.Data, GROUPIDX_DATANAME)))
and (GroupIndex = PtrUInt(gtk_object_get_data(Item^.Data, GROUPIDX_DATANAME)))
then begin
Result := gtk_radio_menu_item_group(PGtkRadioMenuItem(Item^.Data));
Exit;

View File

@ -65,7 +65,7 @@ begin
msg.Msg := CN_NOTIFY;
FillChar(NM, SizeOf(NM), 0);
NM.hdr.hwndfrom := PtrInt(AList);
NM.hdr.hwndfrom := PtrUInt(AList);
NM.hdr.code := LVN_COLUMNCLICK;
NM.iItem := -1;
NM.iSubItem := AColumn;
@ -86,7 +86,7 @@ begin
msg.Msg := CN_NOTIFY;
FillChar(NM, SizeOf(NM), 0);
NM.hdr.hwndfrom := PtrInt(AList);
NM.hdr.hwndfrom := PtrUInt(AList);
NM.hdr.code := LVN_DELETEITEM;
NM.iItem := AnOldIdx;
msg.NMHdr := @NM.hdr;
@ -108,7 +108,7 @@ begin
msg.Msg := CN_NOTIFY;
FillChar(NM, SizeOf(NM), 0);
NM.hdr.hwndfrom := PtrInt(AList);
NM.hdr.hwndfrom := PtrUInt(AList);
NM.hdr.code := LVN_ITEMCHANGED;
NM.iItem := ARow;
NM.iSubItem := AColumn;
@ -126,7 +126,7 @@ begin
msg.Msg := CN_NOTIFY;
FillChar(NM, SizeOf(NM), 0);
NM.hdr.hwndfrom := PtrInt(AList);
NM.hdr.hwndfrom := PtrUInt(AList);
NM.hdr.code := LVN_ITEMCHANGED;
NM.iItem := ARow;
NM.iSubItem := AColumn;
@ -146,7 +146,7 @@ begin
msg.Msg := CN_NOTIFY;
FillChar(NM, SizeOf(NM), 0);
NM.hdr.hwndfrom := PtrInt(AList);
NM.hdr.hwndfrom := PtrUInt(AList);
NM.hdr.code := LVN_ITEMCHANGED;
NM.iItem := AList^.focus_row;
NM.iSubItem := 0;
@ -168,7 +168,7 @@ begin
ListView := AInfo^.LCLObject as TListView;
FillChar(NM, SizeOf(NM), 0);
NM.hdr.hwndfrom := PtrInt(AList);
NM.hdr.hwndfrom := PtrUInt(AList);
NM.hdr.code := LVN_ITEMCHANGED;
for n := 0 to Listview.Items.Count - 1 do
begin
@ -195,7 +195,7 @@ begin
ListView := AInfo^.LCLObject as TListView;
FillChar(NM, SizeOf(NM), 0);
NM.hdr.hwndfrom := PtrInt(AList);
NM.hdr.hwndfrom := PtrUInt(AList);
NM.hdr.code := LVN_ITEMCHANGED;
for n := 0 to Listview.Items.Count - 1 do
begin
@ -760,7 +760,7 @@ begin
// check if the row is are already selected
// since we are in singleselect, the first item is checked
if (CListWidget^.selection <> nil)
and (PtrInt(CListWidget^.selection^.Data) = AIndex)
and (PtrUInt(CListWidget^.selection^.Data) = AIndex)
then Exit;
gtk_clist_unselect_all(CListWidget);
end;
@ -1057,7 +1057,7 @@ begin
if CListWidget^.selection = nil
then Result := -1
else Result := PtrInt(CListWidget^.selection^.data)
else Result := PtrUInt(CListWidget^.selection^.data)
end;
class function TGtkWSCustomListView.GetTopItem(const ALV: TCustomListView): Integer;

View File

@ -255,7 +255,7 @@ begin
gtk_notebook_set_tab_pos(AWidget, GtkPositionTypeMap[TCustomNotebook(AWinControl).TabPosition]);
GTKWidgetSet.FinishComponentCreate(AWinControl, AWidget);
Result := THandle(AWidget);
Result := TLCLIntfHandle(AWidget);
end;
class procedure TGtkWSCustomNotebook.AddPage(const ANotebook: TCustomNotebook;

View File

@ -411,7 +411,7 @@ begin
if GList = nil then
Result := -1
else
Result := PtrInt(GList^.Data);
Result := PtrUInt(GList^.Data);
end;
end;
{!$EndIf}
@ -459,7 +459,7 @@ begin
Widget:=GetWidgetInfo(Pointer(Handle),True)^.CoreWidget;
GList:= PGtkCList(Widget)^.selection;
while Assigned(GList) do begin
if PtrInt(GList^.data) = AIndex then begin
if PtrUInt(GList^.data) = AIndex then begin
Result:=true;
exit;
end else

View File

@ -48,6 +48,11 @@ function gdk_window_xwindow(win : PGdkDrawable): TXID; cdecl; external gdklib na
procedure laz_gdk_gc_set_dashes(gc:PGdkGC; dash_offset:gint;
dashlist:Pgint8; n:gint); cdecl; external gdkdll name 'gdk_gc_set_dashes';
type
PPPangoAttrList = ^PPangoAttrList;
procedure gtk_im_context_get_preedit_string_laz(context:PGtkIMContext; str:PPgchar; attrs:PPPangoAttrList; cursor_pos:Pgint); cdecl; external gtklib name 'gtk_im_context_get_preedit_string';
// gdk 2.2
procedure gdk_display_get_pointer(display : PGdkDisplay; screen :PGdkScreen; x :Pgint; y : Pgint; mask : PGdkModifierType); cdecl; external gdklib;
function gdk_display_get_default:PGdkDisplay; cdecl; external gdklib;

View File

@ -74,6 +74,9 @@ type
function CreateThemeServices: TThemeServices; override;
public
constructor Create;
destructor Destroy; override;
function LCLPlatform: TLCLPlatform; override;
function AppHandle: Thandle; override;

View File

@ -252,6 +252,13 @@ begin
end;
end;
procedure gtk_commit_cb (context: PGtkIMContext; const Str: Pgchar;
Data: Pointer); cdecl;
begin
//DebugLn(['gtk_commit_cb ',dbgstr(Str),'="',Str,'"']);
im_context_string:=Str;
end;
{$IfNDef GTK2_2}
Procedure gtkTreeSelectionCountSelectedRows(model : PGtkTreeModel; path : PGtkTreePath;
iter : PGtkTreeIter; data : PGint); cdecl;
@ -834,6 +841,22 @@ begin
Result := TGtk2ThemeServices.Create;
end;
constructor TGtk2WidgetSet.Create;
begin
inherited Create;
im_context:=gtk_im_multicontext_new;
g_signal_connect (G_OBJECT (im_context), 'commit',
G_CALLBACK (@gtk_commit_cb), nil);
end;
destructor TGtk2WidgetSet.Destroy;
begin
g_object_unref(im_context);
im_context:=nil;
im_context_widget:=nil;
inherited Destroy;
end;
function TGtk2WidgetSet.LCLPlatform: TLCLPlatform;
begin
Result:= lpGtk2;