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