View Issue Details

IDProjectCategoryView StatusLast Update
0029294LazarusLCLpublic2021-02-26 15:53
ReporterOndrej Pokorny Assigned ToZeljan Rikalo  
PrioritynormalSeverityminorReproducibilityalways
Status confirmedResolutionopen 
PlatformLinuxOSKubuntu Linux 
Product Version1.7 (SVN) 
Target Version2.2 
Summary0029294: fsStayOnTop non-modal window cannot get active in Qt
DescriptionfsStayOnTop non-modal window cannot get active in Qt
Steps To Reproduce1.) Show an fsStayOnTop non-modal window.
2.) Switch to a different application with Alt+Tab or mouse.
3.) Switch back to the fsStayOnTop non-modal window with Alt+Tab or mouse. You'll see that the form can't get active/focused.
Additional InformationSee the attached screencast and test project. The code is:

procedure TForm1.Button1Click(Sender: TObject);
var
  Form2: TForm;
begin
  Form2 := TForm.CreateNew(Self);
  Form2.Position := poDesigned;
  Form2.Left := 0;
  Form2.Top := 0;
  Form2.FormStyle := fsStayOnTop;
  Form2.Show;
end;
TagsNo tags attached.
Fixed in Revision
LazTarget-
WidgetsetQT
Attached Files

Activities

Ondrej Pokorny

2015-12-31 10:02

developer  

Ondrej Pokorny

2015-12-31 10:05

developer  

bug29294.zip (2,056 bytes)

Zeljan Rikalo

2015-12-31 12:09

developer   ~0088461

Yes, it's bug. On my window manager even without Alt-Tab it is possible to reproduce bug. Just activate another application. Now try to activate fsStayOnTop form with mouse - no way. Only if you click onto main form app is activated.

Zeljan Rikalo

2015-12-31 13:42

developer  

qtStayOnTopActivation.diff (5,629 bytes)   
Index: lcl/interfaces/qt/qtobject.inc
===================================================================
--- lcl/interfaces/qt/qtobject.inc	(revision 51047)
+++ lcl/interfaces/qt/qtobject.inc	(working copy)
@@ -491,7 +491,7 @@
 function TQtWidgetSet.AppRestoreStayOnTopFlags(const ASystemTopAlso: Boolean = False): Boolean;
 begin
   Result := True;
-  QtRestoreStayOnTop(ASystemTopAlso);
+  QtRestoreStayOnTop(nil, ASystemTopAlso);
 end;
 
 procedure TQtWidgetSet.SetOverrideCursor(const AValue: TObject);
@@ -547,7 +547,8 @@
   end;
 end;
 
-procedure TQtWidgetSet.QtRestoreStayOnTop(const ASystemTopAlso: Boolean = False);
+procedure TQtWidgetSet.QtRestoreStayOnTop(ActiveWin: QWidgetH;
+  const ASystemTopAlso: Boolean);
 var
   i: Integer;
   AForm: TCustomForm;
@@ -570,9 +571,23 @@
         begin
           W.BeginUpdate;
           Flags := W.windowFlags;
-          W.setWindowFlags(Flags or QtWindowStaysOnTopHint);
-          W.Show;
-          W.setAttribute(QtWA_ShowWithoutActivating, False);
+          if Flags and QtWindowStaysOnTopHint <> QtWindowStaysOnTopHint then
+          begin
+            {$IF DEFINED(QTDEBUGAPPACTIVATE) OR DEFINED(VerboseQtEvents)}
+            DebugLn('** QtRestoreStayOnTop ! FOR ',dbgsName(W.LCLObject));
+            {$ENDIF}
+            if ActiveWin = nil then
+              W.setAttribute(QtWA_ShowWithoutActivating, True)
+            else
+              W.setAttribute(QtWA_ShowWithoutActivating, False);
+            W.setWindowFlags(Flags or QtWindowStaysOnTopHint);
+            W.Show;
+            if ActiveWin = nil then
+            begin
+              W.setAttribute(QtWA_ShowWithoutActivating, False);
+              W.Activate;
+            end;
+          end;
           W.EndUpdate;
         end;
       end;
@@ -766,6 +781,12 @@
       end;
     QEventApplicationActivate:
     begin
+      {$IF DEFINED(QTDEBUGAPPACTIVATE) OR DEFINED(VerboseQtEvents)}
+      DebugLn('TQtWidgetSet.EventFilter: QEventApplicationActivate - time ',dbgs(GetTickCount));
+      W := TQtMainWindow(HWNDFromWidgetH(QApplication_activeWindow()));
+      if W <> nil then
+        DebugLn('ACTIVATED WIDGET IS ',dbgsName(W));
+      {$ENDIF}
       LCLEvent := QLCLMessageEvent_create(LCLQt_ApplicationActivate);
        // activate it imediatelly (high priority)
       QCoreApplication_postEvent(Sender, LCLEvent, 1 {high priority});
@@ -785,7 +806,10 @@
         else
           W := nil;
         Application.IntfAppActivate;
-        QtRestoreStayOnTop;
+        if (W <> nil) and Assigned(StayOnTopList) and not StayOnTopList.HasId(W) then
+          QtRestoreStayOnTop(QApplication_activeWindow())
+        else
+          QtRestoreStayOnTop(nil);
         if (W <> nil) and Assigned(StayOnTopList) and StayOnTopList.HasId(W) then
           W.Activate;
         Result := True;
Index: lcl/interfaces/qt/qtwidgets.pas
===================================================================
--- lcl/interfaces/qt/qtwidgets.pas	(revision 51047)
+++ lcl/interfaces/qt/qtwidgets.pas	(working copy)
@@ -6980,8 +6980,41 @@
       end;
       QEventWindowUnblocked: Blocked := False;
       QEventWindowBlocked: Blocked := True;
-      QEventWindowActivate: if not IsMDIChild then SlotActivateWindow(True);
-      QEventWindowDeactivate: if not IsMDIChild then SlotActivateWindow(False);
+      QEventWindowActivate:
+      begin
+        if not IsMDIChild then
+        begin
+          {$IF DEFINED(QTDEBUGAPPACTIVATE) OR DEFINED(VerboseQtEvents)}
+          DebugLn('QEventWindowActivate: ',dbgsName(LCLObject),
+          ' AppActive=',dbgs(QtWidgetSet.AppActive));
+          {$ENDIF}
+          if not QtWidgetSet.AppActive and (LCLObject.Parent = nil) then
+          begin
+            BeginUpdate;
+            //    procedure QtRestoreStayOnTop(const ASystemTopAlso: Boolean = False);
+            QtWidgetSet.QtRestoreStayOnTop(Widget, True);
+            //if TCustomForm(LCLObject).FormStyle in fsAllStayOnTop then
+            Activate;
+            writeln('ACTIVATED !!!!');
+            if TCustomForm(LCLObject).FormStyle in fsAllStayOnTop then
+              X11Raise(QWidget_winId(Widget));
+            writeln('RAISED !!!!');
+            EndUpdate;
+          end;
+          SlotActivateWindow(True);
+        end;
+      end;
+      QEventWindowDeactivate:
+      begin
+        if not IsMDIChild then
+        begin
+          {$IF DEFINED(QTDEBUGAPPACTIVATE) OR DEFINED(VerboseQtEvents)}
+          DebugLn('QEventWindowDeActivate: ',dbgsName(LCLObject),
+          ' AppActive=',dbgs(QtWidgetSet.AppActive));
+          {$ENDIF}
+          SlotActivateWindow(False);
+        end;
+      end;
       QEventShowToParent: ; // do nothing for TQtMainWindow, but leave it unhandled
       QEventWindowStateChange:
       begin
Index: lcl/interfaces/qt/qtint.pp
===================================================================
--- lcl/interfaces/qt/qtint.pp	(revision 51047)
+++ lcl/interfaces/qt/qtint.pp	(working copy)
@@ -97,7 +97,6 @@
     function GetStyleName: String;
     procedure SetOverrideCursor(const AValue: TObject);
     procedure QtRemoveStayOnTop(const ASystemTopAlso: Boolean = False);
-    procedure QtRestoreStayOnTop(const ASystemTopAlso: Boolean = False);
     procedure SetDefaultAppFontName;
   protected
     FStockNullBrush: HBRUSH;
@@ -171,6 +170,7 @@
     procedure HideAllHints;
     procedure RestoreAllHints;
     {$ENDIF}
+    procedure QtRestoreStayOnTop(ActiveWin: QWidgetH; const ASystemTopAlso: Boolean = False);
 
     // application global actions (mainform mainmenu mnemonics Alt+XX)
     procedure ClearGlobalActions;
qtStayOnTopActivation.diff (5,629 bytes)   

Zeljan Rikalo

2015-12-31 13:44

developer   ~0088462

Attached patch is for my purposes only...patch fixes activation of fsStayOnTop with mouse, but Alt+Tab is still problematic since wild QEventApplicationDeactivate arrives imediatelly after QEventApplicationActivate.
Uploaded here just in case if I delete it from my disk.

Issue History

Date Modified Username Field Change
2015-12-31 10:02 Ondrej Pokorny New Issue
2015-12-31 10:02 Ondrej Pokorny File Added: fsStayOnTop.mp4
2015-12-31 10:05 Ondrej Pokorny File Added: bug29294.zip
2015-12-31 11:46 Zeljan Rikalo Assigned To => Zeljan Rikalo
2015-12-31 11:46 Zeljan Rikalo Status new => assigned
2015-12-31 12:09 Zeljan Rikalo Note Added: 0088461
2015-12-31 12:09 Zeljan Rikalo Status assigned => confirmed
2015-12-31 13:42 Zeljan Rikalo File Added: qtStayOnTopActivation.diff
2015-12-31 13:44 Zeljan Rikalo Note Added: 0088462
2021-02-26 15:53 Martin Friebe Target Version 1.6 => 2.2