mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-30 19:22:42 +02:00
1008 lines
32 KiB
PHP
1008 lines
32 KiB
PHP
{%MainUnit win32int.pp}
|
|
{ $Id$ }
|
|
{******************************************************************************
|
|
All GTK interface communication implementations.
|
|
Initial Revision : Sun Nov 23 23:53:53 2003
|
|
|
|
|
|
!! Keep alphabetical !!
|
|
|
|
Support routines go to gtkproc.pp
|
|
|
|
******************************************************************************
|
|
Implementation
|
|
******************************************************************************
|
|
|
|
*****************************************************************************
|
|
* *
|
|
* This file is part of the Lazarus Component Library (LCL) *
|
|
* *
|
|
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
}
|
|
|
|
//##apiwiz##sps## // Do not remove
|
|
|
|
function TWin32WidgetSet.AddEventHandler(AHandle: THandle; AFlags: dword;
|
|
AEventHandler: TWaitHandleEvent; AData: PtrInt): PEventHandler;
|
|
var
|
|
listlen: dword;
|
|
lListIndex: pdword;
|
|
begin
|
|
listlen := Length(FWaitHandles);
|
|
if FWaitHandleCount = listlen then
|
|
begin
|
|
inc(listlen, 16);
|
|
SetLength(FWaitHandles, listlen);
|
|
SetLength(FWaitHandlers, listlen);
|
|
end;
|
|
New(lListIndex);
|
|
FWaitHandles[FWaitHandleCount] := AHandle;
|
|
FWaitHandlers[FWaitHandleCount].ListIndex := lListIndex;
|
|
FWaitHandlers[FWaitHandleCount].UserData := AData;
|
|
FWaitHandlers[FWaitHandleCount].OnEvent := AEventHandler;
|
|
lListIndex^ := FWaitHandleCount;
|
|
Inc(FWaitHandleCount);
|
|
{$ifdef DEBUG_ASYNCEVENTS}
|
|
DebugLn('Waiting for handle: ', IntToHex(AHandle, 8));
|
|
{$endif}
|
|
Result := lListIndex;
|
|
end;
|
|
|
|
function TWin32WidgetSet.AddPipeEventHandler(AHandle: THandle;
|
|
AEventHandler: TPipeEvent; AData: PtrInt): PPipeEventHandler;
|
|
var
|
|
lHandler: PPipeEventInfo;
|
|
begin
|
|
if AEventHandler = nil then exit;
|
|
New(lHandler);
|
|
lHandler^.Handle := AHandle;
|
|
lHandler^.UserData := AData;
|
|
lHandler^.OnEvent := AEventHandler;
|
|
lHandler^.Prev := nil;
|
|
lHandler^.Next := FWaitPipeHandlers;
|
|
if FWaitPipeHandlers <> nil then
|
|
FWaitPipeHandlers^.Prev := lHandler;
|
|
FWaitPipeHandlers := lHandler;
|
|
Result := lHandler;
|
|
end;
|
|
|
|
function TWin32WidgetSet.AddProcessEventHandler(AHandle: THandle;
|
|
AEventHandler: TChildExitEvent; AData: PtrInt): PProcessEventHandler;
|
|
var
|
|
lProcessEvent: PProcessEvent;
|
|
begin
|
|
if AEventHandler = nil then exit;
|
|
New(lProcessEvent);
|
|
lProcessEvent^.Handle := AHandle;
|
|
lProcessEvent^.UserData := AData;
|
|
lProcessEvent^.OnEvent := AEventHandler;
|
|
lProcessEvent^.Handler := AddEventHandler(AHandle, 0,
|
|
@HandleProcessEvent, PtrInt(lProcessEvent));
|
|
Result := lProcessEvent;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: ExtUTF8Out
|
|
|
|
As ExtTextOut except that Str is treated as UTF8
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.ExtUTF8Out(DC: HDC; X, Y: Integer; Options: Longint; Rect: PRect;
|
|
Str: PChar; Count: Longint; Dx: PInteger): Boolean;
|
|
begin
|
|
Result := ExtTextOut(DC, X, Y, Options, Rect, Str, Count, Dx);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
function FontCanUTF8(Font: HFont): boolean;
|
|
|
|
True if font recognizes Unicode UTF8 encoding.
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.FontCanUTF8(Font: HFont): boolean;
|
|
begin
|
|
{$ifdef WindowsUnicodeSupport}
|
|
Result := True;
|
|
{$else}
|
|
Result := False;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TWin32WidgetSet.HandleProcessEvent(AData: PtrInt; AFlags: dword);
|
|
var
|
|
lProcessEvent: PProcessEvent absolute AData;
|
|
exitcode: dword;
|
|
begin
|
|
if not Windows.GetExitCodeProcess(lProcessEvent^.Handle, exitcode) then
|
|
exitcode := 0;
|
|
lProcessEvent^.OnEvent(lProcessEvent^.UserData, cerExit, exitcode);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: RawImage_QueryDescription
|
|
Params: AFlags:
|
|
ADesc:
|
|
Returns:
|
|
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.RawImage_QueryDescription(AFlags: TRawImageQueryFlags; var ADesc: TRawImageDescription): Boolean;
|
|
begin
|
|
if riqfAlpha in AFlags
|
|
then begin
|
|
//always return rgba description
|
|
if not (riqfUpdate in AFlags)
|
|
then ADesc.Init;
|
|
|
|
ADesc.Format := ricfRGBA;
|
|
ADesc.Depth := 32;
|
|
ADesc.BitOrder := riboReversedBits;
|
|
ADesc.ByteOrder := riboLSBFirst;
|
|
ADesc.LineOrder := riloTopToBottom;
|
|
ADesc.LineEnd := rileDWordBoundary;
|
|
ADesc.BitsPerPixel := 32;
|
|
|
|
ADesc.AlphaPrec := 8;
|
|
ADesc.AlphaShift := 24;
|
|
|
|
if riqfRGB in AFlags
|
|
then begin
|
|
ADesc.RedPrec := 8;
|
|
ADesc.GreenPrec := 8;
|
|
ADesc.BluePrec := 8;
|
|
ADesc.RedShift := 16;
|
|
ADesc.GreenShift := 8;
|
|
ADesc.BlueShift := 0;
|
|
end;
|
|
|
|
AFlags := AFlags - [riqfRGB, riqfAlpha, riqfUpdate];
|
|
if AFlags = [] then Exit(True);
|
|
|
|
// continue with default
|
|
Include(AFlags, riqfUpdate);
|
|
end;
|
|
|
|
Result := inherited RawImage_QueryDescription(AFlags, ADesc);
|
|
// reduce mem
|
|
if Result and (ADesc.Depth = 24)
|
|
then ADesc.BitsPerPixel := 24;
|
|
end;
|
|
|
|
procedure TWin32WidgetSet.RemoveProcessEventHandler(var AHandler: PProcessEventHandler);
|
|
var
|
|
lProcessEvent: PProcessEvent absolute AHandler;
|
|
begin
|
|
if AHandler = nil then exit;
|
|
RemoveEventHandler(lProcessEvent^.Handler);
|
|
Dispose(lProcessEvent);
|
|
AHandler := nil;
|
|
end;
|
|
|
|
procedure TWin32WidgetSet.SetRubberBandRect(const ARubberBand: HWND; const ARect: TRect);
|
|
begin
|
|
with ARect do
|
|
SetWindowPos(ARubberBand, 0, Left, Top, Right - Left, Bottom - Top, SWP_NOZORDER or SWP_NOACTIVATE);
|
|
end;
|
|
|
|
function TWin32WidgetSet.AppHandle: THandle;
|
|
begin
|
|
Result:= FAppHandle;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function:
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.CreateStandardCursor(ACursor: SmallInt): hCursor;
|
|
begin
|
|
Result := 0;
|
|
if ACursor < crLow then Exit;
|
|
if ACursor > crHigh then Exit;
|
|
|
|
case ACursor of
|
|
crSqlWait..crDrag,
|
|
crHandPoint, crNone: begin
|
|
// TODO: load custom cursors here not in the LCL
|
|
end;
|
|
else
|
|
Result := Windows.LoadCursor(0, LclCursorToWin32CursorMap[ACursor]);
|
|
end;
|
|
end;
|
|
|
|
function DockWindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
|
|
LParam: Windows.LParam): LResult; stdcall;
|
|
begin
|
|
if (Msg = WM_ACTIVATE) and (LoWord(WParam) <> WA_INACTIVE) and (LParam <> 0) then
|
|
Windows.SendMessage(LParam, WM_NCACTIVATE, 1, 0);
|
|
Result := Windows.DefWindowProc(Window, Msg, WParam, LParam);
|
|
end;
|
|
|
|
function TWin32WidgetSet.CreateRubberBand(const ARect: TRect; const ABrush: HBrush = 0): HWND;
|
|
var
|
|
WindowClass: Windows.WNDCLASS;
|
|
WndClassName: String;
|
|
begin
|
|
WndClassName := 'LazRubberBand' + IntToStr(ABrush);
|
|
|
|
if not Windows.GetClassInfo(System.HInstance, PChar(WndClassName), WindowClass) then
|
|
begin
|
|
with WindowClass do
|
|
begin
|
|
Style := 0;
|
|
LPFnWndProc := @DockWindowProc;
|
|
CbClsExtra := 0;
|
|
CbWndExtra := 0;
|
|
hInstance := System.HInstance;
|
|
hIcon := Windows.LoadIcon(0, IDI_APPLICATION);
|
|
hCursor := Windows.LoadCursor(0, IDC_ARROW);
|
|
if ABrush = 0 then
|
|
hbrBackground := GetSysColorBrush(COLOR_HIGHLIGHT)
|
|
else
|
|
hbrBackground := ABrush;
|
|
LPSzMenuName := nil;
|
|
LPSzClassName := PChar(WndClassName);
|
|
end;
|
|
Windows.RegisterClass(@WindowClass);
|
|
end;
|
|
|
|
if WindowsVersion >= wv2000 then
|
|
begin
|
|
Result := CreateWindowEx(WS_EX_LAYERED or WS_EX_TRANSPARENT or WS_EX_TOPMOST or WS_EX_TOOLWINDOW,
|
|
PChar(WndClassName), PChar(WndClassName), WS_POPUP or WS_VISIBLE,
|
|
ARect.Left, ARect.Top, ARect.Right - ARect.Left, ARect.Bottom - ARect.Top, AppHandle, 0, System.HInstance, nil);
|
|
|
|
SetLayeredWindowAttributes(Result, 0, $30, LWA_ALPHA);
|
|
end
|
|
else
|
|
Result := CreateWindowEx(WS_EX_TOPMOST or WS_EX_TOOLWINDOW,
|
|
PChar(WndClassName), PChar(WndClassName), WS_POPUP or WS_VISIBLE,
|
|
ARect.Left, ARect.Top, ARect.Right - ARect.Left, ARect.Bottom - ARect.Top, AppHandle, 0, System.HInstance, nil);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: CallbackAllocateHWnd
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Callback for the AllocateHWnd function
|
|
------------------------------------------------------------------------------}
|
|
procedure CallbackAllocateHWnd(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam); stdcall;
|
|
var
|
|
Msg: TLMessage;
|
|
PMethod: ^TLCLWndMethod;
|
|
begin
|
|
FillChar(Msg, SizeOf(Msg), #0);
|
|
|
|
Msg.msg := uMsg;
|
|
Msg.wParam := wParam;
|
|
Msg.lParam := lParam;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Here we get the callback WndMethod associated with this window
|
|
------------------------------------------------------------------------------}
|
|
PMethod := Pointer(Widgetset.GetWindowLong(ahwnd, GWL_USERDATA));
|
|
|
|
if Assigned(PMethod) then PMethod^(Msg);
|
|
|
|
Windows.DefWindowProc(ahwnd, uMsg, wParam, lParam);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWin32WidgetSet.AllocateHWnd
|
|
Params: Method - The callback method for the window. Can be nil
|
|
Returns: A window handle
|
|
|
|
Allocates a non-visible window that can be utilized to receive and send message
|
|
|
|
On Windows, you must call Windows.DefWindowProc(MyHandle, Msg.msg, Msg.wParam, msg.lParam);
|
|
in your callback function, if you provide one at all, of course.
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.AllocateHWnd(Method: TLCLWndMethod): HWND;
|
|
var
|
|
PMethod: ^TLCLWndMethod;
|
|
begin
|
|
Result := Windows.CreateWindow(@ClsName[0],
|
|
'', WS_OVERLAPPED, 0, 0, 0, 0, 0, 0, MainInstance, nil);
|
|
|
|
{------------------------------------------------------------------------------
|
|
SetWindowLong has only space for 1 pointer on each slot, but a method is
|
|
referenced as a structure with 2 pointers, so here we allocate memory for
|
|
the structure before it can be used to transport data between the callback
|
|
and this function
|
|
------------------------------------------------------------------------------}
|
|
if Assigned(Method) then
|
|
begin
|
|
Getmem(PMethod, SizeOf(TMethod));
|
|
PMethod^ := Method;
|
|
|
|
Self.SetWindowLong(Result, GWL_USERDATA, PtrInt(PMethod));
|
|
end;
|
|
|
|
Self.SetWindowLong(Result, GWL_WNDPROC, PtrInt(@CallbackAllocateHWnd))
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWin32WidgetSet.DeallocateHWnd
|
|
Params: Wnd - A Window handle, that was created with AllocateHWnd
|
|
Returns: Nothing
|
|
------------------------------------------------------------------------------}
|
|
procedure TWin32WidgetSet.DeallocateHWnd(Wnd: HWND);
|
|
var
|
|
PMethod: ^TLCLWndMethod;
|
|
begin
|
|
PMethod := Pointer(Self.GetWindowLong(Wnd, GWL_USERDATA));
|
|
|
|
if Wnd <> 0 then Windows.DestroyWindow(Wnd);
|
|
|
|
{------------------------------------------------------------------------------
|
|
This must be done after DestroyWindow, otherwise a Access Violation will
|
|
happen when WM_CLOSE message is sent to the callback
|
|
|
|
This memory is for the TMethod structure allocated on AllocateHWnd
|
|
------------------------------------------------------------------------------}
|
|
if Assigned(PMethod) then Freemem(PMethod);
|
|
end;
|
|
|
|
procedure TWin32WidgetSet.DestroyRubberBand(ARubberBand: HWND);
|
|
var
|
|
WndClassName: array[0..255] of Char;
|
|
begin
|
|
GetClassName(ARubberBand, @WndClassName, 255);
|
|
// preserve the brush or it will be deleted
|
|
SetClassLongPtr(ARubberBand, GCL_HBRBACKGROUND, 0);
|
|
DestroyWindow(ARubberBand);
|
|
Windows.UnRegisterClass(@WndClassName, System.HINSTANCE);
|
|
end;
|
|
|
|
procedure TWin32WidgetSet.DrawDefaultDockImage(AOldRect, ANewRect: TRect; AOperation: TDockImageOperation);
|
|
const
|
|
LineSize = 4;
|
|
|
|
procedure DrawHorzLine(DC: HDC; x1, x2, y: integer); inline;
|
|
begin
|
|
PatBlt(DC, x1, y, x2 - x1, LineSize, PATINVERT);
|
|
end;
|
|
|
|
procedure DrawVertLine(DC: HDC; y1, y2, x: integer); inline;
|
|
begin
|
|
PatBlt(DC, x, y1, LineSize, y2 - y1, PATINVERT);
|
|
end;
|
|
|
|
procedure DefaultDockImage(ARect: TRect);
|
|
var
|
|
DC: HDC;
|
|
NewBrush, OldBrush: HBrush;
|
|
begin
|
|
DC := GetDCEx(0, 0, DCX_LOCKWINDOWUPDATE); // drawing during tracking
|
|
try
|
|
NewBrush := CreatePatternBrush(Win32WidgetSet.DotsPatternBitmap);
|
|
OldBrush := SelectObject(DC, NewBrush);
|
|
with ARect do
|
|
begin
|
|
DrawHorzLine(DC, Left, Right, Top);
|
|
DrawVertLine(DC, Top + LineSize, Bottom - LineSize, Left);
|
|
DrawHorzLine(DC, Left, Right, Bottom - LineSize);
|
|
DrawVertLine(DC, Top + LineSize, Bottom - LineSize, Right - LineSize);
|
|
end;
|
|
DeleteObject(SelectObject(DC, OldBrush));
|
|
finally
|
|
ReleaseDC(0, DC);
|
|
end;
|
|
end;
|
|
var
|
|
WindowClass: WndClass;
|
|
begin
|
|
if WindowsVersion >= wv2000 then
|
|
begin
|
|
case AOperation of
|
|
disShow:
|
|
begin
|
|
with WindowClass do
|
|
begin
|
|
Style := 0;
|
|
LPFnWndProc := @DockWindowProc;
|
|
CbClsExtra := 0;
|
|
CbWndExtra := 0;
|
|
hInstance := System.HInstance;
|
|
hIcon := Windows.LoadIcon(0, IDI_APPLICATION);
|
|
hCursor := Windows.LoadCursor(0, IDC_ARROW);
|
|
hbrBackground := GetSysColorBrush(COLOR_HIGHLIGHT);
|
|
LPSzMenuName := nil;
|
|
LPSzClassName := 'LazDockWnd';
|
|
end;
|
|
Windows.RegisterClass(@WindowClass);
|
|
FDockWndHandle := CreateWindowEx(WS_EX_LAYERED or WS_EX_TRANSPARENT or WS_EX_TOPMOST or WS_EX_TOOLWINDOW,
|
|
'LazDockWnd', 'LazDockWnd', WS_POPUP or WS_VISIBLE,
|
|
ANewRect.Left, ANewRect.Top, ANewRect.Right - ANewRect.Left, ANewRect.Bottom - ANewRect.Top, AppHandle, 0, System.HINSTANCE, nil);
|
|
|
|
SetLayeredWindowAttributes(FDockWndHandle, 0, $30, LWA_ALPHA);
|
|
end;
|
|
disHide:
|
|
begin
|
|
DestroyWindow(FDockWndHandle);
|
|
Windows.UnRegisterClass('LazDockWnd', System.HINSTANCE);
|
|
end;
|
|
disMove:
|
|
with ANewRect do
|
|
SetWindowPos(FDockWndHandle, 0, Left, Top, Right - Left, Bottom - Top, SWP_NOZORDER or SWP_NOACTIVATE);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if AOperation in [disMove, disHide] then
|
|
DefaultDockImage(AOldRect);
|
|
if AOperation in [disMove, disShow] then
|
|
DefaultDockImage(ANewRect);
|
|
end;
|
|
end;
|
|
|
|
procedure TWin32WidgetSet.DrawGrid(DC: HDC; const R: TRect; DX, DY: Integer);
|
|
var
|
|
x, y: integer;
|
|
ALogPen: TLogPen;
|
|
begin
|
|
GetObject(GetCurrentObject(DC, OBJ_PEN), SizeOf(ALogPen), @ALogPen);
|
|
x := R.Left;
|
|
while x <= R.Right do
|
|
begin
|
|
y := R.Top;
|
|
while y <= R.Bottom do
|
|
begin
|
|
DCSetPixel(DC, X, Y, ALogPen.lopnColor);
|
|
Inc(y, DY);
|
|
end;
|
|
Inc(x, DX);
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: GetAcceleratorString
|
|
Params: AVKey:
|
|
AShiftState:
|
|
Returns:
|
|
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.GetAcceleratorString(const AVKey: Byte; const AShiftState: TShiftState): String;
|
|
begin
|
|
//TODO: Implement
|
|
Result := '';
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: GetControlConstraints
|
|
Params: Constraints: TObject
|
|
Returns: true on success
|
|
|
|
Updates the constraints object (e.g. TSizeConstraints) with interface specific
|
|
bounds.
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.GetControlConstraints(Constraints: TObject): boolean;
|
|
var
|
|
SizeConstraints: TSizeConstraints absolute Constraints;
|
|
SizeRect: TRect;
|
|
Height, Width: Integer;
|
|
FixedHeight, FixedWidth: boolean;
|
|
MinWidth, MinHeight, MaxWidth, MaxHeight: Integer;
|
|
begin
|
|
Result := True;
|
|
|
|
if Constraints is TSizeConstraints then
|
|
begin
|
|
if (SizeConstraints.Control=nil) then exit;
|
|
|
|
FixedHeight := false;
|
|
FixedWidth := false;
|
|
|
|
MinWidth := 0;
|
|
MinHeight := 0;
|
|
MaxWidth := 0;
|
|
MaxHeight := 0;
|
|
|
|
if SizeConstraints.Control is TCustomComboBox then
|
|
begin
|
|
// win32 combo (but not csSimple) has fixed height
|
|
FixedHeight := TCustomComboBox(SizeConstraints.Control).Style <> csSimple;
|
|
end
|
|
// The ProgressBar needs a minimum Height of 10 when themed,
|
|
// as required by Windows, otherwise it's image is corrupted
|
|
else if ThemeServices.ThemesEnabled and (SizeConstraints.Control is TCustomProgressBar) then
|
|
begin
|
|
MinHeight := 10;
|
|
|
|
SizeConstraints.SetInterfaceConstraints(
|
|
MinWidth, MinHeight, MaxWidth, MaxHeight);
|
|
end;
|
|
|
|
if (FixedHeight or FixedWidth)
|
|
and TWinControl(SizeConstraints.Control).HandleAllocated then
|
|
begin
|
|
Windows.GetWindowRect(TWinControl(SizeConstraints.Control).Handle, @SizeRect);
|
|
|
|
if FixedHeight then
|
|
Height := SizeRect.Bottom - SizeRect.Top
|
|
else
|
|
Height := 0;
|
|
if FixedWidth then
|
|
Width := SizeRect.Right - SizeRect.Left
|
|
else
|
|
Width := 0;
|
|
|
|
SizeConstraints.SetInterfaceConstraints(Width, Height, Width, Height);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TWin32WidgetSet.GetDesignerDC(WindowHandle: HWND): HDC;
|
|
var
|
|
OverlayWindow: HWND;
|
|
ARect: Windows.RECT;
|
|
WindowInfo, OverlayWindowInfo: PWin32WindowInfo;
|
|
begin
|
|
WindowInfo := GetWin32WindowInfo(WindowHandle);
|
|
OverlayWindow := WindowInfo^.Overlay;
|
|
if OverlayWindow = HWND(nil) then
|
|
begin
|
|
// create 'overlay' window
|
|
Windows.GetClientRect(WindowHandle, @ARect);
|
|
OverlayWindow := Windows.CreateWindowEx(WS_EX_TRANSPARENT,
|
|
@ClsName, '', WS_CHILD or WS_VISIBLE,
|
|
ARect.Left, ARect.Top, ARect.Right, ARect.Bottom,
|
|
WindowHandle, HMENU(nil), HInstance, nil);
|
|
OverlayWindowInfo := AllocWindowInfo(OverlayWindow);
|
|
OverlayWindowInfo^.DefWndProc := Windows.WNDPROC(SetWindowLong(
|
|
OverlayWindow, GWL_WNDPROC, PtrInt(@OverlayWindowProc)));
|
|
OverlayWindowInfo^.WinControl := WindowInfo^.WinControl;
|
|
WindowInfo^.Overlay := OverlayWindow;
|
|
end;
|
|
// bring overlay window to front
|
|
Windows.SetWindowPos(OverlayWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE);
|
|
Result := Windows.GetDC(OverlayWindow);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
function TWin32WidgetSet.IntfSendsUTF8KeyPress: boolean;
|
|
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.IntfSendsUTF8KeyPress: boolean;
|
|
begin
|
|
{$ifdef WindowsUnicodeSupport}
|
|
Result := true;
|
|
{$else}
|
|
Result := false;
|
|
{$endif}
|
|
end;
|
|
|
|
function TWin32WidgetSet.IsDesignerDC(WindowHandle: HWND; DC: HDC): Boolean;
|
|
var
|
|
OverlayWindow: HWND;
|
|
begin
|
|
OverlayWindow := GetWin32WindowInfo(WindowHandle)^.Overlay;
|
|
if OverlayWindow <> 0 then
|
|
Result := Windows.WindowFromDC(DC) = OverlayWindow
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: RawImage_CreateBitmaps
|
|
Params: ARawImage:
|
|
ABitmap:
|
|
AMask:
|
|
ASkipMask: When set there is no mask created
|
|
Returns:
|
|
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.RawImage_CreateBitmaps(const ARawImage: TRawImage; out ABitmap, AMask: HBitmap; ASkipMask: Boolean): Boolean;
|
|
var
|
|
ADesc: TRawImageDescription absolute ARawImage.Description;
|
|
|
|
function DoBitmap: Boolean;
|
|
var
|
|
DC: HDC;
|
|
Info: record
|
|
Header: Windows.TBitmapInfoHeader;
|
|
Colors: array[0..1] of Cardinal; // reserve extra color for mono bitmaps
|
|
end;
|
|
DstLinePtr, SrcLinePtr: PByte;
|
|
SrcPixelPtr, DstPixelPtr: PByte;
|
|
DstLineSize, SrcLineSize: PtrUInt;
|
|
x, y: Integer;
|
|
Ridx, Gidx, Bidx, Aidx, Align: Byte;
|
|
begin
|
|
if (ADesc.BitsPerPixel = 1) and (ADesc.LineEnd = rileWordBoundary)
|
|
then begin
|
|
// default BW, word aligned bitmap
|
|
ABitmap := Windows.CreateBitmap(ADesc.Width, ADesc.Height, 1, 1, ARawImage.Data);
|
|
Exit(ABitmap <> 0);
|
|
end;
|
|
|
|
FillChar(Info, SizeOf(Info), 0);
|
|
Info.Header.biSize := SizeOf(Info.Header);
|
|
Info.Header.biWidth := ADesc.Width;
|
|
Info.Header.biHeight := -ADesc.Height; // create top to bottom
|
|
Info.Header.biPlanes := 1;
|
|
// for 24 bits images, BPP can be 24 or 32
|
|
// 32 shouldn't be use since we don't fill the alpha channel
|
|
if ADesc.Depth = 24
|
|
then Info.Header.biBitCount := 24
|
|
else Info.Header.biBitCount := ADesc.BitsPerPixel;
|
|
Info.Header.biCompression := BI_RGB;
|
|
{Info.Header.biSizeImage := 0;}
|
|
{ first color is black, second color is white, for monochrome bitmap }
|
|
Info.Colors[1] := $FFFFFFFF;
|
|
|
|
DC := Windows.GetDC(0);
|
|
// Use createDIBSection, since only devicedepth bitmaps can be selected into a DC
|
|
// when they are created with createDIBitmap
|
|
// ABitmap := Windows.CreateDIBitmap(DC, Info.Header, CBM_INIT, ARawImage.Data, Windows.PBitmapInfo(@Info)^, DIB_RGB_COLORS);
|
|
ABitmap := Windows.CreateDIBSection(DC, Windows.PBitmapInfo(@Info)^, DIB_RGB_COLORS, DstLinePtr, 0, 0);
|
|
Windows.ReleaseDC(0, DC);
|
|
|
|
if ABitmap = 0
|
|
then begin
|
|
DebugLn('Windows.CreateDIBSection returns 0. Reason = ' + GetLastErrorText(Windows.GetLastError));
|
|
Exit(False);
|
|
end;
|
|
if DstLinePtr = nil then Exit(False);
|
|
|
|
DstLineSize := (Windows.MulDiv(ADesc.Depth, ADesc.Width, 8) + 3) and not 3;
|
|
Align := DstLineSize and 3;
|
|
if Align > 0
|
|
then Inc(DstLineSize, 4 - Align);
|
|
|
|
SrcLinePtr := ARawImage.Data;
|
|
SrcLineSize := ADesc.BytesPerLine;
|
|
|
|
// copy the image data
|
|
if ADesc.Depth >= 24
|
|
then begin
|
|
// check if a pixel copy is needed
|
|
// 1) Windows uses alpha channel in 32 bpp modes, despite documentation statement that it is ignored. Tested under Windows XP SP3
|
|
// Wine also relies on this undocumented behaviour!
|
|
// So, we need to cut unused A-channel, otherwise we would get black image
|
|
//
|
|
// 2) incompatible channel order
|
|
ADesc.GetRGBIndices(Ridx, Gidx, Bidx, Aidx);
|
|
|
|
if ((ADesc.BitsPerPixel = 32) and (ADesc.Depth = 24))
|
|
or (Bidx <> 0) or (Gidx <> 1) or (Ridx <> 2)
|
|
then begin
|
|
// copy pixels
|
|
|
|
for y := 0 to ADesc.Height - 1 do
|
|
begin
|
|
DstPixelPtr := DstLinePtr;
|
|
SrcPixelPtr := SrcLinePtr;
|
|
for x := 0 to ADesc.Width - 1 do
|
|
begin
|
|
DstPixelPtr[0] := SrcPixelPtr[Bidx];
|
|
DstPixelPtr[1] := SrcPixelPtr[Gidx];
|
|
DstPixelPtr[2] := SrcPixelPtr[Ridx];
|
|
|
|
Inc(DstPixelPtr, 3); //move to the next dest RGB triple
|
|
Inc(SrcPixelPtr, 4);
|
|
end;
|
|
|
|
Inc(DstLinePtr, DstLineSize);
|
|
Inc(SrcLinePtr, SrcLineSize);
|
|
end;
|
|
|
|
Exit(True);
|
|
end;
|
|
end;
|
|
|
|
// no pixelcopy needed
|
|
// check if we can move using one call
|
|
if ADesc.LineEnd = rileDWordBoundary
|
|
then begin
|
|
Move(SrcLinePtr^, DstLinePtr^, DstLineSize * ADesc.Height);
|
|
Exit(True);
|
|
end;
|
|
|
|
//Can't use just one move, as different alignment
|
|
for y := 0 to ADesc.Height - 1 do
|
|
begin
|
|
Move(SrcLinePtr^, DstLinePtr^, DstLineSize);
|
|
Inc(DstLinePtr, DstLineSize);
|
|
Inc(SrcLinePtr, SrcLineSize);
|
|
end;
|
|
|
|
Result := True;
|
|
end;
|
|
|
|
begin
|
|
AMask := 0;
|
|
Result := DoBitmap;
|
|
if not Result then Exit;
|
|
|
|
//DbgDumpBitmap(ABitmap, 'CreateBitmaps - Image');
|
|
if ASkipMask then Exit;
|
|
|
|
AMask := Windows.CreateBitmap(ADesc.Width, ADesc.Height, 1, 1, ARawImage.Mask);
|
|
if AMask = 0 then
|
|
DebugLn('Windows.CreateBitmap returns 0. Reason = ' + GetLastErrorText(Windows.GetLastError));
|
|
Result := AMask <> 0;
|
|
//DbgDumpBitmap(AMask, 'CreateBitmaps - Mask');
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: RawImage_DescriptionFromBitmap
|
|
Params: ABitmap:
|
|
ADesc:
|
|
Returns:
|
|
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.RawImage_DescriptionFromBitmap(ABitmap: HBITMAP; out ADesc: TRawImageDescription): Boolean;
|
|
var
|
|
ASize: Integer;
|
|
WinDIB: Windows.TDIBSection;
|
|
begin
|
|
ASize := Windows.GetObject(ABitmap, SizeOf(WinDIB), @WinDIB);
|
|
Result := ASize > 0;
|
|
if Result then
|
|
begin
|
|
FillRawImageDescription(WinDIB.dsBm, ADesc);
|
|
// if it is not DIB then alpha in bitmaps is not supported => use 0 alpha prec
|
|
if ASize < SizeOf(WinDIB) then
|
|
ADesc.AlphaPrec := 0;
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: RawImage_DescriptionFromDevice
|
|
Params: ADC:
|
|
ADesc:
|
|
Returns:
|
|
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.RawImage_DescriptionFromDevice(ADC: HDC; out ADesc: TRawImageDescription): Boolean;
|
|
var
|
|
DC: HDC;
|
|
begin
|
|
Result := True;
|
|
|
|
ADesc.Init;
|
|
|
|
if ADC = 0
|
|
then DC := Windows.GetDC(0)
|
|
else DC := ADC;
|
|
|
|
ADesc.Format := ricfRGBA;
|
|
ADesc.Width := Windows.GetDeviceCaps(DC, HORZRES);
|
|
ADesc.Height := Windows.GetDeviceCaps(DC, VERTRES);
|
|
ADesc.Depth := Windows.GetDeviceCaps(DC, BITSPIXEL) * Windows.GetDeviceCaps(DC, PLANES);
|
|
ADesc.BitOrder := riboReversedBits;
|
|
ADesc.ByteOrder := riboLSBFirst;
|
|
ADesc.LineOrder := riloTopToBottom;
|
|
ADesc.LineEnd := rileDWordBoundary;
|
|
ADesc.BitsPerPixel := ADesc.Depth;
|
|
|
|
if (Windows.GetDeviceCaps(DC, RASTERCAPS) and RC_PALETTE) <> 0
|
|
then begin
|
|
// has palette
|
|
ADesc.PaletteColorCount := Windows.GetDeviceCaps(DC, NUMCOLORS);
|
|
end;
|
|
|
|
if ADC = 0
|
|
then Windows.ReleaseDC(0, DC);
|
|
|
|
FillRawImageDescriptionColors(ADesc);
|
|
|
|
ADesc.MaskBitsPerPixel := 1;
|
|
ADesc.MaskShift := 0;
|
|
ADesc.MaskLineEnd := rileWordBoundary;
|
|
ADesc.MaskBitOrder := riboReversedBits;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: RawImage_FromBitmap
|
|
Params: ABitmap:
|
|
AMask:
|
|
ARect:
|
|
ARawImage:
|
|
Returns:
|
|
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.RawImage_FromBitmap(out ARawImage: TRawImage; ABitmap, AMask: HBITMAP; ARect: PRect = nil): Boolean;
|
|
var
|
|
WinDIB: Windows.TDIBSection;
|
|
WinBmp: Windows.TBitmap absolute WinDIB.dsBm;
|
|
ASize: Integer;
|
|
R: TRect;
|
|
begin
|
|
ARawImage.Init;
|
|
FillChar(WinDIB, SizeOf(WinDIB), 0);
|
|
ASize := Windows.GetObject(ABitmap, SizeOf(WinDIB), @WinDIB);
|
|
if ASize = 0
|
|
then Exit(False);
|
|
|
|
//DbgDumpBitmap(ABitmap, 'FromBitmap - Image');
|
|
//DbgDumpBitmap(AMask, 'FromMask - Mask');
|
|
|
|
FillRawImageDescription(WinBmp, ARawImage.Description);
|
|
// if it is not DIB then alpha in bitmaps is not supported => use 0 alpha prec
|
|
if ASize < SizeOf(WinDIB) then
|
|
ARawImage.Description.AlphaPrec := 0;
|
|
|
|
if ARect = nil
|
|
then begin
|
|
R := Rect(0, 0, WinBmp.bmWidth, WinBmp.bmHeight);
|
|
end
|
|
else begin
|
|
R := ARect^;
|
|
if R.Top > WinBmp.bmHeight then
|
|
R.Top := WinBmp.bmHeight;
|
|
if R.Bottom > WinBmp.bmHeight then
|
|
R.Bottom := WinBmp.bmHeight;
|
|
if R.Left > WinBmp.bmWidth then
|
|
R.Left := WinBmp.bmWidth;
|
|
if R.Right > WinBmp.bmWidth then
|
|
R.Right := WinBmp.bmWidth;
|
|
end;
|
|
|
|
ARawImage.Description.Width := R.Right - R.Left;
|
|
ARawImage.Description.Height := R.Bottom - R.Top;
|
|
|
|
// copy bitmap
|
|
Result := GetBitmapBytes(WinBmp, ABitmap, R, ARawImage.Description.LineEnd, ARawImage.Description.LineOrder, ARawImage.Data, ARawImage.DataSize);
|
|
|
|
// check mask
|
|
if AMask <> 0 then
|
|
begin
|
|
if Windows.GetObject(AMask, SizeOf(WinBmp), @WinBmp) = 0
|
|
then Exit(False);
|
|
|
|
Result := GetBitmapBytes(WinBmp, AMask, R, ARawImage.Description.MaskLineEnd, ARawImage.Description.LineOrder, ARawImage.Mask, ARawImage.MaskSize);
|
|
end
|
|
else begin
|
|
ARawImage.Description.MaskBitsPerPixel := 0;
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: RawImage_FromDevice
|
|
Params: ADC:
|
|
ARect:
|
|
ARawImage:
|
|
Returns:
|
|
|
|
------------------------------------------------------------------------------}
|
|
function TWin32WidgetSet.RawImage_FromDevice(out ARawImage: TRawImage; ADC: HDC; const ARect: TRect): Boolean;
|
|
const
|
|
FILL_PIXEL: array[0..3] of Byte = ($00, $00, $00, $FF);
|
|
var
|
|
Info: record
|
|
Header: Windows.TBitmapInfoHeader;
|
|
Colors: array[0..1] of Cardinal; // reserve extra color for mono bitmaps
|
|
end;
|
|
|
|
BitsPtr: Pointer;
|
|
|
|
copyDC, fillDC: HDC;
|
|
bmp, copyOld, fillOld, copyBmp, fillBmp: HBITMAP;
|
|
w, h: Integer;
|
|
|
|
begin
|
|
if Windows.GetObjectType(ADC) = OBJ_MEMDC
|
|
then begin
|
|
// we can use bitmap directly
|
|
bmp := Windows.GetCurrentObject(ADC, OBJ_BITMAP);
|
|
copyBmp := 0;
|
|
end
|
|
else begin
|
|
// we need to copy the image
|
|
// use a dibsection, so we can easily retrieve the bytes
|
|
copyDC := Windows.CreateCompatibleDC(ADC);
|
|
|
|
w := Windows.GetDeviceCaps(ADC, DESKTOPHORZRES);
|
|
if w = 0
|
|
then w := Windows.GetDeviceCaps(ADC, HORZRES);
|
|
h := Windows.GetDeviceCaps(ADC, DESKTOPVERTRES);
|
|
if h = 0
|
|
then h := Windows.GetDeviceCaps(ADC, VERTRES);
|
|
|
|
FillChar(Info, SizeOf(Info), 0);
|
|
Info.Header.biSize := SizeOf(Info.Header);
|
|
Info.Header.biWidth := w;
|
|
Info.Header.biHeight := -h;
|
|
Info.Header.biPlanes := 1;
|
|
Info.Header.biBitCount := Windows.GetDeviceCaps(ADC, BITSPIXEL);
|
|
Info.Header.biCompression := BI_RGB;
|
|
|
|
copyBmp := Windows.CreateDIBSection(copyDC, Windows.PBitmapInfo(@Info)^, DIB_RGB_COLORS, BitsPtr, 0, 0);
|
|
copyOld := Windows.SelectObject(copyDC, copyBmp);
|
|
|
|
// prefill bitmap, to create an alpha channel in case of 32bpp bitmap
|
|
if Info.Header.biBitCount > 24
|
|
then begin
|
|
// using a stretchblt is faster than filling the memory ourselves,
|
|
// which is in its turn faster than using a 24bpp bitmap
|
|
fillBmp := Windows.CreateBitmap(1, 1, 1, 32, @FILL_PIXEL);
|
|
fillDC := Windows.CreateCompatibleDC(ADC);
|
|
fillOld := Windows.SelectObject(fillDC, fillBmp);
|
|
|
|
Windows.StretchBlt(copyDC, 0, 0, w, h, fillDC, 0, 0, 1, 1, SRCCOPY);
|
|
|
|
Windows.SelectObject(fillDC, fillOld);
|
|
Windows.DeleteDC(fillDC);
|
|
Windows.DeleteObject(fillBmp);
|
|
|
|
Windows.BitBlt(copyDC, 0, 0, w, h, ADC, 0, 0, SRCPAINT);
|
|
end
|
|
else begin
|
|
// copy image
|
|
Windows.BitBlt(copyDC, 0, 0, w, h, ADC, 0, 0, SRCCOPY);
|
|
end;
|
|
|
|
Windows.SelectObject(copyDC, copyOld);
|
|
Windows.DeleteDC(copyDC);
|
|
|
|
bmp := copyBmp;
|
|
end;
|
|
|
|
if bmp = 0 then Exit(False);
|
|
|
|
Result := RawImage_FromBitmap(ARawImage, bmp, 0, @ARect);
|
|
if copyBmp <> 0
|
|
then Windows.DeleteObject(copyBmp);
|
|
end;
|
|
|
|
function TWin32WidgetSet.ReleaseDesignerDC(Window: HWND; DC: HDC): Integer;
|
|
var
|
|
OverlayWindow: HWND;
|
|
begin
|
|
Assert(False, Format('Trace:> [TWin32WidgetSet.ReleaseDC] DC:0x%x', [DC]));
|
|
OverlayWindow := GetWin32WindowInfo(Window)^.Overlay;
|
|
if OverlayWindow <> HWND(nil) then
|
|
Result := Windows.ReleaseDC(OverlayWindow, DC);
|
|
Assert(False, Format('Trace:< [TWin32WidgetSet.ReleaseDC] DC:0x%x', [DC]));
|
|
end;
|
|
|
|
procedure TWin32WidgetSet.RemoveEventHandler(var AHandler: PEventHandler);
|
|
var
|
|
lListIndex: pdword absolute AHandler;
|
|
I: dword;
|
|
begin
|
|
if AHandler = nil then exit;
|
|
{$ifdef DEBUG_ASYNCEVENTS}
|
|
DebugLn('Removing handle: ', IntToHex(FWaitHandles[lListIndex^], 8));
|
|
if Length(FWaitHandles) > 0 then
|
|
DebugLn(' WaitHandleCount=', IntToStr(FWaitHandleCount), ', WaitHandle[0]=', IntToHex(FWaitHandles[0], 8));
|
|
{$endif}
|
|
// swap with last one
|
|
if FWaitHandleCount >= 2 then
|
|
begin
|
|
I := lListIndex^;
|
|
FWaitHandles[I] := FWaitHandles[FWaitHandleCount-1];
|
|
FWaitHandlers[I] := FWaitHandlers[FWaitHandleCount-1];
|
|
FWaitHandlers[I].ListIndex^ := I;
|
|
end;
|
|
Dec(FWaitHandleCount);
|
|
Dispose(lListIndex);
|
|
AHandler := nil;
|
|
end;
|
|
|
|
procedure TWin32WidgetSet.RemovePipeEventHandler(var AHandler: PPipeEventHandler);
|
|
var
|
|
lHandler: PPipeEventInfo absolute AHandler;
|
|
begin
|
|
if AHandler = nil then exit;
|
|
if lHandler^.Prev <> nil then
|
|
lHandler^.Prev^.Next := lHandler^.Next
|
|
else
|
|
FWaitPipeHandlers := lHandler^.Next;
|
|
if lHandler^.Next <> nil then
|
|
lHandler^.Next^.Prev := lHandler^.Prev;
|
|
Dispose(lHandler);
|
|
AHandler := nil;
|
|
end;
|
|
|
|
//##apiwiz##eps## // Do not remove, no wizard declaration after this line
|