gtk1, gtk2: Add CreateIconIndirect implementation which returns pixbuf. Move CreateCursor code there and remove its declaration.

git-svn-id: trunk@15457 -
This commit is contained in:
paul 2008-06-18 09:14:27 +00:00
parent 66ca0835ec
commit db26dddf06
6 changed files with 265 additions and 218 deletions

View File

@ -1139,16 +1139,14 @@ begin
EndGDKErrorTrap;
end;
function ScalePixmapAndMask(AScaleGC: PGDKGC; AScaleMethod: TGdkInterpType;
ASrc: PGdkPixmap; ASrcX, ASrcY, ASrcWidth, ASrcHeight: integer;
ASrcColorMap: PGdkColormap; ASrcMask: PGdkBitmap;
ADstWidth, ADstHeight: Integer; out ADst, ADstMask: PGdkPixmap) : Boolean;
function CreatePixbufFromImageAndMask(ASrc: PGdkPixmap; ASrcX, ASrcY, ASrcWidth,
ASrcHeight: integer; ASrcColorMap: PGdkColormap; ASrcMask: PGdkBitmap): PGdkPixbuf;
procedure Warn(const AText: String);
begin
DebugLn('[WARNING] ScalePixmapAndMask: ' + AText);
end;
procedure ApplyMask(APixels, AMask: pguchar);
type
TPixbufPixel = record
@ -1169,10 +1167,10 @@ function ScalePixmapAndMask(AScaleGC: PGDKGC; AScaleMethod: TGdkInterpType;
end;
var
ScaleSrc, ScaleDst, ScaleMsk: PGdkPixbuf;
Msk: PGdkPixbuf;
FullSrcWidth, FullSrcHeight: integer;
begin
Result := False;
Result := nil;
if ASrc = nil then Exit;
gdk_window_get_size(PGDKWindow(ASrc), @FullSrcWidth, @FullSrcHeight);
@ -1186,27 +1184,48 @@ begin
end;
// Creating PixBuf from pixmap
ScaleSrc := CreatePixbufFromDrawable(ASrc, ASrcColorMap, ASrcMask <> nil, ASrcX, ASrcY, 0, 0, ASrcWidth, ASrcHeight);
if ScaleSrc = nil
Result := CreatePixbufFromDrawable(ASrc, ASrcColorMap, ASrcMask <> nil, ASrcX, ASrcY, 0, 0, ASrcWidth, ASrcHeight);
if Result = nil
then begin
Warn('ScaleSrc=nil');
Warn('Result=nil');
Exit;
end;
// Apply mask if present
if ASrcMask <> nil
then begin
if gdk_pixbuf_get_rowstride(ScaleSrc) <> ASrcWidth shl 2
if gdk_pixbuf_get_rowstride(Result) <> ASrcWidth shl 2
then begin
Warn('rowstride <> 4*width');
gdk_pixbuf_unref(ScaleSrc);
gdk_pixbuf_unref(Result);
Result := nil;
Exit;
end;
ScaleMsk := CreatePixbufFromDrawable(ASrcMask, nil, True, ASrcX, ASrcY, 0, 0, ASrcWidth, ASrcHeight);
ApplyMask(gdk_pixbuf_get_pixels(ScaleSrc), gdk_pixbuf_get_pixels(ScaleMsk));
gdk_pixbuf_unref(ScaleMsk);
Msk := CreatePixbufFromDrawable(ASrcMask, nil, True, ASrcX, ASrcY, 0, 0, ASrcWidth, ASrcHeight);
ApplyMask(gdk_pixbuf_get_pixels(Result), gdk_pixbuf_get_pixels(Msk));
gdk_pixbuf_unref(Msk);
end;
end;
function ScalePixmapAndMask(AScaleGC: PGDKGC; AScaleMethod: TGdkInterpType;
ASrc: PGdkPixmap; ASrcX, ASrcY, ASrcWidth, ASrcHeight: integer;
ASrcColorMap: PGdkColormap; ASrcMask: PGdkBitmap;
ADstWidth, ADstHeight: Integer; out ADst, ADstMask: PGdkPixmap) : Boolean;
procedure Warn(const AText: String);
begin
DebugLn('[WARNING] ScalePixmapAndMask: ' + AText);
end;
var
ScaleSrc, ScaleDst: PGdkPixbuf;
begin
Result := False;
// Creating PixBuf from pixmap
ScaleSrc := CreatePixbufFromImageAndMask(ASrc, ASrcX, ASrcY, ASrcWidth, ASrcHeight,
ASrcColorMap, ASrcMask);
// Scaling PixBuf
ScaleDst := gdk_pixbuf_scale_simple(ScaleSrc, ADstWidth, ADstHeight, AScaleMethod);

View File

@ -630,6 +630,8 @@ procedure MergeClipping(DestinationDC: TGtkDeviceContext; DestinationGC: PGDKGC;
X,Y,Width,Height: integer; ClipMergeMask: PGdkBitmap;
ClipMergeMaskX, ClipMergeMaskY: integer;
var NewClipMask: PGdkBitmap);
function CreatePixbufFromImageAndMask(ASrc: PGdkPixmap; ASrcX, ASrcY, ASrcWidth,
ASrcHeight: integer; ASrcColorMap: PGdkColormap; ASrcMask: PGdkBitmap): PGdkPixbuf;
function ScalePixmapAndMask(AScaleGC: PGDKGC; AScaleMethod: TGdkInterpType;
ASrc: PGdkPixmap; ASrcX, ASrcY, ASrcWidth, ASrcHeight: integer;
ASrcColorMap: PGdkColormap; ASrcMask: PGdkBitmap;

View File

@ -1226,136 +1226,19 @@ begin
Assert(False,Format('trace: [TGtkWidgetSet.CreateCompatibleDC] DC: 0x%x --> 0x%x', [Integer(DC), Integer(Result)]));
end;
function TGtkWidgetSet.CreateCursor(ACursorInfo: PIconInfo): hCursor;
procedure GetColorMask(AImage, AMask: PGDKPixmap; AImgBits, AMskBits: PByte; AWidth, AHeight: integer);
var
i, j: integer;
colormap: PGDKColormap;
Image, MaskImage: PGDKImage;
GDKColor: TGDKColor;
Pixel, MaskPixel: LongWord;
offset: byte;
procedure SetColorAndMask(c: TGDKColor; MaskPixel: LongWord);
var
c_bit, m_bit: byte;
begin
// c_bit := Ord(0.222 * c.red + 0.707 * c.green + 0.071 * c.blue >= $8000);
// do some int math
c_bit := Ord(cardinal(222) * c.red
+ cardinal(707) * c.green
+ cardinal(071) * c.blue
>= $8000 * 1000);
m_bit := ord(MaskPixel = 1);
AImgBits^ := AImgBits^ or (c_bit shl offset);
AMskBits^ := AMskBits^ or (m_bit shl offset);
inc(offset);
if offset > 7 then
begin
inc(AImgBits);
inc(AMskBits);
offset := 0;
end;
end;
begin
// most of this code was taken from TGtkWidgetSet.DCGetPixel
Image := gdk_drawable_get_image(AImage, 0, 0, AWidth, AHeight);
MaskImage := gdk_drawable_get_image(AMask, 0, 0, AWidth, AHeight);
{$ifdef Gtk1}
// previously gdk_image_get_colormap(image) was used, implementation
// was casting GdkImage to GdkWindow which is not valid and cause AVs
if gdk_window_get_type(PGdkWindow(AImage))= GDK_WINDOW_PIXMAP then
colormap := nil // pixmaps are created with null colormap, get system one instead
else
colormap := gdk_window_get_colormap(PGdkWindow(AImage));
{$else}
colormap := gdk_image_get_colormap(image);
{$endif}
if colormap = nil then
colormap := gdk_colormap_get_system;
offset := 0;
for j := 0 to AHeight - 1 do
for i := 0 to AWidth - 1 do
begin
Pixel := gdk_image_get_pixel(Image, i, j);
MaskPixel := gdk_image_get_pixel(MaskImage, i, j);
FillChar(GDKColor,SizeOf(GDKColor), 0);
// does not work with TBitmap.Canvas
gdk_colormap_query_color(colormap, Pixel, @GDKColor);
SetColorAndMask(GDKColor, MaskPixel);
end;
gdk_image_unref(Image);
gdk_image_unref(MaskImage);
end;
var
FG, BG: TGDKColor;
Img, Msk: PGdkPixmap;
srcbitmap, mskbitmap: PGdkPixmap;
W, H, bitlen: integer;
ImgBits, MskBits: array of byte;
begin
Result := 0;
if not IsValidGDIObject(ACursorInfo^.hbmColor) then Exit;
{$IFDEF VerboseGtkToDos}{$note TODO: add support for mono cursors}{$ENDIF}
Img := PGDIObject(ACursorInfo^.hbmColor)^.GDIBitmapObject;
if (PGDIObject(ACursorInfo^.hbmColor)^.GDIBitmapType = gbPixmap) and
(PGDIObject(ACursorInfo^.hbmColor)^.GDIPixmapObject.Mask <> nil) then
Msk := PGDIObject(ACursorInfo^.hbmColor)^.GDIPixmapObject.Mask
else
Msk := PGDIObject(ACursorInfo^.hbmMask)^.GDIBitmapObject;
gdk_drawable_get_size(Img, @W, @H);
bitlen := (W * H) shr 3;
SetLength(ImgBits, bitlen);
SetLength(MskBits, bitlen);
FillChar(ImgBits[0], bitlen, 0);
FillChar(MskBits[0], bitlen, 0);
GetColorMask(Img, Msk, @ImgBits[0], @MskBits[0], W, H);
srcbitmap := gdk_bitmap_create_from_data(nil, @ImgBits[0], W, H);
mskbitmap := gdk_bitmap_create_from_data(nil, @MskBits[0], W, H);
// white
fg.red := $FFFF;
fg.green := $FFFF;
fg.blue := $FFFF;
fg.pixel := 0;
// black
bg.red := 0;
bg.green := 0;
bg.blue := 0;
bg.pixel := 0;
Result := HCursor(PtrUInt(gdk_cursor_new_from_pixmap(srcbitmap, mskbitmap,
@fg, @bg, ACursorInfo^.xHotspot, ACursorInfo^.yHotspot)));
gdk_pixmap_unref(srcbitmap);
gdk_pixmap_unref(mskbitmap);
if Msk <> nil then
gdk_pixmap_unref(msk);
end;
function TGtkWidgetSet.DestroyCursor(Handle: hCursor): Boolean;
begin
if Handle <> 0 then
Result := Handle <> 0;
if Result then
gdk_cursor_destroy(PGdkCursor(Handle));
Result:=true;
end;
function TGTKWidgetSet.DestroyIcon(Handle: HICON): Boolean;
begin
// todo: handle cursors here, but how to check whether it is a cursor or an icon?
Result := Handle <> 0;
if Result then
gdk_pixbuf_unref(PGdkPixbuf(Handle));
end;
{------------------------------------------------------------------------------
@ -1908,6 +1791,135 @@ begin
end;
{$EndIf}
function TGTKWidgetSet.CreateIconIndirect(IconInfo: PIconInfo): HICON;
procedure GetColorMask(AImage, AMask: PGDKPixmap; AImgBits, AMskBits: PByte; AWidth, AHeight: integer);
var
i, j: integer;
colormap: PGDKColormap;
Image, MaskImage: PGDKImage;
GDKColor: TGDKColor;
Pixel, MaskPixel: LongWord;
offset: byte;
procedure SetColorAndMask(c: TGDKColor; MaskPixel: LongWord);
var
c_bit, m_bit: byte;
begin
// c_bit := Ord(0.222 * c.red + 0.707 * c.green + 0.071 * c.blue >= $8000);
// do some int math
c_bit := Ord(cardinal(222) * c.red
+ cardinal(707) * c.green
+ cardinal(071) * c.blue
>= $8000 * 1000);
m_bit := ord(MaskPixel = 1);
AImgBits^ := AImgBits^ or (c_bit shl offset);
AMskBits^ := AMskBits^ or (m_bit shl offset);
inc(offset);
if offset > 7 then
begin
inc(AImgBits);
inc(AMskBits);
offset := 0;
end;
end;
begin
// most of this code was taken from TGtkWidgetSet.DCGetPixel
Image := gdk_drawable_get_image(AImage, 0, 0, AWidth, AHeight);
MaskImage := gdk_drawable_get_image(AMask, 0, 0, AWidth, AHeight);
{$ifdef Gtk1}
// previously gdk_image_get_colormap(image) was used, implementation
// was casting GdkImage to GdkWindow which is not valid and cause AVs
if gdk_window_get_type(PGdkWindow(AImage))= GDK_WINDOW_PIXMAP then
colormap := nil // pixmaps are created with null colormap, get system one instead
else
colormap := gdk_window_get_colormap(PGdkWindow(AImage));
{$else}
colormap := gdk_image_get_colormap(image);
{$endif}
if colormap = nil then
colormap := gdk_colormap_get_system;
offset := 0;
for j := 0 to AHeight - 1 do
for i := 0 to AWidth - 1 do
begin
Pixel := gdk_image_get_pixel(Image, i, j);
MaskPixel := gdk_image_get_pixel(MaskImage, i, j);
FillChar(GDKColor,SizeOf(GDKColor), 0);
// does not work with TBitmap.Canvas
gdk_colormap_query_color(colormap, Pixel, @GDKColor);
SetColorAndMask(GDKColor, MaskPixel);
end;
gdk_image_unref(Image);
gdk_image_unref(MaskImage);
end;
var
FG, BG: TGDKColor;
Img, Msk: PGdkPixmap;
srcbitmap, mskbitmap: PGdkBitmap;
W, H, bitlen: integer;
ImgBits, MskBits: array of byte;
APixbuf: PGdkPixbuf;
begin
Result := 0;
if not IsValidGDIObject(IconInfo^.hbmColor) then Exit;
{$IFDEF VerboseGtkToDos}{$note TODO: add support for mono cursors}{$ENDIF}
Img := PGDIObject(IconInfo^.hbmColor)^.GDIBitmapObject;
if (PGDIObject(IconInfo^.hbmColor)^.GDIBitmapType = gbPixmap) and
(PGDIObject(IconInfo^.hbmColor)^.GDIPixmapObject.Mask <> nil) then
Msk := PGDIObject(IconInfo^.hbmColor)^.GDIPixmapObject.Mask
else
Msk := PGDIObject(IconInfo^.hbmMask)^.GDIBitmapObject;
gdk_drawable_get_size(Img, @W, @H);
if IconInfo^.fIcon then
begin
// Creating PixBuf from pixmap and mask
Result := HICON(PtrUInt(CreatePixbufFromImageAndMask(Img, 0, 0, W, H, nil, Msk)));
end
else
begin
bitlen := (W * H) shr 3;
SetLength(ImgBits, bitlen);
SetLength(MskBits, bitlen);
FillChar(ImgBits[0], bitlen, 0);
FillChar(MskBits[0], bitlen, 0);
GetColorMask(Img, Msk, @ImgBits[0], @MskBits[0], W, H);
srcbitmap := gdk_bitmap_create_from_data(nil, @ImgBits[0], W, H);
mskbitmap := gdk_bitmap_create_from_data(nil, @MskBits[0], W, H);
// white
fg.red := $FFFF;
fg.green := $FFFF;
fg.blue := $FFFF;
fg.pixel := 0;
// black
bg.red := 0;
bg.green := 0;
bg.blue := 0;
bg.pixel := 0;
Result := HCURSOR(PtrUInt(gdk_cursor_new_from_pixmap(srcbitmap, mskbitmap,
@fg, @bg, IconInfo^.xHotspot, IconInfo^.yHotspot)));
gdk_pixmap_unref(srcbitmap);
gdk_pixmap_unref(mskbitmap);
end;
end;
{------------------------------------------------------------------------------
Function: CreatePalette
Params: LogPalette

View File

@ -52,9 +52,9 @@ function CreateBrushIndirect(const LogBrush: TLogBrush): HBRUSH; override;
function CreateCaret(Handle : HWND; Bitmap : hBitmap; width, Height : Integer) : Boolean; override;
function CreateCompatibleBitmap(DC: HDC; Width, Height: Integer): HBITMAP; override;
function CreateCompatibleDC(DC: HDC): HDC; override;
function CreateCursor(ACursorInfo: PIconInfo): hCursor; override;
function CreateFontIndirect(const LogFont: TLogFont): HFONT; override;
function CreateFontIndirectEx(const LogFont: TLogFont; const LongFontName: string): HFONT; override;
function CreateIconIndirect(IconInfo: PIconInfo): HICON; override;
function CreatePalette(const LogPalette: TLogPalette): HPALETTE; override;
function CreatePenIndirect(const LogPen: TLogPen): HPEN; override;
function CreatePolygonRgn(Points: PPoint; NumPts: Integer; FillMode: integer): HRGN; Override;
@ -64,7 +64,8 @@ procedure DeleteCriticalSection(var CritSection: TCriticalSection); override;
function DeleteDC(hDC: HDC): Boolean; override;
function DeleteObject(GDIObject: HGDIOBJ): Boolean; override;
function DestroyCaret(Handle : HWND): Boolean; override;
function DestroyCursor(Handle: hCursor): Boolean; override;
function DestroyCursor(Handle: HCURSOR): Boolean; override;
function DestroyIcon(Handle: HICON): Boolean; override;
function DrawFrameControl(DC: HDC; const Rect : TRect; uType, uState : Cardinal) : Boolean; override;
function DrawFocusRect(DC: HDC; const Rect: TRect): boolean; override;
function DrawEdge(DC: HDC; var ARect: TRect; Edge: Cardinal; grfFlags: Cardinal): Boolean; override;

View File

@ -67,78 +67,6 @@ begin
end;
end;
function TGtk2WidgetSet.CreateCursor(ACursorInfo: PIconInfo): hCursor;
var
pixmap: PGdkPixmap;
bitmap: PGdkBitmap;
Width, Height: integer;
MaxWidth, MaxHeight: guint;
pixbuf, masked_pixbuf: PGdkPixbuf;
{$ifdef Windows}
Old80807CW: Word;
procedure SetCW; inline;
begin
Old80807CW := Get8087CW;
Set8087CW($133F);
end;
procedure ResetCW; inline;
begin
Set8087CW(Old80807CW);
end;
{$endif}
begin
Result := 0;
if not IsValidGDIObject(ACursorInfo^.hbmColor) then Exit;
pixmap := PGDIObject(ACursorInfo^.hbmColor)^.GDIPixmapObject.Image;
bitmap := PGDIObject(ACursorInfo^.hbmColor)^.GDIPixmapObject.Mask;
gdk_drawable_get_size(pixmap, @Width, @Height);
gdk_display_get_maximal_cursor_size(gdk_display_get_default,
@MaxWidth, @MaxHeight);
if (Width > integer(MaxWidth)) or (Height > integer(MaxHeight)) then
exit;
{
MaxWidth := gdk_display_get_default_cursor_size(gdk_display_get_default);
if (Width > MaxWidth) or (Height > MaxWidth) then
DebugLn(['CreateCursor cursor size:',Width,'x',Height,' > default size:', MaxWidth]);
}
// create alpha pixbuf
pixbuf := gdk_pixbuf_new(GDK_COLORSPACE_RGB, True, 8, Width, Height);
// fill pixbuf from pixmap
gdk_pixbuf_get_from_drawable(pixbuf, pixmap, nil, 0, 0, 0, 0, -1, -1);
masked_pixbuf := GdkPixbufAddBitmapMask(pixbuf, bitmap, 0);
if masked_pixbuf <> nil then
begin
// masked_pixuf is a new pixbuf created from pixbuf with applying mask
gdk_pixbuf_unref(pixbuf);
pixbuf := masked_pixbuf;
end;
// create cursor from pixbuf
try
{$IFDEF Windows}
// we'll get 'division by zero' error in CMCheckColorsInGamut in other case
SetCW;
{$ENDIF}
Result := HCursor(PtrUInt(gdk_cursor_new_from_pixbuf(gdk_display_get_default, pixbuf,
ACursorInfo^.xHotSpot, ACursorInfo^.yHotSpot)));
finally
{$IFDEF Windows}
ResetCW;
{$ENDIF}
end;
end;
function TGtk2WidgetSet.CreateFontIndirectEx(const LogFont: TLogFont;
const LongFontName: string): HFONT;
{off $DEFINE VerboseFonts}
@ -320,6 +248,90 @@ begin
end;
end;
function TGtk2WidgetSet.CreateIconIndirect(IconInfo: PIconInfo): HICON;
var
pixmap: PGdkPixmap;
bitmap: PGdkBitmap;
Width, Height: integer;
MaxWidth, MaxHeight: guint;
pixbuf, masked_pixbuf: PGdkPixbuf;
{$ifdef Windows}
Old80807CW: Word;
procedure SetCW; inline;
begin
Old80807CW := Get8087CW;
Set8087CW($133F);
end;
procedure ResetCW; inline;
begin
Set8087CW(Old80807CW);
end;
{$endif}
begin
Result := 0;
if not IsValidGDIObject(IconInfo^.hbmColor) then Exit;
pixmap := PGDIObject(IconInfo^.hbmColor)^.GDIPixmapObject.Image;
bitmap := PGDIObject(IconInfo^.hbmColor)^.GDIPixmapObject.Mask;
gdk_drawable_get_size(pixmap, @Width, @Height);
gdk_display_get_maximal_cursor_size(gdk_display_get_default,
@MaxWidth, @MaxHeight);
if (Width > integer(MaxWidth)) or (Height > integer(MaxHeight)) then
exit;
// create alpha pixbuf
pixbuf := gdk_pixbuf_new(GDK_COLORSPACE_RGB, True, 8, Width, Height);
// fill pixbuf from pixmap
gdk_pixbuf_get_from_drawable(pixbuf, pixmap, nil, 0, 0, 0, 0, -1, -1);
masked_pixbuf := GdkPixbufAddBitmapMask(pixbuf, bitmap, 0);
if masked_pixbuf <> nil then
begin
// masked_pixuf is a new pixbuf created from pixbuf with applying mask
gdk_pixbuf_unref(pixbuf);
pixbuf := masked_pixbuf;
end;
if IconInfo^.fIcon then
Result := HICON(PtrUInt(pixbuf))
else
begin
// create cursor from pixbuf
try
{$IFDEF Windows}
// we'll get 'division by zero' error in CMCheckColorsInGamut in other case
SetCW;
{$ENDIF}
Result := HCURSOR(PtrUInt(gdk_cursor_new_from_pixbuf(gdk_display_get_default, pixbuf,
IconInfo^.xHotSpot, IconInfo^.yHotSpot)));
finally
{$IFDEF Windows}
ResetCW;
{$ENDIF}
end;
end;
end;
function TGtk2WidgetSet.DestroyIcon(Handle: HICON): Boolean;
begin
Result := (Handle <> 0) and
(
GDK_IS_PIXBUF(Pointer(Handle)) or
// todo: replace with GDK_IS_CURSOR when fpc will have it
G_TYPE_CHECK_INSTANCE_TYPE(Pointer(Handle),GDK_TYPE_CURSOR)
);
if Result then
if GDK_IS_PIXBUF(Pointer(Handle)) then
gdk_pixbuf_unref(PGdkPixbuf(Handle))
else
gdk_cursor_unref(PGdkCursor(Handle));
end;
{------------------------------------------------------------------------------
Function: EndPaint

View File

@ -35,8 +35,9 @@
function BeginPaint(Handle: hWnd; Var PS : TPaintStruct) : hdc; override;
function CreateCursor(ACursorInfo: PIconInfo): hCursor; override;
function CreateFontIndirectEx(const LogFont: TLogFont; const LongFontName: string): HFONT; override;
function CreateIconIndirect(IconInfo: PIconInfo): HICON; override;
function DestroyIcon(Handle: HICON): Boolean; override;
function EndPaint(Handle : hwnd; var PS : TPaintStruct): Integer; override;
function ExtTextOut(DC: HDC; X, Y: Integer; Options: Longint; Rect: PRect; Str: PChar; Count: Longint; Dx: PInteger): Boolean; override;