Gtk2: fixed clientRect of TCustomForm with main menu. Patch by rich2014. issue #40071

This commit is contained in:
Željan Rikalo 2023-02-01 16:56:26 +01:00
parent 3990e8a080
commit d195570688
6 changed files with 122 additions and 58 deletions

View File

@ -1105,6 +1105,7 @@ var
SizeMsg: TLMSize;
GtkWidth: LongInt;
GtkHeight: LongInt;
clientRectFix: TRect;
{$IFDEF HasX}
NetAtom: TGdkAtom;
AtomType: TGdkAtom;
@ -1138,6 +1139,11 @@ begin
if GtkWidth<0 then GtkWidth:=0;
GtkHeight:=Widget^.Allocation.Height;
if GtkHeight<0 then GtkHeight:=0;
clientRectFix:= GetWidgetInfo(Widget)^.FormClientRectFix;
inc( GtkWidth, clientRectFix.Width );
inc( GtkHeight, clientRectFix.Height );
//debugln('GTKWindowStateEventCB ',DbgSName(TObject(Data)),' ',dbgs(state^.new_window_state),' ',WidgetFlagsToString(Widget));
if ((GDK_WINDOW_STATE_ICONIFIED and state^.new_window_state)>0) then
begin

View File

@ -484,6 +484,8 @@ type
PaintDepth: integer; // increased/decreased by Begin/EndPaint
DataOwner: Boolean; // Set if the UserData should be freed when the info is freed
UserData: Pointer;
FormClientRectFix: TRect; // used only by forms, eg. MainMenu occupy client rect
FormBorderStyle: Integer; // used only by forms
FormWindowState: TGdkEventWindowState; // used only by forms to stop infinite loops eg. issue #16505
FirstPaint: boolean; // for accurate frame - forms only

View File

@ -6571,11 +6571,62 @@ begin
{$ENDIF}
end;
// move from gtk2wscontrls.pp
// to avoid unit circular references
procedure SetWidgetConstraints(const AWinControl: TWinControl);
var
Widget: PGtkWidget;
Geometry: TGdkGeometry;
clientRectFix: TRect;
begin
Widget := {%H-}PGtkWidget(AWinControl.Handle);
if (Widget <> nil) and (GtkWidgetIsA(Widget, gtk_window_get_type)) then
begin
clientRectFix:= GetWidgetInfo(Widget)^.FormClientRectFix;
with Geometry do
begin
if AWinControl.Constraints.MinWidth > 0 then
min_width := AWinControl.Constraints.MinWidth
else
min_width := 1;
if AWinControl.Constraints.MaxWidth > 0 then
max_width := AWinControl.Constraints.MaxWidth
else
max_width := 32767;
if AWinControl.Constraints.MinHeight > 0 then
min_height := AWinControl.Constraints.MinHeight
else
min_height := 1;
if AWinControl.Constraints.MaxHeight > 0 then
max_height := AWinControl.Constraints.MaxHeight
else
max_height := 32767;
if min_width>0 then inc(min_width, clientRectFix.Width);
if max_width>0 then inc(max_width, clientRectFix.Width);
if min_height>0 then inc(min_height, clientRectFix.Height);
if max_height>0 then inc(max_height, clientRectFix.Height);
base_width := AWinControl.Width + clientRectFix.Width;
base_height := AWinControl.Height + clientRectFix.Height;
width_inc := 1;
height_inc := 1;
min_aspect := 0;
max_aspect := 1;
win_gravity := gtk_window_get_gravity(PGtkWindow(Widget));
end;
//debugln('TGtk2WSWinControl.ConstraintsChange A ',GetWidgetDebugReport(Widget),' max=',dbgs(Geometry.max_width),'x',dbgs(Geometry.max_height));
gtk_window_set_geometry_hints(PGtkWindow(Widget), nil, @Geometry,
GDK_HINT_POS or GDK_HINT_MIN_SIZE or GDK_HINT_MAX_SIZE);
end;
end;
procedure SendSizeNotificationToLCL(aWidget: PGtkWidget);
var
LCLControl: TWinControl;
LCLLeft, LCLTop, LCLWidth, LCLHeight: integer;
GtkLeft, GtkTop, GtkWidth, GtkHeight: integer;
clientRectFix: PRect;
TopLeftChanged, WidthHeightChanged, IsTopLevelWidget: boolean;
MessageDelivered: boolean;
SizeMsg: TLMSize;
@ -6617,17 +6668,43 @@ begin
GetWidgetRelativePosition(MainWidget,GtkLeft,GtkTop);
gtk_widget_get_size_request(MainWidget, @GtkWidth, @GtkHeight);
if LCLControl is TCustomForm then begin
gtk_widget_get_size_request(FixedWidget, @GtkWidth, @GtkHeight);
if GtkWidth < 0 then
GtkWidth:=FixedWidget^.Allocation.Width;
if GtkHeight <0 then
GtkHeight:=FixedWidget^.Allocation.Height;
if GtkWidth < 0 then
GtkWidth:=MainWidget^.Allocation.Width
else
MainWidget^.Allocation.Width:=GtkWidth;
if GtkHeight < 0 then
GtkHeight:=MainWidget^.Allocation.Height
else
MainWidget^.Allocation.Height:=GtkHeight;
//DebugLn(['SendSizeNotificationToLCL ',DbgSName(LCLControl),' gtk=',GtkLeft,',',GtkTop,',',GtkWidth,'x',GtkHeight,' Allocation=',MainWidget^.Allocation.Width,'x',MainWidget^.Allocation.Height]);
// if ClientRect of the Form is occupied,
// record the occupied size into FormClientRectFix,
// it will be used when setting the Real Gtk Window elsewhere
WidthHeightChanged:= false;
clientRectFix:= @(GetWidgetInfo(aWidget)^.FormClientRectFix);
if (GtkWidth+clientRectFix^.Width) <> MainWidget^.Allocation.Width then begin
clientRectFix^.Width:= MainWidget^.Allocation.Width - GtkWidth;
WidthHeightChanged:= true;
end;
if (GtkHeight+clientRectFix^.Height) <> MainWidget^.Allocation.Height then begin
clientRectFix^.Height:= MainWidget^.Allocation.Height - GtkHeight;
WidthHeightChanged:= true;
end;
if WidthHeightChanged then begin
SetResizeRequest(MainWidget);
SetWidgetConstraints(LCLControl);
end;
end else begin
gtk_widget_get_size_request(MainWidget, @GtkWidth, @GtkHeight);
if GtkWidth < 0 then
GtkWidth:=MainWidget^.Allocation.Width
else
MainWidget^.Allocation.Width:=GtkWidth;
if GtkHeight < 0 then
GtkHeight:=MainWidget^.Allocation.Height
else
MainWidget^.Allocation.Height:=GtkHeight;
//DebugLn(['SendSizeNotificationToLCL ',DbgSName(LCLControl),' gtk=',GtkLeft,',',GtkTop,',',GtkWidth,'x',GtkHeight,' Allocation=',MainWidget^.Allocation.Width,'x',MainWidget^.Allocation.Height]);
end;
if GtkWidth<0 then GtkWidth:=0;
if GtkHeight<0 then GtkHeight:=0;
@ -7008,12 +7085,14 @@ procedure SetWindowSizeAndPosition(Window: PGtkWindow;
var
Width, Height: integer;
allocation: TGtkAllocation;
clientRectFix: TRect;
//Info: PGtkWindowGeometryInfo;
begin
Width:=AWinControl.Width;
clientRectFix:= GetWidgetInfo(Window)^.FormClientRectFix;
Width:=AWinControl.Width+clientRectFix.Width;
// 0 and negative values have a special meaning, so don't use them
if Width<=0 then Width:=1;
Height:=AWinControl.Height;
Height:=AWinControl.Height+clientRectFix.Height;
if Height<=0 then Height:=1;
{$IFDEF VerboseSizeMsg}

View File

@ -657,6 +657,7 @@ function gtkListGetSelectionMode(list: PGtkList): TGtkSelectionMode;cdecl;
procedure SaveSizeNotification(Widget: PGtkWidget);
procedure SaveClientSizeNotification(FixWidget: PGtkWidget);
procedure SendSizeNotificationToLCL(aWidget: PGtkWidget);
procedure SetWidgetConstraints(const AWinControl: TWinControl);
function CreateTopologicalSortedWidgets(HashArray: TDynHashArray): TFPList;
procedure GetGTKDefaultWidgetSize(AWinControl: TWinControl;
var PreferredWidth, PreferredHeight: integer; {%H-}WithThemeSpace: Boolean);

View File

@ -555,44 +555,8 @@ begin
end;
class procedure TGtk2WSWinControl.ConstraintsChange(const AWinControl: TWinControl);
var
Widget: PGtkWidget;
Geometry: TGdkGeometry;
begin
Widget := {%H-}PGtkWidget(AWinControl.Handle);
if (Widget <> nil) and (GtkWidgetIsA(Widget, gtk_window_get_type)) then
begin
with Geometry do
begin
if AWinControl.Constraints.MinWidth > 0 then
min_width := AWinControl.Constraints.MinWidth
else
min_width := 1;
if AWinControl.Constraints.MaxWidth > 0 then
max_width := AWinControl.Constraints.MaxWidth
else
max_width := 32767;
if AWinControl.Constraints.MinHeight > 0 then
min_height := AWinControl.Constraints.MinHeight
else
min_height := 1;
if AWinControl.Constraints.MaxHeight > 0 then
max_height := AWinControl.Constraints.MaxHeight
else
max_height := 32767;
base_width := AWinControl.Width;
base_height := AWinControl.Height;
width_inc := 1;
height_inc := 1;
min_aspect := 0;
max_aspect := 1;
win_gravity := gtk_window_get_gravity(PGtkWindow(Widget));
end;
//debugln('TGtk2WSWinControl.ConstraintsChange A ',GetWidgetDebugReport(Widget),' max=',dbgs(Geometry.max_width),'x',dbgs(Geometry.max_height));
gtk_window_set_geometry_hints(PGtkWindow(Widget), nil, @Geometry,
GDK_HINT_POS or GDK_HINT_MIN_SIZE or GDK_HINT_MAX_SIZE);
end;
SetWidgetConstraints(AWinControl);
end;
class procedure TGtk2WSWinControl.DestroyHandle(const AWinControl: TWinControl);
@ -657,6 +621,7 @@ var
Geometry: TGdkGeometry;
AHints: TGdkWindowHints;
AFixedWidthHeight: Boolean;
clientRectFix: TRect;
begin
if not WSCheckHandleAllocated(AWinControl, 'SetBounds')
then Exit;
@ -667,10 +632,12 @@ begin
if (not (AWinControl is TCustomForm)) or (AWinControl.Parent<>nil)
or (AWinControl.ParentWindow<>0) then
exit;
AForm := TCustomForm(AWinControl);
if not (csDesigning in AForm.ComponentState) and
AForm.HandleObjectShouldBeVisible then
begin
clientRectFix:= GetWidgetInfo(PGtkWidget(AForm.Handle))^.FormClientRectFix;
// we must set fixed size, gtk_window_set_resizable does not work
// as expected for some reason.issue #20741.
// Constraints fix issue #29563
@ -704,8 +671,13 @@ begin
if not AFixedWidthHeight and (AForm.Constraints.MaxWidth = 0) then
max_width := 32767;
base_width := AForm.Width;
base_height := AForm.Height;
if min_width>0 then inc(min_width, clientRectFix.Width);
if max_width>0 then inc(max_width, clientRectFix.Width);
if min_height>0 then inc(min_height, clientRectFix.Height);
if max_height>0 then inc(max_height, clientRectFix.Height);
base_width := AForm.Width + clientRectFix.Width;
base_height := AForm.Height + clientRectFix.Height;
width_inc := 1;
height_inc := 1;
min_aspect := 0;
@ -740,7 +712,9 @@ begin
gtk_window_set_geometry_hints({%H-}PGtkWindow(AForm.Handle), nil, @Geometry,
AHints);
end;
gtk_window_resize({%H-}PGtkWindow(AForm.Handle), AForm.Width, AForm.Height);
gtk_window_resize( {%H-}PGtkWindow(AForm.Handle),
AForm.Width+clientRectFix.Width,
AForm.Height+clientRectFix.Height);
end;
end;
end;

View File

@ -705,6 +705,7 @@ var
AForm, APopupParent: TCustomForm;
GtkWindow: PGtkWindow;
Geometry: TGdkGeometry;
clientRectFix: TRect;
function ShowNonModalOverModal: Boolean;
var
@ -820,17 +821,18 @@ begin
AForm.HandleObjectShouldBeVisible and
(AForm.BorderStyle in [bsDialog, bsSingle]) then
begin
clientRectFix:= GetWidgetInfo(PGtkWidget(AForm.Handle))^.FormClientRectFix;
// we must set fixed size, gtk_window_set_resizable does not work
// as expected for some reason.issue #20741
with Geometry do
begin
min_width := AForm.Width;
max_width := AForm.Width;
min_height := AForm.Height;
max_height := AForm.Height;
min_width := AForm.Width + clientRectFix.Width;
max_width := AForm.Width + clientRectFix.Width;
min_height := AForm.Height + clientRectFix.Height;
max_height := AForm.Height + clientRectFix.Height;
base_width := AForm.Width;
base_height := AForm.Height;
base_width := AForm.Width + clientRectFix.Width;
base_height := AForm.Height + clientRectFix.Height;
width_inc := 1;
height_inc := 1;
min_aspect := 0;