1{
2 /***************************************************************************
3                             Gtk2WinapiWindow.pp
4                             -------------------
5                       gtkimplementation for basic window
6                   Initial Revision  : Sun Jan 9 16:00:00 GMT+1 2000
7
8
9 ***************************************************************************/
10
11 *****************************************************************************
12  This file is part of the Lazarus Component Library (LCL)
13
14  See the file COPYING.modifiedLGPL.txt, included in this distribution,
15  for details about the license.
16 *****************************************************************************
17}
18{
19@abstract(A GTK widget to support controls derived from a wincontrol)
20@author(TGTK2WinapiWindow - Marc Weustink <marc@@freepascal.org>)
21@created(2000)
22@lastmod(2004)
23}
24unit Gtk2WinapiWindow;
25
26{$mode objfpc}{$H+}
27
28interface
29
30uses
31  // RTL
32  SysUtils, glib2, gdk2, gtk2,
33  // LCL
34  LCLProc, Gtk2Extra, Controls, Gtk2Proc, Gtk2Def;
35
36{ $Define VerboseCaret}
37// the gtk has a function to draw the cursor, but it does not support xor
38// so it does not work with synedit and twilight hightlighter settings
39{off $DEFINE Has_gtk_draw_insertion_cursor}
40
41type
42  PGTKAPIWidget = ^TGTKAPIWidget;
43  TGTKAPIWidget = record
44    // ! the ScrolledWindow must be the first attribute of this record !
45    ScrolledWindow: TGTKScrolledWindow;
46    Reserved1: Word; // workaround gtk2 win32 fpc bug: SizeOf(TGTKScrolledWindow) is less than in real
47    Frame: PGtkFrame;
48    Client: PGtkWidget;
49  end;
50
51  PGTKAPIWidgetClass = ^TGTKAPIWidgetClass;
52  TGTKAPIWidgetClass = record
53    ParentClass: TGTKScrolledWindowClass;
54  end;
55
56procedure HideCaretOfWidgetGroup(ChildWidget: PGtkWidget;
57  var MainWidget: PGtkWidget; var CaretWasVisible: boolean);
58
59function GTKAPIWidget_GetType: GType;
60function GTKAPIWidget_New: PGTKWidget;
61procedure GTKAPIWidget_CreateCaret(APIWidget: PGTKAPIWidget;
62                                 AWidth, AHeight: Integer; ABitmap: PGDKPixmap);
63procedure GTKAPIWidget_DestroyCaret(APIWidget: PGTKAPIWidget);
64procedure GTKAPIWidget_InvalidateCaret(APIWidget: PGTKAPIWidget);
65procedure GTKAPIWidget_HideCaret(APIWidget: PGTKAPIWidget; var OldVisible: boolean);
66procedure GTKAPIWidget_ShowCaret(APIWidget: PGTKAPIWidget);
67procedure GTKAPIWidget_SetCaretPos(APIWidget: PGTKAPIWidget; X, Y: Integer);
68procedure GTKAPIWidget_GetCaretPos(APIWidget: PGTKAPIWidget; var X, Y: Integer);
69procedure GTKAPIWidget_SetCaretRespondToFocus(APIWidget: PGTKAPIWidget;
70  ShowHideOnFocus: boolean);
71procedure GTKAPIWidget_GetCaretRespondToFocus(APIWidget: PGTKAPIWidget;
72  var ShowHideOnFocus: boolean);
73
74procedure GTKAPIWidget_SetShadowType(APIWidget: PGTKAPIWidget; AShadowType: TGtkShadowType);
75
76function GTK_APIWIDGETCLIENT_TYPE: GType;
77
78implementation
79
80const
81  CURSOR_ON_MULTIPLIER    = 2;
82  CURSOR_OFF_MULTIPLIER   = 1;
83  CURSOR_DIVIDER          = 3;
84
85//---------------------------------------------------------------------------
86// gtk_winapiwindow_internal
87//---------------------------------------------------------------------------
88type
89  TCaretInfo = record
90    X: Integer;
91    Y: Integer;
92    Width: Integer;
93    Height: Integer;
94    Visible: Boolean;   // Caret is on (can be visible/invisible due to Blinking)
95    IsDrawn: Boolean;   // Caret is visible at the moment
96    Blinking: Boolean;  // Caret should blink
97    BlinkTime: Integer; // Blink time = show + hide time
98    BlinkTimeout: Integer; // Time after which if there is no user interaction happened blinking must finish
99    BlinkHide: boolean; // current blinking phase is Hide
100    Pixmap: PGDKPixMap;
101    BackPixmap: PGDKPixMap;
102    Timer: guint;
103    ShowHideOnFocus: boolean; // true = hide on loose focus, show on get focus
104    Invalidated: boolean;
105  end;
106
107  PGTKAPIWidgetClient = ^TGTKAPIWidgetClient;
108  TGTKAPIWidgetClient = record
109    // ! the Widget must be the first attribute of the record !
110    Widget: TGtkFixed;
111    Caret: TCaretInfo;
112  end;
113
114  PGTKAPIWidgetClientClass = ^TGTKAPIWidgetClientClass;
115  TGTKAPIWidgetClientClass = record
116    ParentClass: TGTKFixedClass;
117//    ParentClass: TGTKWidgetClass;
118
119    set_scroll_adjustments: procedure(Widget: PGTKWidget;
120                               HAdjustment, VAdjustment: PGTKAdjustment); cdecl;
121  end;
122
123{------------------------------------------------------------------------------
124  procedure HideCaretOfWidgetGroup(ChildWidget: PGtkWidget;
125    var MainWidget: PGtkWidget; var CaretWasVisible: boolean);
126
127  Find main widget and if it is a API widget, hide caret.
128 ------------------------------------------------------------------------------}
129procedure HideCaretOfWidgetGroup(ChildWidget: PGtkWidget;
130  var MainWidget: PGtkWidget; var CaretWasVisible: boolean);
131var
132  LCLObject: TObject;
133  IsAPIWidget: Boolean;
134begin
135  MainWidget:=ChildWidget;
136  LCLObject:=GetNearestLCLObject(ChildWidget);
137  if (LCLObject is TWinControl) then
138    MainWidget:={%H-}PGtkWidget(TWinControl(LCLObject).Handle);
139  IsAPIWidget:=GtkWidgetIsA(MainWidget,GTKAPIWidget_GetType);
140  CaretWasVisible:=false;
141  if IsAPIWidget then
142    GTKAPIWidget_HideCaret(PGTKAPIWidget(MainWidget),CaretWasVisible);
143end;
144
145////////////////////////////////////////////////////
146// TEMP solution until gtkmarshal.inc is implemeted
147//      to get this compiled
148////////////////////////////////////////////////////
149procedure gtk_marshal_VOID__POINTER_POINTER (closure: PGClosure;
150                                             return_value: PGValue;
151                                             n_param_values: guint;
152                                             param_values: PGValue;
153                                             invocation_hint: gpointer;
154                                             marshal_data: gpointer); cdecl; external gtklib;
155////////////////////////////////////////////////////
156
157type
158  GTKEventResult = gboolean;
159
160var
161  MParentClass: PGtkFixedClass;
162
163function GTKAPIWidgetClient_Timer(Client: Pointer): GTKEventResult; cdecl; forward;
164procedure GTKAPIWidgetClient_Realize(AWidget: PGTKWidget); cdecl; forward;
165procedure GTKAPIWidgetClient_UnRealize(AWidget: PGTKWidget); cdecl; forward;
166procedure GTKAPIWidgetClient_SizeAllocate (AWidget: PGTKWidget; AAllocation: PGtkAllocation); cdecl; forward;
167
168
169function GTKAPIWidgetClient_KeyPress(Widget: PGTKWidget;
170  Event: PGDKEventKey): GTKEventResult; cdecl; forward;
171function GTKAPIWidgetClient_ButtonPress({%H-}Widget: PGTKWidget;
172  Event: PGDKEventButton): GTKEventResult; cdecl; forward;
173function GTKAPIWidgetClient_FocusIn(AWidget: PGTKWidget;
174  {%H-}Event: PGdkEventFocus): GTKEventResult; cdecl; forward;
175function GTKAPIWidgetClient_FocusOut(AWidget: PGTKWidget;
176  {%H-}Event: PGdkEventFocus): GTKEventResult; cdecl; forward;
177
178procedure GTKAPIWidgetClient_ClassInit(theClass: Pointer);cdecl; forward;
179procedure GTKAPIWidgetClient_Init(Client:PGTypeInstance; theClass: Pointer); cdecl; forward;
180function GTKAPIWidgetClient_GetType: GType; forward;
181function GTKAPIWidgetClient_New: PGTKWidget; forward;
182
183procedure GTKAPIWidgetClient_HideCaret(Client: PGTKAPIWidgetClient;
184                                       out OldVisible: boolean); forward;
185procedure GTKAPIWidgetClient_ShowCaret(Client: PGTKAPIWidgetClient); forward;
186procedure GTKAPIWidgetClient_DrawCaret(Client: PGTKAPIWidgetClient; {%H-}CalledByTimer: boolean); forward;
187procedure GTKAPIWidgetClient_CreateCaret(Client: PGTKAPIWidgetClient;
188  AWidth, AHeight: Integer; ABitmap: PGDKPixmap); forward;
189procedure GTKAPIWidgetClient_DestroyCaret(Client: PGTKAPIWidgetClient); forward;
190procedure GTKAPIWidgetClient_InvalidateCaret(Client: PGTKAPIWidgetClient); forward;
191function GTKAPIWidgetClient_IsPainting(Client: PGTKAPIWidgetClient): boolean; forward;
192procedure GTKAPIWidgetClient_SetCaretPos(Client: PGTKAPIWidgetClient;
193  AX, AY: Integer); forward;
194procedure GTKAPIWidgetClient_GetCaretPos(Client: PGTKAPIWidgetClient;
195  var X, Y: Integer); forward;
196procedure GTKAPIWidgetClient_SetCaretRespondToFocus(Client: PGTKAPIWidgetClient;
197  ShowHideOnFocus: boolean); forward;
198procedure GTKAPIWidgetClient_GetCaretRespondToFocus(Client: PGTKAPIWidgetClient;
199  var ShowHideOnFocus: boolean); forward;
200
201function GTKAPIWidgetClient_GetCursorBlink(Client: PGTKAPIWidgetClient): gboolean; forward;
202function GTKAPIWidgetClient_GetCursorBlinkTime(Client: PGTKAPIWidgetClient): gint; forward;
203function GTKAPIWidgetClient_GetCursorBlinkTimeout(Client: PGTKAPIWidgetClient): gint; forward;
204//-----------------------------
205
206procedure GTKAPIWidget_SetShadowType(APIWidget: PGTKAPIWidget;
207  AShadowType: TGtkShadowType);
208begin
209  if (APIWidget^.Frame <> nil) then
210    gtk_frame_set_shadow_type(APIWidget^.Frame, AShadowType)
211  else
212    gtk_scrolled_window_set_shadow_type(PGtkScrolledWindow(APIWidget), AShadowType);
213end;
214
215function GTK_APIWIDGETCLIENT_TYPE: GType;
216begin
217  GTK_APIWIDGETCLIENT_TYPE := GTKAPIWidgetClient_GetType;
218end;
219
220
221function GTKAPIWidgetClient_GetType: GType;
222const
223  TYPE_NAME = 'LCLWinapiClient';
224  TheType: GType = 0;
225  Info: TGTKTypeInfo = (
226    type_name: TYPE_NAME;
227    object_size: SizeOf(TGTKAPIWidgetClient){+100};
228    class_size:  SizeOf(TGTKAPIWidgetClientClass){+100};
229    class_init_func:  @GTKAPIWidgetClient_ClassInit;
230    object_init_func: @GTKAPIWidgetClient_Init;
231    reserved_1: nil;
232    reserved_2: nil;
233    base_class_init_func: nil;
234  );
235begin
236  if (TheType = 0)
237  then begin
238    TheType := gtk_type_from_name(TYPE_NAME);
239    if TheType = 0 then TheType := gtk_type_unique(GTK_TYPE_FIXED, @Info);
240  end;
241  Result := TheType;
242end;
243
244procedure GTKAPIWidgetClient_ClassInit(theClass: Pointer);cdecl;
245// theClass: PGTKAPIWidgetClientClass
246var
247  ObjectClass: PGTKObjectClass;
248  WidgetClass: PGTKWidgetClass;
249  ClientClass: PGTKAPIWidgetClientClass;
250  SignalID: Guint;
251begin
252  ObjectClass := PGTKObjectClass(theClass);
253  WidgetClass := PGTKWidgetClass(theClass);
254  ClientClass := PGTKAPIWidgetClientClass(theClass);
255
256  MParentClass := gtk_type_class(gtk_fixed_get_type);
257  SignalID := gtk_signal_new(
258    'set_scroll_adjustments',
259    GTK_RUN_FIRST,
260    gtk_class_type(ObjectClass),
261    (@ClientClass^.set_scroll_adjustments - Pointer(theClass)),
262    @gtk_marshal_VOID__POINTER_POINTER,
263    GTK_TYPE_NONE,
264    2,
265    [gtk_adjustment_get_type, gtk_adjustment_get_type]
266  );
267
268  ClientClass^.set_scroll_adjustments := nil;
269
270  with WidgetClass^ do
271  begin
272    set_scroll_adjustments_signal := SignalID;
273    realize := @GTKAPIWidgetClient_Realize;
274    unrealize := @GTKAPIWidgetClient_UnRealize;
275    size_allocate := @GTKAPIWidgetClient_SizeAllocate;
276    button_press_event := @GTKAPIWidgetClient_ButtonPress;
277    key_press_event := @GTKAPIWidgetClient_KeyPress;
278    focus_in_event := @GTKAPIWidgetClient_FocusIn;
279    focus_out_event := @GTKAPIWidgetClient_FocusOut;
280  end;
281end;
282
283procedure GTKAPIWidgetClient_Init(Client:PGTypeInstance; theClass: Pointer); cdecl;
284// Client: PGTKAPIWidgetClient
285// theClass: PGTKAPIWidgetClientClass
286begin
287  if theClass=nil then ;
288  gtk_widget_set_flags(PGTKWidget(Client), GTK_CAN_FOCUS);
289  gtk_widget_set_flags(PGTKWidget(Client), GTK_CAN_DEFAULT);
290  gtk_widget_unset_flags(PGTKWidget(Client), GTK_NO_WINDOW);
291  with PGTKAPIWidgetClient(Client)^.Caret do
292  begin
293    Visible := False;
294    IsDrawn := False;
295    Blinking := GTKAPIWidgetClient_GetCursorBlink(PGTKAPIWidgetClient(Client));
296    BlinkTime := GTKAPIWidgetClient_GetCursorBlinkTime(PGTKAPIWidgetClient(Client));
297    BlinkTimeout := GTKAPIWidgetClient_GetCursorBlinkTimeout(PGTKAPIWidgetClient(Client));
298    if (gtk_major_version = 2) and (gtk_minor_version >= 18) then
299    begin
300      if not Blinking and (BlinkTimeOut > 0) then
301        Blinking := True;
302    end;
303    X := 0;
304    Y := 0;
305    Width := 1;
306    Height := 10;
307    Pixmap := nil;
308    BackPixmap := nil;
309    Timer := 0;
310    ShowHideOnFocus := true;
311  end;
312
313  {$IFNDEF NoStyle}
314  gtk_widget_set_app_paintable(PGTKWidget(Client),true);
315  {$ENDIF}
316end;
317
318function GTKAPIWidgetClient_New: PGTKWidget;
319begin
320  Result := PGTKWidget(gtk_type_new(GTKAPIWidgetClient_GetType()));
321end;
322
323function GTKAPIWidgetClient_Timer(Client: Pointer): GTKEventResult; cdecl;
324// returning 0 would stop the timer, 1 will restart it
325var
326  WClient: PGTKAPIWidgetClient;
327begin
328  Result := gtk_false;
329  WClient := PGTKAPIWidgetClient(Client);
330  if WClient^.Caret.Timer <> 0 then
331  begin
332    WClient^.Caret.BlinkHide := not WClient^.Caret.BlinkHide;
333    GTKAPIWidgetClient_DrawCaret(Client,true);
334    if WClient^.Caret.Timer <> 0 then
335      Result := gtk_true;
336  end;
337end;
338
339procedure GTKAPIWidgetClient_Realize(AWidget: PGTKWidget); cdecl;
340
341// All //@ marked lines are already set by the inherited realize
342// we only have to (re)set the event mask
343
344var
345  Info: PWidgetInfo;
346//@  Attributes: TGdkWindowAttr;
347//@  AttributesMask: gint;
348begin
349  PGTKWidgetClass(MParentClass)^.realize(AWidget);
350
351//@  gtk_widget_set_flags(AWidget, GTK_REALIZED);
352
353  gtk_widget_set_double_buffered(AWidget, True); // True bites caret => ToDo
354  gtk_widget_set_redraw_on_allocate(AWidget, False);
355
356//@  with Attributes do
357//@  begin
358//@    Window_type := gdk_window_child;
359//@    X := AWidget^.allocation.x;
360//@    Y := AWidget^.allocation.y;
361//@    Width := AWidget^.allocation.width;
362//@    Height := AWidget^.allocation.height;
363//@    WClass := GDK_INPUT_OUTPUT;
364//@    Visual := gtk_widget_get_visual(AWidget);
365//@    Colormap := gtk_widget_get_colormap(AWidget);
366//@    Event_mask := gtk_widget_get_events(AWidget)
367//@      or GDK_EXPOSURE_MASK or GDK_BUTTON_PRESS_MASK or GDK_BUTTON_RELEASE_MASK
368//@      or GDK_BUTTON_MOTION_MASK or GDK_ENTER_NOTIFY_MASK or GDK_LEAVE_NOTIFY_MASK
369//@      or GDK_KEY_PRESS_MASK or GDK_KEY_RELEASE_MASK;
370//@  end;
371//@  AttributesMask := GDK_WA_X or GDK_WA_Y or GDK_WA_VISUAL or GDK_WA_COLORMAP;
372//@
373//@  AWidget^.Window := gdk_window_new(gtk_widget_get_parent_window(AWidget),
374//@                                    @Attributes, AttributesMask);
375//@
376//@  gdk_window_set_user_data(AWidget^.Window, AWidget);
377
378  gdk_window_set_events(AWidget^.Window, gdk_window_get_events(AWidget^.Window)
379    or GDK_EXPOSURE_MASK or GDK_BUTTON_PRESS_MASK or GDK_BUTTON_RELEASE_MASK
380    or GDK_BUTTON_MOTION_MASK or GDK_ENTER_NOTIFY_MASK or GDK_LEAVE_NOTIFY_MASK
381    or GDK_KEY_PRESS_MASK or GDK_KEY_RELEASE_MASK);
382
383//@  AWidget^.Style := gtk_style_attach(AWidget^.Style, AWidget^.Window);
384//@  gtk_style_set_background(AWidget^.Style, AWidget^.Window, GTK_STATE_NORMAL);
385  Info := GetWidgetInfo(AWidget);
386  if (Info = nil) or ([wwiNoEraseBkgnd] * Info^.Flags = []) then begin
387    gdk_window_set_back_pixmap(AWidget^.Window, nil, GdkFalse);
388    if AWidget^.parent<>nil then begin
389      // clear parent window background pixmap too, just in case AWidget is a nowindow
390      // see note of gtk docs about gtk_widget_modify_bg
391      gdk_window_set_back_pixmap(AWidget^.parent^.Window, nil, GdkFalse);
392    end;
393  end;
394end;
395
396procedure GTKAPIWidgetClient_UnRealize(AWidget: PGTKWidget); cdecl;
397begin
398  with PGTKAPIWidgetClient(AWidget)^.Caret do
399  begin
400    if Timer <> 0
401    then begin
402      gtk_timeout_remove(Timer);
403      Timer := 0;
404    end;
405  end;
406
407  PGTKWidgetClass(MParentClass)^.unrealize(AWidget);
408end;
409
410procedure GTKAPIWidgetClient_SizeAllocate(AWidget: PGTKWidget;
411  AAllocation: PGtkAllocation); cdecl;
412begin
413  PGTKWidgetClass(MParentClass)^.size_allocate(AWidget, AAllocation);
414
415end;
416
417
418function GTKAPIWidgetClient_KeyPress(Widget: PGTKWidget;
419  Event: PGDKEventKey): GTKEventResult; cdecl;
420begin
421  if (Widget=nil) or (Event=nil) then ;
422  // DO NOT supress further processing. The next one who changes that please do the debugging too.
423  // just do not.
424  Result := gtk_False;
425end;
426
427function GTKAPIWidgetClient_ButtonPress(Widget: PGTKWidget;
428  Event: PGDKEventButton): GTKEventResult; cdecl;
429begin
430  {$IFDEF VerboseFocus}
431  DebugLn('GTKAPIWidgetClient_ButtonPress ',DbgS(Widget));
432  {$ENDIF}
433  if Event=nil then ;
434  Result := gtk_False;
435end;
436
437function GTKAPIWidgetClient_FocusIn(AWidget: PGTKWidget;
438  Event: PGdkEventFocus): GTKEventResult; cdecl;
439begin
440  {$IFDEF VerboseFocus}
441  DebugLn('GTKAPIWidgetClient_FocusIn ',DbgS(AWidget),' ',dbgs(event^._in));
442  {$ENDIF}
443
444  gtk_widget_set_flags(AWidget, GTK_HAS_FOCUS);
445  GTKAPIWidgetClient_DrawCaret(PGTKAPIWidgetClient(AWidget), False);
446  gtk_widget_queue_draw(AWidget);
447  Result := gtk_False;
448end;
449
450function GTKAPIWidgetClient_FocusOut(AWidget: PGTKWidget;
451  Event: PGdkEventFocus): GTKEventResult; cdecl;
452begin
453  {$IFDEF VerboseFocus}
454  DebugLn('GTKAPIWidgetClient_FocusOut ',DbgS(AWidget),' ',dbgs(event^._in));
455  {$ENDIF}
456
457  gtk_widget_unset_flags(AWidget, GTK_HAS_FOCUS);
458  GTKAPIWidgetClient_DrawCaret(PGTKAPIWidgetClient(AWidget), False);
459  gtk_widget_queue_draw(AWidget);
460  Result := gtk_False;
461end;
462
463procedure GTKAPIWidgetClient_HideCaret(Client: PGTKAPIWidgetClient;
464  out OldVisible: boolean);
465begin
466  if Client = nil
467  then begin
468    OldVisible:=false;
469    DebugLn('WARNING: [GTKAPIWidgetClient_HideCaret] Got nil client');
470    Exit;
471  end;
472  {$IFDEF VerboseCaret}
473  DebugLn(['GTKAPIWidgetClient_HideCaret ',DbgS(Client),' ShowHideOnFocus=',Client^.Caret.ShowHideOnFocus]);
474  {$ENDIF}
475  OldVisible:=Client^.Caret.Visible;
476  Client^.Caret.Visible := False;
477  GTKAPIWidgetClient_DrawCaret(Client,false);
478
479  {if (Client^.Caret.IsDrawn) then begin
480    with Client^.Caret do begin
481      DebugLn('GTKAPIWidgetClient_ShowCaret IsDrawn=',dbgs(IsDrawn),' Visible=',dbgs(Visible),
482        ' Blinking='+dbgs(Blinking),' HasFocus=',dbgs(gtk_widget_has_focus(PGtkWidget(Client))),
483        ' ShowHideOnFocus='+dbgs(ShowHideOnFocus),
484        ' Window='+dbgs(PGtkWidget(Client)^.Window<>nil),
485        ' Style='+dbgs(gtk_widget_get_style(PGtkWidget(Client))<>nil));
486    end;
487  end;}
488end;
489
490function GTKAPIWidgetClient_GetCursorBlink(Client: PGTKAPIWidgetClient): gboolean;
491var
492  settings: PGtkSettings;
493begin
494  settings := gtk_widget_get_settings(PGtkWidget(Client));
495  g_object_get(settings, 'gtk-cursor-blink', @Result, nil);
496end;
497
498function GTKAPIWidgetClient_GetCursorBlinkTime(Client: PGTKAPIWidgetClient): gint;
499var
500  settings: PGtkSettings;
501begin
502  settings := gtk_widget_get_settings(PGtkWidget(Client));
503  Result := 1200; // default value of gtk-cursor-blink-timeout
504  // property valid since 2.12
505  if (gtk_major_version = 2) and (gtk_minor_version > 10) then
506    g_object_get(settings, 'gtk-cursor-blink-time', @Result, nil);
507end;
508
509function GTKAPIWidgetClient_GetCursorBlinkTimeout(Client: PGTKAPIWidgetClient): gint;
510var
511  settings: PGtkSettings;
512begin
513  settings := gtk_widget_get_settings(PGtkWidget(Client));
514  Result := MaxInt; // default value of gtk-cursor-blink-timeout
515  // property valid since 2.12
516  if (gtk_major_version = 2) and (gtk_minor_version > 10) then
517    g_object_get(settings, 'gtk-cursor-blink-timeout', @Result, nil);
518end;
519
520procedure GTKAPIWidgetClient_DrawCaret(Client: PGTKAPIWidgetClient; CalledByTimer: boolean);
521{ ShowCaret/HideCaret are used in winapi like:
522   ShowCaret (paint xor)
523   Blinking (restore)
524   StartPaintEvent
525   HideCaret
526   Painting
527   ShowCaret
528   EndPaintEvent
529   Blinking
530
531   Moving a caret works like this: HideCaret, move, ShowCaret
532
533   The gtk2 uses double buffering with clipping.
534   This means, during a paint event you can only paint in the clipping area,
535   which does not need to be rectangular.
536   => If the caret would be painted outside the paint event, then we can not hide
537   it if the clipping area does not completely contain the old position.
538   => Therefore we can only paint either inside or outside the paint event.
539   Painting outside the paint event means that between painting and showing
540   caret there are other events, so continuus painting will hardly show the
541   caret. It appears to be almost invisible.
542   => Therefore we must paint only inside the paint event
543   Algorithm:
544     InvalidateRect automatically invalidates the caret
545     Hide
546       outside paint event: invalidate and IsDrawn:=false
547       inside paint event: IsDrawn:=false
548     Show
549       outside paint event: invalidate
550       inside paint event: draw and IsDrawn:=true
551
552     Blinking makes it more complicated, because a Hide triggers an OnPaint,
553     which triggers in synedit code HideCaret+ShowCaret.
554}
555var
556  Widget: PGTKWidget;
557  WidgetStyle: PGTKStyle;
558  HasFocus: boolean;
559  WidgetIsPainting: Boolean;
560{$IFDEF Has_gtk_draw_insertion_cursor}
561  location: TGdkRectangle;
562{$ENDIF}
563
564  procedure DrawCursor(Pixmap: PGdkPixmap; X, Y, Width, Height: Integer);
565  const
566    GC_STATE: array[Boolean] of TGtkStateType =
567   (
568     GTK_STATE_INSENSITIVE,
569     GTK_STATE_NORMAL
570   );
571  var
572    ForeGroundGC: PGdkGC;
573  begin
574    // set draw function to xor
575    ForeGroundGC := WidgetStyle^.fg_gc[GC_STATE[{%H-}PtrUInt(Pixmap) <> 1]];
576    //gdk_gc_get_values(ForeGroundGC,@ForeGroundGCValues);
577    //OldGdkFunction:=ForeGroundGCValues.thefunction;
578    {$IFDEF VerboseCaret}
579    DebugLn(['GTKAPIWidgetClient_DrawCaret Real Draw ',X,',',Y]);
580    {$ENDIF}
581    gdk_gc_set_function(ForeGroundGC,GDK_invert);
582    try
583      // draw the caret
584      //DebugLn('DRAWING');
585      gdk_draw_rectangle(
586        Widget^.Window,
587        ForeGroundGC,
588        1,
589        X, Y-1,  // Y-1 for Delphi compatibility
590        Width, Height
591      );
592    finally
593      // restore draw function
594      gdk_gc_set_function(ForeGroundGC, GDK_COPY);
595    end;
596  end;
597
598begin
599  if Client = nil then
600  begin
601    DebugLn('WARNING: [GTKAPIWidgetClient_DrawCaret] Got nil client');
602    Exit;
603  end;
604
605  Widget := PGTKWidget(Client);
606  WidgetStyle := gtk_widget_get_style(Widget);
607  WidgetIsPainting := GTKAPIWidgetClient_IsPainting(Client);
608
609  with Client^.Caret do
610  begin
611    HasFocus := gtk_widget_has_focus(Widget);
612    if WidgetIsPainting then
613      Invalidated := false;
614
615    {$IFDEF VerboseCaret}
616    DebugLn(['GTKAPIWidgetClient_DrawCaret START Client=',DbgS(Client),' Timer=',Timer,' Blink=',Blinking,' BlinkHide=',BlinkHide,' Visible=',Visible,' ShowHideOnFocus=',ShowHideOnFocus,' Focus=',gtk_widget_has_focus(Widget),' IsDrawn=',IsDrawn,' W=',Width,' H=',Height,' WidgetIsPainting=',WidgetIsPainting]);
617    {$ENDIF}
618
619    if IsDrawn and
620       (
621         (not Visible) or
622         (Blinking and BlinkHide)
623       ) then
624    begin
625      // hide caret (restore background)
626      if WidgetIsPainting then
627      begin
628        if (BackPixmap <> nil) and (Widget<>nil) and (WidgetStyle<>nil) then
629        begin
630          gdk_draw_pixmap(
631            Widget^.Window,
632            WidgetStyle^.bg_gc[GTK_STATE_NORMAL],
633            BackPixmap, 0, 0,
634            X, Y-1, // Y-1 for Delphi compatibility
635            Width, Height
636          );
637          {$IFDEF VerboseCaret}
638          DebugLn(['GTKAPIWidgetClient_DrawCaret Real Hide ',X,',',Y]);
639          {$ENDIF}
640        end;
641        IsDrawn := False;
642        Invalidated:=false;
643      end else
644      begin
645        // paint only during painting, otherwise invalidate
646        {$IFDEF VerboseCaret}
647        DebugLn(['GTKAPIWidgetClient_DrawCaret Invalidate Hide ',X,',',Y]);
648        {$ENDIF}
649        GTKAPIWidgetClient_InvalidateCaret(Client);
650        IsDrawn := false;
651      end;
652    end
653    else
654    if Visible
655    and (HasFocus or (not ShowHideOnFocus))
656    and (not IsDrawn)
657    and (not (Blinking and BlinkHide))
658    and (Widget^.Window<>nil)
659    and (WidgetStyle<>nil)
660    then begin
661      if WidgetIsPainting then
662      begin
663        //Create backbitmap if needed
664        if (BackPixmap = nil)
665        and (Widget^.Window<>nil)
666        and (Width>0)
667        and (Height>0)
668        then
669          BackPixmap := gdk_pixmap_new(Widget^.Window, Width, Height, -1);
670
671        // store background
672        if (BackPixmap <> nil)
673        and (Widget<>nil)
674        and (WidgetStyle<>nil)
675        and (Width>0) and (Height>0)
676        then begin
677          {$IFDEF VerboseCaret}
678          DebugLn(['GTKAPIWidgetClient_DrawCaret Store ',X,',',Y]);
679          {$ENDIF}
680          gdk_draw_pixmap(
681            BackPixmap,
682            WidgetStyle^.bg_gc[GTK_STATE_NORMAL],
683            Widget^.Window,
684              X, Y-1, // Y-1 for Delphi compatibility
685              0, 0,
686              Width, Height
687          );
688        end;
689
690        // draw caret
691        {$IFDEF VerboseCaret}
692        DebugLn(['GTKAPIWidgetClient_DrawCaret SHOWING Client=',DbgS(Client)
693        ,' ',cardinal(WidgetStyle)
694        ,' ',cardinal(Widget^.Window)
695        ,' X=',X,' Y=',Y
696        ,' W=',Width
697        ,' H=',Height
698        ]);
699        {$ENDIF}
700        if (WidgetStyle<>nil)
701        and (Widget^.Window<>nil)
702        and (Width>0)
703        and (Height>0)
704        then begin
705          {$IFDEF Has_gtk_draw_insertion_cursor}
706          if Width <= 3 then
707          begin
708            location.x := X;
709            location.y := Y - 1;
710            location.width := 0;
711            location.height := Height;
712            gtk_draw_insertion_cursor(Widget, Widget^.Window, nil, @location, PtrUInt(Pixmap) <> 1,
713               GTK_TEXT_DIR_LTR, false);
714          end
715          else
716          {$ENDIF}
717            DrawCursor(Pixmap, X, Y, Width, Height);
718        end else
719          DebugLn('***: Draw Caret failed: Client=',DbgS(Client),
720            ' X='+dbgs(X)+' Y='+dbgs(Y)+' W='+dbgs(Width)+' H='+dbgs(Height),
721            ' ',dbgs(Pixmap<>nil),',',dbgs(Widget^.Window),',',dbgs(WidgetStyle));
722        IsDrawn := True;
723        Invalidated:=false;
724      end else begin
725        // not in a paint event => use only invalidate
726        {$IFDEF VerboseCaret}
727        DebugLn(['GTKAPIWidgetClient_DrawCaret Invalidate Show']);
728        {$ENDIF}
729        GTKAPIWidgetClient_InvalidateCaret(Client);
730      end;
731    end;
732
733    // stop, start timer
734    if Visible and Blinking and ((not ShowHideOnFocus) or HasFocus) then
735    begin
736      if Timer = 0 then
737        if IsDrawn then
738          Timer := gtk_timeout_add(BlinkTime * CURSOR_ON_MULTIPLIER div CURSOR_DIVIDER,
739            @GTKAPIWidgetClient_Timer, Client)
740        else
741          Timer := gtk_timeout_add(BlinkTime * CURSOR_OFF_MULTIPLIER div CURSOR_DIVIDER,
742            @GTKAPIWidgetClient_Timer, Client)
743    end else
744    begin
745      if Timer <> 0 then
746      begin
747        gtk_timeout_remove(Timer);
748        Timer := 0;
749      end;
750    end;
751
752    {$IFDEF VerboseCaret}
753    DebugLn(['GTKAPIWidgetClient_DrawCaret END Client=',DbgS(Client),' Timer=',Timer,' Blink=',Blinking,' BlinkHide=',BlinkHide,' Visible=',Visible,' ShowHideOnFocus=',ShowHideOnFocus,' Focus=',gtk_widget_has_focus(Widget),' IsDrawn=',IsDrawn,' W=',Width,' H=',Height,' WidgetIsPainting=',WidgetIsPainting]);
754    {$ENDIF}
755  end;
756end;
757
758procedure GTKAPIWidgetClient_ShowCaret(Client: PGTKAPIWidgetClient);
759begin
760  //DebugLn('[GTKAPIWidgetClient_ShowCaret] A Client=',DbgS(Client));
761  if Client = nil
762  then begin
763    DebugLn('WARNING: [GTKAPIWidgetClient_ShowCaret] Got nil client');
764    Exit;
765  end;
766
767  {$IFDEF VerboseCaret}
768  DebugLn('GTKAPIWidgetClient_ShowCaret ',DbgS(Client));
769  {$ENDIF}
770
771  Client^.Caret.Visible := True;
772  GTKAPIWidgetClient_DrawCaret(Client,false);
773end;
774
775procedure GTKAPIWidgetClient_CreateCaret(Client: PGTKAPIWidgetClient;
776  AWidth, AHeight: Integer; ABitmap: PGDKPixmap);
777var
778  IsVisible: Boolean;
779  WasVisible: boolean;
780begin
781  {$IFDEF VerboseCaret}
782  DebugLn(['********** [GTKAPIWidgetClient_CreateCaret] A Client=',DbgS(Client),' Width=',AWidth,' Height=',AHeight,' Bitmap=',ABitmap<>nil]);
783  {$ENDIF}
784  if Client = nil
785  then begin
786    DebugLn('WARNING: [GTKAPIWidgetClient_CreateCaret] Got nil client');
787    Exit;
788  end;
789
790  with Client^.Caret do
791  begin
792    IsVisible := Visible;
793    if IsVisible then GTKAPIWidgetClient_HideCaret(Client,WasVisible);
794
795    if (Width <> AWidth) or (Height <> AHeight)
796    then begin
797      if BackPixmap <> nil then gdk_pixmap_unref(BackPixmap);
798      BackPixmap := nil;
799      Width := AWidth;
800      Height := AHeight;
801    end;
802
803    Pixmap := ABitmap;
804    BlinkHide:=false;// start show phase
805    Invalidated:=false;
806
807    if IsVisible then GTKAPIWidgetClient_ShowCaret(Client);
808  end;
809end;
810
811procedure GTKAPIWidgetClient_DestroyCaret(Client: PGTKAPIWidgetClient);
812var
813  WasVisible: boolean;
814begin
815  {$IFDEF VerboseCaret}
816  DebugLn('********** [GTKAPIWidgetClient_DestroyCaret] A Client=',DbgS(Client));
817  {$ENDIF}
818  if Client = nil
819  then begin
820    DebugLn('WARNING: [GTKAPIWidgetClient_DestroyCaret] Got nil client');
821    Exit;
822  end;
823
824  with Client^.Caret do begin
825    if Visible then begin
826      Visible:=false;
827      GTKAPIWidgetClient_HideCaret(Client,WasVisible);
828    end;
829
830    if Timer<>0 then begin
831      gtk_timeout_remove(Timer);
832      Timer:=0;
833    end;
834
835    if BackPixmap <> nil then begin
836      gdk_pixmap_unref(BackPixmap);
837      BackPixmap := nil;
838    end;
839    Pixmap := nil;
840  end;
841  {$IFDEF VerboseCaret}
842  DebugLn('********** B[GTKAPIWidgetClient_DestroyCaret] A Client=',DbgS(Client));
843  {$ENDIF}
844end;
845
846procedure GTKAPIWidgetClient_InvalidateCaret(Client: PGTKAPIWidgetClient);
847begin
848  {$IFDEF VerboseCaret}
849  DebugLn('********** [GTKAPIWidgetClient_InvalidateCaret] A Client=',DbgS(Client));
850  {$ENDIF}
851  with Client^.Caret do begin
852    if not Invalidated then begin
853      {$IFDEF VerboseCaret}
854      DebugLn(['GTKAPIWidgetClient_InvalidateCaret invalidate caret: X=',X,' Y=',Y-1,' ',Width,'x',Height]);
855      {$ENDIF}
856      gtk_widget_queue_draw_area(PGtkWidget(Client),
857          X, Y-1, // Y-1 for Delphi compatibility
858          Width,Height);
859      Invalidated:=true;
860    end;
861  end;
862  {$IFDEF VerboseCaret}
863  DebugLn('********** B[GTKAPIWidgetClient_InvalidateCaret] A Client=',DbgS(Client));
864  {$ENDIF}
865end;
866
867function GTKAPIWidgetClient_IsPainting(Client: PGTKAPIWidgetClient): boolean;
868var
869  Info: PWidgetInfo;
870begin
871  Info:=GetWidgetInfo(Client);
872  Result:=(Info<>nil) and (Info^.PaintDepth>0);
873end;
874
875procedure GTKAPIWidgetClient_SetCaretPos(Client: PGTKAPIWidgetClient;
876  AX, AY: Integer);
877var
878  IsVisible, WasVisible: Boolean;
879begin
880  {$IFDEF VerboseCaret}
881  DebugLn('[GTKAPIWIDGETCLIENT] SetCaretPos '+inttostr(ax)+','+Inttostr(ay));
882  {$ENDIF}
883
884  if Client = nil
885  then begin
886    DebugLn('WARNING: [GTKAPIWidgetClient_SetCaretPos] Got nil client');
887    Exit;
888  end;
889
890  with Client^.Caret do
891  begin
892    if (X=AX) and (Y=AY) then exit;
893    IsVisible := Visible;
894    if IsVisible then GTKAPIWidgetClient_HideCaret(Client,WasVisible);
895    X := AX;
896    Y := AY;
897    BlinkHide:=false;// start show phase
898    Invalidated:=false;
899    if Timer<>0 then begin
900      // reset timer
901      gtk_timeout_remove(Timer);
902      Timer:=0;
903    end;
904    if IsVisible then GTKAPIWidgetClient_ShowCaret(Client);
905  end;
906end;
907
908procedure GTKAPIWidgetClient_GetCaretPos(Client: PGTKAPIWidgetClient;
909  var X, Y: Integer);
910begin
911  if Client = nil
912  then begin
913    DebugLn('WARNING: [GTKAPIWidgetClient_GetCaretPos] Got nil client');
914    Exit;
915  end;
916
917  X := Client^.Caret.X;
918  Y := Client^.Caret.Y;
919end;
920
921procedure GTKAPIWidgetClient_SetCaretRespondToFocus(Client: PGTKAPIWidgetClient;
922  ShowHideOnFocus: boolean);
923begin
924  {$IFDEF VerboseCaret}
925  DebugLn(['[GTKAPIWidgetClient_SetCaretRespondToFocus] A ',ShowHideOnFocus]);
926  {$ENDIF}
927  if Client = nil
928  then begin
929    DebugLn(
930      'WARNING: [GTKAPIWidgetClient_SetCaretRespondToFocus] Got nil client');
931    Exit;
932  end;
933
934  Client^.Caret.ShowHideOnFocus:=ShowHideOnFocus;
935end;
936
937procedure GTKAPIWidgetClient_GetCaretRespondToFocus(Client: PGTKAPIWidgetClient;
938  var ShowHideOnFocus: boolean);
939begin
940  if Client = nil
941  then begin
942    DebugLn(
943      'WARNING: [GTKAPIWidgetClient_GetCaretRespondToFocus] Got nil client');
944    Exit;
945  end;
946
947  ShowHideOnFocus:=Client^.Caret.ShowHideOnFocus;
948end;
949
950//---------------------------------------------------------------------------
951// GTKAPIWidget
952//---------------------------------------------------------------------------
953
954function GTKAPIWidget_FocusIn(Widget: PGTKWidget;
955  {%H-}Event: PGdkEventFocus): GTKEventResult; cdecl;
956var
957  TopLevel, FocusWidget: PGTKWidget;
958begin
959  TopLevel := gtk_widget_get_toplevel(Widget);
960  if gtk_type_is_a(gtk_object_type(PGTKObject(TopLevel)), gtk_window_get_type)
961  then begin
962    if GTK_WIDGET_CAN_FOCUS(PGTKAPIWidget(Widget)^.Client) then
963      FocusWidget:=PGTKAPIWidget(Widget)^.Client
964    else
965      FocusWidget:=Widget;
966    {debugln(['GTKAPIWidget_FocusIn ',
967      ' Widget=',GetWidgetDebugReport(Widget),
968      ' Client=',GetWidgetDebugReport(PGTKAPIWidget(Widget)^.Client),
969      ' GTK_WIDGET_CAN_FOCUS(Widget)=',GTK_WIDGET_CAN_FOCUS(Widget),
970      ' GTK_WIDGET_CAN_FOCUS(Client)=',GTK_WIDGET_CAN_FOCUS(PGTKAPIWidget(Widget)^.Client),
971      '']);}
972    gtk_window_set_focus(PGTKWindow(TopLevel), FocusWidget);
973  end;
974
975  Result := gtk_True;
976end;
977
978function GTKAPIWidget_FocusOut({%H-}Widget: PGTKWidget;
979  {%H-}Event: PGdkEventFocus): GTKEventResult; cdecl;
980begin
981  Result := gtk_True;
982end;
983
984
985procedure GTKAPIWidget_ClassInit(wawClass: Pointer); cdecl;
986//wawClass: PGTKAPIWidgetClass
987var
988  WidgetClass: PGTKWidgetClass;
989begin
990  WidgetClass := PGTKWidgetClass(wawClass);
991
992  WidgetClass^.focus_in_event := @GTKAPIWidget_FocusIn;
993  WidgetClass^.focus_out_event := @GTKAPIWidget_FocusOut;
994end;
995
996procedure GTKAPIWidget_Init(waw:PGTypeInstance; theClass: Pointer); cdecl;
997// waw: PGTKAPIWidget;
998// theClass: PGTKAPIWidgetClass
999var
1000  Widget: PGTKWidget;
1001begin
1002  if theClass=nil then ;
1003  Widget := PGTKWidget(waw);
1004  gtk_widget_set_flags(Widget, GTK_CAN_FOCUS);
1005end;
1006
1007function GTKAPIWidget_GetType: GType;
1008const
1009  WAW_NAME = 'LCLWinapiWidget';
1010  wawInfo: TGTKTypeInfo = (
1011    type_name: WAW_NAME;
1012    object_size: SizeOf(TGTKAPIWidget)+100; // a TGTKScrolledWindow
1013    class_size: SizeOf(TGTKAPIWidgetClass)+100;
1014    class_init_func: @GTKAPIWidget_ClassInit;
1015    object_init_func : @GTKAPIWidget_Init;
1016    reserved_1: nil;
1017    reserved_2: nil;
1018    base_class_init_func: nil;
1019  );
1020begin
1021  if (GTKAPIWidget_Type = 0)
1022  then begin
1023    GTKAPIWidget_Type := gtk_type_from_name(WAW_NAME);
1024    if GTKAPIWidget_Type = 0
1025    then GTKAPIWidget_Type := gtk_type_unique(gtk_scrolled_window_get_type, @wawInfo);
1026  end;
1027  Result := GTKAPIWidget_Type;
1028end;
1029
1030function GTKAPIWidget_new: PGTKWidget;
1031var
1032  APIWidget: PGTKAPIWidget;
1033begin
1034  Result := gtk_widget_new(GTKAPIWidget_GetType, nil, []);
1035
1036  APIWidget := PGTKAPIWidget(Result);
1037  gtk_container_set_border_width(PGTKContainer(APIWidget),0);
1038
1039  // create client widget
1040  APIWidget^.Client := GTKAPIWidgetClient_New;
1041  g_object_set_data(PGObject(Result), 'Fixed', APIWidget^.Client);
1042  g_object_set_data(PGObject(APIWidget^.Client), 'Main', Result);
1043  gtk_widget_show(APIWidget^.Client);
1044  gtk_container_add(PGTKContainer(APIWidget), APIWidget^.Client);
1045end;
1046
1047procedure GTKAPIWidget_CreateCaret(APIWidget: PGTKAPIWidget;
1048  AWidth, AHeight: Integer; ABitmap: PGDKPixmap);
1049begin
1050  if APIWidget = nil
1051  then begin
1052    DebugLn('WARNING: [GTKAPIWidget_CreateCaret] Got nil client');
1053    Exit;
1054  end;
1055  GTKAPIWidgetClient_CreateCaret(PGTKAPIWidgetClient(APIWidget^.Client),
1056    AWidth, AHeight, ABitmap);
1057end;
1058
1059procedure GTKAPIWidget_DestroyCaret(APIWidget: PGTKAPIWidget);
1060begin
1061  if APIWidget = nil
1062  then begin
1063    DebugLn('WARNING: [GTKAPIWidget_DestroyCaret] Got nil client');
1064    Exit;
1065  end;
1066  GTKAPIWidgetClient_DestroyCaret(PGTKAPIWidgetClient(APIWidget^.Client));
1067end;
1068
1069procedure GTKAPIWidget_InvalidateCaret(APIWidget: PGTKAPIWidget);
1070begin
1071  {$IFDEF VerboseCaret}
1072  DebugLn('[GTKAPIWidget_InvalidateCaret] A');
1073  {$ENDIF}
1074  if APIWidget = nil
1075  then begin
1076    DebugLn('WARNING: [GTKAPIWidget_InvalidateCaret] Got nil client');
1077    Exit;
1078  end;
1079  GTKAPIWidgetClient_InvalidateCaret(PGTKAPIWidgetClient(APIWidget^.Client));
1080end;
1081
1082procedure GTKAPIWidget_HideCaret(APIWidget: PGTKAPIWidget;
1083  var OldVisible: boolean);
1084begin
1085  {$IFDEF VerboseCaret}
1086  DebugLn('[GTKAPIWidget_HideCaret] A');
1087  {$ENDIF}
1088  if APIWidget = nil
1089  then begin
1090    DebugLn('WARNING: [GTKAPIWidget_HideCaret] Got nil client');
1091    Exit;
1092  end;
1093  GTKAPIWidgetClient_HideCaret(PGTKAPIWidgetClient(APIWidget^.Client),OldVisible);
1094end;
1095
1096procedure GTKAPIWidget_ShowCaret(APIWidget: PGTKAPIWidget);
1097begin
1098  {$IFDEF VerboseCaret}
1099  DebugLn('[GTKAPIWidget_ShowCaret] A');
1100  {$ENDIF}
1101  if APIWidget = nil
1102  then begin
1103    DebugLn('WARNING: [GTKAPIWidget_ShowCaret] Got nil client');
1104    Exit;
1105  end;
1106  GTKAPIWidgetClient_ShowCaret(PGTKAPIWidgetClient(APIWidget^.Client));
1107end;
1108
1109procedure GTKAPIWidget_SetCaretPos(APIWidget: PGTKAPIWidget; X, Y: Integer);
1110begin
1111  {$IFDEF VerboseCaret}
1112  DebugLn('[GTKAPIWidget_SetCaretPos] A');
1113  {$ENDIF}
1114  if APIWidget = nil
1115  then begin
1116    DebugLn('WARNING: [GTKAPIWidget_SetCaretPos] Got nil client');
1117    Exit;
1118  end;
1119  GTKAPIWidgetClient_SetCaretPos(PGTKAPIWidgetClient(APIWidget^.Client), X, Y);
1120end;
1121
1122procedure GTKAPIWidget_GetCaretPos(APIWidget: PGTKAPIWidget; var X, Y: Integer);
1123begin
1124  if APIWidget = nil
1125  then begin
1126    DebugLn('WARNING: [GTKAPIWidget_GetCaretPos] Got nil client');
1127    Exit;
1128  end;
1129  GTKAPIWidgetClient_GetCaretPos(PGTKAPIWidgetClient(APIWidget^.Client), X, Y);
1130end;
1131
1132procedure GTKAPIWidget_SetCaretRespondToFocus(APIWidget: PGTKAPIWidget;
1133  ShowHideOnFocus: boolean);
1134begin
1135  {$IFDEF VerboseCaret}
1136  DebugLn(['[GTKAPIWidget_SetCaretRespondToFocus] A ',ShowHideOnFocus]);
1137  {$ENDIF}
1138  if APIWidget = nil
1139  then begin
1140    DebugLn('WARNING: [GTKAPIWidget_SetCaretRespondToFocus] Got nil client');
1141    Exit;
1142  end;
1143  GTKAPIWidgetClient_SetCaretRespondToFocus(
1144    PGTKAPIWidgetClient(APIWidget^.Client), ShowHideOnFocus);
1145end;
1146
1147procedure GTKAPIWidget_GetCaretRespondToFocus(APIWidget: PGTKAPIWidget;
1148  var ShowHideOnFocus: boolean);
1149begin
1150  if APIWidget = nil
1151  then begin
1152    DebugLn('WARNING: [GTKAPIWidget_GetCaretRespondToFocus] Got nil client');
1153    Exit;
1154  end;
1155  GTKAPIWidgetClient_GetCaretRespondToFocus(
1156    PGTKAPIWidgetClient(APIWidget^.Client), ShowHideOnFocus);
1157end;
1158
1159initialization
1160  MParentClass := nil;
1161
1162end.
1163
1164
1165