From afb190401d34fea6ab23fe3dede4180aa163bd65 Mon Sep 17 00:00:00 2001 From: zeljko Date: Sun, 10 Oct 2010 15:26:45 +0000 Subject: [PATCH] Gtk2: fixed setCapture(), now it uses new way of capturing, old can be used with -dGTK2_USE_OLD_CAPTURE. fixed unwanted focus grab of THintWindow. fixed bug when scrollbar button double clicked, we need 2 clicks to focus our client area. Fixed bugs #13878 #17596. git-svn-id: trunk@27638 - --- lcl/interfaces/gtk2/gtk2callback.inc | 55 +++++++++++++++++++++------ lcl/interfaces/gtk2/gtk2globals.pp | 1 - lcl/interfaces/gtk2/gtk2proc.inc | 10 +++-- lcl/interfaces/gtk2/gtk2proc.pp | 8 ++++ lcl/interfaces/gtk2/gtk2widgetset.inc | 17 ++++++++- lcl/interfaces/gtk2/gtk2winapi.inc | 26 +++++++++++++ lcl/interfaces/gtk2/gtk2wscontrols.pp | 8 ++-- lcl/interfaces/gtk2/gtk2wsforms.pp | 4 +- 8 files changed, 107 insertions(+), 22 deletions(-) diff --git a/lcl/interfaces/gtk2/gtk2callback.inc b/lcl/interfaces/gtk2/gtk2callback.inc index 9cbafad51e..0141c795a5 100644 --- a/lcl/interfaces/gtk2/gtk2callback.inc +++ b/lcl/interfaces/gtk2/gtk2callback.inc @@ -1277,11 +1277,12 @@ function gtkMotionNotify(Widget:PGTKWidget; Event: PGDKEventMotion; var DesignOnlySignal: boolean; ShiftState: TShiftState; + {$IFNDEF GTK2_USE_OLD_CAPTURE} + W: PGtkWidget; + {$ENDIF} begin Result := CallBackDefaultReturn; - MousePositionValid:=false; - {$IFDEF VerboseMouseBugfix} DesignOnlySignal:=GetDesignOnlySignalFlag(Widget,dstMouseMotion); DebugLn('[GTKMotionNotify] ', @@ -1295,12 +1296,22 @@ begin UpdateMouseCaptureControl; ShiftState := GTKEventStateToShiftState(Event^.State); - if (MouseCaptureWidget=Widget) - and (MouseCaptureType=mctGTK) - and ([ssLeft,ssRight,ssMiddle]*ShiftState=[]) then begin + + if (MouseCaptureWidget = Widget) and (MouseCaptureType = mctGTK) and + ([ssLeft,ssRight,ssMiddle]*ShiftState=[]) then + begin + {$IFNDEF GTK2_USE_OLD_CAPTURE} + W := gtk_grab_get_current; + {$ENDIF} {$IFDEF VerboseMouseCapture} DebugLn(['gtkMotionNotify gtk capture without mouse down: ',GetWidgetDebugReport(Widget)]); {$ENDIF} + {$IFNDEF GTK2_USE_OLD_CAPTURE} + if W = nil then + SetCapture(0) + else + gtk_grab_remove(W); + {$ENDIF} end; if not (csDesigning in TComponent(Data).ComponentState) then @@ -1331,7 +1342,6 @@ function GTKMotionNotifyAfter(widget:PGTKWidget; event: PGDKEventMotion; data: gPointer): GBoolean; cdecl; begin Result := true; // stop event propagation - MousePositionValid := False; {$IFDEF VerboseMouseBugfix} DebugLn('[GTKMotionNotifyAfter] ', @@ -1364,6 +1374,33 @@ begin end; end; + +{------------------------------------------------------------------------------- +We must stop delivery of events from scrollbars of GtkScrollable, otherwise +if we make an double click on scollbar button, and after that click into +our control client area we need 2 click to make it focused. +gtk_signal_connect_after() is used, otherwise our scrollbar won't react on +such event. +-------------------------------------------------------------------------------} +function gtk2ScrollBarMouseBtnPress(widget: PGtkWidget; event: pgdkEventButton; + data: gPointer): GBoolean; cdecl; +begin + Result := True; +end; + +{------------------------------------------------------------------------------- +We must stop delivery of events from scrollbars of GtkScrollable, otherwise +if we make an double click on scollbar button, and after that click into +our control client area we need 2 click to make it focused. +gtk_signal_connect_after() is used, otherwise our scrollbar won't react on +such event. +-------------------------------------------------------------------------------} +function gtk2ScrollBarMouseBtnRelease(widget: PGtkWidget; event: pgdkEventButton; + data: gPointer): GBoolean; cdecl; +begin + Result := True; +end; + {------------------------------------------------------------------------------- gtkMouseBtnPress Params: widget: PGTKWidget; event: PGDKEventMotion; data: gPointer @@ -1429,7 +1466,6 @@ var {$ENDIF} begin Result := CallBackDefaultReturn; - MousePositionValid := False; {$IFDEF VerboseMouseBugfix} AWinControl := TWinControl(Data); @@ -1640,7 +1676,6 @@ var end; begin - MousePositionValid := False; EventXY := Point(TruncToInt(Event^.X), TruncToInt(Event^.Y)); ShiftState := GTKEventStateToShiftState(Event^.State); @@ -1709,7 +1744,6 @@ function gtkMouseBtnPressAfter(widget: PGtkWidget; event : pgdkEventButton; data: gPointer) : GBoolean; cdecl; begin Result := True; - MousePositionValid := False; {$IFDEF VerboseMouseBugfix} debugln('[gtkMouseBtnPressAfter] ', @@ -1822,7 +1856,6 @@ var DesignOnlySignal: boolean; begin Result := CallBackDefaultReturn; - MousePositionValid := False; {$IFDEF VerboseMouseBugfix} DesignOnlySignal:=GetDesignOnlySignalFlag(Widget,dstMouseRelease); @@ -1856,7 +1889,6 @@ begin Result := not CallBackDefaultReturn; end; end; - if DeliverMouseUpMessage(Widget, Event, TWinControl(Data)) then Result := not CallBackDefaultReturn; end; @@ -1873,7 +1905,6 @@ function gtkMouseBtnReleaseAfter(widget: PGtkWidget; event : pgdkEventButton; data: gPointer) : GBoolean; cdecl; begin Result := True; - MousePositionValid := False; {$IFDEF VerboseMouseBugfix} DebugLn('[gtkMouseBtnReleaseAfter] ',DbgSName(TObject(Data)),' ', diff --git a/lcl/interfaces/gtk2/gtk2globals.pp b/lcl/interfaces/gtk2/gtk2globals.pp index c7c04b5f5d..5d003014f2 100644 --- a/lcl/interfaces/gtk2/gtk2globals.pp +++ b/lcl/interfaces/gtk2/gtk2globals.pp @@ -61,7 +61,6 @@ var MouseCaptureWidget: PGtkWidget; MouseCaptureType: TMouseCaptureType; MouseCaptureIndex: cardinal; - MousePositionValid: boolean = false; MousePosition: TPoint; MousePositionTime: TDateTime; diff --git a/lcl/interfaces/gtk2/gtk2proc.inc b/lcl/interfaces/gtk2/gtk2proc.inc index 4b0955cefa..f6b3fb1d5e 100644 --- a/lcl/interfaces/gtk2/gtk2proc.inc +++ b/lcl/interfaces/gtk2/gtk2proc.inc @@ -4467,6 +4467,9 @@ var OldMouseCaptureWidget, CurMouseCaptureWidget: PGtkWidget; begin + {$IFNDEF GTK2_USE_OLD_CAPTURE} + exit; + {$ENDIF} OldMouseCaptureWidget:=MouseCaptureWidget; CurMouseCaptureWidget:=gtk_grab_get_current; @@ -4510,7 +4513,7 @@ begin {$ENDIF} if not (Owner in [mctGTKIntf,mctLCL]) then exit; // not every widget can capture the mouse - CaptureWidget:=GetDefaultMouseCaptureWidget(Widget); + CaptureWidget := GetDefaultMouseCaptureWidget(Widget); if CaptureWidget=nil then exit; UpdateMouseCaptureControl; @@ -4548,7 +4551,7 @@ var LCLObject: TObject; CanCapture: Boolean; Parent: TWinControl; - {$IFDEF DEBUG_GTK_MOUSECAPTURE} + {$IFDEF VerboseMouseCapture} CurrentGrab: PGtkWidget; GrabInfo: PWinWidgetInfo; {$ENDIF} @@ -4571,7 +4574,6 @@ begin if CanCapture then begin - if GTK_IS_NOTEBOOK(PGtkWidget(TWinControl(LCLObject).Handle)) then exit; @@ -4584,7 +4586,7 @@ begin WidgetInfo:=GetWidgetInfo(PGtkWidget(TWinControl(LCLObject).Handle),false); if WidgetInfo <> nil then begin - {$IFDEF DEBUG_GTK_MOUSECAPTURE} + {$IFDEF VerboseMouseCapture} CurrentGrab := gtk_grab_get_current; writeln('GetDefaultMouseCaptureWidget: ',TWinControl(LCLObject).ClassName,' core ', dbghex(PtrUInt(WidgetInfo^.CoreWidget)),' client ',dbghex(PtrUInt(WidgetInfo^.ClientWidget)), diff --git a/lcl/interfaces/gtk2/gtk2proc.pp b/lcl/interfaces/gtk2/gtk2proc.pp index 587e616e08..dc3dfa0cd2 100644 --- a/lcl/interfaces/gtk2/gtk2proc.pp +++ b/lcl/interfaces/gtk2/gtk2proc.pp @@ -151,6 +151,14 @@ function ControlGetsMouseDownBefore(AControl: TControl; AWidget: PGtkWidget): boolean; procedure DeliverMouseDownMessage(widget: PGtkWidget; event: pgdkEventButton; AWinControl: TWinControl); + +function gtk2ScrollBarMouseBtnPress(widget: PGtkWidget; event: pgdkEventButton; + data: gPointer): GBoolean; cdecl; + +function gtk2ScrollBarMouseBtnRelease(widget: PGtkWidget; event: pgdkEventButton; + data: gPointer): GBoolean; cdecl; + + function gtkMouseBtnPress(widget: PGtkWidget; event: pgdkEventButton; data: gPointer): GBoolean; cdecl; function gtkMouseBtnPressAfter(widget: PGtkWidget; event: pgdkEventButton; diff --git a/lcl/interfaces/gtk2/gtk2widgetset.inc b/lcl/interfaces/gtk2/gtk2widgetset.inc index daa1ef1387..d4b8fe81c2 100644 --- a/lcl/interfaces/gtk2/gtk2widgetset.inc +++ b/lcl/interfaces/gtk2/gtk2widgetset.inc @@ -912,8 +912,23 @@ end; procedure TGtk2WidgetSet.SetCommonCallbacks(const AGTKObject: PGTKObject; const ALCLObject: TObject); +var + Widget: PGtkWidget; begin - // original gtk1 code + if GTK_IS_SCROLLED_WINDOW(AGtkObject) then + begin + Widget := PGtkWidget(AGTKObject); + g_signal_connect_after(GTK_SCROLLED_WINDOW(Widget)^.vscrollbar, 'button-press-event', + TGCallback(@gtk2ScrollBarMouseBtnPress), ALCLObject); + g_signal_connect_after(GTK_SCROLLED_WINDOW(Widget)^.vscrollbar, 'button-release-event', + TGCallback(@gtk2ScrollBarMouseBtnRelease), ALCLObject); + + g_signal_connect_after(GTK_SCROLLED_WINDOW(Widget)^.hscrollbar, 'button-press-event', + TGCallback(@gtk2ScrollBarMouseBtnPress), ALCLObject); + g_signal_connect_after(GTK_SCROLLED_WINDOW(Widget)^.hscrollbar, 'button-release-event', + TGCallback(@gtk2ScrollBarMouseBtnRelease), ALCLObject); + end; + SetCallback(LM_SHOWWINDOW, AGTKObject, ALCLObject); SetCallback(LM_DESTROY, AGTKObject, ALCLObject); SetCallback(LM_FOCUS, AGTKObject, ALCLObject); diff --git a/lcl/interfaces/gtk2/gtk2winapi.inc b/lcl/interfaces/gtk2/gtk2winapi.inc index 5057b2040d..c0b28ddc0b 100644 --- a/lcl/interfaces/gtk2/gtk2winapi.inc +++ b/lcl/interfaces/gtk2/gtk2winapi.inc @@ -7738,6 +7738,9 @@ end; function TGtk2WidgetSet.SetCapture(AHandle: HWND): HWND; var Widget: PGtkWidget; + {$IFNDEF GTK2_USE_OLD_CAPTURE} + CaptureWidget: PGtkWidget; + {$ENDIF} begin Assert(False, Format('Trace:> [TGtk2WidgetSet.SetCapture] 0x%x', [AHandle])); Widget := PGtkWidget(AHandle); @@ -7748,8 +7751,31 @@ begin // return old capture handle Result := GetCapture; + {$IFDEF GTK2_USE_OLD_CAPTURE} // capture CaptureMouseForWidget(Widget, mctLCL); + {$ELSE} + + if Result <> 0 then + gtk_grab_remove(gtk_grab_get_current); + + MouseCaptureWidget := nil; + + if Widget = nil then + exit; + + CaptureWidget := GetDefaultMouseCaptureWidget(Widget); + if CaptureWidget = nil then exit; + + if not gtk_widget_has_focus(CaptureWidget) then + gtk_widget_grab_focus(CaptureWidget); + + gtk_grab_add(CaptureWidget); + MouseCaptureWidget := CaptureWidget; + if MouseCaptureWidget<>nil then + SendMessage(HWnd(PtrUInt(MouseCaptureWidget)), LM_CAPTURECHANGED, 0, + Result); + {$ENDIF} end; {------------------------------------------------------------------------------ diff --git a/lcl/interfaces/gtk2/gtk2wscontrols.pp b/lcl/interfaces/gtk2/gtk2wscontrols.pp index f2213ae71c..9f8ef56114 100644 --- a/lcl/interfaces/gtk2/gtk2wscontrols.pp +++ b/lcl/interfaces/gtk2/gtk2wscontrols.pp @@ -228,11 +228,13 @@ begin gtk_widget_size_allocate(Widget, @Allocation); Set_RC_Name(AWinControl, Widget); - + TGtk2WSWinControl.SetCallbacks(GTK_OBJECT(Widget), AWinControl); - g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.hscrollbar, 'change-value', TGCallback(@Gtk2RangeScrollCB), WidgetInfo); - g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.vscrollbar, 'change-value', TGCallback(@Gtk2RangeScrollCB), WidgetInfo); + g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.hscrollbar, 'change-value', + TGCallback(@Gtk2RangeScrollCB), WidgetInfo); + g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.vscrollbar, 'change-value', + TGCallback(@Gtk2RangeScrollCB), WidgetInfo); g_signal_connect(Widget, 'scroll-event', TGCallback(@Gtk2ScrolledWindowScrollCB), WidgetInfo); end; diff --git a/lcl/interfaces/gtk2/gtk2wsforms.pp b/lcl/interfaces/gtk2/gtk2wsforms.pp index 9c6b2c1b07..70bfc36e5f 100644 --- a/lcl/interfaces/gtk2/gtk2wsforms.pp +++ b/lcl/interfaces/gtk2/gtk2wsforms.pp @@ -813,13 +813,15 @@ var begin ACustomForm := TCustomForm(AWinControl); - p := gtk_window_new(gtk_window_popup); + p := gtk_window_new(GTK_WINDOW_POPUP); WidgetInfo := CreateWidgetInfo(p, AWinControl, AParams); gtk_window_set_policy(GTK_WINDOW(p), 0, 0, 0); + gtk_window_set_focus_on_map(P, False); // Create the form client area TempWidget := CreateFixedClientWidget; gtk_container_add(p, TempWidget); + GTK_WIDGET_UNSET_FLAGS(TempWidget, GTK_CAN_FOCUS); gtk_widget_show(TempWidget); SetFixedWidget(p, TempWidget); SetMainWidget(p, TempWidget);