diff --git a/lcl/interfaces/gtk/gtkcallback.inc b/lcl/interfaces/gtk/gtkcallback.inc index 4662a56b6b..2cdf5e68fb 100644 --- a/lcl/interfaces/gtk/gtkcallback.inc +++ b/lcl/interfaces/gtk/gtkcallback.inc @@ -242,9 +242,10 @@ begin {$IFDEF DebugGDK}EndGDKErrorTrap;{$ENDIF} end; - if TheWinControl<>nil then begin + if TheWinControl<>nil then + begin TheWinControl.CNPreferredSizeChanged; - SetCursor(TheWinControl, crDefault); + SetCursor(TheWinControl, Screen.Cursors[TheWinControl.Cursor]); ConnectInternalWidgetsSignals(MainWidget,TheWinControl); if TheWinControl is TCustomPage then diff --git a/lcl/interfaces/gtk/gtkobject.inc b/lcl/interfaces/gtk/gtkobject.inc index c4db933883..50fa296472 100644 --- a/lcl/interfaces/gtk/gtkobject.inc +++ b/lcl/interfaces/gtk/gtkobject.inc @@ -365,7 +365,6 @@ begin FExtUTF8OutCacheSize:=0; FreeAllStyles; - FreeGDKCursors; FreeStockItems; if FGTKToolTips<>nil then begin @@ -3530,7 +3529,7 @@ procedure TGtkWidgetSet.SetDesigning(AComponent: TComponent); begin // change cursor if AComponent is TWinControl then - gtkproc.SetCursor(TWinControl(AComponent), TCursor(PtrUInt(nil))); + gtkproc.SetCursor(TWinControl(AComponent), Screen.Cursors[TWinControl(AComponent).Cursor]); end; {------------------------------------------------------------------------------ @@ -5238,8 +5237,46 @@ begin end; function TGTKWidgetSet.CreateStandardCursor(ACursor: SmallInt): hCursor; +var + CursorValue: Integer; begin - Result := GetPredefinedCursor(ACursor); + Result := 0; + if ACursor < crLow then Exit; + if ACursor > crHigh then Exit; + + case TCursor(ACursor) of + crDefault: CursorValue := GDK_LEFT_PTR; + crNone: CursorValue := GDK_LEFT_PTR; + crArrow: CursorValue := GDK_Arrow; + crCross: CursorValue := GDK_Cross; + crIBeam: CursorValue := GDK_XTerm; +// crSize: CursorValue := GDK_FLEUR; + crSizeNESW: CursorValue := GDK_BOTTOM_LEFT_CORNER; + crSizeNS: CursorValue := GDK_SB_V_DOUBLE_ARROW; + crSizeNWSE: CursorValue := GDK_TOP_LEFT_CORNER; + crSizeWE: CursorValue := GDK_SB_H_DOUBLE_ARROW; + crSizeNW: CursorValue := GDK_TOP_LEFT_CORNER; + crSizeN: CursorValue := GDK_TOP_SIDE; + crSizeNE: CursorValue := GDK_TOP_RIGHT_CORNER; + crSizeW: CursorValue := GDK_LEFT_SIDE; + crSizeE: CursorValue := GDK_RIGHT_SIDE; + crSizeSW: CursorValue := GDK_BOTTOM_LEFT_CORNER; + crSizeS: CursorValue := GDK_BOTTOM_SIDE; + crSizeSE: CursorValue := GDK_BOTTOM_RIGHT_CORNER; + crUpArrow: CursorValue := GDK_LEFT_PTR; + crHourGlass:CursorValue := GDK_CLOCK; + crHSplit: CursorValue := GDK_SB_H_DOUBLE_ARROW; + crVSplit: CursorValue := GDK_SB_V_DOUBLE_ARROW; + crNo: CursorValue := GDK_LEFT_PTR; + crAppStart: CursorValue := GDK_LEFT_PTR; + crHelp: CursorValue := GDK_QUESTION_ARROW; + crHandPoint:CursorValue := GDK_Hand1; + crSizeAll: CursorValue := GDK_FLEUR; + else + CursorValue := -1; + end; + if CursorValue <> -1 then + Result := hCursor(gdk_cursor_new(CursorValue)); end; {------------------------------------------------------------------------------ diff --git a/lcl/interfaces/gtk/gtkproc.inc b/lcl/interfaces/gtk/gtkproc.inc index 51afc0fa8e..b175e65c17 100644 --- a/lcl/interfaces/gtk/gtkproc.inc +++ b/lcl/interfaces/gtk/gtkproc.inc @@ -4630,109 +4630,39 @@ var AWindow: PGdkWindow; NewCursor: PGdkCursor; begin + {$ifdef gtk2} + // MWE: + // We seriously need to rethink the way of setting cursors. + // for instance a button doesn't have an own xwindow. + // so setting the cursor results in a cursor set for the parent (=most times form) + // buttons have for instance a event_window, we might be able to set a cursor + // for that (if an input only window allows that). + // using an overridden Tgtk2WSButtonPrivate.SetCursor might solve it. + {$note Rethink gtk2 setcursor} + Exit; + {$endif} + if not ((AWinControl is TWinControl) and AWinControl.HandleAllocated) then exit; AWidget:= PGtkWidget(AWinControl.Handle); + {$note Move designcursor to LCL} if csDesigning in AWinControl.ComponentState then begin AWindow:=GetControlWindow(AWidget); - if AWindow = nil then exit; - if ACursor = crDefault then - SetCursorRecursive(AWindow, GetGDKMouseCursor(GetPredefinedCursor(crDefault))) - else begin - NewCursor:= GetGDKMouseCursor(ACursor); - if NewCursor <> nil then SetCursorRecursive(AWindow, NewCursor); - end; - end - else begin - + ACursor := Screen.Cursors[crDefault]; + end else + begin FixWidget:= GetFixedWidget(AWidget); AWindow:= GetControlWindow(FixWidget); - if AWindow = nil then exit; - - NewCursor:= GetGDKMouseCursor(AWinControl.Cursor); - if NewCursor <> nil then DoSetCursor(AWindow, NewCursor); end; -end; + if AWindow = nil then exit; -function GetPredefinedCursor(ACursor: TCursor): HCursor; -begin - Result := 0; - if ACursor > crHigh then Exit; - if ACursor < crLow then Exit; + NewCursor := PGdkCursor(ACursor); + if NewCursor = nil then Exit; - Result := ACursor - PREDEFINED_CURSOR_OFFSET; -end; - -function GetGDKMouseCursor(ACursor: HCursor): PGdkCursor; -var - CursorValue: Integer; -begin - Result := nil; - if ACursor < Low(SmallInt) then Exit; - if ACursor > High(SmallInt) then Exit; - - if MMouseCursorMap.GetData(ACursor, Result) then Exit; - // not yet created or illegal value - - if TCursor(ACursor + PREDEFINED_CURSOR_OFFSET) > crHigh then Exit; - if TCursor(ACursor + PREDEFINED_CURSOR_OFFSET) < crLow then Exit; - - // add it now - case TCursor(ACursor + PREDEFINED_CURSOR_OFFSET) of - crDefault: CursorValue := GDK_LEFT_PTR; - crNone: CursorValue := GDK_LEFT_PTR; - crArrow: CursorValue := GDK_Arrow; - crCross: CursorValue := GDK_Cross; - crIBeam: CursorValue := GDK_XTerm; -// crSize: CursorValue := GDK_FLEUR; - crSizeNESW: CursorValue := GDK_BOTTOM_LEFT_CORNER; - crSizeNS: CursorValue := GDK_SB_V_DOUBLE_ARROW; - crSizeNWSE: CursorValue := GDK_TOP_LEFT_CORNER; - crSizeWE: CursorValue := GDK_SB_H_DOUBLE_ARROW; - crSizeNW: CursorValue := GDK_TOP_LEFT_CORNER; - crSizeN: CursorValue := GDK_TOP_SIDE; - crSizeNE: CursorValue := GDK_TOP_RIGHT_CORNER; - crSizeW: CursorValue := GDK_LEFT_SIDE; - crSizeE: CursorValue := GDK_RIGHT_SIDE; - crSizeSW: CursorValue := GDK_BOTTOM_LEFT_CORNER; - crSizeS: CursorValue := GDK_BOTTOM_SIDE; - crSizeSE: CursorValue := GDK_BOTTOM_RIGHT_CORNER; - crUpArrow: CursorValue := GDK_LEFT_PTR; - crHourGlass:CursorValue := GDK_CLOCK; - crDrag: CursorValue := GDK_SAILBOAT; - crNoDrop: CursorValue := GDK_IRON_CROSS; - crHSplit: CursorValue := GDK_SB_H_DOUBLE_ARROW; - crVSplit: CursorValue := GDK_SB_V_DOUBLE_ARROW; - crMultiDrag:CursorValue := GDK_SAILBOAT; - crSQLWait: CursorValue := GDK_LEFT_PTR; - crNo: CursorValue := GDK_LEFT_PTR; - crAppStart: CursorValue := GDK_LEFT_PTR; - crHelp: CursorValue := GDK_QUESTION_ARROW; - crHandPoint:CursorValue := GDK_Hand1; - crSizeAll: CursorValue := GDK_FLEUR; - else - CursorValue := GDK_LEFT_PTR; - end; - - Result := gdk_cursor_new(CursorValue); - MMouseCursorMap.Add(ACursor, Result); -end; - -procedure FreeGDKCursors; -var - Iterator: TMapIterator; -begin - Iterator := TMapIterator.Create(MMouseCursorMap); - while not Iterator.EOM do - begin - gdk_Cursor_destroy(PGdkCursor(Iterator.DataPtr^)); - Iterator.Next; - end; - Iterator.Free; - MMouseCursorMap.Clear; + SetCursorRecursive(AWindow, NewCursor); end; {------------------------------------------------------------------------------- diff --git a/lcl/interfaces/gtk/gtkproc.pp b/lcl/interfaces/gtk/gtkproc.pp index f018bf95c5..1e732d615b 100644 --- a/lcl/interfaces/gtk/gtkproc.pp +++ b/lcl/interfaces/gtk/gtkproc.pp @@ -492,9 +492,6 @@ procedure UpdateMouseCaptureControl; // mouse cursor procedure SetCursor(AWinControl: TWinControl; ACursor: HCursor); -function GetPredefinedCursor(ACursor: TCursor): HCursor; -function GetGDKMouseCursor(ACursor: hCursor): PGdkCursor; -procedure FreeGDKCursors; const // for now return the same value, in the future we may want to return an diff --git a/lcl/interfaces/gtk/gtkwinapi.inc b/lcl/interfaces/gtk/gtkwinapi.inc index 294e9f66d3..425ba48d06 100644 --- a/lcl/interfaces/gtk/gtkwinapi.inc +++ b/lcl/interfaces/gtk/gtkwinapi.inc @@ -1256,6 +1256,127 @@ 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(c.pixel = $FFFFFF); + m_bit := ord(MaskPixel = 0); + + 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; + + Img := PGDIObject(ACursorInfo^.hbmColor)^.GDIBitmapObject; + Msk := PGDIObject(ACursorInfo^.hbmColor)^.GDIBitmapMaskObject; + + 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; + + // TODO: for gtk2, use gdk_cursor_new_from_pixbuf for colored cursors + Result := hCursor(gdk_cursor_new_from_pixmap (srcbitmap, mskbitmap, @fg, @bg, + ACursorInfo^.xHotspot, ACursorInfo^.yHotspot)); + + gdk_pixmap_unref(srcbitmap); + gdk_pixmap_unref(mskbitmap); +end; + +function TGtkWidgetSet.DestroyCursor(Handle: hCursor): Boolean; +begin + if Handle <> 0 then + gdk_cursor_destroy(PGdkCursor(Handle)); +end; + {------------------------------------------------------------------------------ Function: CreateFontIndirect Params: const LogFont: TLogFont diff --git a/lcl/interfaces/gtk/gtkwinapih.inc b/lcl/interfaces/gtk/gtkwinapih.inc index 9e86a1c767..a9d045e189 100644 --- a/lcl/interfaces/gtk/gtkwinapih.inc +++ b/lcl/interfaces/gtk/gtkwinapih.inc @@ -53,6 +53,7 @@ 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 CreatePalette(const LogPalette: TLogPalette): HPALETTE; override; @@ -65,6 +66,7 @@ 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 DrawFrameControl(DC: HDC; var 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;