View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0031832 | Lazarus | LCL | public | 2017-05-17 23:02 | 2017-05-18 19:30 |
Reporter | Kostas Michalopoulos | Assigned To | Zeljan Rikalo | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Platform | Linux | OS | Debian | ||
Product Version | 1.9 (SVN) | ||||
Summary | 0031832: SW_SHOWNORMAL on Gtk2 widgetset shrinks the window in some window managers | ||||
Description | Calling ShowWindow(Handle, SW_SHOWNORMAL) on Gtk2 widgetset will shrink the window under some window managers. This call is made at several places during design time, including changing components and loading forms. The video below shows the issue with Window Maker: https://webmshare.com/q78rb The bug seems to be in Gtk2's gtk_window_unmaximize which attempts to resize the window even if it is maximized. While it ideally the bug should be fixed in Gtk2, the development seems to be almost halted (mainly build and documentation fixes seem to happen) and with Lazarus targeting earlier versions like 2.8 (from 2005) it is a better idea to address this on LCL side. The attached patch contains a workaround for TCustomForm descendants that checks the maximized state (Gtk2 doesn't provide any way to query the current state, but LCL already tracks it for forms) before calling gtk_window_unmaximize, which fixes the issue shown in the video above. The patch was made against revision 54956, but should apply to 1.8RC1 and earlier versions (maybe by hand - it is a small patch after all). | ||||
Steps To Reproduce | 1. Install Window Maker 2. Build Lazarus with the Gtk2 widgetset 3. Run Lazarus 4. Try to select any component from the palette 5. Notice how the window shrinks alternatively check the video | ||||
Tags | component palette, designer, gtk2, lcl, widgetset | ||||
Fixed in Revision | 54958,54975 | ||||
LazTarget | - | ||||
Widgetset | GTK 2 | ||||
Attached Files |
|
|
gtk2-window-unmaximize-workaround-for-sw_shownormal-patch.diff (1,476 bytes)
Index: lcl/interfaces/gtk2/gtk2winapi.inc =================================================================== --- lcl/interfaces/gtk2/gtk2winapi.inc (revision 54956) +++ lcl/interfaces/gtk2/gtk2winapi.inc (working copy) @@ -9400,6 +9400,7 @@ GtkWindow: PGtkWindow; B: Boolean; Widget: PGtkWidget; + Control: TWinControl; begin Result := False; @@ -9446,7 +9447,19 @@ if not GTK_WIDGET_VISIBLE(PGtkWidget(GtkWindow)) then gtk_widget_show(PGtkWidget(GtkWindow)); gtk_window_deiconify(GtkWindow); - gtk_window_unmaximize(GtkWindow); + // Workaround for gtk2 bug with some window managers: + // calling gtk_window_unmaximize when the window is not maximized + // will cause window to shrink. Here we check if the window we are + // resizing is a form and use its WindowState property to make sure + // it is maximized before trying to unmaximize it which avoids the + // issue (custom code that uses the Win32 API will still have the + // problem though, but gtk2 does not offer a is_maximized method) + Control:=TWinControl(GetLCLObject({%H-}Pointer(hWnd))); + if Assigned(Control) and (Control is TCustomForm) then begin + if TCustomForm(Control).WindowState=wsMaximized then + gtk_window_unmaximize(GtkWindow); + end else + gtk_window_unmaximize(GtkWindow); gtk_window_unfullscreen(GtkWindow); end; end; |
|
|
|
I attached the video for future reference in case the URL disappears. |
|
+ if Assigned(Control) and (Control is TCustomForm) then begin + if TCustomForm(Control).WindowState=wsMaximized then + gtk_window_unmaximize(GtkWindow); + end else + gtk_window_unmaximize(GtkWindow); better to do change := true; if Assigned(Control) and (Control is TCustomForm) then change:= TCustomForm(Control).WindowState=wsMaximized; if change then gtk_window_unmaximize(GtkWindow); |
|
Mighty thanks! I simplified the condition. |
|
issue31832.diff (1,821 bytes)
Index: gtk2winapi.inc =================================================================== --- gtk2winapi.inc (revision 54966) +++ gtk2winapi.inc (working copy) @@ -9446,20 +9446,16 @@ begin if not GTK_WIDGET_VISIBLE(PGtkWidget(GtkWindow)) then gtk_widget_show(PGtkWidget(GtkWindow)); - gtk_window_deiconify(GtkWindow); - // Workaround for gtk2 bug with some window managers: - // calling gtk_window_unmaximize when the window is not maximized - // will cause window to shrink. Here we check if the window we are - // resizing is a form and use its WindowState property to make sure - // it is maximized before trying to unmaximize it which avoids the - // issue (custom code that uses the Win32 API will still have the - // problem though, but gtk2 does not offer a is_maximized method) - // see https://bugs.freepascal.org/view.php?id=31832 - Control:=TWinControl(GetLCLObject({%H-}Pointer(hWnd))); - if (not (Control is TCustomForm)) or - (TCustomForm(Control).WindowState=wsMaximized) then - gtk_window_unmaximize(GtkWindow); - gtk_window_unfullscreen(GtkWindow); + if GDK_IS_WINDOW(PGtkWidget(GtkWindow)^.window) then + begin + // see https://bugs.freepascal.org/view.php?id=31832 + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_ICONIFIED then + gtk_window_deiconify(GtkWindow); + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_MAXIMIZED then + gtk_window_unmaximize(GtkWindow); + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_FULLSCREEN then + gtk_window_unfullscreen(GtkWindow); + end; end; end; |
|
I've attached possibly better solution, so just decide to commit it or not. Above that code is check with B:boolean which check for window validity, so my patch is clean gtk patch without involving lcl. |
|
issue31832_2.diff (3,622 bytes)
Index: gtk2winapi.inc =================================================================== --- gtk2winapi.inc (revision 54969) +++ gtk2winapi.inc (working copy) @@ -9446,20 +9446,20 @@ begin if not GTK_WIDGET_VISIBLE(PGtkWidget(GtkWindow)) then gtk_widget_show(PGtkWidget(GtkWindow)); - gtk_window_deiconify(GtkWindow); - // Workaround for gtk2 bug with some window managers: - // calling gtk_window_unmaximize when the window is not maximized - // will cause window to shrink. Here we check if the window we are - // resizing is a form and use its WindowState property to make sure - // it is maximized before trying to unmaximize it which avoids the - // issue (custom code that uses the Win32 API will still have the - // problem though, but gtk2 does not offer a is_maximized method) + // see https://bugs.freepascal.org/view.php?id=31832 - Control:=TWinControl(GetLCLObject({%H-}Pointer(hWnd))); - if (not (Control is TCustomForm)) or - (TCustomForm(Control).WindowState=wsMaximized) then - gtk_window_unmaximize(GtkWindow); - gtk_window_unfullscreen(GtkWindow); + if GDK_IS_WINDOW(PGtkWidget(GtkWindow)^.window) and + (gdk_window_get_window_type(PGtkWidget(GtkWindow)^.window) <> GDK_WINDOW_CHILD) then + begin + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_ICONIFIED then + gtk_window_deiconify(GtkWindow) + else + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_MAXIMIZED then + gtk_window_unmaximize(GtkWindow) + else + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_FULLSCREEN then + gtk_window_unfullscreen(GtkWindow); + end; end; end; @@ -9475,9 +9475,17 @@ gtk_widget_show(PGtkWidget(GtkWindow)) else begin - gtk_window_deiconify(GtkWindow); - gtk_window_unfullscreen(GtkWindow); - gtk_window_maximize(GtkWindow); + // see https://bugs.freepascal.org/view.php?id=31832 + if GDK_IS_WINDOW(PGtkWidget(GtkWindow)^.window) and + (gdk_window_get_window_type(PGtkWidget(GtkWindow)^.window) <> GDK_WINDOW_CHILD) then + begin + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_ICONIFIED then + gtk_window_deiconify(GtkWindow) + else + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_FULLSCREEN then + gtk_window_unfullscreen(GtkWindow); + gtk_window_maximize(GtkWindow); + end; end; SW_SHOWFULLSCREEN: @@ -9488,11 +9496,20 @@ SW_RESTORE: begin - gtk_window_deiconify(GtkWindow); - gtk_window_unmaximize(GtkWindow); - gtk_window_unfullscreen(GtkWindow); + // see https://bugs.freepascal.org/view.php?id=31832 + if GDK_IS_WINDOW(PGtkWidget(GtkWindow)^.window) and + (gdk_window_get_window_type(PGtkWidget(GtkWindow)^.window) <> GDK_WINDOW_CHILD) then + begin + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_ICONIFIED then + gtk_window_deiconify(GtkWindow) + else + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_MAXIMIZED then + gtk_window_unmaximize(GtkWindow) + else + if gdk_window_get_state(PGtkWidget(GtkWindow)^.window) = GDK_WINDOW_STATE_FULLSCREEN then + gtk_window_unfullscreen(GtkWindow); + end; end; - end; Result := True; |
|
Added new patch issue31832_2.diff which checks for level, but also checks other conditions in SW_RESTORE and others. |
|
Pls, do not apply issue31832_2.diff since gdk_window_get_state() does not return correct results. Must check why it is so. Since gtk2 2.22 there's gtk_window_state() which returns correct results, but we are supporting all since gtk2-2.8 and such statement cannot be used for gtk2 < 2.22 |
|
Ok, found what happens: gtk_window_maximize(PGtkWindow(MyWindow)); if gdk_window_get_state(PGtkWindow(MyWindow)^.window) and GDK_WINDOW_STATE_MAXIMIZED <> 0 then writeln('OK') else writeln('BAD'); gtk_window_unmaximize(PGtkWindow(MyWindow)); 1.Note that code above is written from head, so maybe won't compile. 2.Such thing does not work under gtk2 since gdk window flag isn't updated imediatelly, but after events processing, under qt and win32 this works fine. My real test was: with TForm2.Create(Self) do begin Show; LCLIntf.ShowWindow(Handle, SW_SHOWMAXIMIZED); LCLIntf.ShowWindow(Handle, SW_RESTORE); end; So, my patch doesn't work correct in such scenario because gdk_window_get_state() does not return correct value in this case. Conclusion: Do not close this issue, leave workaround inside for now, this need to be rewritten in another way by using only gtk2/gdk code. |
|
Let's keep it "resolved" for now, but pls leave bug unclosed |
|
Please test with r54975. I'll add it to the merge list for 1.8RC2, but will not merge until someone confirm that this bug is fixed with r54975. |
Date Modified | Username | Field | Change |
---|---|---|---|
2017-05-17 23:02 | Kostas Michalopoulos | New Issue | |
2017-05-17 23:02 | Kostas Michalopoulos | File Added: gtk2-window-unmaximize-workaround-for-sw_shownormal-patch.diff | |
2017-05-17 23:04 | Kostas Michalopoulos | Tag Attached: component palette | |
2017-05-17 23:04 | Kostas Michalopoulos | Tag Attached: designer | |
2017-05-17 23:04 | Kostas Michalopoulos | Tag Attached: gtk2 | |
2017-05-17 23:04 | Kostas Michalopoulos | Tag Attached: lcl | |
2017-05-17 23:04 | Kostas Michalopoulos | Tag Attached: widgetset | |
2017-05-17 23:04 | Kostas Michalopoulos | File Added: webmshare_q78rb.webm | |
2017-05-17 23:05 | Kostas Michalopoulos | Note Added: 0100374 | |
2017-05-17 23:30 | CudaText man | Note Added: 0100377 | |
2017-05-18 01:12 | Mattias Gaertner | Fixed in Revision | => 54958 |
2017-05-18 01:12 | Mattias Gaertner | LazTarget | => - |
2017-05-18 01:12 | Mattias Gaertner | Note Added: 0100380 | |
2017-05-18 01:12 | Mattias Gaertner | Status | new => resolved |
2017-05-18 01:12 | Mattias Gaertner | Resolution | open => fixed |
2017-05-18 01:12 | Mattias Gaertner | Assigned To | => Mattias Gaertner |
2017-05-18 13:41 | Zeljan Rikalo | File Added: issue31832.diff | |
2017-05-18 13:42 | Zeljan Rikalo | Note Added: 0100434 | |
2017-05-18 14:08 | Zeljan Rikalo | File Added: issue31832_2.diff | |
2017-05-18 14:09 | Zeljan Rikalo | Note Added: 0100435 | |
2017-05-18 14:32 | Zeljan Rikalo | Note Added: 0100437 | |
2017-05-18 14:39 | Mattias Gaertner | Assigned To | Mattias Gaertner => Zeljan Rikalo |
2017-05-18 14:39 | Mattias Gaertner | Status | resolved => assigned |
2017-05-18 16:07 | Zeljan Rikalo | Note Added: 0100441 | |
2017-05-18 16:08 | Zeljan Rikalo | Note Added: 0100442 | |
2017-05-18 16:08 | Zeljan Rikalo | Status | assigned => resolved |
2017-05-18 19:29 | Zeljan Rikalo | Status | resolved => assigned |
2017-05-18 19:29 | Zeljan Rikalo | Resolution | fixed => reopened |
2017-05-18 19:30 | Zeljan Rikalo | Fixed in Revision | 54958 => 54958,54975 |
2017-05-18 19:30 | Zeljan Rikalo | Note Added: 0100451 | |
2017-05-18 19:30 | Zeljan Rikalo | Status | assigned => resolved |
2017-05-18 19:30 | Zeljan Rikalo | Resolution | reopened => fixed |