Fix Gtk 1.2 LCL backend.

There are still some minor glitches, but the IDE and most examples i
tried seem to work fine.  Some examples didn't work but that seemed to
be mainly a Gtk 1.2 limitation (e.g. no rotating fonts).
This commit is contained in:
Bad Sector 2022-02-07 01:51:48 +02:00 committed by Maxim Ganetsky
parent deea0b1e74
commit 8f08573815
14 changed files with 71 additions and 39 deletions

View File

@ -204,7 +204,7 @@ type
TTimerRecord = record TTimerRecord = record
Control: TControl; Control: TControl;
Notify: TTimerNotify; Notify: TTimerNotify;
Id: LongWord; Id: UINT_PTR;
TimerHandle: guint; TimerHandle: guint;
end; end;
PTimerRecord = ^TTimerRecord; PTimerRecord = ^TTimerRecord;
@ -217,9 +217,9 @@ type
public public
constructor Create; constructor Create;
destructor Destroy; override; destructor Destroy; override;
function Add(hWnd: THandle; ID: LongWord; NotifyFunc: TTimerNotify; WinControl: TControl):PTimerRecord; function Add(hWnd: THandle; ID: UINT_PTR; NotifyFunc: TTimerNotify; WinControl: TControl):PTimerRecord;
function GetTimerInfo(Handle: hWnd; idEvent:LongWord; out TimerInfo: TTimerRecord):Boolean; function GetTimerInfo(Handle: hWnd; idEvent:UINT_PTR; out TimerInfo: TTimerRecord):Boolean;
function GetTimerInfoPtr(Handle: hWnd; idEvent:LongWord): PTimerRecord; function GetTimerInfoPtr(Handle: hWnd; idEvent:UINT_PTR): PTimerRecord;
end; end;
var var
@ -244,7 +244,7 @@ begin
inherited Destroy; inherited Destroy;
end; end;
function TTimerList.Add(hWnd: THandle; ID: LongWord; NotifyFunc: TTimerNotify; WinControl: TControl):PTimerRecord; function TTimerList.Add(hWnd: THandle; ID: UINT_PTR; NotifyFunc: TTimerNotify; WinControl: TControl):PTimerRecord;
var var
AID: QWord; AID: QWord;
ATimerRec: TTimerRecord; ATimerRec: TTimerRecord;
@ -263,13 +263,13 @@ begin
end; end;
end; end;
function TTimerList.GetTimerInfo(Handle: hWnd; idEvent: LongWord; out function TTimerList.GetTimerInfo(Handle: hWnd; idEvent: UINT_PTR; out
TimerInfo: TTimerRecord): Boolean; TimerInfo: TTimerRecord): Boolean;
begin begin
Result:= FList.GetData(MakeQWord(Handle,idEvent),TimerInfo); Result:= FList.GetData(MakeQWord(Handle,idEvent),TimerInfo);
end; end;
function TTimerList.GetTimerInfoPtr(Handle: hWnd; idEvent: LongWord function TTimerList.GetTimerInfoPtr(Handle: hWnd; idEvent: UINT_PTR
): PTimerRecord; ): PTimerRecord;
begin begin
Result := FList.GetDataPtr(MakeQWord(Handle,idEvent)); Result := FList.GetDataPtr(MakeQWord(Handle,idEvent));
@ -300,7 +300,7 @@ begin
end; end;
end; end;
function SetTimer(hWnd:THandle; nIDEvent:LongWord; uElapse:LongWord; lpTimerFunc:TTimerNotify):LongWord; function SetTimer(hWnd:THandle; nIDEvent:UINT_PTR; uElapse:LongWord; lpTimerFunc:TTimerNotify):UINT_PTR;
var var
TimerInfo: PTimerRecord; TimerInfo: PTimerRecord;
Control: TControl; Control: TControl;
@ -313,13 +313,15 @@ begin
Control := nil; Control := nil;
TimerInfo := FTimerList.Add(hWnd, nIDEvent, lpTimerFunc, Control); TimerInfo := FTimerList.Add(hWnd, nIDEvent, lpTimerFunc, Control);
TimerInfo^.TimerHandle := gtk_timeout_add(uElapse, @gtkTimerCB, TimerInfo); TimerInfo^.TimerHandle := gtk_timeout_add(uElapse, @gtkTimerCB, TimerInfo);
Result:=nIDEvent;
//DebugLn('SetTimer HWnd: %d ID: %d TimerHandle: %d',[hWnd,nIDEvent,TimerInfo^.TimerHandle]); //DebugLn('SetTimer HWnd: %d ID: %d TimerHandle: %d',[hWnd,nIDEvent,TimerInfo^.TimerHandle]);
end; end;
function KillTimer(hWnd:THandle; nIDEvent: LongWord):Boolean; function KillTimer(hWnd:THandle; nIDEvent: UINT_PTR):Boolean;
var var
TimerInfo: PTimerRecord; TimerInfo: PTimerRecord;
begin begin
Result:=True;
TimerInfo := FTimerList.GetTimerInfoPtr(hWnd,nIDEvent); TimerInfo := FTimerList.GetTimerInfoPtr(hWnd,nIDEvent);
if TimerInfo <> nil then if TimerInfo <> nil then
begin begin

View File

@ -513,7 +513,7 @@ begin
end; end;
function TMainIDEBar.CalcNonClientHeight: Integer; function TMainIDEBar.CalcNonClientHeight: Integer;
{$IF DEFINED(LCLWin32) OR DEFINED(LCLGtk2) OR DEFINED(LCLQt) OR DEFINED(LCLQt5)} {$IF DEFINED(LCLWin32) OR DEFINED(LCLGtk) OR DEFINED(LCLGtk2) OR DEFINED(LCLQt) OR DEFINED(LCLQt5)}
var var
WindowRect, WindowClientRect: TRect; WindowRect, WindowClientRect: TRect;
{$ENDIF} {$ENDIF}
@ -534,7 +534,7 @@ begin
if not Showing then if not Showing then
Exit(0); Exit(0);
{$IF DEFINED(LCLWin32) OR DEFINED(LCLGtk2) OR DEFINED(LCLQt) OR DEFINED(LCLQt5)} {$IF DEFINED(LCLWin32) OR DEFINED(LCLGtk) OR DEFINED(LCLGtk2) OR DEFINED(LCLQt) OR DEFINED(LCLQt5)}
//Gtk2 + Win32 + Qt //Gtk2 + Win32 + Qt
//retrieve real main menu height because //retrieve real main menu height because
// - Win32: multi-line is possible (SM_CYMENU reflects only single line) // - Win32: multi-line is possible (SM_CYMENU reflects only single line)

View File

@ -613,7 +613,7 @@ implementation
uses uses
// until all code is transfered to objects, these circles are needed; // until all code is transfered to objects, these circles are needed;
gtkint, gtkproc, GtkFontCache, GTKWinApiWindow; gtkint, gtkproc, GtkFontCache, GTKWinApiWindow, LazUtilities;
{$IFOpt R+}{$Define RangeChecksOn}{$Endif} {$IFOpt R+}{$Define RangeChecksOn}{$Endif}

View File

@ -40,6 +40,9 @@ interface
implementation implementation
uses
LazUtilities;
{$ifdef gtk1} {$ifdef gtk1}
{$I gtk1extra.inc} {$I gtk1extra.inc}
{$endif} {$endif}

View File

@ -92,6 +92,9 @@ var
implementation implementation
uses
LazUtilities;
type type
TLogFontAndName = record TLogFontAndName = record
LogFont: TLogFont; LogFont: TLogFont;

View File

@ -355,7 +355,8 @@ uses
GtkThemes, GtkThemes,
Buttons, StdCtrls, PairSplitter, Buttons, StdCtrls, PairSplitter,
GTKWinApiWindow, ComCtrls, Calendar, Spin, GTKWinApiWindow, ComCtrls, Calendar, Spin,
ExtCtrls, FileCtrl, LResources, gtkglobals; ExtCtrls, FileCtrl, LResources, gtkglobals,
LazUtilities;
{$I gtklistsl.inc} {$I gtklistsl.inc}
{$I gtkfiledialogutils.inc} {$I gtkfiledialogutils.inc}

View File

@ -271,6 +271,11 @@ begin
// remove the dummy page (a gtk_notebook needs at least one page) // remove the dummy page (a gtk_notebook needs at least one page)
RemoveDummyNotebookPage(PGtkNotebook(TabControlWidget)); RemoveDummyNotebookPage(PGtkNotebook(TabControlWidget));
// unrealize the page widget if it is already realized as Gtk 1.2 will try to
// deref PageWidget->window for realized widgets when the latter are added to
// a container without checking if the pointer is not null
if GTK_WIDGET_REALIZED(PageWidget) then
gtk_widget_unrealize(PageWidget);
// insert the page // insert the page
gtk_notebook_insert_page_menu(PGtkNotebook(TabControlWidget), PageWidget, gtk_notebook_insert_page_menu(PGtkNotebook(TabControlWidget), PageWidget,
TabWidget, MenuWidget, AIndex); TabWidget, MenuWidget, AIndex);

View File

@ -1601,7 +1601,7 @@ var
begin begin
if DC=0 then ; if DC=0 then ;
if not (cfColorAllocated in GDIColor^.ColorFlags) then begin if not (cfColorAllocated in GDIColor^.ColorFlags) then begin
RGBColor := ColorToRGB(GDIColor^.ColorRef); RGBColor := ColorToRGB(TColor(GDIColor^.ColorRef));
With GDIColor^.Color do begin With GDIColor^.Color do begin
Red := gushort(GetRValue(RGBColor)) shl 8; Red := gushort(GetRValue(RGBColor)) shl 8;
@ -4528,15 +4528,11 @@ begin
// get the tab container and the tab components: pixmap, label and closebtn // get the tab container and the tab components: pixmap, label and closebtn
TabWidget:=gtk_notebook_get_tab_label(PGtkNoteBook(NotebookWidget), TabWidget:=gtk_notebook_get_tab_label(PGtkNoteBook(NotebookWidget),
PageWidget); PageWidget);
if TabWidget<>nil then begin if TabWidget=nil then exit;
TabImageWidget:=gtk_object_get_data(PGtkObject(TabWidget), 'TabImage');
TabLabelWidget:=gtk_object_get_data(PGtkObject(TabWidget), 'TabLabel'); TabImageWidget:=gtk_object_get_data(PGtkObject(TabWidget), 'TabImage');
TabCloseBtnWidget:=gtk_object_get_data(PGtkObject(TabWidget),'TabCloseBtn'); TabLabelWidget:=gtk_object_get_data(PGtkObject(TabWidget), 'TabLabel');
end else begin TabCloseBtnWidget:=gtk_object_get_data(PGtkObject(TabWidget),'TabCloseBtn');
TabImageWidget:=nil;
TabLabelWidget:=nil;
TabCloseBtnWidget:=nil;
end;
// get the menu container and its components: pixmap and label // get the menu container and its components: pixmap and label
MenuWidget:=gtk_notebook_get_menu_label(PGtkNoteBook(NotebookWidget), MenuWidget:=gtk_notebook_get_menu_label(PGtkNoteBook(NotebookWidget),
@ -4589,7 +4585,7 @@ begin
Result.Y:=0; Result.Y:=0;
end; end;
// check if the gdkwindow is the clientwindow of the parent // check if the gdkwindow is the clientwindow of the parent
if gtk_widget_get_parent_window(TheWidget)=TheWindow then begin if (TheWidget^.Parent<>nil) and (gtk_widget_get_parent_window(TheWidget)=TheWindow) then begin
// the widget is using its parent window // the widget is using its parent window
// -> adjust the coordinates // -> adjust the coordinates
inc(Result.X,TheWidget^.Allocation.X); inc(Result.X,TheWidget^.Allocation.X);
@ -8567,7 +8563,7 @@ begin
GC := nil; GC := nil;
Pixmap := nil; Pixmap := nil;
SysColor := ColorToRGB(Color); SysColor := ColorToRGB(TColor(Color));
Result.Fill := GDK_Solid; Result.Fill := GDK_Solid;
RedGreenBlue(TColor(SysColor), Red, Green, Blue); RedGreenBlue(TColor(SysColor), Red, Green, Blue);
Result.foreground.Red:=gushort(Red) shl 8 + Red; Result.foreground.Red:=gushort(Red) shl 8 + Red;
@ -9869,6 +9865,8 @@ begin
ay:=current_desktop[1]; ay:=current_desktop[1];
awidth:=current_desktop[2]; awidth:=current_desktop[2];
aheight:=current_desktop[3]; aheight:=current_desktop[3];
// if an invalid size was given, assume garbage from the window manager
if (awidth < 1) or (aheight < 1) then result := -1;
end; end;
if current_desktop <> nil then if current_desktop <> nil then
XFree (current_desktop); XFree (current_desktop);

View File

@ -791,7 +791,7 @@ implementation
uses uses
{$IFDEF StaticXinerama} Xinerama, {$ENDIF} {$IFDEF StaticXinerama} Xinerama, {$ENDIF}
dynlibs, GtkWSPrivate, URIParser, GtkInt; dynlibs, GtkWSPrivate, URIParser, GtkInt, LazUtilities;
const const
KCINFO_FLAG_SHIFT = $01; KCINFO_FLAG_SHIFT = $01;

View File

@ -1864,7 +1864,7 @@ begin
{$IFDEF VerboseFonts} {$IFDEF VerboseFonts}
DebugLn('[TGtkWidgetSet.CreateFontIndirect] ',DbgS(GdiObject),' ',dbgs(FGDIObjects.Count)); DebugLn('[TGtkWidgetSet.CreateFontIndirect] ',DbgS(GdiObject),' ',dbgs(FGDIObjects.Count));
{$ENDIF} {$ENDIF}
DisposeGDIObject(GdiObject); ReleaseGDIObject(GdiObject);
Result := 0; Result := 0;
end end
else begin else begin
@ -6820,7 +6820,10 @@ begin
Rect^.Top := 0;//PaintWidget^.Allocation.Y; Rect^.Top := 0;//PaintWidget^.Allocation.Y;
Rect^.Right := PaintWidget^.Allocation.Width; Rect^.Right := PaintWidget^.Allocation.Width;
Rect^.Bottom := PaintWidget^.Allocation.Height; Rect^.Bottom := PaintWidget^.Allocation.Height;
end; end
// ignore the request if the rectangle is invalid
else if (Rect^.Left >= Rect^.Right) or (Rect^.Top >= Rect^.Bottom) then
Exit(True);
gdkRect.X := Rect^.Left; gdkRect.X := Rect^.Left;
gdkRect.Y := Rect^.Top; gdkRect.Y := Rect^.Top;
gdkRect.Width := (Rect^.Right - Rect^.Left); gdkRect.Width := (Rect^.Right - Rect^.Left);
@ -8066,6 +8069,15 @@ end;
------------------------------------------------------------------------------} ------------------------------------------------------------------------------}
function TGtkWidgetSet.ScrollWindowEx(hWnd: HWND; dx, dy: Integer; prcScroll, prcClip: PRect; hrgnUpdate: HRGN; prcUpdate: PRect; flags: UINT): Boolean; function TGtkWidgetSet.ScrollWindowEx(hWnd: HWND; dx, dy: Integer; prcScroll, prcClip: PRect; hrgnUpdate: HRGN; prcUpdate: PRect; flags: UINT): Boolean;
begin begin
// HACK: the full functionality necessary by ScrollWindowEx isn't supported
// but as this is mainly used to update controls, we'll invalidate the full
// window to ensure that the control is up to date (this fixes controls that
// rely on ScrollWindowEx for scrolling part of the content with the irony
// that the idea of using it was to make painting faster but this fix makes
// it slower than if they just repainted themselves)
InvalidateRect(hWnd, nil, False);
// We'll still report this as a failure since, technically speaking, the
// request didn't work
Result := False; Result := False;
end; end;

View File

@ -287,9 +287,8 @@ var
Pixbuf: PGdkPixbuf; Pixbuf: PGdkPixbuf;
Mask: PGdkBitmap; Mask: PGdkBitmap;
AGlyph: TBitmap; AGlyph: TBitmap;
AIndex, aPPI: Integer; AIndex: Integer;
AEffect: TGraphicsDrawEffect; AEffect: TGraphicsDrawEffect;
aCanvasScaleFactor: Double;
ImgResolution: TScaledImageListResolution; ImgResolution: TScaledImageListResolution;
begin begin
WidgetInfo := GetWidgetInfo(Pointer(ABitBtn.Handle)); WidgetInfo := GetWidgetInfo(Pointer(ABitBtn.Handle));
@ -298,8 +297,8 @@ begin
if ABitBtn.CanShowGlyph then if ABitBtn.CanShowGlyph then
begin begin
AGlyph := TBitmap.Create; AGlyph := TBitmap.Create;
AValue.GetImageIndexAndEffect(AButtonState, aPPI, aCanvasScaleFactor, AValue.GetImageIndexAndEffect(AButtonState, ABitBtn.Font.PixelsPerInch,
ImgResolution, AIndex, AEffect); ABitBtn.GetCanvasScaleFactor, ImgResolution, AIndex, AEffect);
if (AIndex <> -1) and (AValue.Images <> nil) then if (AIndex <> -1) and (AValue.Images <> nil) then
AValue.Images.GetBitmap(AIndex, AGlyph, AEffect); AValue.Images.GetBitmap(AIndex, AGlyph, AEffect);
end end

View File

@ -249,7 +249,7 @@ type
implementation implementation
uses uses
SysUtils, SysUtils, LazUtilities,
GtkProc, GtkInt, GtkGlobals, GtkProc, GtkInt, GtkGlobals,
GtkWSControls; GtkWSControls;

View File

@ -281,18 +281,27 @@ begin
end; end;
function GtkWSFormUnMapEvent(Widget: PGtkWidget; Event: PGdkEvent; WidgetInfo: PWidgetInfo): gboolean; cdecl; function GtkWSFormUnMapEvent(Widget: PGtkWidget; Event: PGdkEvent; WidgetInfo: PWidgetInfo): gboolean; cdecl;
const
LastSleepTime: QWord = 0;
var var
Message: TLMSize; Message: TLMSize;
AForm: TCustomForm; AForm: TCustomForm;
begin begin
// HACK: sleep for a bit to avoid the race condition where the unmap event is
// sent before the window manager updates the state attribute. We also only
// do that if some time has passed since the last Sleep, otherwise every
// window will cause Sleep to be called by itself.
if GetTickCount64 - LastSleepTime > 100 then begin
Sleep(100); // even 10ms seems to work on my PC so 100ms should be safe
LastSleepTime:=GetTickCount64;
end;
// ignore the unmap signal if the window is not being minimized (e.g. desktop
// switches or windows become shaded)
if not GDK_WINDOW_GET_MINIMIZED(PGdkWindowPrivate(Widget^.Window)) then Exit;
Result := True; Result := True;
FillChar(Message, 0, SizeOf(Message)); FillChar(Message, 0, SizeOf(Message));
AForm := TCustomForm(WidgetInfo^.LCLObject); AForm := TCustomForm(WidgetInfo^.LCLObject);
// ignore the unmap signals when we switch desktops
// as this results in irritating behavior when we return to the desktop
if GDK_GET_CURRENT_DESKTOP <> GDK_WINDOW_GET_DESKTOP(PGdkWindowPrivate(Widget^.Window)) then Exit;
Message.Msg := LM_SIZE; Message.Msg := LM_SIZE;
Message.SizeType := SIZEICONIC or Size_SourceIsInterface; Message.SizeType := SIZEICONIC or Size_SourceIsInterface;
Message.Width := AForm.Width; Message.Width := AForm.Width;

View File

@ -306,7 +306,7 @@ procedure WidgetSetSelLength(const Widget: PGtkWidget; NewLength: integer);
implementation implementation
uses uses
GtkWSControls; GtkWSControls, LazUtilities;
const const
StaticBorderShadowMap: array[TStaticBorderStyle] of TGtkShadowType = StaticBorderShadowMap: array[TStaticBorderStyle] of TGtkShadowType =