From 4b57ac797bb514afb6bd1f8be1b3ae60d619adb0 Mon Sep 17 00:00:00 2001 From: juha Date: Sun, 5 Jun 2011 06:22:54 +0000 Subject: [PATCH] IDE & LCL: Move focus to editor after hitting breakpoint. Patch from August Klein, issue #15967 git-svn-id: trunk@31087 - --- ide/debugmanager.pas | 24 ++++++--- lcl/interfaces/gtk2/gtk2extrah.inc | 2 + lcl/interfaces/gtk2/gtk2int.pas | 4 ++ lcl/interfaces/gtk2/gtk2widgetset.inc | 70 +++++++++++++++++++++++++++ lcl/interfaces/gtk2/gtk2winapi.inc | 15 ++++++ lcl/interfaces/gtk2/gtk2winapih.inc | 1 + lcl/interfaces/qt/qtint.pp | 2 + lcl/interfaces/qt/qtwidgets.pas | 5 +- lcl/interfaces/qt/qtwinapi.inc | 18 ++++++- lcl/interfaces/qt/qtwinapih.inc | 1 + lcl/interfaces/qt/qtx11.inc | 63 ++++++++++++++++++++++++ 11 files changed, 193 insertions(+), 12 deletions(-) diff --git a/ide/debugmanager.pas b/ide/debugmanager.pas index 787ba3495b..992ad6c269 100644 --- a/ide/debugmanager.pas +++ b/ide/debugmanager.pas @@ -96,6 +96,7 @@ type FDebugger: TDebugger; FDialogs: array[TDebugDialogType] of TDebuggerDlg; FPrevShownWindow: HWND; + FStepping: Boolean; // keep track of the last reported location FCurrentLocation: TDBGLocationRec; FIgnoreSourceFiles: TStringList; // a list of unfindable sourcefiles, that should not be prompted anymore @@ -868,10 +869,10 @@ begin if (FDebugger.State in [dsRun]) then begin // hide IDE during run - if EnvironmentOptions.HideIDEOnRun and (MainIDE.ToolStatus=itDebugger) + if EnvironmentOptions.HideIDEOnRun and (MainIDE.ToolStatus=itDebugger) and not FStepping then MainIDE.HideIDE; - if FPrevShownWindow <> 0 then + if (FPrevShownWindow <> 0) and not FStepping then begin SetForegroundWindow(FPrevShownWindow); FPrevShownWindow := 0; @@ -887,10 +888,14 @@ begin end else if (OldState in [dsRun]) then begin - if EnvironmentOptions.HideIDEOnRun - then MainIDE.UnhideIDE; - FPrevShownWindow := GetForegroundWindow; - Application.BringToFront; + if not FStepping then + begin + FPrevShownWindow := GetForegroundWindow; + if EnvironmentOptions.HideIDEOnRun then + MainIDE.UnhideIDE; + if not EnvironmentOptions.SingleTaskBarButton then + Application.BringToFront; + end; end; end; @@ -932,6 +937,7 @@ begin FDebugger.ErrorStateInfo, ftError, [frStop]); end; dsStop: begin + FPrevShownWindow:=0; if (OldState<>dsIdle) then begin if EnvironmentOptions.DebuggerShowStopMessage @@ -1956,6 +1962,7 @@ begin Exit; end; + FStepping:=True; FDebugger.StepInto; Result := mrOk; end; @@ -1970,6 +1977,7 @@ begin Exit; end; + FStepping:=True; FDebugger.StepOver; Result := mrOk; end; @@ -1984,6 +1992,7 @@ begin Exit; end; + FStepping:=True; FDebugger.StepIntoInstr; Result := mrOk; // Todo: move to DebuggerChangeState (requires the last run-command-type to be avail) @@ -2000,6 +2009,7 @@ begin Exit; end; + FStepping:=True; FDebugger.StepOverInstr; Result := mrOk; // Todo: move to DebuggerChangeState (requires the last run-command-type to be avail) @@ -2016,6 +2026,7 @@ begin Exit; end; + FStepping:=True; FDebugger.StepOut; Result := mrOk; end; @@ -2152,6 +2163,7 @@ begin exit; end; Include(FManagerStates,dmsRunning); + FStepping:=False; try FDebugger.Run; finally diff --git a/lcl/interfaces/gtk2/gtk2extrah.inc b/lcl/interfaces/gtk2/gtk2extrah.inc index 3fc3212e14..1fd05cf049 100644 --- a/lcl/interfaces/gtk2/gtk2extrah.inc +++ b/lcl/interfaces/gtk2/gtk2extrah.inc @@ -168,6 +168,8 @@ procedure gdk_draw_pixbuf(drawable : PGdkDrawable; gc : PGdkGC; pixbuf : PGdkPix dither : TGdkRgbDither; x_dither, y_dither : gint); cdecl; external gdklib; function gdk_screen_get_default: PGdkScreen; cdecl; external gdklib; function gdk_screen_get_rgb_colormap(screen: PGdkScreen): PGdkColormap; cdecl; external gdklib; +function gdk_x11_get_default_xdisplay: pointer; cdecl; external gdklib; +function gdk_x11_get_default_root_xwindow: guint; cdecl; external gdklib; // gdk 2.4 function gdk_cursor_new_from_pixbuf(display: PGdkDisplay; pixbuf: PGdkPixbuf; x, y: gint): PGdkCursor; cdecl; external gdklib name 'gdk_cursor_new_from_pixbuf'; diff --git a/lcl/interfaces/gtk2/gtk2int.pas b/lcl/interfaces/gtk2/gtk2int.pas index ee02a52807..c90697aeba 100644 --- a/lcl/interfaces/gtk2/gtk2int.pas +++ b/lcl/interfaces/gtk2/gtk2int.pas @@ -298,6 +298,10 @@ type {$I gtk2winapih.inc} {$I gtk2lclintfh.inc} public + {$IFDEF HASX} + function X11Raise(AHandle: HWND): boolean; + function X11GetActiveWindow: HWND; + {$ENDIF} procedure StartFocusTimer; property AppActive: Boolean read GetAppActive write SetAppActive; property LastFocusIn: PGtkWidget read FLastFocusIn write FLastFocusIn; diff --git a/lcl/interfaces/gtk2/gtk2widgetset.inc b/lcl/interfaces/gtk2/gtk2widgetset.inc index 8899621d71..460f03dd3e 100644 --- a/lcl/interfaces/gtk2/gtk2widgetset.inc +++ b/lcl/interfaces/gtk2/gtk2widgetset.inc @@ -1156,6 +1156,8 @@ procedure TGtk2WidgetSet.AppBringToFront; begin if Assigned(Application.MainForm) and Application.MainForm.HandleAllocated then gdk_window_raise(PGtkWidget(Application.MainForm.Handle)^.window); + gdk_window_focus(PGtkWidget(Application.MainForm.Handle)^.window, + gtk_get_current_event_time); end; procedure TGtk2WidgetSet.AppMinimize; @@ -4251,6 +4253,74 @@ begin then gdk_pixmap_unref(TempMaskBitmap); end; +{$IFDEF HASX} +function TGtk2WidgetSet.X11Raise(AHandle: HWND): boolean; +var + Display: PDisplay; + RootWin: TWindow; + ScreenNum: Integer; + XClient: TXClientMessageEvent; + WMAtom: TAtom; + screen: PGdkScreen; +begin + Result:=false; + screen:=gdk_screen_get_default; + Display := gdk_x11_get_default_xdisplay; + + if Display = nil then + exit; + ScreenNum := gdk_screen_get_number(screen); + RootWin := gdk_x11_get_default_root_xwindow; + + XClient._type := ClientMessage; + XClient.window := AHandle; + WMAtom := XInternAtom(Display,'_NET_ACTIVE_WINDOW', False); + XClient.message_type := WMATom; + XClient.format := 32; + XClient.data.l[0] := 1; + XClient.data.l[1] := 0; + XClient.data.l[2] := 0; + Result:=XSendEvent (Display, RootWin, False, + SubstructureRedirectMask or SubstructureNotifyMask, + @XClient)<>0; +end; + +function TGtk2WidgetSet.X11GetActivewindow: HWND; +var + Display: PDisplay; + RootWin: TWindow; + ScreenNum: Integer; + WMAtom: TAtom; + ActualTypeReturn: TAtom; + ActualFormatReturn: LongInt; + NItemsReturn, BytesAfterReturn: Cardinal; + Ptr: PByte; + screen: PGdkScreen; + Valid: Boolean; +begin + screen:=gdk_screen_get_default; + Display := gdk_x11_get_default_xdisplay; + + if Display = nil then + exit; + ScreenNum := gdk_screen_get_number(screen); + RootWin := gdk_x11_get_default_root_xwindow; + WMAtom := XInternAtom(Display,'_NET_ACTIVE_WINDOW', False); + Valid:=XGetWindowProperty(Display, RootWin, WMAtom, 0, 1, False, + AnyPropertyType, @ActualTypeReturn, + @ActualFormatReturn, @NItemsReturn, + @BytesAfterReturn, @Ptr)=0; + if Valid then + try + if (ActualTypeReturn = None) or (ActualFormatReturn <> 32) or not Assigned(Ptr) then + Valid := False; + if Valid then Result := PCardinal(Ptr)^; + finally + if Assigned(Ptr) then + XFree(Ptr); + end; +end; +{$ENDIF} {------------------------------------------------------------------------------ procedure TGtk2WidgetSet.BringFormToFront(Sender: TObject); ------------------------------------------------------------------------------} diff --git a/lcl/interfaces/gtk2/gtk2winapi.inc b/lcl/interfaces/gtk2/gtk2winapi.inc index 7d323c30c0..98b8b87a02 100644 --- a/lcl/interfaces/gtk2/gtk2winapi.inc +++ b/lcl/interfaces/gtk2/gtk2winapi.inc @@ -3719,6 +3719,14 @@ begin then g_list_free(TopList); end; +function TGtk2WidgetSet.GetForegroundWindow: HWND; +begin + Result:=0; + {$IFDEF HASX} + Result:=X11GetActiveWindow; + {$ENDIF} +end; + {------------------------------------------------------------------------------ Function: GetDIBits Params: @@ -8114,6 +8122,7 @@ var GdkWindow: PGdkWindow; AForm: TCustomForm; begin + try {$IFDEF VerboseFocus} DbgOut('TGtk2WidgetSet.SetForegroundWindow hWnd=',DbgS(hWnd)); LCLObject:=TControl(GetLCLObject(Pointer(hWnd))); @@ -8152,6 +8161,7 @@ begin {$ENDIF} gdk_window_show(GdkWindow); gdk_window_raise(GdkWindow); + gdk_window_focus(GdkWindow, gtk_get_current_event_time); {$IFDEF DebugGDKTraps} EndGDKErrorTrap; {$ENDIF} @@ -8159,6 +8169,11 @@ begin gtk_window_present(PGtkWindow(hWnd)); end; end; + except + {$IFDEF HASX} + Result:=X11Raise(hWnd); + {$ENDIF} + end; end; function TGtk2WidgetSet.SetMapMode(DC: HDC; fnMapMode : Integer): Integer; diff --git a/lcl/interfaces/gtk2/gtk2winapih.inc b/lcl/interfaces/gtk2/gtk2winapih.inc index fa6ade2772..d9f4f403e6 100644 --- a/lcl/interfaces/gtk2/gtk2winapih.inc +++ b/lcl/interfaces/gtk2/gtk2winapih.inc @@ -124,6 +124,7 @@ function GetDeviceSize(DC: HDC; var p: TPoint): boolean; override; function GetDIBits(DC: HDC; Bitmap: HBitmap; StartScan, NumScans: UINT; Bits: Pointer; var BitInfo: BitmapInfo; Usage: UINT): Integer; override; function GetFocus: HWND; override; function GetFontLanguageInfo(DC: HDC): DWord; override; +function GetForegroundWindow: HWND; override; function GetKeyState(nVirtKey: Integer): Smallint; override; function GetMapMode(DC: HDC): Integer; override; function GetMonitorInfo(Monitor: HMONITOR; lpmi: PMonitorInfo): Boolean; override; diff --git a/lcl/interfaces/qt/qtint.pp b/lcl/interfaces/qt/qtint.pp index fc5863a56c..aa570a088e 100644 --- a/lcl/interfaces/qt/qtint.pp +++ b/lcl/interfaces/qt/qtint.pp @@ -203,6 +203,8 @@ type function QtVersionCheck(const AMajor, AMinor, AMicro: Integer): Boolean; {$IFDEF HASX11} function IsCurrentDesktop(AWidget: QWidgetH): Boolean; + function X11Raise(AHandle: HWND): boolean; + function X11GetActiveWindow: HWND; function GetWindowManager: String; procedure SetSkipX11Taskbar(Widget: QWidgetH; const ASkipTaskBar: Boolean); {check if we are running under kde3 installation} diff --git a/lcl/interfaces/qt/qtwidgets.pas b/lcl/interfaces/qt/qtwidgets.pas index d1b3cb41e8..b4e340800d 100644 --- a/lcl/interfaces/qt/qtwidgets.pas +++ b/lcl/interfaces/qt/qtwidgets.pas @@ -4958,11 +4958,8 @@ begin else inherited Activate; {$IFDEF HASX11} - // qt X11 bug ? activates window but it's not in - // front of others. - {$note TQtWidget.Activate: Check this with next qt version (>=4.7)} if not QWidget_isModal(Widget) then - QWidget_raise(Widget); + X11Raise(QWidget_winId(Widget)); {$ENDIF} end; diff --git a/lcl/interfaces/qt/qtwinapi.inc b/lcl/interfaces/qt/qtwinapi.inc index 76fa2d7ebd..72c1ba8125 100644 --- a/lcl/interfaces/qt/qtwinapi.inc +++ b/lcl/interfaces/qt/qtwinapi.inc @@ -4972,13 +4972,27 @@ begin end; end; +function TQtWidgetSet.GetForegroundWindow: HWND; +begin + Result:=0; + {$IFDEF HASX11} + Result:=X11GetActivewindow; + {$ENDIF} +end; + function TQtWidgetSet.SetForegroundWindow(HWnd: HWND): boolean; begin Result := False; if HWND <> 0 then begin - Result := TQtWidget(HWND).IsActiveWindow; - TQtWidget(HWnd).Activate; + try + Result := TQtWidget(HWND).IsActiveWindow; + TQtWidget(HWnd).Activate; + except + {$IFDEF HASX11} + Result:=X11Raise(HWnd); + {$ENDIF} + end; end; end; diff --git a/lcl/interfaces/qt/qtwinapih.inc b/lcl/interfaces/qt/qtwinapih.inc index 94691289c4..dadd6d41b8 100644 --- a/lcl/interfaces/qt/qtwinapih.inc +++ b/lcl/interfaces/qt/qtwinapih.inc @@ -111,6 +111,7 @@ function GetDeviceSize(DC: HDC; var P: TPoint): Boolean; Override; function GetDIBits(DC: HDC; Bitmap: HBitmap; StartScan, NumScans: UINT; Bits: Pointer; var BitInfo: BitmapInfo; Usage: UINT): Integer; Override; function GetDoubleClickTime: UINT; override; function GetFocus: HWND; override; +function GetForegroundWindow: HWND; override; function GetKeyState(nVirtKey: Integer): Smallint; override; function GetMapMode(DC: HDC): Integer; override; function GetMonitorInfo(Monitor: HMONITOR; lpmi: PMonitorInfo): Boolean; override; diff --git a/lcl/interfaces/qt/qtx11.inc b/lcl/interfaces/qt/qtx11.inc index d9f12e55e0..8e075fe9e0 100644 --- a/lcl/interfaces/qt/qtx11.inc +++ b/lcl/interfaces/qt/qtx11.inc @@ -81,6 +81,69 @@ begin end; end; +function X11Raise(AHandle: HWND): boolean; +var + Display: PDisplay; + RootWin: TWindow; + ScreenNum: Integer; + XClient: TXClientMessageEvent; + WMAtom: TAtom; +begin + Result:=false; + Display := QX11Info_display(); + + if Display = nil then + exit; + ScreenNum := QX11Info_appScreen(); + RootWin := XRootWindow(Display, ScreenNum); + + XClient._type := ClientMessage; + XClient.window := AHandle; + WMAtom := XInternAtom(Display,'_NET_ACTIVE_WINDOW', False); + XClient.message_type := WMATom; + XClient.format := 32; + XClient.data.l[0] := 1; + XClient.data.l[1] := 0; + XClient.data.l[2] := 0; + Result:=XSendEvent (Display, RootWin, False, + SubstructureRedirectMask or SubstructureNotifyMask, + @XClient)<>0; +end; + +function X11GetActivewindow: HWND; +var + Display: PDisplay; + RootWin: TWindow; + ScreenNum: Integer; + WMAtom: TAtom; + ActualTypeReturn: TAtom; + ActualFormatReturn: LongInt; + NItemsReturn, BytesAfterReturn: Cardinal; + Ptr: PByte; + Valid: Boolean; +begin + Display := QX11Info_display(); + + if Display = nil then + exit; + ScreenNum := QX11Info_appScreen(); + RootWin := XRootWindow(Display, ScreenNum); + WMAtom := XInternAtom(Display,'_NET_ACTIVE_WINDOW', False); + Valid:=XGetWindowProperty(Display, RootWin, WMAtom, 0, 1, False, + AnyPropertyType, @ActualTypeReturn, + @ActualFormatReturn, @NItemsReturn, + @BytesAfterReturn, @Ptr)=0; + if Valid then + try + if (ActualTypeReturn = None) or (ActualFormatReturn <> 32) or not Assigned(Ptr) then + Valid := False; + if Valid then Result := PCardinal(Ptr)^; + finally + if Assigned(Ptr) then + XFree(Ptr); + end; +end; + function GetWindowManager: String; {used to get window manager name, so we can handle different wm's behaviour eg. kde vs. gnome}