mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-19 07:28:20 +02:00
1200 lines
38 KiB
PHP
1200 lines
38 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 license.
|
|
*****************************************************************************
|
|
}
|
|
|
|
//##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(nil);
|
|
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(nil);
|
|
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;
|
|
|
|
type
|
|
TFontIsMonoSpaceRec = record
|
|
Name: string;
|
|
Result: Boolean;
|
|
end;
|
|
PFontIsMonoSpaceRec = ^TFontIsMonoSpaceRec;
|
|
|
|
function EnumFontsCallBack(
|
|
var LogFont: TEnumLogFontEx;
|
|
var Metric: TNewTextMetricEx;
|
|
FontType: Longint;
|
|
Data: LParam):LongInt; stdcall;
|
|
var
|
|
R: PFontIsMonoSpaceRec;
|
|
begin
|
|
R := PFontIsMonoSpaceRec(Data);
|
|
if ((logfont.elfLogFont.lfPitchAndFamily and FIXED_PITCH) = FIXED_PITCH)
|
|
and (CompareStr(R^.Name, LogFont.elfLogFont.lfFaceName) = 0) then
|
|
begin
|
|
R^.Result := True;
|
|
Result := 0 // we found it -> stop enumeration
|
|
end else
|
|
Result := 1;
|
|
end;
|
|
|
|
|
|
function TWin32WidgetSet.FontIsMonoSpace(Font: HFont): boolean;
|
|
var
|
|
LF: LogFontA;
|
|
Res: LongInt;
|
|
DC: HDC;
|
|
Rec: TFontIsMonoSpaceRec;
|
|
begin
|
|
Result := False;
|
|
FillChar(LF{%H-}, SizeOf(LogFontA), #0);
|
|
Res := GetObject(Font, SizeOf(LogFontA),@LF);
|
|
//writeln('TWin32WidgetSet.FontIsMonoSpace: Res = ',Res,' SizeOf(LogFont) = ',SizeOf(LogFontA));
|
|
//TWin32WidgetSet.GetObject uses LogFontW and converts back to LogFontA, so Res should be SizeOf(LogFontW)
|
|
if (Res <> SizeOf(LogFontW)) then
|
|
Exit;
|
|
LF.lfCharSet := DEFAULT_CHARSET;
|
|
LF.lfPitchAndFamily := 0;
|
|
Rec.Name := LF.lfFaceName;
|
|
Rec.Result := False;
|
|
DC := GetDC(0);
|
|
try
|
|
EnumFontFamiliesEX(DC, @LF, @EnumFontsCallback, LPARAM(@Rec), 0);
|
|
finally
|
|
ReleaseDC(0, DC);
|
|
end;
|
|
Result := Rec.Result;
|
|
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:
|
|
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, 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{%H-}, SizeOf(Msg), #0);
|
|
|
|
Msg.msg := uMsg;
|
|
Msg.wParam := wParam;
|
|
Msg.lParam := lParam;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Here we get the callback WndMethod associated with this window
|
|
------------------------------------------------------------------------------}
|
|
PMethod := {%H-}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, {%H-}PtrInt(PMethod));
|
|
end;
|
|
|
|
Self.SetWindowLong(Result, GWL_WNDPROC, {%H-}PtrInt(@CallbackAllocateHWnd))
|
|
end;
|
|
|
|
function TWin32WidgetSet.AskUser(const DialogCaption, DialogMessage: string;
|
|
DialogType: LongInt; Buttons: TDialogButtons; HelpCtx: Longint): LongInt;
|
|
var
|
|
i: Integer;
|
|
Caption: String;
|
|
TaskConfig: TTASKDIALOGCONFIG;
|
|
DialogButtons: PTASKDIALOG_BUTTON;
|
|
State: TApplicationState;
|
|
begin
|
|
//TaskDialogIndirect is available in Vista and up, but only if app was built with manifest.
|
|
//The check for the latter is done by checking for ComCtlVersionIE6 (which is set in the manifest)
|
|
//The availability of TaskDialogIndirect does not depend on the status of ThemeServices
|
|
//Issue #0027664
|
|
if (WindowsVersion >= wvVista) and (GetFileVersion(comctl32) >= ComCtlVersionIE6) then
|
|
begin
|
|
FillChar(TaskConfig{%H-}, SizeOf(TaskConfig), 0);
|
|
TaskConfig.cbSize := SizeOf(TaskConfig);
|
|
// if we skip hwndParent our form will be a root window - with the taskbar item and icon
|
|
// this is unwanted
|
|
if Assigned(Screen.ActiveCustomForm) then
|
|
TaskConfig.hwndParent := Screen.ActiveCustomForm.Handle
|
|
else
|
|
if Assigned(Application.MainForm) then
|
|
TaskConfig.hwndParent := Application.MainFormHandle
|
|
else
|
|
TaskConfig.hwndParent := AppHandle;
|
|
TaskConfig.hInstance := HInstance;
|
|
TaskConfig.dwFlags := TDF_ALLOW_DIALOG_CANCELLATION;
|
|
if DialogCaption <> '' then
|
|
Caption := DialogCaption
|
|
else
|
|
case DialogType of
|
|
idDialogConfirm,
|
|
idDialogInfo,
|
|
idDialogWarning,
|
|
idDialogError: Caption := GetDialogCaption(DialogType);
|
|
else
|
|
Caption := Application.Title;
|
|
end;
|
|
TaskConfig.pszWindowTitle := PWideChar(UTF8ToUTF16(Caption));
|
|
|
|
case DialogType of
|
|
idDialogConfirm:
|
|
begin
|
|
TaskConfig.hMainIcon := Windows.LoadIcon(0, IDI_QUESTION);
|
|
TaskConfig.dwFlags := TaskConfig.dwFlags or TDF_USE_HICON_MAIN;
|
|
end;
|
|
idDialogInfo: TaskConfig.pszMainIcon := TD_INFORMATION_ICON;
|
|
idDialogWarning: TaskConfig.pszMainIcon := TD_WARNING_ICON;
|
|
idDialogError: TaskConfig.pszMainIcon := TD_ERROR_ICON;
|
|
idDialogShield: TaskConfig.pszMainIcon := TD_SHIELD_ICON;
|
|
else
|
|
TaskConfig.dwFlags := TaskConfig.dwFlags or TDF_USE_HICON_MAIN;
|
|
end;
|
|
|
|
TaskConfig.pszContent := PWideChar(UTF8ToUTF16(DialogMessage));
|
|
|
|
// question dialog button magic :)
|
|
|
|
TaskConfig.cButtons := Buttons.Count;
|
|
GetMem(DialogButtons, SizeOf(TTASKDIALOG_BUTTON) * TaskConfig.cButtons);
|
|
for i := 0 to TaskConfig.cButtons - 1 do
|
|
begin
|
|
DialogButtons[i].nButtonID := Buttons[i].ModalResult;
|
|
DialogButtons[i].pszButtonText := UTF8StringToPWideChar(Buttons[i].Caption);
|
|
end;
|
|
TaskConfig.pButtons := DialogButtons;
|
|
if Assigned(Buttons.DefaultButton) then
|
|
TaskConfig.nDefaultButton := Buttons.DefaultButton.ModalResult;
|
|
|
|
State := SaveApplicationState;
|
|
try
|
|
Result := IDCANCEL;
|
|
TaskDialogIndirect(@TaskConfig, @Result, nil, nil);
|
|
if (Result = IDCANCEL) then
|
|
begin
|
|
if Assigned(Buttons.CancelButton) then
|
|
Result := Buttons.CancelButton.ModalResult
|
|
else
|
|
Result := mrCancel;
|
|
end;
|
|
finally
|
|
RestoreApplicationState(State);
|
|
for i := 0 to TaskConfig.cButtons - 1 do
|
|
FreeMem(DialogButtons[i].pszButtonText);
|
|
FreeMem(DialogButtons);
|
|
end;
|
|
end
|
|
else
|
|
Result := inherited AskUser(DialogCaption, DialogMessage, DialogType,
|
|
Buttons, HelpCtx);
|
|
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 := {%H-}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);
|
|
DrawHorzLine(DC, ARect.Left, ARect.Right, ARect.Top);
|
|
DrawVertLine(DC, ARect.Top + LineSize, ARect.Bottom - LineSize, ARect.Left);
|
|
DrawHorzLine(DC, ARect.Left, ARect.Right, ARect.Bottom - LineSize);
|
|
DrawVertLine(DC, ARect.Top + LineSize, ARect.Bottom - LineSize, ARect.Right - LineSize);
|
|
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;
|
|
|
|
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 = {%H-}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, {%H-}HMENU(nil), HInstance, nil);
|
|
OverlayWindowInfo := AllocWindowInfo(OverlayWindow);
|
|
OverlayWindowInfo^.DefWndProc := {%H-}Windows.WNDPROC(SetWindowLong(
|
|
OverlayWindow, GWL_WNDPROC, {%H-}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.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 TWin32WidgetSet.PromptUser(const DialogCaption, DialogMessage: String;
|
|
DialogType: longint; Buttons: PLongint; ButtonCount, DefaultIndex,
|
|
EscapeResult: Longint): Longint;
|
|
var
|
|
i: Integer;
|
|
Caption: String;
|
|
TaskConfig: TTASKDIALOGCONFIG;
|
|
DialogButtons: PTASKDIALOG_BUTTON;
|
|
State: TApplicationState;
|
|
begin
|
|
//TaskDialogIndirect is available in Vista and up, but only if app was built with manifest.
|
|
//The check for the latter is done by checking for ComCtlVersionIE6 (which is set in the manifest)
|
|
//The availability of TaskDialogIndirect does not depend on the status of ThemeServices
|
|
//Issue #0027664
|
|
if (WindowsVersion >= wvVista) and (GetFileVersion(comctl32) >= ComCtlVersionIE6) then
|
|
begin
|
|
FillChar(TaskConfig, SizeOf(TaskConfig), 0);
|
|
TaskConfig.cbSize := SizeOf(TaskConfig);
|
|
// if we skip hwndParent our form will be a root window - with the taskbar item and icon
|
|
// this is unwanted
|
|
if Assigned(Screen.ActiveCustomForm) then
|
|
TaskConfig.hwndParent := Screen.ActiveCustomForm.Handle
|
|
else
|
|
if Assigned(Application.MainForm) then
|
|
TaskConfig.hwndParent := Application.MainFormHandle
|
|
else
|
|
TaskConfig.hwndParent := AppHandle;
|
|
TaskConfig.hInstance := HInstance;
|
|
TaskConfig.dwFlags := TDF_ALLOW_DIALOG_CANCELLATION;
|
|
if DialogCaption <> '' then
|
|
Caption := DialogCaption
|
|
else
|
|
case DialogType of
|
|
idDialogConfirm,
|
|
idDialogInfo,
|
|
idDialogWarning,
|
|
idDialogError: Caption := GetDialogCaption(DialogType);
|
|
else
|
|
Caption := Application.Title;
|
|
end;
|
|
TaskConfig.pszWindowTitle := PWideChar(UTF8ToUTF16(Caption));
|
|
|
|
case DialogType of
|
|
idDialogConfirm:
|
|
begin
|
|
TaskConfig.hMainIcon := Windows.LoadIcon(0, IDI_QUESTION);
|
|
TaskConfig.dwFlags := TaskConfig.dwFlags or TDF_USE_HICON_MAIN;
|
|
end;
|
|
idDialogInfo: TaskConfig.pszMainIcon := TD_INFORMATION_ICON;
|
|
idDialogWarning: TaskConfig.pszMainIcon := TD_WARNING_ICON;
|
|
idDialogError: TaskConfig.pszMainIcon := TD_ERROR_ICON;
|
|
idDialogShield: TaskConfig.pszMainIcon := TD_SHIELD_ICON;
|
|
else
|
|
TaskConfig.dwFlags := TaskConfig.dwFlags or TDF_USE_HICON_MAIN;
|
|
end;
|
|
|
|
TaskConfig.pszContent := PWideChar(UTF8ToUTF16(DialogMessage));
|
|
|
|
TaskConfig.cButtons := ButtonCount;
|
|
GetMem(DialogButtons, SizeOf(TTASKDIALOG_BUTTON) * ButtonCount);
|
|
for i := 0 to ButtonCount - 1 do
|
|
begin
|
|
DialogButtons[i].nButtonID := Buttons[i];
|
|
DialogButtons[i].pszButtonText := UTF8StringToPWideChar(GetButtonCaption(Buttons[i]));
|
|
end;
|
|
TaskConfig.pButtons := DialogButtons;
|
|
//we need idButtonXX value
|
|
if DefaultIndex < ButtonCount then
|
|
TaskConfig.nDefaultButton := Buttons[DefaultIndex]
|
|
else
|
|
TaskConfig.nDefaultButton := 0;
|
|
|
|
State := SaveApplicationState;
|
|
try
|
|
Result := IDCANCEL;
|
|
TaskDialogIndirect(@TaskConfig, @Result, nil, nil);
|
|
if Result = IDCANCEL then
|
|
Result := EscapeResult;
|
|
finally
|
|
RestoreApplicationState(State);
|
|
for i := 0 to ButtonCount - 1 do
|
|
FreeMem(DialogButtons[i].pszButtonText);
|
|
FreeMem(DialogButtons);
|
|
end;
|
|
end
|
|
else
|
|
Result := inherited PromptUser(DialogCaption, DialogMessage, DialogType,
|
|
Buttons, ButtonCount, DefaultIndex, EscapeResult);
|
|
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, SrcBytes, DstBpp: 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;
|
|
|
|
// 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 DstBpp := 24
|
|
else DstBpp := ADesc.BitsPerPixel;
|
|
|
|
FillChar(Info, SizeOf(Info), 0);
|
|
Info.Header.biSize := SizeOf(Info.Header);
|
|
Info.Header.biWidth := ADesc.Width;
|
|
if ADesc.LineOrder = riloTopToBottom
|
|
then Info.Header.biHeight := -ADesc.Height // create top to bottom
|
|
else Info.Header.biHeight := ADesc.Height; // create bottom to top
|
|
Info.Header.biPlanes := 1;
|
|
Info.Header.biBitCount := DstBpp;
|
|
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(DstBpp, ADesc.Width, 8);
|
|
// align to DWord
|
|
Align := DstLineSize and 3;
|
|
if Align > 0
|
|
then Inc(DstLineSize, PtrUInt(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
|
|
SrcBytes := ADesc.BitsPerPixel div 8;
|
|
|
|
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, SrcBytes);
|
|
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
|
|
OverlayWindow := GetWin32WindowInfo(Window)^.Overlay;
|
|
if OverlayWindow <> 0 then
|
|
Result := Windows.ReleaseDC(OverlayWindow, DC)
|
|
else
|
|
Result := 0;
|
|
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
|