237
239
EventTrace('realizeafter', nil);
240
HiddenLCLObject:=GetHiddenLCLObject(Widget);
241
if HiddenLCLObject=nil then begin
242
// this is a normal lcl wigdet
244
MainWidget:=GetMainWidget(Widget);
245
if MainWidget=nil then
247
WinWidgetInfo:=GetWidgetInfo(MainWidget,true);
248
LCLObject:=GetLCLObject(MainWidget);
249
if (LCLObject<>nil) and (WinWidgetInfo<>nil) then begin
250
ClientWidget:=GetFixedWidget(Widget);
251
if (LCLObject is TWinControl) then
252
TheWinControl:=TWinControl(LCLObject)
256
// set extra signal masks after the widget window is created
257
// define extra events we're interrested in
258
//write('GTKRealizeAfterCB ');
259
//if TheWinControl<>nil then DbgOut(' ',TheWinControl.Name,':',TheWinControl.ClassName,' ',DbgS(TheWinControl.Handle));
260
//DebugLn(' Widget=',DbgS(Widget),' Fixed=',DbgS(GetFixedWidget(Widget)),' Main=',DbgS(GetMainWidget(Widget)));
261
if (TheWinControl<>nil) then begin
262
//DebugLn(['gtkRealizeAfterCB ',GetWidgetDebugReport(Widget)]);
263
{$IFDEF DebugGDK}BeginGDKErrorTrap;{$ENDIF}
265
NewEventMask:=gdk_window_get_events(GetControlWindow(Widget))
242
MainWidget:=GetMainWidget(Widget);
243
WinWidgetInfo:=GetWidgetInfo(MainWidget,true);
244
LCLObject:=GetLCLObject(MainWidget);
245
if (LCLObject<>nil) and (WinWidgetInfo<>nil) then begin
246
ClientWidget:=GetFixedWidget(Widget);
247
if (LCLObject is TWinControl) then
248
TheWinControl:=TWinControl(LCLObject)
252
// set extra signal masks after the widget window is created
253
// define extra events we're interrested in
254
//write('GTKRealizeAfterCB ');
255
//if TheWinControl<>nil then DbgOut(' ',TheWinControl.Name,':',TheWinControl.ClassName,' ',DbgS(TheWinControl.Handle));
256
//DebugLn(' Widget=',DbgS(Widget),' Fixed=',DbgS(GetFixedWidget(Widget)),' Main=',DbgS(GetMainWidget(Widget)));
257
if (TheWinControl<>nil) then begin
258
//DebugLn(['gtkRealizeAfterCB ',GetWidgetDebugReport(Widget)]);
259
{$IFDEF DebugGDK}BeginGDKErrorTrap;{$ENDIF}
261
NewEventMask:=gdk_window_get_events(GetControlWindow(Widget))
262
or WinWidgetInfo^.EventMask;
263
gtk_widget_add_events(Widget,NewEventMask);
264
gdk_window_set_events(GetControlWindow(Widget),NewEventMask);
266
if (ClientWidget<>nil) and (GetControlWindow(ClientWidget)<>nil)
267
and (GetControlWindow(ClientWidget)<>GetControlWindow(Widget)) then begin
268
//DebugLn(['gtkRealizeAfterCB ClientWindow<>Window']);
269
NewEventMask:=gdk_window_get_events(GetControlWindow(ClientWidget))
266
270
or WinWidgetInfo^.EventMask;
267
gtk_widget_add_events(Widget,NewEventMask);
268
gdk_window_set_events(GetControlWindow(Widget),NewEventMask);
270
if (ClientWidget<>nil) and (GetControlWindow(ClientWidget)<>nil)
271
and (GetControlWindow(ClientWidget)<>GetControlWindow(Widget)) then begin
272
//DebugLn(['gtkRealizeAfterCB ClientWindow<>Window']);
273
NewEventMask:=gdk_window_get_events(GetControlWindow(ClientWidget))
274
or WinWidgetInfo^.EventMask;
275
gtk_widget_add_events(ClientWidget,WinWidgetInfo^.EventMask);
276
gdk_window_set_events(GetControlWindow(ClientWidget),NewEventMask);
278
//DebugLn('BBB1 ',DbgS(NewEventMask),8),' ',DbgS(Cardinal(gdk_window_get_events(Widget^.Window)));
279
{$IFDEF DebugGDK}EndGDKErrorTrap;{$ENDIF}
282
if TheWinControl<>nil then
284
TheWinControl.CNPreferredSizeChanged;
285
TGtkPrivateWidgetClass(TheWinControl.WidgetSetClass.WSPrivate).UpdateCursor(WinWidgetInfo);
286
ConnectInternalWidgetsSignals(MainWidget,TheWinControl);
288
if TheWinControl is TCustomPage then
289
UpdateNotebookPageTab(nil,TheWinControl);
291
if TheWinControl is TCustomForm then
292
SetFormShowInTaskbar(TCustomForm(TheWinControl),
293
TCustomForm(TheWinControl).ShowInTaskbar);
298
// this is a hidden child widget of a lcl widget
299
if HiddenLCLObject is TWinControl then
300
ConnectInternalWidgetsSignals(Widget,TWinControl(HiddenLCLObject));
271
gtk_widget_add_events(ClientWidget,WinWidgetInfo^.EventMask);
272
gdk_window_set_events(GetControlWindow(ClientWidget),NewEventMask);
274
//DebugLn('BBB1 ',DbgS(NewEventMask),8),' ',DbgS(Cardinal(gdk_window_get_events(Widget^.Window)));
275
{$IFDEF DebugGDK}EndGDKErrorTrap;{$ENDIF}
278
if TheWinControl<>nil then
280
TheWinControl.CNPreferredSizeChanged;
281
TGtkPrivateWidgetClass(TheWinControl.WidgetSetClass.WSPrivate).UpdateCursor(WinWidgetInfo);
282
ConnectInternalWidgetsSignals(MainWidget,TheWinControl);
284
if TheWinControl is TCustomPage then
285
UpdateNotebookPageTab(nil,TheWinControl);
287
if TheWinControl is TCustomForm then
288
SetFormShowInTaskbar(TCustomForm(TheWinControl),
289
TCustomForm(TheWinControl).ShowInTaskbar);
421
428
NeedCursorCheck := False;
422
429
if GTK_IS_ENTRY(Widget) then
424
{cheat GtkEditable to update cursor pos in gtkEntry. issue #7243}
425
gtk_editable_get_selection_bounds(PGtkEditable(Widget), @GStart, @GEnd);
426
EntryText := gtk_entry_get_text(PGtkEntry(Widget));
427
if (GStart = GEnd) and
428
(UTF8Length(EntryText) >= PGtkEntry(Widget)^.text_length) then
431
// lcl-do-not-change-selection comes from gtkKeyPress.
432
// Only floatspinedit sets that data, so default is nil. issue #18679
433
if g_object_get_data(PGObject(Widget),'lcl-do-not-change-selection') = nil then
430
Info := GetWidgetInfo(Widget, False);
431
{do not update position if backspace or delete pressed}
432
if wwiInvalidEvent in Info^.Flags then
433
exclude(Info^.Flags, wwiInvalidEvent)
435
{cheat GtkEditable to update cursor pos in gtkEntry. issue #7243}
436
gtk_editable_get_selection_bounds(PGtkEditable(Widget), @GStart, @GEnd);
437
EntryText := gtk_entry_get_text(PGtkEntry(Widget));
438
if (GStart = GEnd) and
439
(UTF8Length(EntryText) >= PGtkEntry(Widget)^.text_length) then
436
// if we change selstart in OnChange event new cursor pos need to
437
// be postponed in TGtk2WSCustomEdit.SetSelStart
438
NeedCursorCheck := True;
439
gtk_editable_set_position(PGtkEditable(Widget), GStart + 1);
441
Info := GetWidgetInfo(Widget, False);
442
{do not update position if backspace or delete pressed}
443
if wwiInvalidEvent in Info^.Flags then
445
Exclude(Info^.Flags, wwiInvalidEvent);
447
{take care of pasted data since it does not return proper cursor pos.}
449
if g_object_get_data(PGObject(Widget),'lcl-delay-cm_textchaged') <> nil then
451
g_object_set_data(PGObject(Widget),'lcl-delay-cm_textchaged',nil);
452
g_object_set_data(PGObject(Widget),'lcl-gtkentry-pasted-data',Widget);
453
g_idle_add(@GtkEntryDelayCursorPos, Widget);
458
// if we change selstart in OnChange event new cursor pos need to
459
// be postponed in TGtk2WSCustomEdit.SetSelStart
460
NeedCursorCheck := True;
461
if g_object_get_data(PGObject(Widget),'lcl-gtkentry-pasted-data') <> nil then
463
g_object_set_data(PGObject(Widget),'lcl-gtkentry-pasted-data',nil);
464
gtk_editable_set_position(PGtkEditable(Widget), GStart);
467
//NeedCursorCheck := True;
468
if gtk_minor_version < 17 then
470
g_object_set_data(PGObject(Widget),'lcl-gtkentry-pasted-data',Widget);
471
g_idle_add(@GtkEntryDelayCursorPos, Widget);
474
gtk_editable_set_position(PGtkEditable(Widget), GStart + 1);
479
g_object_set_data(PGObject(Widget),'lcl-do-not-change-selection', nil);
444
482
if NeedCursorCheck then
445
483
LockOnChange(PgtkObject(Widget), +1);
446
FillByte(Mess,SizeOf(Mess),0);
484
FillByte(Mess{%H-},SizeOf(Mess),0);
447
485
Mess.Msg := CM_TEXTCHANGED;
448
486
DeliverMessage(Data, Mess);
449
487
if NeedCursorCheck then
453
491
function gtkchanged_spinbox(widget: PGtkWidget; data: gPointer): GBoolean; cdecl;
495
AValue, AMin, AMax: Double;
498
ADecimalSeparator: Char;
455
500
Result := CallBackDefaultReturn;
456
501
if LockOnChange(PgtkObject(Widget),0) > 0 then exit;
457
503
// prior to gtk2-2.12 there's bug with signalling of spin button
458
504
// which leads to crash.See issue #18554
505
// we are passing this code only for gtk2 >= 2.12
459
506
if GTK_IS_SPIN_BUTTON(Widget) and (gtk_minor_version >= 12) then
460
gtk_spin_button_update(PGtkSpinButton(Widget));
508
NumDigits := gtk_spin_button_get_digits(PGtkSpinButton(Widget));
509
if NumDigits > 0 then
511
{$IF FPC_FULLVERSION<20600}
512
ADecimalSeparator := DecimalSeparator;
514
ADecimalSeparator := DefaultFormatSettings.DecimalSeparator;
516
SValue := gtk_entry_get_text(PGtkEntry(Widget));
518
{do not try to parse SValue if it's empty, eg started typing on
519
selected value. issue #23190}
520
if (SValue = '') or (SValue = ',') or
521
(SValue = '.') or (SValue = '+') or
522
(SValue = '-') or (SValue = ADecimalSeparator) then
524
FillByte(Mess{%H-},SizeOf(Mess),0);
525
Mess.Msg := CM_TEXTCHANGED;
526
DeliverMessage(Data, Mess);
531
AValue := StrToFloatDef(SValue, 0);
533
{do not freeze (below) if clocale isn't used. issue #23190}
534
if (ADecimalSeparator <> '.') and (Pos('.', SValue) <> 0) then
536
SValue := StringReplace(SValue, '.', ADecimalSeparator, [rfReplaceAll]);
537
if (SValue[1] = ADecimalSeparator) then
538
SValue := '0' + SValue;
540
AValue := StrToFloatDef(SValue, 0);
542
if (ADecimalSeparator <> ',') and (Pos(',', SValue) <> 0) then
544
SValue := StringReplace(SValue, ',', ADecimalSeparator, [rfReplaceAll]);
545
if (SValue[1] = ADecimalSeparator) then
546
SValue := '0' + SValue;
548
AValue := StrToFloatDef(SValue, 0);
551
gtk_spin_button_get_range(PGtkSpinButton(Widget), @AMin, @AMax);
555
// gtk2 have different meaning how validator should work and trigger
556
// so we change it. #18679
557
// do not use while loop, but assign to minimum or maximum allowed. #23190
558
if (AValue < AMin) or (AValue > AMax) then
560
if AValue < AMin then
561
SValue := FloatToStr(AMin);
562
if AValue > AMax then
563
SValue := FloatToStr(AMax);
564
AValue := StrToFloatDef(SValue, 0);
566
if (Pos(ADecimalSeparator, SValue) > 0) and (length(SValue) > 1) then
568
SNewValue := Copy(SValue,Pos(ADecimalSeparator, SValue) + 1, length(SValue));
569
while length(SNewValue) > NumDigits do
571
Delete(SValue, length(SValue), 1);
575
if SNewValue <> SValue then
576
gtk_entry_set_text(PGtkEntry(Widget), PChar(SValue));
578
// inform LCL about our changes to entry
579
FillByte(Mess{%H-},SizeOf(Mess),0);
580
Mess.Msg := CM_TEXTCHANGED;
581
DeliverMessage(Data, Mess);
583
// always signal update to pure TSpinEdit
584
gtk_spin_button_update(PGtkSpinButton(Widget));
463
588
function gtkchanged_editbox_backspace(widget: PGtkWidget;
609
734
//DebugLn(['gtkExposeEventAfter ',GetWidgetDebugReport(Widget),' ',dbgGRect(@Event^.Area)]);
611
736
DeliverGtkPaintMessage(Data,Widget,@Event^.Area,false,true);
613
// Some widgets in gtk2 don't have their own exclusive "windows" so a synthetic event must be sent
614
// MG: That is already done by the gtk2. For which widgets does this not work?
615
// Enabling this results in double painting, which is slower and
616
// wrong for anitaliased text.
617
{if GTK_IS_FIXED(Widget) then begin
618
children := gtk_container_get_children(PGtkContainer(Widget));
619
while children <> nil do begin
620
if (children^.data <> nil) then begin
621
if GTK_WIDGET_NO_WINDOW(PGtkWidget(children^.data)) then
622
gtk_container_propagate_expose(PGtkContainer(Widget), PGtkWidget(children^.data), Event);
623
if children^.next = nil then break;
624
children := children^.next;
627
g_list_free(children);
631
739
function gtkfrmactivateAfter(widget: PGtkWidget; Event : PgdkEventFocus;
1004
// we do not show selection (gtk behaviour) when widget is unfocused,
1005
// so revert back CursorPos.issues #18164,#21897,#23182
1006
if GtkWidgetIsA(Widget, gtk_type_entry) then
1008
AInfo := GetWidgetInfo(Widget);
1009
if AInfo <> nil then
1011
if (AInfo^.LCLObject is TCustomEdit) and
1012
not TCustomEditHack(AInfo^.LCLObject).AutoSelect then
1013
if (AInfo^.CursorPos > 0) or (AInfo^.SelLength > 0) then
1015
// gtk_entry_set_position(PGtkEntry(Widget), AInfo^.CursorPos);
1016
// gtk_editable_select_region(PGtkEditable(Widget), AInfo^.CursorPos, AInfo^.CursorPos);
1017
// do not trigger signals, only update pos for lcl
1018
PGtkEntry(Widget)^.current_pos := AInfo^.CursorPos;
1019
PGtkEntry(Widget)^.selection_bound := AInfo^.CursorPos + AInfo^.SelLength;
888
1024
ResetDefaultIMContext;
889
UpdateMouseCaptureControl;
891
1026
//TODO: fill in old focus
892
FillChar(Mess, SizeOf(Mess), 0);
1027
FillChar(Mess{%H-}, SizeOf(Mess), 0);
893
1028
Mess.msg := LM_SETFOCUS;
894
1029
DeliverMessage(Data, Mess);
994
1146
ResetDefaultIMContext;
995
UpdateMouseCaptureControl;
997
FillChar(Mess,SizeOf(Mess),0);
1148
FillChar(Mess{%H-},SizeOf(Mess),0);
998
1149
Mess.msg := LM_KILLFOCUS;
999
1150
// do not release the capture widget here
1001
1152
//TODO: fill in new focus
1002
Assert(False, Format('Trace:TODO: [gtkkillfocusCB] %s finish', [TObject(Data).ClassName]));
1153
//DebugLn(Format('Trace:TODO: [gtkkillfocusCB] %s finish', [TObject(Data).ClassName]));
1004
1155
DeliverMessage(Data, Mess);
1157
// do not show selection when widget is unfocused
1158
// issues #18164,#21897,#23182
1159
if GtkWidgetIsA(Widget, gtk_type_entry) then
1161
g_idle_add(@GtkEntryDelayClearCursorPos, Widget);
1162
//save now CursorPos and SelStart in WidgetInfo
1163
if (Widget <> nil) then
1165
Info := GetWidgetInfo(Widget);
1168
if (Info^.LCLObject is TCustomEdit) and
1169
not TCustomEditHack(Info^.LCLObject).AutoSelect then
1171
gtk_editable_get_selection_bounds(PGtkEditable(Widget),@AStart, @AEnd);
1172
Info^.CursorPos := Min(AStart, AEnd);
1173
Info^.SelLength := Abs(AEnd - AStart);
1072
SizeMsg.SizeType := SIZEICONIC;
1245
SizeMsg.SizeType := SIZE_MINIMIZED;
1074
1247
else if (GDK_WINDOW_STATE_MAXIMIZED and state^.new_window_state)>0 then
1076
1249
// it can be both maximized + iconified and just loose iconified state
1077
1250
if (state^.changed_mask and (GDK_WINDOW_STATE_MAXIMIZED or GDK_WINDOW_STATE_ICONIFIED)) = 0 then Exit;
1078
SizeMsg.SizeType := SIZEFULLSCREEN;
1251
SizeMsg.SizeType := SIZE_MAXIMIZED;
1081
SizeMsg.SizeType := SIZENORMAL;
1254
SizeMsg.SizeType := SIZE_RESTORED;
1083
1256
if (TheForm = Application.MainForm) and
1084
(SizeMsg.SizeType <> SIZEICONIC) and
1257
(SizeMsg.SizeType <> SIZE_MINIMIZED) and
1085
1258
(TheForm.WindowState = wsMinimized) then
1086
1259
Application.IntfAppRestore;
1088
1261
// don't bother the LCL if nothing changed
1089
1262
case SizeMsg.SizeType of
1090
SIZENORMAL: if TheForm.WindowState=wsNormal then exit;
1091
SIZEICONIC: if TheForm.WindowState=wsMinimized then exit;
1092
SIZEFULLSCREEN: if TheForm.WindowState=wsMaximized then exit;
1263
SIZE_RESTORED: if TheForm.WindowState=wsNormal then exit;
1264
SIZE_MINIMIZED: if TheForm.WindowState=wsMinimized then exit;
1265
SIZE_MAXIMIZED: if TheForm.WindowState=wsMaximized then exit;
1266
SIZE_FULLSCREEN: if TheForm.WindowState=wsFullScreen then exit;
1095
1269
with SizeMsg do
1257
1431
// send the message directly to the LCL
1258
1432
// (Posting the message via queue
1259
1433
// has the risk of getting out of sync with the gtk)
1260
NotifyApplicationUserInput(Msg.Msg);
1434
NotifyApplicationUserInput(AWinControl, Msg.Msg);
1261
1435
//DebugLn(['DeliverMouseMoveMessage ',dbgsName(AWinControl)]);
1262
1436
DeliverMessage(AWinControl, Msg);
1438
// if dragmanager is started later then inform g_object issue #19914
1439
if GTK_IS_NOTEBOOK({%H-}PGtkWidget(AWinControl.Handle)) and
1440
DragManager.IsDragging and
1441
(g_object_get_data({%H-}PGObject(AWinControl.Handle),'lclnotebookdragging') = nil)
1443
g_object_set_data({%H-}PGObject(AWinControl.Handle),
1444
'lclnotebookdragging', gpointer(PtrInt(1)));
1447
procedure FixListViewRubberBand(AWidget: PGtkWidget);
1450
IconView: PGtkIconView;
1451
Priv: _PGtkIconViewPrivate;
1453
Info := GetWidgetInfo(AWidget);
1454
IconView := PGtkIconView(Info^.CoreWidget);
1455
Priv := IconView^.priv;
1457
if Priv^.doing_rubberband then
1459
Priv^.doing_rubberband := False;
1460
gtk_widget_queue_draw(AWidget);
1265
1464
{-------------------------------------------------------------------------------
1266
1465
function ControlGetsMouseMoveBefore(AControl: TControl): boolean;
1268
Returns true, if mouse move event should be sent before the widget istelf
1467
Returns true, if mouse move event should be sent before the widget itself
1270
1469
-------------------------------------------------------------------------------}
1271
function ControlGetsMouseMoveBefore(AControl: TControl): boolean;
1470
function ControlGetsMouseMoveBefore(AControl: TControl;
1471
const ABefore: Boolean; Event: PGDKEventMotion): boolean;
1473
ShiftState: TShiftState;
1475
MainView: PGtkWidget;
1273
1477
if (AControl=nil) then ;
1274
1479
// currently there are no controls, that need after events.
1480
if not ABefore then exit;
1482
// gtk2 column resizing ... issue #21354
1483
if (Event <> nil) and not (csDesigning in AControl.ComponentState) and
1484
(AControl is TListView) and
1485
(TListView(AControl).ViewStyle = vsReport) and
1486
(TListView(AControl).ShowColumnHeaders) then
1488
ShiftState := GTKEventStateToShiftState(Event^.State);
1489
if ssLeft in ShiftState then
1491
Widget := {%H-}PGtkWidget(TWinControl(AControl).Handle);
1492
if GTK_IS_SCROLLED_WINDOW(Widget) then
1494
MainView := gtk_bin_get_child(PGtkBin(Widget));
1495
if GTK_IS_TREE_VIEW(MainView) then
1498
if gtk_tree_view_get_bin_window(PGtkTreeView(MainView)) <> Event^.window then
1500
//TODO: queue column resize when x < 0
1501
// gtk_tree_view_column_queue_resize(tree_column: PGtkTreeViewColumn)
1506
if (Event <> nil) and not (csDesigning in AControl.ComponentState) and
1507
(AControl is TWinControl) and
1508
(TWinControl(AControl).FCompStyle = csListView) and
1509
(TListView(AControl).ViewStyle in [vsIcon, vsSmallIcon]) and
1510
TListView(AControl).MultiSelect then
1512
ShiftState := GTKEventStateToShiftState(Event^.State);
1513
// issue #22991 - this fixes rubberbanding
1514
if [ssShift, ssAlt, ssCtrl, ssLeft, ssRight, ssMiddle, ssDouble] * ShiftState = [] then
1515
FixListViewRubberBand(PGtkWidget(TWinControl(AControl).Handle));
1278
1519
procedure GTKGetDevicePointer(win: PGdkWindow; dev: PGdkDevice;
1399
1639
// stop the signal, so that it is not sent to the parent widgets
1400
1640
g_signal_stop_emission_by_name(PGTKObject(Widget),'motion-notify-event');
1402
UpdateMouseCaptureControl;
1404
1642
if (csDesigning in TComponent(Data).ComponentState) then exit;
1405
if ControlGetsMouseMoveBefore(TControl(Data)) then exit;
1643
if ControlGetsMouseMoveBefore(TControl(Data), True, Event) then exit;
1407
1645
DeliverMouseMoveMessage(Widget,Event, TWinControl(Data));
1649
// restore old column sizing after dblclick. issue #18381
1650
function ReturnColumnSizing(AGtkWidget: Pointer): gboolean; cdecl;
1653
ASizing: TGtkTreeViewColumnSizing;
1654
Column: PGtkTreeViewColumn;
1657
Result := AGtkWidget <> nil;
1658
if AGtkWidget <> nil then
1660
if g_object_get_data(PGObject(AGtkWidget),'lcl-column-resized-dblclick') <> nil then
1662
AIndex := {%H-}PtrInt(g_object_get_data(PGObject(AGtkWidget),'lcl-column-resized-dblclick') - 1);
1663
ASizing := TGtkTreeViewColumnSizing({%H-}PtrUInt(g_object_get_data(PGObject(AGtkWidget),'lcl-column-resized-dblclick-oldsizing')) - 1);
1664
g_object_set_data(PGObject(AGtkWidget),'lcl-column-resized-dblclick', nil);
1665
g_object_set_data(PGObject(AGtkWidget),'lcl-column-resized-dblclick-oldsizing', nil);
1666
if (AIndex >= 0) then
1668
Column := gtk_tree_view_get_column(PGtkTreeView(AGtkWidget), AIndex);
1669
ColWidth := gtk_tree_view_column_get_width(Column);
1670
gtk_tree_view_column_set_sizing(Column, ASizing);
1671
gtk_tree_view_column_set_fixed_width(Column, ColWidth);
1674
g_idle_remove_by_data(AGtkWidget);
1678
{resizes column to like autosize does when dblclicked separator. issue #18381}
1679
function ResizeColumnOnDblClick({%H-}ACtl: TWinControl; ScrolledWin: PGtkWidget;
1680
TreeView: PGtkTreeView; const AMouseCoord: TPoint): Boolean;
1682
Adjustment: PGtkAdjustment;
1684
Column: PGtkTreeViewColumn;
1688
CurSizing: TGtkTreeViewColumnSizing;
1696
// think about horizontal scrollbar position too !
1697
Adjustment := gtk_scrolled_window_get_hadjustment(PGtkScrolledWindow(ScrolledWin));
1698
if Adjustment <> nil then
1699
xoffset := Round(gtk_adjustment_get_value(Adjustment))
1703
List := gtk_tree_view_get_columns(TreeView);
1705
for i := 0 to g_list_length(List) - 1 do
1707
Column := g_list_nth_data(List, i);
1708
if Column = nil then
1710
if gtk_tree_view_column_get_visible(Column) then
1712
ColWidth := gtk_tree_view_column_get_width(Column);
1713
if (Accu + ColWidth + 3 >= Pt.X + xoffset) then
1715
// DebugLn('NOTICE: GtkTreeView column resizing on dblclick ',i);
1716
CurSizing := gtk_tree_view_column_get_sizing(Column);
1717
if gtk_tree_view_column_get_resizable(Column) and
1718
(CurSizing <> GTK_TREE_VIEW_COLUMN_AUTOSIZE) then
1720
gtk_tree_view_column_set_sizing(Column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1721
gtk_tree_view_column_set_resizable(Column, True);
1724
// we are adding i + 1 since if i = 0 then ptr is null !
1725
g_object_set_data(PGObject(TreeView),'lcl-column-resized-dblclick', {%H-}GPointer(ColIndex + 1));
1726
Accu := Ord(CurSizing);
1727
// we are adding Accu + 1 since if Accu = 0 then ptr is null !
1728
g_object_set_data(PGObject(TreeView),'lcl-column-resized-dblclick-oldsizing', {%H-}GPointer(Accu + 1));
1729
Accu := g_idle_add(@ReturnColumnSizing, TreeView);
1734
Accu := Accu + ColWidth + 3 {section separator offset};
1737
Result := not (ColIndex >= 0);
1410
1743
{-------------------------------------------------------------------------------
1411
1744
function ControlGetsMouseDownBefore(AControl: TControl): boolean;
1415
1748
-------------------------------------------------------------------------------}
1416
1749
function ControlGetsMouseDownBefore(AControl: TControl;
1417
AWidget: PGtkWidget): boolean;
1750
{%H-}AWidget: PGtkWidget; Event : PGdkEventButton): boolean;
1753
MainView: PGtkWidget;
1420
if AControl=nil then exit;
1421
if GtkWidgetIsA(AWidget,gtk_toggle_button_get_type) then begin
1757
if AControl = nil then exit;
1759
if not (csDesigning in AControl.ComponentState) and
1760
(Event^.button = 1) and
1761
(gdk_event_get_type(Event) = GDK_2BUTTON_PRESS) and
1762
(AControl is TWinControl) and
1763
(TWinControl(AControl).FCompStyle = csListView) and
1764
(TListView(AControl).ViewStyle = vsReport) and
1765
(TListView(AControl).ShowColumnHeaders) then
1767
Widget := {%H-}PGtkWidget(TWinControl(AControl).Handle);
1768
if GTK_IS_SCROLLED_WINDOW(Widget) then
1770
MainView := gtk_bin_get_child(PGtkBin(Widget));
1771
if GTK_IS_TREE_VIEW(MainView) then
1773
if gtk_tree_view_get_bin_window(PGtkTreeView(MainView)) <> Event^.window then
1775
Pt.X := Round(Event^.x_root);
1776
Pt.Y := Round(Event^.y_root);
1777
ScreenToClient(TWinControl(AControl).Handle, Pt);
1778
Result := ResizeColumnOnDblClick(TWinControl(AControl), Widget,
1779
PGtkTreeView(MainView), Pt);
1784
if not (csDesigning in AControl.ComponentState) and
1785
(Event^.button = 1) and
1786
(gdk_event_get_type(Event) = GDK_BUTTON_PRESS) and
1787
(AControl is TWinControl) and
1788
(TWinControl(AControl).FCompStyle = csListView) and
1789
(TListView(AControl).ViewStyle in [vsIcon, vsSmallIcon]) and
1790
TListView(AControl).MultiSelect then
1792
// issue #22991 - this fixes crash after click on listview when modal form
1794
FixListViewRubberBand(PGtkWidget(TWinControl(AControl).Handle));
1582
1974
Issues #16972, #17888. }
1583
1975
if Result and GTK_IS_TREE_VIEW(Widget) and (event^.button = 3) then
1586
FillChar(Mess,SizeOf(Mess),0);
1587
Mess.msg := LM_SelChange;
1588
DeliverMessage(TWinControl(Data), Mess);
1977
Column := gtk_tree_view_get_column(GTK_TREE_VIEW(Widget), 0);
1979
if gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(Widget), Round(Event^.x), Round(Event^.y),
1980
Path, Column, @x, @y) then
1982
gtk_tree_view_set_cursor(GTK_TREE_VIEW(Widget), Path, Column, False);
1983
gtk_widget_queue_draw(Widget);
1589
1985
g_signal_stop_emission_by_name(PGTKObject(Widget), 'button-press-event');
1594
1990
if (event^.Button=1) and
1595
((TControl(Data) is TCustomNoteBook) or (TControl(Data) is TCustomTabControl)) then
1991
(TControl(Data) is TCustomTabControl) then
1597
// clicks on the notebook should be handled by the gtk (switching page)
1993
// clicks on the tab control should be handled by the gtk (switching page)
1943
2371
//' GDK_BUTTON_RELEASE_MASK=',DbgS(GDK_BUTTON_RELEASE_MASK));
1945
2373
ResetDefaultIMContext;
1946
UpdateMouseCaptureControl;
1948
2375
if not (csDesigning in TComponent(Data).ComponentState) then
1950
2377
DesignOnlySignal := GetDesignOnlySignalFlag(Widget, dstMouseRelease);
2379
if (TControl(Data) is TCustomListView) and
2380
(TListView(Data).ViewStyle in [vsIcon, vsSmallIcon]) and
2381
TListView(Data).MultiSelect then
2383
// fixed crash.See issue #22778
2384
FixListViewRubberBand(Widget);
1951
2387
ReleaseMouseCapture;
1952
2388
if DesignOnlySignal or (not ControlGetsMouseUpBefore(TControl(Data))) then
1956
2392
// stop the signal, so that the widget does not auto react
1957
if (not (TControl(Data) is TCustomNoteBook)) and
1958
(not (TControl(Data) is TCustomTabControl))
2393
if not (TControl(Data) is TCustomTabControl) then
1960
2395
g_signal_stop_emission_by_name(PGTKObject(Widget), 'button-release-event');
1961
2396
Result := not CallBackDefaultReturn;
2026
2460
EventXY:=Point(TruncToInt(Event^.X),TruncToInt(Event^.Y));
2027
2461
ShiftState := GTKEventStateToShiftState(Event^.State);
2028
2462
MappedXY:=TranslateGdkPointToClientArea(Event^.Window,EventXY,
2029
PGtkWidget(AWinControl.Handle));
2030
MappedXY := SubtractScoll(PGtkWidget(AWinControl.Handle), MappedXY);
2463
{%H-}PGtkWidget(AWinControl.Handle));
2464
MappedXY := SubtractScoll({%H-}PGtkWidget(AWinControl.Handle), MappedXY);
2031
2465
//DebugLn('gtkMouseWheelCB ',DbgSName(AWinControl),' Mapped=',dbgs(MappedXY.X),',',dbgs(MappedXY.Y),' Event=',dbgs(EventXY.X),',',dbgs(EventXY.Y));
2033
2467
// this is a mouse wheel event
2034
FillChar(MessE,SizeOf(MessE),0);
2468
FillChar(MessE{%H-},SizeOf(MessE),0);
2035
2469
MessE.Msg := LM_MOUSEWHEEL;
2036
2470
case event^.direction of
2037
2471
GDK_SCROLL_UP: MessE.WheelDelta := 120;
2682
3117
SmallPos := High(SmallPos);
2684
ScrollBar := HWND(PtrUInt(ARange));
3119
ScrollBar := HWND({%H-}PtrUInt(ARange));
2685
3120
ScrollCode := GtkScrollTypeToScrollCode(AScrollType);
3122
DeliverMessage(AWidgetInfo^.LCLObject, Msg);
3124
if Msg.Scrollcode=SB_THUMBTRACK then
3126
if Widget^.state = 0 then
3128
Msg.ScrollCode := SB_THUMBPOSITION;
3129
DeliverMessage(AWidgetInfo^.LCLObject, Msg);
3130
Msg.ScrollCode:=SB_ENDSCROLL;
3131
DeliverMessage(AWidgetInfo^.LCLObject, Msg);
3134
else Widget^.state := 1;
3136
if (AWidgetInfo^.LCLObject is TScrollingWinControl) and
3137
((Msg.ScrollCode=SB_LINEUP) or (Msg.ScrollCode=SB_LINEDOWN)) then
3141
function Gtk2RangeScrollPressCB(Widget: PGtkWidget;
3142
Event: PGdkEventButton; Data: gPointer): gboolean; cdecl;
3145
Result := CallBackDefaultReturn;;
3148
function Gtk2RangeScrollReleaseCB(Widget: PGtkWidget;
3149
Event: PGdkEventButton; Data: gPointer): gboolean; cdecl;
3152
WidgetInfo: PWidgetInfo;
3154
AValue:=PGtkRange(Widget)^.adjustment^.value;
3155
WidgetInfo:=GetWidgetInfo(Widget, False);
3156
if not Assigned(WidgetInfo) then
3157
WidgetInfo:=GetWidgetInfo(Widget^.parent, False);
3158
if Assigned(WidgetInfo) and (Widget^.state = 1) then
3159
Gtk2RangeScrollCB(PGtkRange(Widget), 0, AValue, WidgetInfo);
3161
Result := CallBackDefaultReturn;
3164
function Gtk2RangeUbuntuScrollCB(Adjustment: PGTKAdjustment; data: GPointer): GBoolean; cdecl;
3167
AWidgetInfo: PWidgetInfo;
3169
ScrollType: TGtkScrollType;
3172
Result := CallBackDefaultReturn;
3173
AWidgetInfo:=PWidgetInfo(Data);
3175
//debugln(['Gtk2RangeUbuntuScrollCB ',DbgSName(AWidgetInfo^.LCLObject)]);
3176
Scroll := PgtkRange(gtk_object_get_data(PGTKObject(Adjustment), odnScrollBar));
3177
if Scroll<>nil then begin
3178
FillByte(Msg{%H-},SizeOf(Msg),0);
3179
if Scroll^.orientation=GTK_ORIENTATION_VERTICAL then
3180
Msg.Msg := LM_VSCROLL
3182
Msg.Msg := LM_HSCROLL;
3184
Pos := Round(Adjustment^.Value);
3185
if Pos < High(SmallPos)
3186
then SmallPos := Pos
3187
else SmallPos := High(SmallPos);
3189
LastPos:={%H-}PtrInt(gtk_object_get_data(PGTKObject(Adjustment), odnScrollBarLastPos));
3190
if LastPos=Pos then begin
3191
//debugln(['Gtk2RangeUbuntuScrollCB duplicate message => skip']);
3194
gtk_object_set_data(PGTKObject(Adjustment), odnScrollBarLastPos, {%H-}gpointer(Pos));
3196
//DebugLn('Gtk2RangeUbuntuScrollCB A Adjustment^.Value=',dbgs(Adjustment^.Value),' SmallPos=',dbgs(SmallPos));
3197
ScrollBar := HWND({%H-}PtrUInt(Scroll));
3198
ScrollType := get_gtk_scroll_type(Scroll);
3199
ScrollCode := ScrollTypeToSbCode(True, ScrollType,
3200
gtk_range_get_update_policy(Scroll));
3201
//DebugLn('Gtk2RangeUbuntuScrollCB B Adjustment^.Value=',dbgs(Adjustment^.Value),' ScrollCode=',dbgs(ScrollCode),' ScrollType=',dbgs(ScrollType));
3203
DeliverMessage(AWidgetInfo^.LCLObject, Msg);
3208
function Gtk2ScrolledWindowScrollCB(AScrollWindow: PGtkScrolledWindow; AEvent: PGdkEventScroll; AWidgetInfo: PWidgetInfo): gboolean; cdecl;
3214
{$IFDEF SYNSCROLLDEBUG}
3215
debugln(['Gtk2ScrolledWindowScrollCB ']);
3217
case AEvent^.direction of
3219
GDK_SCROLL_DOWN: Msg.Msg := LM_VSCROLL;
3221
GDK_SCROLL_RIGHT: Msg.Msg := LM_HSCROLL;
3225
LM_VSCROLL: Range := GTK_RANGE(AScrollWindow^.vscrollbar);
3226
LM_HSCROLL: Range := GTK_RANGE(AScrollWindow^.hscrollbar);
3229
AValue := power(Range^.adjustment^.page_size, 2 / 3);
3231
if (AEvent^.direction = GDK_SCROLL_UP) or
3232
(AEvent^.direction = GDK_SCROLL_LEFT)
3236
AValue := gtk_range_get_value(Range) + AValue;
3238
AValue := Max(AValue, Range^.adjustment^.lower);
3239
AValue := Min(AValue, Range^.adjustment^.upper - Range^.adjustment^.page_size);
3243
Pos := Round(AValue);
3244
if Pos < High(SmallPos) then
3247
SmallPos := High(SmallPos);
3249
ScrollBar := HWND({%H-}PtrUInt(Range));
3250
ScrollCode := SB_THUMBPOSITION;
2687
3252
Result := DeliverMessage(AWidgetInfo^.LCLObject, Msg) <> 0;
3174
3739
GtkList:=PGtkList(widget);
3175
3740
if (GtkList^.selection = nil) or (LockOnChange(PGtkObject(widget),0) > 0) then
3177
FillChar(Mess,SizeOf(Mess),0);
3742
FillChar(Mess{%H-},SizeOf(Mess),0);
3178
3743
Mess.msg := LM_SelChange;
3179
3744
if gtkListGetSelectionMode(GtkList)=GTK_SELECTION_SINGLE then
3180
3745
gtk_list_set_selection_mode(GtkList,GTK_SELECTION_BROWSE);
3181
3746
DeliverMessage(Data, Mess);
3184
{$I gtk2DragCallback.inc}
3185
{$I gtk2ComboBoxCallback.inc}
3186
{$I gtk2PageCallback.inc}
3749
//DRAG CALLBACK FUNCTIONS
3751
function edit_drag_data_received(widget : pgtkWidget;
3752
Context : pGdkDragContext;
3754
SelData : pGtkSelectionData;
3757
data : pointer) : GBoolean; cdecl;
3762
if (Widget=nil) or (X=0) or (Y=0) or (Info=0) then exit;
3763
//DebugLn('Trace:***********Drag Data Received*******************');
3764
if Seldata^.Length > 0 then
3766
Texts := StrPas(PChar(SelData^.data));
3767
//DebugLn('Trace:' + Texts);
3768
//DebugLn('Trace:0');
3769
TCustomEdit(Data).Caption := Texts;
3770
//DebugLn('Trace:1');
3772
gtk_drag_finish(Context,false,false,time);
3775
function edit_source_drag_data_get(widget : pgtkWidget;
3776
Context : pGdkDragContext;
3777
Selection_data : pGtkSelectionData;
3780
data : pointer) : GBoolean; cdecl;
3786
if (Time=0) or (Context=nil) or (Widget=nil) then ;
3787
if (info = TARGET_ROOTWIN) then begin
3788
//DebugLn('Trace:I WAS DROPPED ON THE ROOTWIN')
3791
//DebugLn('Trace:*********Setting Data************');
3792
Texts := TCustomEdit(data).Text;
3793
//DebugLn('Trace:0');
3794
strTemp := StrAlloc(length(Texts) + 1);
3796
StrPCopy(strTemp, Texts);
3797
//DebugLn('Trace:1');
3798
gtk_selection_data_set(selection_data,selection_data^.target,
3802
//DebugLn('Trace:2');
3804
strDispose(strTemp);
3806
//DebugLn('Trace:3');
3811
function Edit_source_drag_data_delete (Widget: pGtkWidget;
3812
Context: pGdkDragContext; Data: gpointer): gBoolean ; cdecl;
3814
if (Widget=nil) or (Context=nil) or (Data=nil) then ;
3815
//DebugLn('Trace:***************');
3816
//DebugLn('Trace:DELETE THE DATA');
3820
// combobox callbacks
3821
function gtkComboBoxShowAfter(widget: PGtkWidget; data: gPointer): GBoolean; cdecl;
3824
AComboBox: TCustomComboBox;
3827
EventTrace('ComboBoxShowAfter', data);
3829
AComboBox:=TObject(Data) as TCustomComboBox;
3830
AComboBox.IntfGetItems;
3832
if (Widget=nil) then ;
3833
FillChar(Mess{%H-},SizeOf(Mess),0);
3834
Mess.Msg := CN_Command;
3835
Mess.NotifyCode := CBN_DROPDOWN;
3837
Result := DeliverMessage(Data, Mess) = 0;
3840
function gtkComboBoxHideAfter(widget: PGtkWidget; data: gPointer): GBoolean; cdecl;
3845
if (Widget=nil) then ;
3846
EventTrace('ComboBoxHideAfter', data);
3847
FillChar(Mess{%H-},SizeOf(Mess),0);
3848
Mess.Msg := CN_Command;
3849
Mess.NotifyCode := CBN_CLOSEUP;
3851
Result := DeliverMessage(Data, Mess) = 0;
3854
// notebook callbacks
3855
procedure DrawNotebookPageIcon(Page: TCustomPage; Widget: PGtkWidget);
3857
NoteBook: TCustomTabControl;
3858
NoteBookWidget: PGtkWidget;
3859
PageWidget: PGtkWidget;
3860
TabWidget: PGtkWidget;
3861
ImageIndex: Integer;
3863
NoteBook := Page.Parent as TCustomTabControl;
3864
ImageIndex := NoteBook.GetImageIndex(Page.PageIndex);
3865
if (NoteBook.Images = nil) or (ImageIndex < 0)
3866
or (Page.ImageIndex >= NoteBook.Images.Count)
3867
or (not NoteBook.HandleAllocated)
3868
or (not Page.HandleAllocated)
3870
NoteBookWidget := {%H-}PGtkWidget(NoteBook.Handle);
3871
PageWidget := {%H-}PGtkWidget(Page.Handle);
3873
// get the tab container and the tab icon widget
3874
TabWidget := gtk_notebook_get_tab_label(PGtkNoteBook(NotebookWidget),
3876
if TabWidget = nil then exit;
3877
{$IFDEF VerboseGtkToDos}{$note reimplement}{$ENDIF}
3878
DrawImageListIconOnWidget(NoteBook.Images, ImageIndex, Widget);
3881
function PageIconWidgetExposeAfter(Widget: PGtkWidget; Event: PGDKEventExpose;
3882
Data: gPointer): GBoolean; cdecl;
3884
ThePage: TCustomPage;
3887
//DebugLn('PageIconWidgetExposeAfter ',DbgS(Widget));
3888
EventTrace('PageIconWidgetExposeAfter', Data);
3889
if (Event^.Count > 0) then exit;
3890
ThePage := TObject(Data) as TCustomPage;
3891
DrawNotebookPageIcon(ThePage, Widget);