{-------------------------------------------------------------------------------
 QWindows.pas

 Copyright (c) 2003,2004, Andre Snepvangers (asn att xs4all dott nl),

 All rights reserved.

 Version 1.0
 Description: Qt based wrappers for common MS Windows API's
 Purpose: Reduce coding effort for porting VCL based components to VisualCLX
          compatible components. Simplify VCL code sharing.

 Contributor(s): Andreas Hausladen [Andreas dott Hausladen att gmx dott de]

 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files(the "Software"), to deal in
 the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is furnished
 to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 The origin of this software must not be misrepresented, you must
 not claim that you wrote the original software. If you use this
 software in a product, an acknowledgment in the product documentation
 would be appreciated but is not required.

 Altered source versions must be plainly marked as such, and must not
 be misrepresented as being the original software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
--------------------------------------------------------------------------------

Known Issues:
  - Covers only a small part of the Windows APIs
  - Not all functionality is supported
{-----------------------------------------------------------------------------}
// $Id$

unit QWindows;

interface

uses
  {$IFDEF MSWINDOWS}
  Windows,
  {$ENDIF MSWINDOWS}
  {$IFDEF LINUX}
  Libc, DateUtils,
  {$ENDIF LINUX}
  Types, StrUtils, SysUtils, Classes, Math, Contnrs, SyncObjs, QDialogs,
  QTypes, Qt, QConsts, QGraphics, QControls, QForms, QExtCtrls, QStdCtrls,
  QButtons, QImgList, QStyle;

type
  IPerformControl = interface
    ['{B11AA73D-D7C2-43E5-BED8-8F82DE6152AB}']
    function Perform(Msg: Cardinal; WPar, LPar: Longint): Longint;
  end;

{$IFDEF LINUX}
resourcestring
  SFCreateError = 'Unable to create file %s';
  SFOpenError = 'Unable to open file %s';
  SReadError = 'Error reading file';
  SWriteError = 'Error writing file';
  SQThreadError = 'Thread Error in QWindows: %s (%d)';
{$ENDIF LINUX}

var
  NewStyleControls: Boolean = True;

const
  { SetBkMode: background modes }
  TRANSPARENT = 1; // BGMode_TransparentMode
  OPAQUE      = 2; // BGMode_OpaqueMode

{ constants for CreateDIBitmap }
  CBM_INIT = 4;     { initialize bitmap  }
  DIB_RGB_COLORS = 0;
//  DIB_PAL_COLORS = 1; // not supported by CreateDIBitmap

  { windows symbolic colors }         { mapping VisualCLX Symbolic colors}
  COLOR_SCROLLBAR = 0;                // clNormalButton
  COLOR_BACKGROUND = 1;               // clNormalBackground
  COLOR_ACTIVECAPTION = 2;            // clActiveHighlightedText
  COLOR_INACTIVECAPTION = 3;          // clDisabledHighlightedText
  COLOR_MENU = 4;                     // clNormalMid
  COLOR_WINDOW = 5;                   // clNormalBase
  COLOR_WINDOWFRAME = 6;              // clNormalHighlight
  COLOR_MENUTEXT = 7;                 // clNormalButtonText
  COLOR_WINDOWTEXT = 8;               // clNormalText
  COLOR_CAPTIONTEXT = 9;              // clNormalHighlightedText
  COLOR_ACTIVEBORDER = 10;            // clActiveHighlight
  COLOR_INACTIVEBORDER = 11;          // clDisabledHighlight
  COLOR_APPWORKSPACE = 12;            // clNormalMid
  COLOR_HIGHLIGHT = 13;               // clNormalHighlight
  COLOR_HIGHLIGHTTEXT = 14;           // clNormalHighlightedText
  COLOR_BTNFACE = 15;                 // clNormalButton
  COLOR_BTNSHADOW = $10;              // clNormalDark
  COLOR_GRAYTEXT = 17;                // clNormalDisabledText
  COLOR_BTNTEXT = 18;                 // clNormalButtonText
  COLOR_INACTIVECAPTIONTEXT = 19;     // clDisabledHighlightedText
  COLOR_BTNHIGHLIGHT = 20;            // clActiveLight
  COLOR_3DDKSHADOW = 21;              // clNormalMid
  COLOR_3DLIGHT = 22;                 // clNormalMidLight
  COLOR_INFOTEXT = 23;                // clNormalText
  COLOR_INFOBK = 24;                  // TColor($E1FFFF)
//             = 25;                  // ?? (asn: defined as clBlack for now)
  COLOR_HOTLIGHT = 26;                // clActiveHighlight (asn: ??)
  COLOR_GRADIENTACTIVECAPTION = 27;   // clActiveHighLight (asn: ??)
  COLOR_GRADIENTINACTIVECAPTION = 28; // clDisabledHighlight (asn: ??)

  COLOR_ENDCOLORS = COLOR_GRADIENTINACTIVECAPTION;
(*
  COLOR_MENUHILIGHT = 29;
  COLOR_MENUBAR = 30;
  COLOR_ENDCOLORS = COLOR_MENUBAR;
*)

  COLOR_DESKTOP     = COLOR_BACKGROUND;
  COLOR_3DFACE      = COLOR_BTNFACE;
  COLOR_3DSHADOW    = COLOR_BTNSHADOW;
  COLOR_3DHIGHLIGHT = COLOR_BTNHIGHLIGHT;
  COLOR_3DHILIGHT   = COLOR_BTNHIGHLIGHT;
  COLOR_BTNHILIGHT  = COLOR_BTNHIGHLIGHT;

  { CombineRgn return values }
  NULLREGION    = 1;     // Region is empty
  SIMPLEREGION  = 2;     // Region is a rectangle
  COMPLEXREGION = 3;     // Region is not a rectangle
  ERROR         = 0;     // Region error
  RGN_ERROR     = ERROR;

  { constants for CreatePolygon  }
  ALTERNATE     = 1;
  WINDING       = 2;

  { flags for DrawFrameControl }
  DFC_CAPTION   = 1;
  DFC_MENU      = 2;
  DFC_SCROLL    = 3;
  DFC_BUTTON    = 4;
  DFC_POPUPMENU = 5;

  DFCS_CAPTIONCLOSE   = 0;
  DFCS_CAPTIONMIN     = 1;
  DFCS_CAPTIONMAX     = 2;
  DFCS_CAPTIONRESTORE = 3;
  DFCS_CAPTIONHELP    = 4;

  DFCS_MENUARROW      = 0;
  DFCS_MENUCHECK      = 1;
  DFCS_MENUBULLET     = 2;
  DFCS_MENUARROWRIGHT = 4;

  DFCS_SCROLLUP            = 0;
  DFCS_SCROLLDOWN          = 1;
  DFCS_SCROLLLEFT          = 2;
  DFCS_SCROLLRIGHT         = 3;
  DFCS_SCROLLCOMBOBOX      = 5;
  DFCS_SCROLLSIZEGRIP      = 8;
  DFCS_SCROLLSIZEGRIPRIGHT = $10;

  DFCS_BUTTONCHECK      = 0;
  DFCS_BUTTONRADIOIMAGE = 1;
  DFCS_BUTTONRADIOMASK  = 2;
  DFCS_BUTTONRADIO      = 4;
  DFCS_BUTTON3STATE     = 8;
  DFCS_BUTTONPUSH       = $10;

  DFCS_INACTIVE    = $100;
  DFCS_PUSHED      = $200;
  DFCS_CHECKED     = $400;
  DFCS_TRANSPARENT = $800;
  DFCS_HOT         = $1000;
  DFCS_ADJUSTRECT  = $2000;
  DFCS_FLAT        = $4000;
  DFCS_MONO        = $8000;

  { 3D border styles }
  BDR_RAISEDOUTER = 1;
  BDR_SUNKENOUTER = 2;
  BDR_RAISEDINNER = 4;
  BDR_SUNKENINNER = 8;

  BDR_OUTER   = BDR_SUNKENOUTER or BDR_RAISEDOUTER;
  BDR_INNER   = BDR_SUNKENINNER or BDR_SUNKENOUTER;
  BDR_RAISED  = BDR_RAISEDINNER or BDR_RAISEDOUTER;
  BDR_SUNKEN  = BDR_SUNKENINNER or BDR_SUNKENOUTER;

  EDGE_RAISED = BDR_RAISEDOUTER or BDR_RAISEDINNER;
  EDGE_SUNKEN = BDR_SUNKENOUTER or BDR_SUNKENINNER;
  EDGE_ETCHED = BDR_SUNKENOUTER or BDR_RAISEDINNER;
  EDGE_BUMP   = BDR_RAISEDOUTER or BDR_SUNKENINNER;

  { Border flags }
  BF_LEFT     = 1;
  BF_TOP      = 2;
  BF_RIGHT    = 4;
  BF_BOTTOM   = 8;
  BF_DIAGONAL = $10;

  BF_TOPLEFT     = BF_TOP or BF_LEFT;
  BF_TOPRIGHT    = BF_TOP or BF_RIGHT;
  BF_BOTTOMLEFT  = BF_BOTTOM or BF_LEFT;
  BF_BOTTOMRIGHT = BF_BOTTOM or BF_RIGHT;
  BF_RECT        = BF_TOPLEFT or BF_BOTTOMRIGHT;

  { For diagonal lines, the BF_RECT flags specify the end point of the}
  { vector bounded by the rectangle parameter.}
  BF_DIAGONAL_ENDTOPRIGHT    = BF_DIAGONAL or BF_TOP or BF_RIGHT;
  BF_DIAGONAL_ENDTOPLEFT     = BF_DIAGONAL or BF_TOP or BF_LEFT;
  BF_DIAGONAL_ENDBOTTOMLEFT  = BF_DIAGONAL or BF_BOTTOM or BF_LEFT;
  BF_DIAGONAL_ENDBOTTOMRIGHT = BF_DIAGONAL or BF_BOTTOM or BF_RIGHT;

  BF_MIDDLE = $800;   { Fill in the middle }
  BF_SOFT   = $1000;  { For softer buttons }
  BF_ADJUST = $2000;  { Calculate the space left over }
  BF_FLAT   = $4000;  { For flat rather than 3D borders }
  BF_MONO   = $8000;  { For monochrome borders }

  { DrawIconEx diFlags }
  DI_MASK        = 1;
  DI_IMAGE       = 2;
  DI_NORMAL      = 3;
//  DI_COMPAT    = 4;   not supported
  DI_DEFAULTSIZE = 8;

  { DrawText format (windows) flags }
  DT_TOP           = 0;
  DT_LEFT          = 0;
  DT_CENTER        = 1;
  DT_RIGHT         = 2;
  DT_VCENTER       = 4;
  DT_BOTTOM        = 8;
  DT_WORDBREAK     = $10;
  DT_SINGLELINE    = $20;
  DT_EXPANDTABS    = $40;
  DT_TABSTOP       = $80;
  DT_NOCLIP        = $100;
(* DT_EXTERNALLEADING = $200;  // not supported *)
  DT_CALCRECT      = $400;
  DT_NOPREFIX      = $800;
  DT_INTERNAL      = $1000;  // Uses the system font to calculate text metrics.
  DT_EDITCONTROL   = $2000;  // ignored
  DT_PATH_ELLIPSIS = $4000;
  DT_ELLIPSIS      = $8000;
  DT_END_ELLIPSIS  = DT_ELLIPSIS;
  DT_MODIFYSTRING  = $10000;
  DT_RTLREADING    = $20000; // ignored
  DT_WORD_ELLIPSIS = $40000;
  DT_HIDEPREFIX    = $100000;
  DT_PREFIXONLY    = $200000;

  { ExtTextOut format flags }
  ETO_OPAQUE     = 2;
  ETO_CLIPPED    = 4;
  ETO_RTLREADING = $80; // ignored

  { font metrics }
  DEFAULT_PITCH   = 0;
  FIXED_PITCH     = 1;
  VARIABLE_PITCH  = 2;
  DEFAULT_CHARSET = 1;

  {$IFDEF LINUX}
  HINSTANCE_ERROR = 0;
  HINSTANCE_OK    = HINSTANCE_ERROR + 1;
  {$ENDIF LINUX}

  { BrushStyle mappings}
  HS_BDIAGONAL  = BrushStyle_BDiagPattern;    // 45-degree downward left-to-right hatch
  HS_CROSS      = BrushStyle_CrossPattern;    // Hor. and vertical crosshatch
  HS_DIAGCROSS  = BrushStyle_DiagCrossPattern;// 45-degree crosshatch
  HS_FDIAGONAL  = BrushStyle_FDiagPattern;    // 45-degree upward left-to-right hatch
  HS_HORIZONTAL = BrushStyle_HorPattern;      // Horizontal hatch
  HS_VERTICAL   = BrushStyle_VerPattern;      // Vertical hatch

  HWND_TOP       = Cardinal(0);
  HWND_BOTTOM    = Cardinal(1);
  HWND_TOPMOST   = Cardinal(-1);
  HWND_NOTOPMOST = Cardinal(-2);

{$IFDEF LINUX}
  { GlobalMemory }
  GMEM_FIXED          = 0;
  GMEM_MOVEABLE       = 2;
  GMEM_NOCOMPACT      = $10;
  GMEM_NODISCARD      = $20;
  GMEM_ZEROINIT       = $40; // only supported flag
  GMEM_MODIFY         = $80;
  GMEM_DISCARDABLE    = $100;
  GMEM_NOT_BANKED     = $1000;
  GMEM_SHARE          = $2000;
  GMEM_DDESHARE       = $2000;
  GMEM_NOTIFY         = $4000;
  GMEM_LOWER          = GMEM_NOT_BANKED;
  GMEM_VALID_FLAGS    = 32626;
  GMEM_INVALID_HANDLE = $8000;

  GHND = GMEM_MOVEABLE or GMEM_ZEROINIT;
  GPTR = GMEM_FIXED or GMEM_ZEROINIT;

{$ENDIF LINUX}


  INFINITE = Longword($FFFFFFFF); // Infinite timeout
  INVALID_HANDLE_VALUE = DWORD(-1);
  MaxWord = High(Cardinal);

  { MessageBox() return values }
  IDCLOSE    = 0;
  IDOK       = 1;
  IDCANCEL   = 2;
  IDYES      = 3;
  IDNO       = 4;
  IDABORT    = 5;
  IDRETRY    = 6;
  IDIGNORE   = 7;
  { aliases }
  ID_OK      = IDOK;
  ID_CANCEL  = IDCANCEL;
  ID_ABORT   = IDABORT;
  ID_RETRY   = IDRETRY;
  ID_IGNORE  = IDIGNORE;
  ID_YES     = IDYES;
  ID_NO      = IDNO;
  ID_CLOSE   = IDCLOSE;
  IDHELP     = 9;        //  not supported
  ID_HELP    = IDHELP;  //  not supported
  IDTRYAGAIN = IDRETRY;
  IDCONTINUE = IDIGNORE;

  {$EXTERNALSYM LB_OKAY}
  LB_OKAY     = 0;
  {$EXTERNALSYM LB_ERR}
  LB_ERR      = -1;
  {$EXTERNALSYM LB_ERRSPACE}
  LB_ERRSPACE = -2;
  {$EXTERNALSYM CB_OKAY}
  CB_OKAY = 0;
  {$EXTERNALSYM CB_ERR}
  CB_ERR = -1;
  {$EXTERNALSYM CB_ERRSPACE}
  CB_ERRSPACE = -2;


  MAX_COMPUTERNAME_LENGTH = 15;

  { MessageBox() WinFlags }
  MB_OK               = $0000;
  MB_OKCANCEL         = $0001;
  MB_ABORTRETRYIGNORE = $0002;
  MB_YESNOCANCEL      = $0003;
  MB_YESNO            = $0004;
  MB_RETRYCANCEL      = $0005;
  MB_HELP             = $4000; { Help Button not supported}
  MB_ICONHAND         = $0010;
  MB_ICONQUESTION     = $0020;
  MB_ICONEXCLAMATION  = $0030;
  MB_ICONASTERISK     = $0040;
  MB_USERICON         = $0080;
  MB_DEFBUTTON1       = $0000;
  MB_DEFBUTTON2       = $0100;
  MB_DEFBUTTON3       = $0200;
  MB_DEFBUTTON4       = $0300;
  MB_ICONWARNING      = MB_ICONEXCLAMATION;
  MB_ICONERROR        = MB_ICONHAND;
  MB_ICONINFORMATION  = MB_ICONASTERISK;
  MB_ICONSTOP         = MB_ICONHAND;

  { MouseKeys }
  MK_LBUTTON   = 1;
  MK_RBUTTON   = 2;
  MK_SHIFT     = 4;
  MK_CONTROL   = 8;
  MK_MBUTTON   = $10;

  { TDrawItemStruct itemstate }
  ODS_DISABLED = 1;
  ODS_SELECTED = 2;
  ODS_FOCUS    = 4;

  { Pen Styles }
  PS_NULL          = 0;   // PenStyle_NoPen
  PS_SOLID         = 1;   // PenStyle_SolidLine
  PS_DASH          = 2;   // PenStyle_DashLine
  PS_DOT           = 3;   // PenStyle_DotLine
  PS_DASHDOT       = 4;   // PenStyle_DashDotLine
  PS_DASHDOTDOT    = 5;   // PenStyle_DashDotDotLine
  PS_STYLE_MASK    = 15;  // PenStyle_MPenStyle
  {caps}
  PS_ENDCAP_FLAT   = 0;   // PenCapStyle_FlatCap
  PS_ENDCAP_SQUARE = 16;  // PenCapStyle_SquareCap
  PS_ENDCAP_ROUND  = 32;  // PenCapStyle_RoundCap
  PS_ENDCAP_MASK   = 48;  // PenCapStyle_MPenCapStyle
  {join}
  PS_JOIN_MITER    = 0;   // PenJoinStyle_MiterJoin
  PS_JOIN_BEVEL    = 64;  // PenJoinStyle_BevelJoin
  PS_JOIN_ROUND    = 128; // PenJoinStyle_RoundJoin
  PS_JOIN_MASK     = $C0; // PenCapStyle_MPenCapStyle

  { BitBlt/StretchBlt: supported  windows dwRop Raster OPerations }
  BLACKNESS   = $00000042;   // RasterOp_ClearROP
  DSTINVERT   = $00550009;   // RasterOp_NotROP
  MERGECOPY   = $00C000CA;   // RasterOp_OrROP
  MERGEPAINT  = $00BB0226;   // RasterOp_NotOrRop
  NOTSRCCOPY  = $00330008;   // RasterOp_NotCopyROP
  NOTSRCERASE = $001100A6;   // RasterOp_NorROP
  SRCAND      = $008800C6;   // RasterOp_AndROP
  SRCCOPY     = $00CC0020;   // RasterOp_CopyROP
  SRCERASE    = $00440328;   // RasterOp_AndNotROP
  SRCINVERT   = $00660046;   // RasterOp_XorROP
  SRCPAINT    = $00EE0086;   // RasterOp_OrROP;
  WHITENESS   = $00FF0062;   // RasterOp_SetROP
  PATCOPY     = $00F00021;   // dest = pattern
  PATPAINT    = $00FB0A09;   // dest = DPSnoo = PDSnoo
  PATINVERT   = $005A0049;   // dest = pattern XOR dest
  ROP_DSPDxax = $00E20746;   // dest = ((pattern XOR dest) AND source) XOR Dest
  ROP_DSna    = $00220326;   // RasterOp_NotAndROP
  ROP_DSno    = MERGEPAINT;
  ROP_DPSnoo  = PATPAINT;
  ROP_D       = $00AA0029;   // RasterOp_NopROP
  ROP_Dn      = DSTINVERT;   // DSTINVERT
  ROP_SDna    = SRCERASE;    // SRCERASE
  ROP_SDno    = $00DD0228;   // RasterOp_OrNotROP
  ROP_DSan    = $007700E6;   // RasterOp_NandROP
  ROP_DSon    = $001100A6;   // NOTSRCERASE
//ROP_Pn      = $000F0001;   //

 { SetROP2:  windows ROP2 values }
  R2_BLACK       = 9;  // RasterOp_ClearROP:  Pixel is always 0.
  R2_WHITE       = 10; // RasterOp_SetROP:Pixel is always 1.
  R2_NOP         = 11; // RasterOp_NopROP: Pixel remains unchanged.
  R2_NOT         = 8;  // RasterOp_NotROP:      inverse of the screen color.
  R2_COPYPEN     = 0;  // RasterOp_CopyROP: Pixel is the pen color.
  R2_NOTCOPYPEN  = 4;  // RasterOp_NotCopyROP; inverse of the pen color.
  R2_MERGEPENNOT = 13; // RasterOp_OrNotROP: combination of the pen color and the inverse of the screen color.
  R2_MASKPENNOT  = 12; // RasterOp_AndNotROP: combination of the colors common to both the pen and the inverse of the screen.
  R2_MERGEPEN    = 1;  // RasterOp_OrROP: combination of the pen color and the screen color.
  R2_NOTMERGEPEN = 15; // RasterOp_NorROP:  inverse of the R2_MERGEPEN color.
  R2_MASKPEN     = 7;  // RasterOp_AndROP: combination of the colors common to both the pen and the screen.
  R2_NOTMASKPEN  = 14; // RasterOp_NandROP: inverse of the R2_MASKPEN color.
  R2_XORPEN      = 2;  // RasterOp_XorROP: combination of the colors in the pen and in the screen, but not in both.
  R2_NOTXORPEN   = 6;  // RasterOp_NotXorROP: inverse of the R2_XORPEN color.
  R2_MASKNOTPEN  = 3;  // RasterOp_NotAndROP: combination of the colors common to both the screen and the inverse of the pen.
  R2_MERGENOTPEN = 5;  // RasterOp_NotOrROP: combination of the screen color and the inverse of the pen color.

  RT_RCDATA = Types.RT_RCDATA;
  RT_BITMAP = PChar(2);

  { WM_xSCROLL ScrollCodes }
  SB_BOTTOM        = 1;
  SB_ENDSCROLL     = 2;
  SB_LINEDOWN      = 3;
  SB_LINEUP        = 4;
  SB_PAGEDOWN      = 5;
  SB_PAGEUP        = 6;
  SB_THUMBPOSITION = 7;
  SB_THUMBTRACK    = 8;
  SB_TOP           = 9;

  SB_HORZ          = 1;
  SB_VERT          = 2;
  SB_BOTH          = SB_HORZ or SB_VERT;


  { semaphores }
  STATUS_WAIT_0           = $00000000;
  STATUS_ABANDONED_WAIT_0 = $00000080;
  STATUS_TIMEOUT          = $00000102;
  WAIT_FAILED             = Longword($FFFFFFFF);
  WAIT_OBJECT_0           = STATUS_WAIT_0;
  WAIT_ABANDONED          = STATUS_ABANDONED_WAIT_0;
  WAIT_ABANDONED_0        = STATUS_ABANDONED_WAIT_0;
  WAIT_TIMEOUT            = STATUS_TIMEOUT;
  MAXIMUM_WAIT_OBJECTS    = 64;

  { ShowWindow() Commands }
  SW_HIDE            = 0;
  SW_SHOWNORMAL      = 1;
  SW_NORMAL          = 1;
  SW_SHOWMINIMIZED   = 2;
  SW_SHOWMAXIMIZED   = 3;
  SW_MAXIMIZE        = 3;
  SW_SHOWNOACTIVATE  = 4;
  SW_SHOW            = 5;
  SW_MINIMIZE        = 6;
  SW_SHOWMINNOACTIVE = 7;
  SW_SHOWNA          = 8;
  SW_RESTORE         = 9;
  SW_SHOWDEFAULT     = 10;
  SW_MAX             = 10;

  { SetWindowPos Flags }
  SWP_NOSIZE         = 1;
  SWP_NOMOVE         = 2;
  SWP_NOZORDER       = 4;
  SWP_NOREDRAW       = 8;
  SWP_NOACTIVATE     = $10;
  SWP_FRAMECHANGED   = $20;  { The frame changed: send WM_NCCALCSIZE }
  SWP_SHOWWINDOW     = $40;
  SWP_HIDEWINDOW     = $80;
  SWP_NOCOPYBITS     = $100; // ignored
  SWP_NOOWNERZORDER  = $200; { Don't do owner Z ordering }
  SWP_NOSENDCHANGING = $400; // ignores
  SWP_DRAWFRAME      = SWP_FRAMECHANGED;
  SWP_NOREPOSITION   = SWP_NOOWNERZORDER;
  SWP_DEFERERASE     = $2000;
  SWP_ASYNCWINDOWPOS = $4000; // ignored

  TA_LEFT       = Integer(AlignmentFlags_AlignLeft);
  TA_RIGHT      = Integer(AlignmentFlags_AlignRight);
  TA_CENTER     = Integer(AlignmentFlags_AlignHCenter);
  TA_TOP        = Integer(AlignmentFlags_AlignTop);
  TA_BOTTOM     = Integer(AlignmentFlags_AlignBottom);
  VTA_CENTER    = Integer(AlignmentFlags_AlignVCenter);
  TA_NOUPDATECP = 0;
  TA_UPDATECP   = $8000;
  TA_BASELINE   = $4000;
  VTA_BASELINE  = TA_BASELINE;

  {$IFDEF LINUX}
  {virtual memory handling}
  PAGE_NOACCESS          = 0;
  PAGE_READONLY          = PROT_READ;
  PAGE_READWRITE         = PROT_READ or PROT_WRITE;
//PAGE_WRITECOPY         = PROT_ ; // not implemented
  PAGE_EXECUTE           = PROT_EXEC;
  PAGE_EXECUTE_READ      = PAGE_EXECUTE or PAGE_READONLY;
  PAGE_EXECUTE_READWRITE = PAGE_EXECUTE or PAGE_READWRITE;
//PAGE_EXECUTE_WRITECOPY = PAGE_EXECUTE or PAGE_WRITECOPY;
  {$ENDIF LINUX}


  { Windows VK_ keycodes to Qt key }
  VK_BACK     = Key_Backspace;
  VK_TAB      = Key_Tab;
  VK_RETURN   = Key_Enter; //Key_Return = Enter key from keypad
  VK_SHIFT    = Key_Shift;
  VK_CONTROL  = Key_Control;
  VK_MENU     = Key_Alt;
  VK_PAUSE    = Key_Pause;
  VK_CAPITAL  = Key_CapsLock;
  VK_ESCAPE   = 4096;
  VK_SPACE    = Key_Space;
  VK_PRIOR    = Key_Prior;
  VK_NEXT     = Key_Next;
  VK_END      = Key_End;
  VK_HOME     = Key_Home;
  VK_LEFT     = Key_Left;
  VK_UP       = Key_Up;
  VK_RIGHT    = Key_Right;
  VK_DOWN     = Key_Down;
  { VK_SELECT   = 41; }
  VK_PRINT    = Key_Print;
  { VK_EXECUTE  = 43; }
  VK_SNAPSHOT = Key_Print;
  VK_INSERT   = Key_Insert;
  VK_DELETE   = Key_Delete;
  VK_HELP     = Key_Help;
  { VK_LWIN     = 91; }
  { VK_RWIN     = 92; }
  VK_APPS     = Key_Menu;
  VK_NUMPAD0  = Key_0;
  VK_NUMPAD1  = Key_1;
  VK_NUMPAD2  = Key_2;
  VK_NUMPAD3  = Key_3;
  VK_NUMPAD4  = Key_4;
  VK_NUMPAD5  = Key_5;
  VK_NUMPAD6  = Key_6;
  VK_NUMPAD7  = Key_7;
  VK_NUMPAD8  = Key_8;
  VK_NUMPAD9  = Key_9;
  VK_MULTIPLY = Key_Asterisk;
  VK_ADD      = Key_Plus;
  VK_SUBTRACT = Key_Minus;
  VK_DECIMAL  = Key_Period;
  VK_DIVIDE   = Key_Slash;
  VK_F1       = Key_F1;
  VK_F2       = Key_F2;
  VK_F3       = Key_F3;
  VK_F4       = Key_F4;
  VK_F5       = Key_F5;
  VK_F6       = Key_F6;
  VK_F7       = Key_F7;
  VK_F8       = Key_F8;
  VK_F9       = Key_F1;
  VK_F10      = Key_F10;
  VK_F11      = Key_F11;
  VK_F12      = Key_F12;
  VK_F13      = Key_F13;
  VK_F14      = Key_F14;
  VK_F15      = Key_F15;
  VK_F16      = Key_F16;
  VK_F17      = Key_F17;
  VK_F18      = Key_F18;
  VK_F19      = Key_F19;
  VK_F20      = Key_F20;
  VK_F21      = Key_F21;
  VK_F22      = Key_F22;
  VK_F23      = Key_F23;
  VK_F24      = Key_F24;
  VK_NUMLOCK  = Key_NumLock;
  VK_SCROLL   = Key_ScrollLock;
  { VK_L.. & VK_R.. mapping:                      }
  { Alt, Ctrl and Shift keys produce same keycode }
  VK_LSHIFT   = Key_Shift;
  VK_RSHIFT   = Key_Shift;
  VK_LCONTROL = Key_Control;
  VK_RCONTROL = Key_Control;
  VK_LMENU    = Key_Alt;
  VK_RMENU    = Key_Alt;

  { Qt alignment flags, (as used by Canvas.TextRect) }
  AlignLeft     = $1;
  AlignRight    = $2;
  AlignHCenter  = $4;
  AlignTop      = $8;
  AlignBottom   = $10;
  AlignVCenter  = $20;
  AlignCenter   = $24;
  SingleLine    = $40;
  DontClip      = $80;
  ExpandTabs    = $100;
  ShowPrefix    = $200;
  WordBreak     = $400;
  BreakAnywhere = $800;
//  DontPrint = $1000; not used
  { Additional constanst for Qt text alignments used by DrawText }
  QtAlignMask   = $FFF;
  CalcRect      = $10000;
  ClipPath      = $20000;
  ClipName      = $40000;
  ClipToWord    = $100000;
  ModifyString  = $200000;

  pf24bit       = pf32bit;
  clSystemColor = $FF000000;
  clMoneyGreen  = TColor($C0DCC0);
  clSkyBlue     = TColor($F0CAA6);
  clCream       = TColor($F0FBFF);
  clMedGray     = TColor($A4A0A0);
  clWindowFrame = cl3DDkShadow;

  crColorTo         = crNoRole;
  clColorTo         = TColor(-15);
  clNormalColorTo   = TColor(clColorTo - cloNormal);
  clActiveColorTo   = TColor(clColorTo - cloActive);
  clDisabledColorTo = TColor(clColorTo - cloDisabled);

  clNoRole         = TColor(-15);
  clNormalNoRole   = TColor(clNoRole - cloNormal);
  clDisabledNoRole = TColor(clNoRole - cloDisabled);
  clActiveNoRole   = TColor(clNoRole - cloActive);
  clDesktop        = clDisabledNoRole;
  clColor0         = clMask;
  clColor1         = clDontMask;

  // Windows symbolic colors to mapping VisualCLX symbolic colors
  Win2TColor: array [0..COLOR_ENDCOLORS] of TColor = (
    clNormalButton, clNormalBackground, clActiveHighlightedText,     // 0
    clDisabledHighlightedText, clNormalMid, clNormalBase,            // 3
    clNormalHighlight, clNormalButtonText, clNormalText,             // 6
    clNormalHighlightedText, clActiveHighlight, clDisabledHighlight, // 9
    clNormalMid, clNormalHighlight,  clNormalHighlightedText,        // 12
    clNormalButton, clNormalDark, clDisabledText,                    // 15
    clNormalButtonText, clDisabledHighlightedText, clActiveLight,    // 18
    clNormalMid, clNormalMidLight, clNormalText,                     // 21
    clInfoBk, clBlack, clActiveHighlight,                            // 24
    clActiveHighLight, clDisabledHighlight                           // 27
  );

  { SendMessage / PostMessage }
  QEventType_Message = QEventType(2105);
  { Timer message id}
  WM_TIMER = $0113;  { 275 }

type
  TAppEventHook = class(TComponent)
  private
    FHook: QApplication_hookH;
  protected
    function EventFilter(Receiver: QObjectH; Event: QEventH): Boolean; cdecl;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

  TMsg = packed record
    hwnd: QWidgetH;
    message: Integer;
    wParam: Integer;
    lParam: Integer;
    case integer of
      0:
      (
        time: Cardinal;
        pt: TPoint;
      );
      1: ( Result: Integer);
      2: ( Handled: LongBool);
  end;
  PMsg = ^TMsg;

  TMessage = packed record
    Msg: Cardinal;
    case Integer of
      0:
      (
        WParam: Longint;
        LParam: Longint;
        Result: Longint;
      );
      1:
      (
        WParamLo: Word;
        WParamHi: Word;
        LParamLo: Word;
        LParamHi: Word;
        ResultLo: Word;
        ResultHi: Word
      );
  end;
  PMessage = ^TMessage;

  { Provided to simplify VCL source sharing }
  HWND        = QWidgetH;
  HCURSOR     = QCursorH;
  HRGN        = QRegionH;
  HBRUSH      = QBrushH;
  HBITMAP     = QPixmapH;
  HDC         = QPainterH;
  HFONT       = QFontH;
  UINT        = Cardinal;
  ULONG       = Cardinal;
  DWORD       = Cardinal;
  BOOL        = LongBool;
  WPARAM      = Integer;
  LPARAM      = Integer;
  LRESULT     = Integer;
  TPointL     = TPoint;
  COLORREF    = Integer;
  TColorRef   = COLORREF;

  TWinControlActionLink = TWidgetControlActionLink;
  TControlClass = class of TControl;

  {$EXTERNALSYM TCaption}
  TCaption    = QTypes.TCaption;

  {$EXTERNALSYM TOwnerDrawState}
  TOwnerDrawState = QStdCtrls.TOwnerDrawState;

  {$EXTERNALSYM PPoint}
  {$EXTERNALSYM TPoint}
  PPoint      = Types.PPoint;
  TPoint      = Types.TPoint;

  {$EXTERNALSYM PRect}
  {$EXTERNALSYM TRect}
  PRect       = Types.PRect;
  TRect       = Types.TRect;

  {$EXTERNALSYM PSize}
  {$EXTERNALSYM TSize}
  TSize       = Types.TSize;
  PSize       = Types.PSize;

  PSmallPoint = Types.PSmallPoint;
  TSmallPoint = Types.TSmallPoint;
  {$EXTERNALSYM PSmallPoint}
  {$EXTERNALSYM TSmallPoint}

  TTime       = type TDateTime;
  TDate       = type TDateTime;
  {$EXTERNALSYM TDate}
  {$EXTERNALSYM TTime}

  { colors }
  TRGBQuad = packed record
    rgbBlue: Byte;
    rgbGreen: Byte;
    rgbRed: Byte;
    rgbReserved: Byte;
  end;
  TRGBTriple  = TRGBQuad; // Qt does not support 24 bit pixmaps

  { fonts }
  tagTEXTMETRICA = record
    tmHeight: Longint;
    tmAscent: Longint;
    tmDescent: Longint;
    //tmInternalLeading: Longint; // not supported
    tmExternalLeading: Longint;
    tmAveCharWidth: Longint;
    tmMaxCharWidth: Longint;
    tmWeight: Longint;
    //tmOverhang: Longint; // not supported
    tmDigitizedAspectX: Longint;
    tmDigitizedAspectY: Longint;
    tmFirstChar: AnsiChar;
    tmLastChar: AnsiChar;
    tmDefaultChar: AnsiChar;
    tmBreakChar: AnsiChar;
    tmItalic: Byte;
    tmUnderlined: Byte;
    tmStruckOut: Byte;
    tmPitchAndFamily: Byte;
    tmCharSet: Byte;
  end;
  TTextMetric = tagTEXTMETRICA;
  TEXTMETRIC  = TTextMetric;

  { Logical Pen }
  PLogPen = ^TLogPen;
  tagLOGPEN = packed record
    lopnStyle: UINT;
    lopnWidth: TPoint;
    lopnColor: COLORREF;
  end;
  TLogPen     = tagLOGPEN;
  LOGPEN      = tagLOGPEN;

  { Logical Palette }
  PPaletteEntry = ^TPaletteEntry;
  tagPALETTEENTRY = packed record
    peRed: Byte;
    peGreen: Byte;
    peBlue: Byte;
    peFlags: Byte;
  end;
  TPaletteEntry = tagPALETTEENTRY;
  PALETTEENTRY = tagPALETTEENTRY;

  PLogPalette = ^TLogPalette;
  tagLOGPALETTE = packed record
    palVersion: Word;
    palNumEntries: Word;
    palPalEntry: array[0..0] of TPaletteEntry;
  end;
  TLogPalette = tagLOGPALETTE;
  LOGPALETTE  = tagLOGPALETTE;

  PMaxLogPalette = ^TMaxLogPalette;
  TMaxLogPalette = packed record
    palVersion: Word;
    palNumEntries: Word;
    palPalEntry: array[Byte] of TPaletteEntry;
  end;

  PtagBITMAP  = ^tagBITMAP;
  tagBITMAP = packed record
    //bmType: Longint;
    bmWidth: Longint;
    bmHeight: Longint;
    //bmWidthBytes: Longint;
    //bmPlanes: Word;
    bmBitsPixel: Word;
    //bmBits: Pointer;
  end;

  PBitmapInfoHeader = ^TBitmapInfoHeader;
  tagBITMAPINFOHEADER = packed record
    biSize: DWORD;
    biWidth: Longint;
    biHeight: Longint;
    biPlanes: Word;
    biBitCount: Word;
    biCompression: DWORD;
    biSizeImage: DWORD;
    biXPelsPerMeter: Longint;
    biYPelsPerMeter: Longint;
    biClrUsed: DWORD;
    biClrImportant: DWORD;
  end;
  TBitmapInfoHeader = tagBITMAPINFOHEADER;
  BITMAPINFOHEADER  = tagBITMAPINFOHEADER;

  PBitmapInfo = ^TBitmapInfo;
  tagBITMAPINFO = packed record
    bmiHeader: TBitmapInfoHeader;
    bmiColors: array[0..0] of TRGBQuad;
  end;
  TBitmapInfo = tagBITMAPINFO;
  BITMAPINFO = tagBITMAPINFO;

  PBitmapFileHeader = ^TBitmapFileHeader;
  tagBITMAPFILEHEADER = packed record
    bfType: Word;
    bfSize: DWORD;
    bfReserved1: Word;
    bfReserved2: Word;
    bfOffBits: DWORD;
  end;
  TBitmapFileHeader = tagBITMAPFILEHEADER;
  BITMAPFILEHEADER  = tagBITMAPFILEHEADER;

  tagDRAWITEMSTRUCT = packed record
    CtlType: Cardinal;
    CtlID: Cardinal;
    itemID: Cardinal;
    itemAction: Cardinal;
    itemState: Cardinal;
    hwndItem: QWidgetH;
    hDC: QPainterH;
    rcItem: TRect;
    itemData: Cardinal;
  end;
  TDrawItemStruct   = tagDRAWITEMSTRUCT;
  DRAWITEMSTRUCT    = tagDRAWITEMSTRUCT;

type
  TDeviceCap = (
    HORZSIZE,        {Horizontal size in millimeters}
    VERTSIZE,        {Vertical size in millimeters}
    HORZRES,         {Horizontal width in pixels}
    VERTRES,         {Vertical height in pixels}
    BITSPIXEL,       {Number of bits per pixel}
    PLANES,          {Number of planes}
    NUMCOLORS,
    LOGPIXELSX,      {Logical pixelsinch in X}
    LOGPIXELSY,      {Logical pixelsinch in Y}
    PHYSICALWIDTH,   {Physical Width in device units}
    PHYSICALHEIGHT,  {Physical Height in device units}
    PHYSICALOFFSETX, {Physical Printable Area X margin}
    PHYSICALOFFSETY  {Physical Printable Area Y margin}
  );

  { Mapping Modes }
  TMapMode = (
    MM_TEXT        = 1,
    MM_LOMETRIC    = 2,
    MM_HIMETRIC    = 3,
    MM_LOENGLISH   = 4,
    MM_HIENGLISH   = 5,
    MM_TWIPS       = 6,
    MM_ISOTROPIC   = 7,
    MM_ANISOTROPIC = 8
  );

const
  { Min and Max Mapping Mode values }
  MM_MIN = MM_TEXT;
  MM_MAX = MM_ANISOTROPIC;
  MM_MAX_FIXEDSCALE = MM_TWIPS;

type
  TMinMaxInfo = packed record
    ptReserved: TPoint;
    ptMaxSize: TPoint;
    ptMaxPosition: TPoint;
    ptMinTrackSize: TPoint;
    ptMaxTrackSize: TPoint;
  end;

(*)
  PPaintStruct = ^TPaintStruct;
  tagPAINTSTRUCT = packed record
    hdc: HDC;
    fErase: BOOL;
    rcPaint: TRect;
    fRestore: BOOL;
    fIncUpdate: BOOL;
    rgbReserved: array[0..31] of Byte;
  end;
  TPaintStruct = tagPAINTSTRUCT;
  PAINTSTRUCT = tagPAINTSTRUCT;
(*)

{ regions }
type
  TCombineMode = (
    RGN_AND,   // Creates the intersection of the two combined regions.
    RGN_COPY,  // Creates a copy of the region identified by hrgnSrc1.
    RGN_DIFF,  // Combines the parts of hrgnSrc1 that are not part of hrgnSrc2.
    RGN_OR,    // Creates the union of two combined regions.
    RGN_XOR    // Creates the union of two combined regions except for any overlapping areas.
  );

  PSecurityAttributes = Pointer;

{ StretchBlt() Modes }
  TStretchMode = (
    BLACKONWHITE = 1,
    WHITEONBLACK = 2,
    COLORONCOLOR = 3,
    HALFTONE     = 4
  );

const
  MAXSTRETCHBLTMODE   = 4;
  STRETCH_ANDSCANS    = BLACKONWHITE;
  STRETCH_ORSCANS     = WHITEONBLACK;
  STRETCH_DELETESCANS = COLORONCOLOR;
  STRETCH_HALFTONE    = HALFTONE;

{ Stock Logical Objects }
type
  TStockObjectBrush = (
    WHITE_BRUSH  = 0,
    LTGRAY_BRUSH = 1,
    GRAY_BRUSH   = 2,
    DKGRAY_BRUSH = 3,
    BLACK_BRUSH  = 4,
    NULL_BRUSH   = 5,
    DC_BRUSH     = 18
  );

  TStockObjectPen = (
    WHITE_PEN = 6,
    BLACK_PEN = 7,
    NULL_PEN  = 8,
    DC_PEN    = 19
  );

  TStockObjectFont = (
    OEM_FIXED_FONT      = 10,
    ANSI_FIXED_FONT     = 11,
    ANSI_VAR_FONT       = 12,
    SYSTEM_FONT         = 13,
    DEVICE_DEFAULT_FONT = 14,
    DEFAULT_PALETTE     = 15,
    SYSTEM_FIXED_FONT   = $10,
    DEFAULT_GUI_FONT    = 17
  );

const
  HOLLOW_BRUSH = NULL_BRUSH;
  STOCK_LAST   = DC_PEN;

type
  TSysMetrics = (
    SM_CXSCREEN,  SM_CYSCREEN,
    SM_CXVSCROLL, SM_CYVSCROLL,
    SM_CXHSCROLL, SM_CYHSCROLL,
    SM_CXSMICON,  SM_CYSMICON,
    SM_CXICON,    SM_CYICON,
    SM_CXBORDER,  SM_CYBORDER,
    SM_CXFRAME,   SM_CYFRAME,
    SM_CYCAPTION, SM_CXDLGFRAME,
    SM_CYDLGFRAME
  );

{$IFDEF LINUX}
  TSystemTime = record
    wYear: Word;
    wMonth: Word;
    wDayOfWeek: Word;
    wDay: Word;
    wHour: Word;
    wMinute: Word;
    wSecond: Word;
    wMilliseconds: Word;
  end;
{$ENDIF LINUX}

  { threads }
type
  TThreadPriority = Integer;

const
  tpIdle: TThreadPriority = 0;
  THREAD_PRIORITY_ERROR_RETURN = 255;

type { wait for object}
  TWOHandleArray = array[0..MAXIMUM_WAIT_OBJECTS - 1] of THandle;
  PWOHandleArray = ^TWOHandleArray;

  TWindowPlacement = packed record
    length: Cardinal;
    flags: Integer;
    showCmd: UInt;
    ptMinPosition: TPoint;
    ptMaxPosition: TPoint;
    rcNormalPosition: TRect;
  end;
  PWindowPlacement = ^TWindowPlacement;

type
  TTimerProc = procedure(Widget: QWidgetH; Msg: Cardinal; WMTimerId: Cardinal;  TickCount: Cardinal);
  TAppEventFilterMethod = function (Sender: QObjectH; Event: QEventH): Boolean; cdecl;
  PAppEventFilterMethod = ^TAppEventFilterMethod;

function InstallApplicationEventHook(EventFilter: TEventFilterMethod): QApplication_hookH;

procedure WakeUpGuiThread;
{
  Dummies for ... VCL
 asn: AFAIK use of RightToLeft or LeftToRight is automatic
}
const
  BiDiMode: TBiDiMode = bdLeftToRight; // asn: var?

function DrawTextBiDiModeFlagsReadingOnly: Longint;
function DrawTextBiDiModeFlags(Flags: Longint): Longint;
procedure ChangeBiDiModeAlignment(var Alignment: TAlignment);
function UseRightToLeftAlignment: Boolean;

{ Palette colors }
function GetSysColor(SysColor: Integer): TColorRef;  // windows SysColor !!
function SetSysColor(RefColor: TColor; TrueColor: TColorRef): Boolean;
function SetSysColors(Elements: Integer; const lpaElements;
  const lpaRgbValues): LongBool;

{
 QGraphics.ColorToRGB supports only
 TMappedColor = clActiveHighlightedText..clNormalForeground
 Returns clBlack for any other color !

  This implementation uses Instance.Palette and supports all colors
  if Instance = nil then it will use Application.MainForm, in that
  case clHighlightedText..clForeground is mapped to clNormalHighlightedText..clNormalForeground
  If the Color is an RGB value, clDefault, clNone,  it returns the Color itself.
}
function ColorToRGB(Color: TColor; Instance: TWidgetControl = nil): TColor;

function RGB(Red, Green, Blue: Integer): TColorRef;
function GetBValue(Col: TColorRef): Byte;
function GetGValue(Col: TColorRef): Byte;
function GetRValue(Col: TColorRef): Byte;
function pfDevice: TPixelFormat;

function SetRect(var R: TRect; Left, Top, Right, Bottom: Integer): LongBool;
function IsRectEmpty(R: TRect): LongBool;
function EqualRect(R1, R2: TRect): LongBool;
function UnionRect(var Dst: TRect; R1, R2: TRect): LongBool;
function CopyRect(var Dst: TRect; const Src: TRect): LongBool; overload;
function SubtractRect(var dR: TRect; const R1, R2: TRect): LongBool;
function CenterRect(InnerRect, OuterRect: TRect): TRect;
function PtInRect(const R: TRect; pt: TPoint): LongBool; overload;
function PtInRect(const R: TRect; X, Y: integer): LongBool; overload;
function IntersectRect(var R: TRect; const R1, R2: TRect): LongBool;
function PointInEllipse(pt: TPoint; BoundingRect: TRect): boolean;
function PtInEllipse(const R: TRect; pt: TPoint): LongBool;

{ brushes }
function CreateSolidBrush(Color: TColor): QBrushH;
function CreateHatchBrush(bStyle: BrushStyle; Color: TColor): QBrushH;
function DeleteObject(Handle: QBrushH): LongBool; overload;

function CreatePen(Style, Width: Integer; Color: TColor): QPenH;
function DeleteObject(Handle: QPenH): LongBool; overload;

function DPtoLP(Handle: QPainterH; var Points; Count: Integer): LongBool;
function LPtoDP(Handle: QPainterH; var Points; Count: Integer): LongBool;
function SetWindowOrgEx(Handle: QPainterH; X, Y: Integer; OldOrg: PPoint): LongBool;
function GetWindowOrgEx(Handle: QPainterH; Org: PPoint): LongBool; overload;
function GetWindowOrgEx(Handle: QPainterH; var Org: TPoint): LongBool; overload;
{ limited implementations of }
function BitBlt(DestDC: QPainterH; X, Y, Width, Height: Integer; SrcDC: QPainterH;
  XSrc, YSrc: Integer; Rop: RasterOp; IgnoreMask: Boolean = true): LongBool; overload;
function BitBlt(DestDC: QPainterH; X, Y, Width, Height: Integer; SrcDC: QPainterH;
  XSrc, YSrc: Integer; WinRop: Cardinal; IgnoreMask: Boolean = true): LongBool; overload;
{
 does the required start/stop painting if needed
 adjust x,y & XSrc,YSrc ico TControlCanvas (as used by TGraphicControl)
}
function BitBlt(DestCanvas: TCanvas; X, Y, Width, Height: Integer; SrcCanvas: TCanvas;
  XSrc, YSrc: Integer; WinRop: Cardinal; IgnoreMask: Boolean = true): LongBool; overload;

{
// Calculates coord of TopLeft in Paintdevice coordinates
// ((0,0) for bitmaps and TWidgetControl derived classes)
}
function PainterOffset(Canvas: TCanvas): TPoint;

function PatBlt(Handle: QPainterH; X, Y, Width, Height: Integer;
  WinRop: Cardinal): LongBool; overload;
function PatBlt(Canvas: TCanvas; X, Y, Width, Height: Integer;
  WinRop: Cardinal): LongBool; overload;

procedure CopyRect(DstCanvas: TCanvas; const Dest: TRect; Canvas: TCanvas;
  const Source: TRect); overload;
procedure BrushCopy(DstCanvas: TCanvas; const Dest: TRect; Bitmap: TBitmap;
  const Source: TRect; Color: TColor);

function StretchBlt(DestDC: QPainterH; dx, dy, dw, dh: Integer;
  SrcDC: QPainterH; sx, sy, sw, sh: Integer; WinRop: Cardinal;
  IgnoreMask: Boolean = True): LongBool; overload;
function StretchBlt(DestDC: QPainterH; dx, dy, dw, dh: Integer;
  SrcDC: QPainterH; sx, sy, sw, sh: Integer; Rop: RasterOp;
  IgnoreMask: Boolean = True): LongBool; overload;
function StretchBlt(DestCanvas: TCanvas; dx, dy, dw, dh: Integer;
  SrcCanvas: TCanvas; sx, sy, sw, sh: Integer; WinRop: Cardinal;
  IgnoreMask: Boolean = True): LongBool; overload;
function ScrollDC(Handle: QPainterH; dx, dy: Integer; var Scroll, Clip: TRect;
  Rgn: QRegionH; Update: PRect): LongBool;

{ TODO -oahuser : StretchBlt function should use the flag }
function GetStretchBltMode(DC: QPainterH): TStretchMode;
function SetStretchBltMode(DC: QPainterH; StretchMode: TStretchMode): TStretchMode;

function SetROP2(Handle: QPainterH; Rop: Integer): Integer; overload;
function GetROP2(Handle: QPainterH): Integer; overload;
function GetPixel(Handle: QPainterH; X, Y: Integer): TColorRef;
function SetPixel(Handle: QPainterH; X, Y: Integer; Color: TColor): TColorRef;
function SetTextColor(Handle: QPainterH; color: TColor): TColorRef;
function SetBkColor(Handle: QPainterH; color: TColor): TColorRef;
function GetBkMode(Handle: QPainterH): Integer;
function SetBkMode(Handle: QPainterH; BkMode: Integer): Integer;
function SetDCBrushColor(Handle: QPainterH; Color: TColor): TColorRef;
function SetDCPenColor(Handle: QPainterH; Color: TColor): TColorRef;
function SetPenColor(Handle: QPainterH; Color: TColor): TColorRef;
procedure SetPainterFont(Handle: QPainterH; Font: TFont);

function CreateCompatibleDC(Handle: QPainterH; Width: Integer = 1; Height: Integer = 1): QPainterH;
function CreateCompatibleBitmap(Handle: QPainterH; Width, Height: Integer): QPixmapH;
function CreateBitmap(Width, Height: Integer; Planes, BitCount: Longint; Bits: Pointer): QPixmapH;
function CreateDIBitmap(Handle: QPainterH; var InfoHeader: TBitmapInfoHeader;
  dwUsage: Longword; InitBits: PChar; var InitInfo: TBitmapInfo; wUsage: Cardinal): QPixmapH;

function GetBitmapBits(Bitmap: QPixmapH; Count: Longint; Bits: Pointer): Longint;
function SetBitmapBits(Bitmap: QPixmapH; Count: Longint; Bits: Pointer): Longint;

function GetObject(Handle: QPixmapH; Size: Cardinal; Data: PtagBITMAP): Boolean; overload;
function GetObject(Handle: QPenH; Size: Cardinal; Data: PLogPen): Boolean; overload;

function GetStockObject(fnObject: TStockObjectBrush): QBrushH; overload;
function GetStockObject(fnObject: TStockObjectPen): QPenH; overload;
function GetStockObject(fnObject: TStockObjectFont): QFontH; overload;

function GetMapMode(Handle: QPainterH): TMapMode;
function SetMapMode(Handle: QPainterH; MapMode: TMapMode): TMapMode;

// DeleteObject is intended to destroy the Handle returned by CreateCompatibleBitmap
// (it destroys the Painter AND PaintDevice)
function DeleteObject(Handle: QPainterH): LongBool; overload;
function DeleteObject(Handle: QPixmapH): LongBool; overload;
function GetDC(Handle: QWidgetH): QPainterH; overload;
function GetDC(Handle: Integer): QPainterH; overload;
function GetWindowDC(Handle: QWidgetH): QPainterH;

function ReleaseDC(wdgtH: QWidgetH; Handle: QPainterH): Integer; overload;
function ReleaseDC(wdgtH: Integer; Handle: QPainterH): Integer; overload;
function DeleteDC(Handle: QPainterH): LongBool;

function SaveDC(Handle: QPainterH): Integer;
{ only negative and zero values of nSaveDC are supported }
function RestoreDC(Handle: QPainterH; nSavedDC: Integer): LongBool;

function ExtTextOut(Handle: QPainterH; X, Y: Integer; WinFlags: Cardinal;
  R: PRect; const Text: WideString; Len: Integer; lpDx: Pointer): LongBool; overload;
function ExtTextOut(Handle: QPainterH; X, Y: Integer; WinFlags: Cardinal;
  R: PRect; pText: PChar; Len: Integer; lpDx: Pointer): LongBool; overload;
function ExtTextOutW(Handle: QPainterH; X, Y: Integer; WinFlags: Cardinal;
  R: PRect; pText: PWideChar; Len: Integer; lpDx: Pointer): LongBool;

{ TODO -oahuser : text functions (ExtTextOut, TextOut) should use these flags }
function SetTextAlign(Handle: QPainterH; Mode: Cardinal): Cardinal;
function GetTextAlign(Handle: QPainterH): Cardinal;

function FillRect(Handle: QPainterH; const R: TRect; Brush: QBrushH): LongBool;

function GetCurrentPositionEx(Handle: QPainterH; pos: PPoint): LongBool;
function GetTextExtentPoint32(Handle: QPainterH; const Text: WideString; Len: Integer;
  var Size: TSize): LongBool; overload;
function GetTextExtentPoint32(Handle: QPainterH; pText: PChar; Len: Integer;
  var Size: TSize): LongBool; overload;
function GetTextExtentPoint32W(Handle: QPainterH; pText: PWideChar; Len: Integer;
  var Size: TSize): LongBool;
function GetTextExtentPoint32(Canvas: TCanvas; const Text: WideString; Len: Integer;
  var Size: TSize): LongBool; overload;

function FrameRect(Handle: QPainterH; const R: TRect; Brush: QBrushH): LongBool; overload;
procedure FrameRect(Canvas: TCanvas; const R: TRect); overload;
function FrameRgn(Handle: QPainterH; Region: QRegionH; Brush: QBrushH; Width, Height: integer): LongBool;

function DrawFocusRect(Handle: QPainterH; const R: TRect): LongBool;
function InvertRect(Handle: QPainterH; const R: TRect): LongBool;
function Rectangle(Handle: QPainterH; Left, Top, Right, Bottom: Integer): LongBool;
function RoundRect(Handle: QPainterH; Left, Top, Right, Bottom, X3, Y3: Integer): LongBool;
function Ellipse(Handle: QPainterH; Left, Top, Right, Bottom: Integer): LongBool;
function LineTo(Handle: QPainterH; X, Y: Integer): LongBool;
function MoveToEx(Handle: QPainterH; X, Y: Integer; Point: PPoint): LongBool;
function DrawIcon(Handle: QPainterH; X, Y: Integer; hIcon: QPixmapH): LongBool;
function DrawIconEx(Handle: QPainterH; X, Y: Integer; hIcon: QPixmapH;
  W, H: Integer; istepIfAniCur: Integer; hbrFlickerFreeDraw: QBrushH;
  diFlags: Cardinal): LongBool;

function DrawFrameControl(Handle: QPainterH; const Rect: TRect; uType,
  uState: Longword): LongBool; overload;
  { missing DrawFrameControl flags:
      DFC_SCROLL: DFCS_SCROLLSIZEGRIP, DFCS_SCROLLSIZEGRIPRIGHT
      DFC_BUTTON: DFCS_BUTTONRADIOIMAGE, DFCS_BUTTONRADIOMASK, DFCS_BUTTON3STATE
      DFC_POPUPMENU: all }
function DrawFrameControl(Canvas: TCanvas; const Rect: TRect; uType,
  uState: Longword): LongBool; overload;
function DrawEdge(Handle: QPainterH; var Rect: TRect; Edge: Cardinal;
  Flags: Cardinal): LongBool;

procedure RequiredState(ACanvas: TCanvas; State: TCanvasState);

{ limited implementation of }
function DrawText2(Handle: QPainterH; var Text: WideString; Len: Integer;
  var R: TRect; WinFlags: Integer): Integer; overload;
function DrawText(Handle: QPainterH; Text: PAnsiChar; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: Integer = 0): Integer; overload;
function DrawText(Handle: QPainterH; Text: TCaption; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: Integer = 0): Integer; overload;
function DrawTextW(Handle: QPainterH; Text: PWideChar; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: Integer = 0): Integer; overload;
function DrawText(Handle: QPainterH; var Text: WideString; Len: Integer;
  x,y, w, h: Integer; WinFlags: Integer; Angle: Integer = 0): Integer;  overload;
function DrawText(Handle: QPainterH; var Text: WideString; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: Integer = 0): Integer; overload;
{
 additional functionality DrawText(Canvas, .....
 - canvas start/stop
 - sets painterfont
}
function DrawText(Canvas :TCanvas; Text: TCaption; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: integer = 0): Integer; overload;
function DrawText(Canvas: TCanvas; Text: PAnsiChar; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: Integer = 0): Integer; overload;
function DrawTextW(Canvas :TCanvas; Text: PWideChar; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: Integer = 0): Integer; overload;
function DrawTextEx(Handle: QPainterH; var Text: WideString; Len: Integer;
  var R: TRect; WinFlags: Integer; DTParams: Pointer): Integer; overload;
function DrawTextEx(Handle: QPainterH; Text: PChar; Len: Integer;
  var R: TRect; WinFlags: Integer; DTParams: Pointer): Integer; overload;

{ limited implementation of }
function GetSystemMetrics(PropItem: TSysMetrics): Integer;

{ (very) limited implementations of }
function GetDeviceCaps(Handle: QPainterH; devcap: TDeviceCap): Integer; overload;
function GetDeviceCaps(Handle: QPaintDeviceH; devcap: TDeviceCap): Integer; overload;

function GetTextMetrics(Handle: QPainterH; var tt: TTextMetric): Integer;
// widget related  function
function BringWindowToTop(Handle: QWidgetH): LongBool;
function CloseWindow(Handle: QWidgetH): LongBool;
function DestroyWindow(Handle: QWidgetH): LongBool;
function EnableWindow(Handle: QWidgetH; Value: Boolean): LongBool;
function GetClientRect(Handle: QWidgetH; var R: TRect): LongBool;
function GetFocus: QWidgetH;
function GetParent(Handle: QWidgetH): QWidgetH;
function SetParent(hWndChild, hWndNewParent: QWidgetH): QWidgetH;
function GetWindowPlacement(Handle: QWidgetH; W: PWindowPlacement): LongBool;
function GetWindowRect(Handle: QWidgetH; var  R: TRect): LongBool;
function WindowFromDC(Handle: QPainterH): QWidgetH; overload;
function WindowFromDC(Handle: QPaintDeviceH): QWidgetH; overload;

{ hWndParent is ignored under Linux }
function ChildWindowFromPoint(hWndParent: QWidgetH; Point: TPoint): QWidgetH;

function WindowFromPoint(Point: TPoint): QWidgetH;
function FindCLXWindow(const Point: TPoint): TWidgetControl;
function FindVCLWindow(const Point: TPoint): TWidgetControl;
function GetClassName(Handle: QWidgetH; Buffer: PChar; MaxCount: Integer): Integer;
function IsIconic(Handle: QWidgetH): LongBool;

function HWND_DESKTOP: QWidgetH;
function GetDesktopWindow: QWidgetH;
function GetActiveWindow: QWidgetH;
function GetForegroundWindow: QWidgetH;
procedure SetActiveWindow(Handle: QWidgetH);
function InvalidateRect(Handle: QWidgetH; R: PRect; EraseBackground: Boolean): LongBool;
function ValidateRect(hWnd: QWidgetH; R: PRect): LongBool;
function UpdateWindow(Handle: QWidgetH): LongBool;
function IsChild(ParentHandle, ChildHandle: QWidgetH): LongBool;
function IsWindowEnabled(Handle: QWidgetH): LongBool;
function IsWindowVisible(Handle: QWidgetH): LongBool;
function MapWindowPoints(WidgetTo, WidgetFrom: QWidgetH; var Points; nr: Cardinal): Integer;
function SetFocus(Handle: QWidgetH): QWidgetH;
function SetForegroundWindow(Handle: QWidgetH): LongBool;
function SetWindowPlacement(Handle: QWidgetH; W: PWindowPlacement): LongBool;
function SwitchToThisWindow(Handle: QWidgetH; Restore: Boolean): LongBool;

function ClientToScreen(Handle: QWidgetH; var Point: TPoint): LongBool;
function ScreenToClient(Handle: QWidgetH; var Point: TPoint): LongBool;
function SmallPointToPoint(const P: TSmallPoint): TPoint;
function PointToSmallPoint(const P: TPoint): TSmallPoint;

function SetWindowPos(Wnd, WndInsertAfter: QWidgetH; X, Y, cx, cy: Integer;
  uFlags: Longword): LongBool; overload;
function SetWindowPos(Wnd, WndInsertAfter: Cardinal; X, Y, cx, cy: Integer;
  uFlags: Longword): LongBool; overload;
function SetWindowPos(Wnd: QWidgetH; WndInsertAfter: Cardinal; X, Y, cx, cy: Integer;
  uFlags: Longword): LongBool; overload;

{ Controls.pas implements, so we need it, too }
procedure MoveWindowOrg(DC: QPainterH; DX, DY: Integer);

function ShowWindow(Handle: QWidgetH; showCmd: UInt): LongBool;

function MessageBox(parent: QWidgetH; Text, Caption: string; WinFlags: Cardinal): Integer; overload;
function MessageBox(parent: QWidgetH; Text, Caption: WideString; WinFlags: Cardinal): Integer; overload;
function MessageBox(parent: QWidgetH; pText, pCaption: PChar; WinFlags: Cardinal): Integer; overload;
//function MessageBoxW(parent: QWidgetH; pText, pCaption: PWideChar; WinFlags: Cardinal): Integer;

function SelectObject(Handle: QPainterH; Font: QFontH): QFontH; overload;
function SelectObject(Handle: QPainterH; Brush: QBrushH): QBrushH; overload;
function SelectObject(Handle: QPainterH; Pen: QPenH): QPenH; overload;
// limited to CreateCompatibleDC Handles.
function SelectObject(Handle: QPainterH; Bitmap: QPixmapH): QPixmapH; overload;

function CombineRgn(DestRgn, Source1, Source2: QRegionH; Operation: TCombineMode): Integer;
function CreateEllipticRgn(Left, Top, Right, Bottom: Integer): QRegionH;
function CreateEllipticRgnIndirect(Rect: TRect): QRegionH;
//function CreatePolygonRgn(p1: TPointArray; FillMode: Integer): QRegionH;
function CreatePolygonRgn(const Points; Count, FillMode: Integer): QRegionH;
function CreateRectRgn(Left, Top, Right, Bottom: Integer): QRegionH;
function CreateRectRgnIndirect(Rect: TRect): QRegionH;
function CreateRoundRectRgn(x1, y1, x2, y2, WidthEllipse, HeightEllipse: Integer): QRegionH;
function DeleteObject(Region: QRegionH): LongBool; overload;
function EqualRgn(Rgn1, Rgn2: QRegionH): LongBool;
function FillRgn(Handle: QPainterH; Region: QRegionH; Brush: QBrushH): LongBool;
function GetClipRgn(Handle: QPainterH; rgn: QRegionH): Integer;
function ExcludeClipRect(Handle: QPainterH; X1, Y1, X2, Y2: Integer): Integer; overload;
function ExcludeClipRect(Handle: QPainterH; const R: TRect): Integer; overload;
function IntersectClipRect(Handle: QPainterH; X1, Y1, X2, Y2: Integer): Integer; overload;
function IntersectClipRect(Handle: QPainterH; const R: TRect): Integer; overload;
function InvertRgn(Handle: QPainterH; Region: QRegionH): LongBool;
function OffsetClipRgn(Handle: QPainterH; X, Y: Integer): Integer;
function OffsetRgn(Region: QRegionH; X, Y: Integer): Integer;
function PtInRegion(Rgn: QRegionH; X, Y: Integer): Boolean;
function RectInRegion(RGN: QRegionH; const Rect: TRect): LongBool;
function SelectClipRgn(Handle: QPainterH; Region: QRegionH): Integer; overload;
function SelectClipRgn(Handle: QPainterH; Region: Integer): Integer; overload;
function SetRectRgn(Rgn: QRegionH; X1, Y1, X2, Y2: Integer): LongBool;
function SetWindowRgn(Handle: QWidgetH; Region: QRegionH; Redraw: LongBool): Integer;
  { SetWindowRgn limitation: The region must have negative top coordinate in
    order to contain the window's caption bar. }
  { asn: Qt operates on the client rectangle of the form: windows/x11 titlebar
         and windows/x11 borders are not included, hence the negative values }
function GetWindowRgn(Handle: QWidgetH; Region: QRegionH): Integer;

{ viewports }
function SetViewportExtEx(Handle: QPainterH; XExt, YExt: Integer; Size: PSize): LongBool;
function SetViewPortOrgEx(Handle: QPainterH; X, Y: Integer; OldOrg: PPoint): LongBool;
function GetViewportExtEx(Handle: QPainterH; Size: PSize): LongBool;

{ Text clipping }
function TruncatePath(const FilePath: string; Canvas: TCanvas; MaxLen: Integer): string;
function TruncateName(const Name: WideString; Canvas: TCanvas; MaxLen: Integer; QtFlags: integer = 0): WideString;

procedure TextOutAngle(Handle: QPainterH; Angle, Left, Top: Integer; Text: WideString); overload;
procedure TextOutAngle(ACanvas: TCanvas; Angle, Left, Top: Integer; Text: WideString); overload;

procedure CopyMemory(Dest: Pointer; Src: Pointer; Len: Cardinal);
procedure FillMemory(Dest: Pointer; Len: Cardinal; Fill: Byte);
procedure MoveMemory(Dest: Pointer; Src: Pointer; Len: Cardinal);
procedure ZeroMemory(Dest: Pointer; Len: Cardinal);

{ ------------ Caret -------------- }
function CreateCaret(Widget: QWidgetH; Pixmap: QPixmapH; Width, Height: Integer): Boolean; overload;
function CreateCaret(Widget: QWidgetH; ColorCaret: Cardinal; Width, Height: Integer): Boolean; overload;
function GetCaretBlinkTime: Cardinal;
function SetCaretBlinkTime(uMSeconds: Cardinal): LongBool;
function HideCaret(Widget: QWidgetH): Boolean;
function ShowCaret(Widget: QWidgetH): Boolean;
function SetCaretPos(X, Y: Integer): Boolean;
function GetCaretPos(var Pt: TPoint): Boolean;
function DestroyCaret: Boolean;

procedure SetCursorPos(X, Y: integer);
function GetCursorPos(var P: TPoint): LongBool;	

function GetDoubleClickTime: Cardinal;
function SetDoubleClickTime(Interval: Cardinal): LongBool;
function ReleaseCapture: LongBool;
function SetCapture(Widget: QWidgetH): QWidgetH;
function GetCapture: QWidgetH;
function SetCursor(Handle: QCursorH; Save: Boolean = False): QCursorH;
function Win2QtAlign(Flags: Integer): Integer;
function QtStdAlign(Flags: Integer): Word;

function IsCharAlpha(Ch: Char): LongBool;
function IsCharAlphaNumeric(Ch: Char): LongBool;

{ Messaging }
function Perform(Control: TControl; Msg: Cardinal; WPar, LPar: Longint): Longint;
function PostMessage(Receiver: QWidgetH; MsgId: Integer; WPar, LPar: Longint): LongBool; overload;
function PostMessage(AControl: TWidgetControl; MsgId: Integer; WPar, LPar: Longint): LongBool; overload;
{ SendMessage synchronizes with the main (event handling) thread. }
function SendMessage(Receiver: QWidgetH; MsgId: Integer; WPar, LPar: Longint): Integer; overload;
function SendMessage(AControl: TWidgetControl; MsgId: Integer; WPar, LPar: Longint): Integer; overload;

// procedure IgnoreNextEvents(Handle: QObjectH; const Events: array of QEventType);
{ equivalent to "while PeekMessage(h, evstart, evend, PM_REMOVE" }
//procedure IgnoreMouseEvents(Handle: QObjectH);
function IgnoreMouseEvents(Handle: QObjectH; Event: QEventH): boolean;

function SetTimer(Wnd: QWidgetH; WMTimerID, Elapse: Cardinal;
  TimerFunc: TTimerProc): Cardinal; overload;
function SetTimer(Instance: TWidgetControl; WMTimerID, Elapse: Cardinal;
  TimerFunc: TTimerProc): Cardinal; overload;
function KillTimer(Wnd: QWidgetH; WMTimerId: Cardinal): LongBool; overload;
function KillTimer(Instance: TWidgetControl; WMTimerId: Cardinal): LongBool; overload;

function MAKEIPRANGE(low, high: Byte): integer;
function MAKEIPADDRESS(b1, b2, b3, b4: cardinal): integer;
function FIRST_IPADDRESS(x: cardinal): cardinal;
function SECOND_IPADDRESS(x: cardinal): cardinal;
function THIRD_IPADDRESS(x: cardinal): cardinal;
function FOURTH_IPADDRESS(x: cardinal): cardinal;

{ wrappers for Windows, implementations for Linux}
function ShellExecute(Handle: QWidgetH; Operation, FileName, Parameters,
  Directory: PChar; ShowCmd: Integer): THandle; overload;
function ShellExecute(Handle: QWidgetH; const Operation, FileName, Parameters,
  Directory: string; ShowCmd: Integer): THandle; overload;
function ShellExecute(Handle: Integer; Operation, FileName, Parameters,
  Directory: PChar; ShowCmd: Integer): THandle; overload;

{ Platform dependendant wrappers}
function GetTickCount: Cardinal;
function GetUserName(Buffer: PChar; var Size: Cardinal): LongBool;
function GetComputerName(Buffer: PChar; var Size: Cardinal): LongBool;
procedure OutputDebugString(lpOutputString: PAnsiChar); overload;
procedure OutputDebugString(OutputString: AnsiString); overload;
function InterlockedIncrement(var I: Integer): Integer;
function InterlockedDecrement(var I: Integer): Integer;
function InterlockedExchange(var A: Integer; B: Integer): Integer;
function InterlockedExchangeAdd(var A: Integer; B: Integer): Integer;
function QueryPerformanceCounter(var PerformanceCount: int64): LongBool;
function QueryPerformanceFrequency(var Frequency: int64): LongBool;

{$IFDEF MSWINDOWS}
function GetKeyState(nVirtKey: Integer): SmallInt;
//
// Taken from QDialogs
//
procedure EnableTaskWindows(WindowList: Pointer);
function DisableTaskWindows(ActiveWindow: Windows.HWnd): Pointer;
{$ENDIF MSWINDOWS}

function CopyFile(lpExistingFileName, lpNewFileName: PChar;
  bFailIfExists: LongBool): LongBool; overload;

function CopyFileA(lpExistingFileName, lpNewFileName: PAnsiChar;
  bFailIfExists: LongBool): LongBool;
function CopyFileW(lpExistingFileName, lpNewFileName: PWideChar;
  bFailIfExists: LongBool): LongBool;
{$IFDEF LINUX}
function CopyFile(const Source, Destination: string;
  FailIfExists: Boolean): LongBool; overload;

function FileGetSize(const FileName: string): Cardinal;
function FileGetAttr(const FileName: string): Integer;
function FileGetTime(const FileName: string): Integer;
function MakeIntResource(Value: Integer): PChar;
function MakeWord(A, B: Byte): Word;
function MakeLong(A, B: Word): Longint;
function HiWord(L: DWORD): Word;
function HiByte(W: Word): Byte;

procedure GetLocalTime(var st: TSystemTime);

procedure MessageBeep(Value: Integer);   // value ignored

function CoCreateGUID(out Guid: TGUID): HResult;

function Succeeded(Res: HResult): Boolean;
function Failed(Res: HResult): Boolean;
function ResultCode(Res: HResult): Integer;

function GetCurrentProcess: THandle;

function TerminateThread(ThreadID: TThreadID; RetVal: Integer): LongBool;
{
 NOTE:
 The Windows API's  SuspendThread & ResumeThread are functions.
 With QWindows / Linux these are procedures
}
function SuspendThread(ThreadID: TThreadID): LongBool;
function ResumeThread(ThreadID: TThreadID): LongBool;
function GetThreadPolicy(ThreadID: TThreadID): Integer;
procedure SetThreadPolicy(ThreadID: TThreadID; value: Integer);
function GetThreadPriority(ThreadID: TThreadID): Integer;
function SetThreadPriority(ThreadID: TThreadID; priority: Integer): LongBool;

function VirtualProtect(lpAddress: Pointer; dwSize, flNewProtect: Cardinal;
  lpflOldProtect: Pointer): LongBool; overload;
function VirtualProtect(lpAddress: Pointer; dwSize, flNewProtect: Cardinal;
  var OldProtect: Cardinal): LongBool; overload;

function ReadProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer;
  lpBuffer: Pointer; nSize: LongWord; var lpNumberOfBytesRead: Longword): LongBool;
function WriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer;
  lpBuffer: Pointer; nSize: LongWord; var lpNumberOfBytesWritten: Longword): LongBool;
procedure FlushInstructionCache(PID: cardinal; OrgCalProc: Pointer; size: Integer);

{ Limitations:
    - GetKeyState calls GetAsyncKeyState
    - GetAsyncKeyState only supports VK_SHIFT, VK_CONTROL and VK_MENU }
function GetKeyState(nVirtKey: Integer): SmallInt;
function GetAsyncKeyState(vKey: Integer): SmallInt;

// events are limited to the process
function CreateEvent(EventAttributes: PSecurityAttributes;
  ManualReset, InitialState: LongBool; Name: PChar): THandle;
function OpenEvent(DesiredAccess: Longword; InheritHandle: LongBool;
  Name: PChar): THandle;
{$ENDIF LINUX}
function SetEvent(Event: THandle): LongBool;
function ResetEvent(Event: THandle): LongBool;
function PulseEvent(Event: THandle): LongBool; // calls SetEvent()

{$IFDEF LINUX}
function CreateMutex(MutexAttributes: PSecurityAttributes; InitialOwner: LongBool;
  Name: PChar): THandle;
function OpenMutex(DesiredAccess: Longword; InheritHandle: Boolean;
  Name: PChar): THandle;
function ReleaseMutex(Mutex: THandle): LongBool;

function CreateSemaphore(SemaphoreAttributes: PSecurityAttributes;
  InitialCount, MaximumCount: Longint; Name: PChar): THandle;
function OpenSemaphore(DesiredAccess: Longword; InheritHandle: LongBool;
  Name: PChar): THandle;
function ReleaseSemaphore(Semaphore: THandle; ReleaseCount: Longint;
  PreviousCount: PInteger): LongBool;

function semtimedop(semid: Integer; sops: PSemaphoreBuffer;
  nsops: size_t; timeout: PTimeSpec): Integer; {$IFDEF DEBUG}cdecl;{$ENDIF}

function WaitForSingleObject(Handle: THandle; Milliseconds: Cardinal): Cardinal;

{ Operate on semaphore.  }

function WaitForMultipleObjects(Count: Cardinal; Handles: PWOHandleArray;
  WaitAll: LongBool; Milliseconds: Cardinal): Cardinal;

{ all Handles are TObject derived classes }

function CloseHandle(hObject: THandle): LongBool;

{ memory management }
function GlobalAllocPtr(Flags: Integer; Bytes: Longint): Pointer;
function GlobalReAllocPtr(P: Pointer; Bytes: Longint; Flags: Integer): Pointer;
function GlobalFreePtr(P: Pointer): THandle;

function GlobalAlloc(uFlags: Cardinal; dwBytes: Longword): Cardinal;
function GlobalReAlloc(hMem: Cardinal; dwBytes: Longword; uFlags: Cardinal): Cardinal;
function GlobalSize(hMem: Cardinal): Longword;
function GlobalLock(hMem: Cardinal): Pointer;
function GlobalHandle(Mem: Pointer): Cardinal;
function GlobalUnlock(hMem: Cardinal): LongBool;
function GlobalFree(hMem: Cardinal): Cardinal;
{$ENDIF LINUX}


{$IFDEF LINUX}
var
  Shell: string = 'kfmclient exec'; // KDE. Gnome equivalent ?
  IpcDirectory: string = '/tmp/kylix/ipc'; // for named semaphores/mutex
{$ENDIF LINUX}

implementation

{$IFDEF MSWINDOWS}
uses
  ShellAPI, DateUtils;
{$ENDIF MSWINDOWS}
{$IFDEF LINUX}
uses
  Xlib;
{$ENDIF LINUX}

const
  VersionInfo = '$URL$' + #13 + '$Revision$' + #13 + '$Date$' + #13;

type
  THackCanvas = class(TCanvas);
  TOpenWidgetControl = class(TWidgetControl);

var
  AppEventHook: TAppEventHook = nil;

procedure AppEventHookNeeded;
begin
  if not Assigned(AppEventHook) then
    AppEventHook := TAppEventHook.Create(nil);
end;
{ used internally }

procedure MapPainterLP(Handle: QPainterH; var x, y: Integer); overload;
begin
  QWMatrix_map(QPainter_worldMatrix(Handle), x, y, @x, @y);
end;

procedure MapPainterLP(Handle: QPainterH; var x0, y0, x1, y1: Integer); overload;
var
  Matrix: QWMatrixH;
begin
  Matrix := QPainter_worldMatrix(Handle);
  QWMatrix_map(Matrix, x0, y0, @x0, @y0);
  QWMatrix_map(Matrix, x1, y1, @x1, @y1);
end;

procedure MapPainterLP(Handle: QPainterH; var Pt: TPoint); overload;
begin
  QWMatrix_map(QPainter_worldMatrix(Handle), PPoint(@Pt), PPoint(@Pt));
end;

procedure MapPainterLP(Handle: QPainterH; var R: TRect); overload;
begin
  QWMatrix_map(QPainter_worldMatrix(Handle), PRect(@R), PRect(@R));
end;

procedure MapPainterLPwh(Handle: QPainterH; var Width, Height: Integer); overload;
var
  Matrix: QWMatrixH;
begin
  Matrix := QPainter_worldMatrix(Handle);

  Matrix := QWMatrix_create(QWMatrix_m11(Matrix), QWMatrix_m12(Matrix),
    QWMatrix_m21(Matrix), QWMatrix_m22(Matrix), 0, 0);  // no translation
  try
    QWMatrix_map(Matrix, Width, Height, @Width, @Height);
  finally
    QWMatrix_destroy(Matrix);
  end;
end;

function CreateMappedRegion(Handle: QPainterH; Region: QRegionH): QRegionH;
var
  Matrix, RelativeMatrix: QWMatrixH;
  Bmp1, Bmp2: QBitmapH;
  Painter: QPainterH;
  R, FillR: TRect;
  Brush: QBrushH;
begin
  Result := QRegion_create(Region);
  Matrix := QPainter_worldMatrix(Handle);

  if (QWMatrix_m11(Matrix) = 1) and (QWMatrix_m12(Matrix) = 0) and
     (QWMatrix_m21(Matrix) = 0) and (QWMatrix_m22(Matrix) = 1) then
  begin
    if (QWMatrix_dx(Matrix) <> 0) or (QWMatrix_dy(Matrix) <> 0) then
      QRegion_translate(Result, Round(QWMatrix_dx(Matrix)), Round(QWMatrix_dy(Matrix)));
  end
  else
  begin
    RelativeMatrix := QWMatrix_create(
      QWMatrix_m11(Matrix), QWMatrix_m12(Matrix),
      QWMatrix_m21(Matrix), QWMatrix_m22(Matrix),
      0, 0
    );
    QRegion_boundingRect(Result, @R);
    QRegion_translate(Result, -R.Left, -R.Top);

    Bmp1 := QBitmap_create(Abs(R.Right - R.Left), Abs(R.Bottom - R.Top), True,
      QPixmapOptimization_DefaultOptim);
    try
      FillR := R;
      OffsetRect(FillR, -R.Left, -R.Top);

      Painter := QPainter_create(Bmp1);
      try
        QPainter_setClipRegion(Painter, Result);
        QPainter_setClipping(Painter, True);

        Brush := GetStockObject(BLACK_BRUSH);
        QPainter_fillRect(Painter, @FillR, Brush);
        DeleteObject(Brush);
      finally
        QPainter_destroy(Painter);
      end;
      QRegion_destroy(Result);

      QWMatrix_map(RelativeMatrix, PRect(@R), PRect(@R));

      Bmp2 := QBitmap_create(Abs(R.Right - R.Left), Abs(R.Bottom - R.Top), False,
        QPixmapOptimization_DefaultOptim);
      try
        QPixmap_xForm(Bmp1, Bmp2, RelativeMatrix);
        Result := QRegion_create(Bmp2);
      finally
        QBitmap_destroy(Bmp2);
      end;
    finally
      QBitmap_destroy(Bmp1);
    end;
  end;
end;

{---------------------------------------}
type
  PPainterInfo = ^TPainterInfo;
  TPainterInfo = record
    Painter: QPainterH;
    IsCompatibleDC: Boolean;
    TextAlignment: Cardinal;
    StetchBltMode: TStretchMode;
    MapMode: TMapMode;
  end;

var
  PainterInfos: TList = nil;

function GetPainterInfo(Handle: QPainterH; var Info: PPainterInfo): Boolean;
var
  i: Integer;
begin
  Result := False;
  Info := nil;
  if PainterInfos <> nil then
  begin
    for i := 0 to PainterInfos.Count - 1 do
      if PPainterInfo(PainterInfos[i])^.Painter = Handle then
      begin
        Result := True;
        Info := PPainterInfo(PainterInfos[i]);
        Exit;
      end;
  end;
end;

function NewPainterInfo(Handle: QPainterH): PPainterInfo;
begin
  New(Result);
  Result^.Painter := Handle;
  Result^.IsCompatibleDC := False;
  Result^.TextAlignment := TA_LEFT or TA_TOP;
  Result^.StetchBltMode := STRETCH_DELETESCANS;
  Result^.MapMode := MM_TEXT;

  if PainterInfos = nil then
    PainterInfos := TList.Create;
  PainterInfos.Add(Result);
end;

function SetPainterInfo(Handle: QPainterH): PPainterInfo;
var
  i: Integer;
begin
  Result := nil;
  if PainterInfos <> nil then
  begin
    for i := 0 to PainterInfos.Count - 1 do
      if PPainterInfo(PainterInfos[i])^.Painter = Handle then
      begin
        Result := PPainterInfo(PainterInfos[i]);
        Exit;
      end;
  end;
  if Result = nil then
    Result := NewPainterInfo(Handle);
end;

procedure DeletePainterInfo(Handle: QPainterH);
var
  P: PPainterInfo;
begin
  if PainterInfos <> nil then
  begin
    if GetPainterInfo(Handle, P) then
    begin
      PainterInfos.Delete(PainterInfos.IndexOf(P));
      Dispose(P);
    end;
  end;
end;

procedure FreePainterInfos;
var
  i: Integer;
begin
  if PainterInfos <> nil then
  begin
    for i := 0 to PainterInfos.Count - 1 do
      Dispose(PPainterInfo(PainterInfos[i]));
    PainterInfos.Free;
  end;
end;
{----------------------------------------}

procedure WakeUpGuiThread;
begin
  QApplication_wakeUpGuiThread(Application.Handle);
end;

function DrawTextBiDiModeFlagsReadingOnly: Longint;
begin
  Result := 0;
end;

function DrawTextBiDiModeFlags(Flags: Longint): Longint;
begin
  Result := Flags;
end;

procedure ChangeBiDiModeAlignment(var Alignment: TAlignment);
begin
end;

function UseRightToLeftAlignment: Boolean;
begin
  Result := False;
end;

function GetSysColor(SysColor: Integer): TColorRef;
// VCL / windows colors
begin
  if (SysColor >= 0) and (SysColor <= COLOR_ENDCOLORS) then
    SysColor := GetSysColor( Win2TColor[SysColor] );
  case SysColor of
    clInfoBk:
      Result := TColorRef(Application.HintColor);
    clDeskTop:
      Result := TColorRef(QColorColor(QWidget_BackgroundColor(QApplication_desktop)));
  else
    Result := TColorRef(Application.Palette.GetColor(SysColor));
  end;
end;

const
  ColorRoles: array[1..15] of TColorRole =(
    crForeground, crButton, crLight, crMidlight, crDark, crMid,
    crText, crBrightText, crButtonText, crBase, crBackground, crShadow,
    crHighlight, crHighlightText, crNoRole);

function SetSysColor(RefColor: TColor; TrueColor: TColorRef): Boolean;
begin
  with Application.Palette do // asn: positive values or only rgb values?
    if TrueColor >= TColor(0)  then
    begin
      Result := True;
      case RefColor of
        clNormalNoRole..clNormalForeground:
          SetColor(cgInactive, ColorRoles[-(RefColor+cloNormal)], TrueColor);
        clDisabledHighlightedText..clDisabledForeground:
          SetColor(cgDisabled, ColorRoles[-(RefColor+cloDisabled)], TrueColor);
        clActiveNoRole..clActiveForeground:
          SetColor(cgActive, ColorRoles[-(RefColor+cloActive)], TrueColor);
      else
        Result := False
      end;
    end
    else  // if
      Result := False;   // only rgb values are accepted (asn: see remark above)

end;

function SetSysColors(Elements: Integer; const lpaElements;
  const lpaRgbValues): LongBool;
var
  i: Integer;
  refcolor : PColor;
  realcolor : PColor;
begin
  Result := True;
  refcolor := PColor(lpaElements);
  realcolor := PColor(lpaRGBvalues);
  Application.Palette.BeginUpdate;
  try
    for i := 0 to Elements-1 do
    begin
      if not SetSysColor( refcolor^, realcolor^)
      then
        Result := False;
      inc(refcolor);
      inc(realcolor);
    end;
  finally
    Application.Palette.EndUpdate;
  end;
end;

type
  TStockObjectResource = class(TObject)
  private
    FStockObject: Integer;
    FHandle: Pointer;
    FRefCount: Integer;
  public
    constructor Create(AHandle: Pointer; AStockObject: Integer);
    destructor Destroy; override;
    function AddRef: Pointer;
    procedure Release;

    property Handle: Pointer read FHandle;
    property StockObject: Integer read FStockObject;
  end;

  TStockObjectList = class(TObjectList)
  public
    function FindStockObject(AStockObject: Integer): TStockObjectResource;
    class function ReleaseStockObject(AHandle: Pointer): Boolean;
  end;

var
  StockObjectList: TStockObjectList = nil;
  StockObjectListCritSect: TRTLCriticalSection;

constructor TStockObjectResource.Create(AHandle: Pointer; AStockObject: Integer);
begin
  inherited Create;
  AddRef;
  FHandle := AHandle;
  FStockObject := AStockObject;
end;

destructor TStockObjectResource.Destroy;
type
  Int = Integer;
begin
  case StockObject of
    Int(WHITE_BRUSH)..Int(NULL_BRUSH), Int(DC_BRUSH):
      QBrush_destroy(QBrushH(Handle));
    Int(WHITE_PEN)..Int(NULL_PEN), Int(DC_PEN):
      QPen_destroy(QPenH(Handle));
    Int(OEM_FIXED_FONT)..Int(DEVICE_DEFAULT_FONT), Int(SYSTEM_FIXED_FONT), Int(DEFAULT_GUI_FONT):
      QFont_destroy(QFontH(Handle));
  end;
  StockObjectList.Extract(Self);
  inherited Destroy;
end;

function TStockObjectResource.AddRef: Pointer;
begin
  Inc(FRefCount);
  Result := Handle;
end;

procedure TStockObjectResource.Release;
begin
  Dec(FRefCount);
  if FRefCount = 0 then
    Free;
end;

function TStockObjectList.FindStockObject(AStockObject: Integer): TStockObjectResource;
var
  i: Integer;
begin
  for i := 0 to Count - 1 do
  begin
    Result := TStockObjectResource(Items[i]);
    if Result.StockObject = AStockObject then
      Exit;
  end;
  Result := nil;
end;

class function TStockObjectList.ReleaseStockObject(AHandle: Pointer): Boolean;
var
  i: Integer;
begin
  EnterCriticalSection(StockObjectListCritSect);
  try
    if Assigned(StockObjectList) then
    begin
      for i := 0 to StockObjectList.Count - 1 do
        if TStockObjectResource(StockObjectList.Items[i]).Handle = AHandle then
        begin
          TStockObjectResource(StockObjectList.Items[i]).Release;
          Result := True;
          Exit;
        end;
    end;
    Result := False;
  finally
    LeaveCriticalSection(StockObjectListCritSect);
  end;
end;

function GetStockObject(fnObject: Integer): Pointer; overload;
const
  BrushColors: array[WHITE_BRUSH..BLACK_BRUSH] of TColor =
    (clWhite, clLtGray, clGray, clDkGray, clBlack);
  {$IFDEF MSWINDOWS}
  SystemFont: WideString = 'System';
  GuiFont: array[Boolean] of WideString = ('MS Sans Serife', 'Tahoma');
  {$ENDIF MSWINDOWS}
  {$IFDEF LINUX}
  SystemFont: WideString = 'Fixed';   // asn: is not always True
//  GuiFont: array[Boolean] of WideString = ('Verdana', 'Verdana');
//asn:  in JVCL units Helvetica is used. Why introduce another?
  GuiFont: array[Boolean] of WideString = ('Helvetica', 'Helvetica');
  {$ENDIF LINUX}
type
  Int = Integer;
var
  Resource: TStockObjectResource;
  GuiFontSelector: Boolean;
begin
  {$IFDEF MSWINDOWS}
  GuiFontSelector := Win32MajorVersion >= 5;
  {$ELSE}
  GuiFontSelector := True;
  {$ENDIF MSWINDOWS}
  EnterCriticalSection(StockObjectListCritSect);
  try
    if not Assigned(StockObjectList) then
      StockObjectList := TStockObjectList.Create;
    Resource := StockObjectList.FindStockObject(fnObject);
    if Resource <> nil then
      Result := Resource.AddRef
    else
    begin
      case fnObject of
        Int(WHITE_BRUSH)..Int(BLACK_BRUSH):
          Result := CreateSolidBrush(BrushColors[TStockObjectBrush(fnObject)]);
        Int(NULL_BRUSH):
          Result := QBrush_create(BrushStyle_NoBrush);
        Int(DC_BRUSH):
          Result := CreateSolidBrush(clWhite);
        Int(WHITE_PEN):
          Result := CreatePen(PS_SOLID, 1, clWhite);
        Int(BLACK_PEN):
          Result := CreatePen(PS_SOLID, 1, clBlack);
        Int(NULL_PEN):
          Result := CreatePen(PS_NULL, 1, clWhite);
        Int(DC_PEN):
          Result := CreatePen(PS_SOLID, 1, clWhite);
        Int(OEM_FIXED_FONT), Int(ANSI_FIXED_FONT), Int(SYSTEM_FONT), Int(SYSTEM_FIXED_FONT):
          Result := QFont_create(@SystemFont, 8, 1, False);
        Int(ANSI_VAR_FONT), Int(DEVICE_DEFAULT_FONT), Int(DEFAULT_GUI_FONT):
          Result := QFont_create(@GuiFont[GuiFontSelector], 8, 1, False);
      else
        Result := nil;
      end;
      if Result <> nil then
        StockObjectList.Add(TStockObjectResource.Create(Result, fnObject));
    end;
  finally
    LeaveCriticalSection(StockObjectListCritSect);
  end;
end;

function GetStockObject(fnObject: TStockObjectBrush): QBrushH;
begin
  Result := QBrushH(GetStockObject(Integer(fnObject)));
end;

function GetStockObject(fnObject: TStockObjectPen): QPenH;
begin
  Result := QPenH(GetStockObject(Integer(fnObject)));
end;

function GetStockObject(fnObject: TStockObjectFont): QFontH;
begin
  Result := QFontH(GetStockObject(Integer(fnObject)));
end;

function GetMapMode(Handle: QPainterH): TMapMode;
var
  P: PPainterInfo;
begin
  if GetPainterInfo(Handle, P) then
    Result := P.MapMode
  else
    Result := MM_TEXT;
end;

function SetMapMode(Handle: QPainterH; MapMode: TMapMode): TMapMode;
var
  Matrix: QWMatrixH;
  dpi: TSize;
  m11, m22: Double;
  dx, dy: Double;

  procedure SetM(const Am11, Am22: Double);
  begin
    m11 := Am11;
    m22 := Am22;
  end;

begin
  dpi.cx := GetDeviceCaps(Handle, LOGPIXELSX);
  dpi.cy := GetDeviceCaps(Handle, LOGPIXELSY);

  Result := GetMapMode(Handle);
  case MapMode of
    MM_TEXT:
      SetM(1, 1);

    MM_LOMETRIC:
      SetM((dpi.cx / 2.54) / 100, -(dpi.cy / 2.54) / 100);
    MM_HIMETRIC:
      SetM((dpi.cx / 2.54) / 1000, -(dpi.cy / 2.54) / 1000);

    MM_LOENGLISH:
      SetM(dpi.cx / 10, -dpi.cy / 10);
    MM_HIENGLISH:
      SetM(dpi.cx / 100, -dpi.cy / 100);

    MM_TWIPS:
      SetM(dpi.cx / 1440, -dpi.cy / 1440);

    MM_ISOTROPIC:

  end;
 // translate matrix
  if QPainter_hasWorldXForm(Handle) then
  begin
    dx := QWMatrix_dx(QPainter_worldMatrix(Handle));
    dy := QWMatrix_dy(QPainter_worldMatrix(Handle));
  end
  else
  begin
    dx := 0;
    dy := 0;
  end;
  Matrix := QWMatrix_create(m11, 0, 0, m22, dx, dy);
  QPainter_setWorldMatrix(Handle, Matrix, False);
  QWMatrix_destroy(Matrix);
  SetPainterInfo(Handle).MapMode := MapMode;
end;

function CreatePen(Style, Width: Integer; Color: TColor): QPenH;
var
  QC: QColorH;
begin
  QC := QColor(Color);
  Result := QPen_create(QC, Width, PenStyle(Style));
  QColor_destroy(QC);
end;

function DeleteObject(Handle: QPenH): LongBool;
begin
  try
//    if not TStockObjectList.ReleaseStockObject(Handle) then
      QPen_destroy(Handle);
    Result := True;
  except
    Result := False;
  end;
end;

function CreateSolidBrush(Color: TColor): QBrushH;
var
  QC: QColorH;
begin
  QC := QColor(Color);
  Result := QBrush_create(QC, BrushStyle_SolidPattern);
  QColor_destroy(QC);
end;

function CreateHatchBrush(bStyle: BrushStyle; Color: TColor): QBrushH;
var
  QC: QColorH;
begin
  QC := QColor(Color);
  Result := QBrush_create(QC, bStyle);
  QColor_destroy(QC);
end;

function DeleteObject(Handle: QBrushH): LongBool;
begin
  Result := False;
  if Handle <> nil then
  begin
    try
//      if not TStockObjectList.ReleaseStockObject(Handle) then
        QBrush_destroy(Handle);
      Result := True;
    except
    end;
  end;
end;

function EnableWindow(Handle: QWidgetH; Value: Boolean): LongBool;
begin
  try
    QWidget_setEnabled(Handle, Value);
    Result := True;
  except
    Result := False;
  end;
end;

function SetWindowPlacement(Handle: QWidgetH; W: PWindowPlacement): LongBool;
begin
  try
    Result := ShowWindow(Handle, W.ShowCmd);
    with W.rcNormalPosition do
       QWidget_setGeometry(Handle, Left, Top, Right - Left, Bottom - Top);
  except
    Result := False;
  end;
end;

function GetWindowPlacement(Handle: QWidgetH; W: PWindowPlacement): LongBool;
var
  R: TRect;
begin
  try
    QWidget_geometry(Handle, @R);
    W.rcNormalPosition.Left := R.Left;
    W.rcNormalPosition.Top := R.Top;
    W.rcNormalPosition.Right := R.Right;
    W.rcNormalPosition.Bottom := R.Bottom;
    if QWidget_isMinimized(Handle) then
      W.showCmd := SW_SHOWMINIMIZED
    else if QWidget_isMaximized(Handle) then
      W.showCmd := SW_SHOWMAXIMIZED
    else if not QWidget_isVisible(Handle) then
      W.showCmd := SW_HIDE
    else
      W.showCmd := SW_SHOWNORMAL;
    Result := True;
  except
    Result := False;
  end;
end;

function GetWindowRect(Handle: QWidgetH; var R: TRect): LongBool;
begin
  try
    QWidget_frameGeometry(Handle, @R);
    Result := True;
  except
    Result := False;
  end;
end;

function GetClientRect(Handle: QWidgetH; var R: TRect): LongBool;
begin
  try
    QWidget_rect(Handle, @R);
    Result := True;
  except
    Result := False;
  end;
end;

function ShowWindow(Handle: QWidgetH; showCmd: UInt): LongBool;
var
  ActWidget: QWidgetH;
begin
  try
    case ShowCmd of
      SW_MINIMIZE, SW_SHOWMINIMIZED:
        QWidget_showMinimized(Handle);
      SW_MAXIMIZE:
        QWidget_showMaximized(Handle);
      SW_HIDE:
        QWidget_hide(Handle);
      SW_SHOWNOACTIVATE, SW_SHOWMINNOACTIVE:
        begin
          ActWidget := QApplication_activeWindow(Application.Handle);
          if ShowCmd = SW_SHOWNOACTIVATE then
            QWidget_showNormal(Handle)
          else
            QWidget_showMinimized(Handle);
          if Assigned(ActWidget) then
            QWidget_setActiveWindow(ActWidget);
        end;
    else
      QWidget_showNormal(Handle);
    end;
    Result := True;
  except
    Result := False;
  end;
end;

type
  THackedWidgetControl = class(TWidgetControl);

function SetWindowPos(Wnd, WndInsertAfter: QWidgetH; X, Y, cx, cy: Integer;
  uFlags: Longword): LongBool;
var
  R, Geometry: TRect;
  WidgetFlags: Cardinal;
  Control: THackedWidgetControl;
  LastActiveWidget: QWidgetH;
  LastActiveWinId: Cardinal;
begin
  Result := False;
  if Wnd = nil then
    Exit;
  try
    LastActiveWidget := QApplication_activeWindow(Application.Handle);
    if LastActiveWidget <> nil then
      LastActiveWinId := QWidget_winId(LastActiveWidget)
    else
      LastActiveWinId := 0;

    // we must use CLX methods or CLX will be a pain.
    Control := THackedWidgetControl(FindControl(Wnd));

    if Control <> nil then
      Geometry := Control.BoundsRect
    else
      QWidget_geometry(Wnd, @Geometry);

    if uFlags and SWP_HIDEWINDOW <> 0 then
    begin
      if Control <> nil then
        Control.Hide
      else
        QWidget_hide(Wnd);
    end;

    if uFlags and SWP_NOSIZE <> 0 then
    begin
      cx := Geometry.Right - Geometry.Left;
      cy := Geometry.Bottom - Geometry.Top;
    end;
    if uFlags and SWP_NOMOVE <> 0 then
    begin
      X := Geometry.Left;
      Y := Geometry.Top;
    end;
    R := Rect(X, Y, X + cx, Y + cy);
    if not EqualRect(R, Geometry) then
    begin
      if Control <> nil then
        Control.BoundsRect := R
      else
        QWidget_setGeometry(Wnd, X, Y, cx, cy);
    end;

    if uFlags and SWP_FRAMECHANGED <> 0 then
    begin
      QWidget_adjustSize(Wnd);
      if Control <> nil then
        Control.AdjustSize;
    end;

    if (uFlags and SWP_NOOWNERZORDER = 0) and (uFlags and SWP_NOZORDER = 0) and
       (Cardinal(WndInsertAfter) <> HWND_TOP) and (Cardinal(WndInsertAfter) <> HWND_BOTTOM) and
       (Cardinal(WndInsertAfter) <> HWND_TOPMOST) then
      if (not QWidget_isTopLevel(Wnd)) and (QWidget_parentWidget(Wnd) <> nil) then
        SetWindowPos(QWidget_parentWidget(Wnd), WndInsertAfter, 0, 0, 0, 0,
          SWP_NOSIZE or SWP_NOMOVE or SWP_NOREDRAW or SWP_NOACTIVATE or
          SWP_NOCOPYBITS or SWP_NOSENDCHANGING);

    if (uFlags and SWP_NOZORDER = 0) then
    begin
      WidgetFlags := QOpenWidget_getWFlags(QOpenWidgetH(Wnd));

      case Cardinal(WndInsertAfter) of
        HWND_TOP:
          QWidget_raise(Wnd);
        HWND_BOTTOM:
          QWidget_lower(Wnd);
        HWND_TOPMOST:
          if (Control <> nil) and (TWidgetControl(Control) is TForm) then
            TForm(Control).FormStyle := fsStayOnTop
          else
            QOpenWidget_setWFlags(QOpenWidgetH(Wnd),
              WidgetFlags or Cardinal(WidgetFlags_WStyle_StaysOnTop));
        HWND_NOTOPMOST:
          if (Control <> nil) and (TWidgetControl(Control) is TForm) then
            TForm(Control).FormStyle := fsNormal
          else
            QOpenWidget_setWFlags(QOpenWidgetH(Wnd),
              WidgetFlags and not Cardinal(WidgetFlags_WStyle_StaysOnTop));
      else
       // remove top most state
        if WidgetFlags and Cardinal(WidgetFlags_WStyle_StaysOnTop) <> 0 then
        begin
          if (Control <> nil) and (TWidgetControl(Control) is TForm) then
            TForm(Control).FormStyle := fsNormal
          else
            QOpenWidget_setWFlags(QOpenWidgetH(Wnd),
              WidgetFlags and not Cardinal(WidgetFlags_WStyle_StaysOnTop));
        end;
        // after widget
        QWidget_stackUnder(Wnd, WndInsertAfter);
      end;
    end;

    if uFlags and SWP_SHOWWINDOW <> 0 then
    begin
      if Control <> nil then
        Control.Show
      else
        QWidget_show(Wnd);
    end;

    if (uFlags and SWP_NOACTIVATE = 0) and (QWidget_isVisible(Wnd)) then
      QWidget_setActiveWindow(Wnd);

    if (uFlags and SWP_NOREDRAW = 0) and (QWidget_isVisible(Wnd)) then
      QWidget_update(Wnd);

    if (uFlags and SWP_NOACTIVATE <> 0) and Assigned(LastActiveWidget) then
      if QWidget_find(LastActiveWinId) = LastActiveWidget then // valid LastActiveWidget
        QWidget_setActiveWindow(LastActiveWidget);
  except
    Result := False;
  end;
end;

function SetWindowPos(Wnd, WndInsertAfter: Cardinal; X, Y, cx, cy: Integer;
  uFlags: Longword): LongBool;
begin
  Result := SetWindowPos(QWidgetH(Wnd), QWidgetH(WndInsertAfter), X, Y, cx, cy, uFlags);
end;

function SetWindowPos(Wnd: QWidgetH; WndInsertAfter: Cardinal; X, Y, cx, cy: Integer;
  uFlags: Longword): LongBool;
begin
  Result := SetWindowPos(Wnd, QWidgetH(WndInsertAfter), X, Y, cx, cy, uFlags);
end;

procedure MoveWindowOrg(DC: QPainterH; DX, DY: Integer);
var
  P: TPoint;
begin
  GetWindowOrgEx(DC, P);
  SetWindowOrgEx(DC, P.X - DX, P.Y - DY, nil);
end;

function IsWindowVisible(Handle: QWidgetH): LongBool;
begin
  Result := QWidget_isVisible(Handle);
end;

function IsWindowEnabled(Handle: QWidgetH): LongBool;
begin
  Result := QWidget_isEnabled(Handle);
end;

function SetFocus(Handle: QWidgetH): QWidgetH;
begin
  try
    Result := GetFocus;
    QWidget_setFocus(Handle);
  except
    Result := nil;
  end;
end;

function GetFocus: QWidgetH;
begin
  Result := QApplication_focusWidget(Application.Handle);
end;

function GetBkMode(Handle: QPainterH): Integer;
begin
  case QPainter_BackgroundMode(Handle) of
    BGMode_TransparentMode:
      Result := TRANSPARENT; // BGMode_TransparentMode
    BGMode_OpaqueMode:
      Result := OPAQUE; // BGMode_OpaqueMode
  else
    Result := OPAQUE;
  end;
end;

function SetBkMode(Handle: QPainterH; BkMode: Integer): Integer;
begin
  Result := GetBkMode(Handle);
  case BkMode of
    TRANSPARENT:
      QPainter_setBackgroundMode(Handle, BGMode_TransparentMode);
    OPAQUE:
      QPainter_setBackgroundMode(Handle, BGMode_OpaqueMode);
  end;
end;

function SetPenColor(Handle: QPainterH; Color: TColor): TColorRef;
var
  QC: QColorH;
begin
  Result :=  QColorColor(QPen_color(QPainter_pen(Handle)));
  QC := QColor(Color);
  QPainter_setPen(Handle, QC);
  QColor_destroy(QC);
end;

function SetTextColor(Handle: QPainterH; Color: TColor): TColorRef;
begin
  Result := SetPenColor(Handle, Color);
end;

function SetBkColor(Handle: QPainterH; Color: TColor): TColorRef;
var
  QC: QColorH;
begin
  Result := QColorColor(QPainter_backgroundColor(Handle));
  QC := QColor(Color);
  QPainter_setBackgroundColor(Handle, QC);
  QColor_destroy(QC);
end;

function SetDCBrushColor(Handle: QPainterH; Color: TColor): TColorRef;
var
  QC: QColorH;
begin
  Result := QColorColor(QBrush_color(QPainter_brush(Handle)));
  QC := QColor(Color);
  QPainter_setBrush(Handle, QC);
  QColor_destroy(QC);
end;

function SetDCPenColor(Handle: QPainterH; Color: TColor): TColorRef;
begin
  Result := SetPenColor(Handle, Color);
end;

procedure SetPainterFont(Handle: QPainterH; Font: QGraphics.TFont);
begin
  QPainter_setFont(Handle, Font.Handle);
  QPainter_setPen(Handle, Font.FontPen);
end;

function GetParent(Handle: QWidgetH): QWidgetH;
begin
  Result := QWidget_parentWidget(Handle);
end;

function SetParent(hWndChild, hWndNewParent: QWidgetH): QWidgetH;
var
  Pt: TPoint;
begin
  try
    Result := GetParent(hWndChild);
    QWidget_pos(hWndChild, @Pt);
    QWidget_reparent(hWndChild, hWndNewParent, @Pt, QWidget_isVisible(hWndChild));
  except
    Result := nil;
  end;
end;

function RasterOpToWinRop(Rop: RasterOp): cardinal;
begin
  case Rop of
    RasterOp_ClearROP   : Result := BLACKNESS;
    RasterOp_NotROP     : Result := DSTINVERT;
    RasterOp_NotOrRop   : Result := MERGEPAINT;
    RasterOp_NotCopyROP : Result := NOTSRCCOPY;
    RasterOp_NorROP     : Result := NOTSRCERASE;
    RasterOp_AndROP     : Result := SRCAND;
    RasterOp_CopyROP    : Result := SRCCOPY;
    RasterOp_AndNotROP  : Result := SRCERASE;
    RasterOp_XorROP     : Result := SRCINVERT;
    RasterOp_OrROP      : Result := SRCPAINT;
    RasterOp_SetROP     : Result := WHITENESS;
    RasterOp_NotAndROP  : Result := ROP_DSna;
    RasterOp_NopROP     : Result := ROP_D;
    RasterOp_OrNotROP   : Result := ROP_SDno;
    RasterOp_NandROP    : Result := ROP_DSan;
  else
    Result := 0;   // to satisfy compiler
  end;
end;

function WinRopToRasterOp(WinRop: Cardinal; var Rop: RasterOp): Boolean;
begin
  Result := True;
  case WinRop of
    BLACKNESS  : Rop := RasterOp_ClearROP;
    DSTINVERT  : Rop := RasterOp_NotROP;
//    MERGECOPY  : Rop := RasterOp_OrROP;     {DSa}
    MERGEPAINT : Rop := RasterOp_NotOrRop;
    NOTSRCCOPY : Rop := RasterOp_NotCopyROP;
    NOTSRCERASE: Rop := RasterOp_NorROP;
    SRCAND     : Rop := RasterOp_AndROP;
    SRCCOPY    : Rop := RasterOp_CopyROP;
    SRCERASE   : Rop := RasterOp_AndNotROP;
    SRCINVERT  : Rop := RasterOp_XorROP;
    SRCPAINT   : Rop := RasterOp_OrROP;
    WHITENESS  : Rop := RasterOp_SetROP;
    ROP_DSna   : Rop := RasterOp_NotAndROP;
    ROP_D      : Rop := RasterOp_NopROP;
    ROP_SDno   : Rop := RasterOp_OrNotROP;
    ROP_DSan   : Rop := RasterOp_NandROP;
  else
    Rop := RasterOp(-1);
    Result := False;
  end;
end;

function PatternPaint(DestDC: QPainterH; X, Y, W, H: Integer; rop: RasterOp): LongBool;
var
  trop: RasterOp;
  bkmode: Integer;
begin
  try
    trop := QPainter_rasterOp(DestDC);
    bkmode := SetBkMode(DestDC, OPAQUE);
    try
      QPainter_setRasterOp(DestDC, rop);    // asn: or use current ?
      QPainter_fillRect(DestDC, X, Y, W, H, QPainter_brush(DestDC)); // current brush
    finally
      QPainter_setRasterOp(DestDC, trop);
      SetBkMode(DestDC, bkmode);
    end;
    Result := True;
  except
    Result := False;
  end;
end;

function BitBlt(DestDC: QPainterH; X, Y, Width, Height: Integer; SrcDC: QPainterH;
  XSrc, YSrc: Integer; WinRop: Cardinal; IgnoreMask: Boolean): LongBool;
var
  TempDC: QPainterH;
  Rop: RasterOp;
begin
  if WinRopToRasterOp(WinRop, Rop) then  // directly maps ?
    Result := BitBlt(DestDC, X, Y, Width, Height, SrcDC, XSrc, YSrc, Rop, IgnoreMask)
  else // no
  begin
    case WinRop of
      MERGECOPY: { PSa: Dest := Pattern AND Source }
        begin
          try
            TempDC := CreateCompatibleDC(DestDC, Width, Height);
            try
              PatternPaint(TempDc, 0, 0, Width, Height, RasterOp_CopyROP); // Create Pattern
              BitBlt(TempDc, 0, 0, Width, Height, SrcDC, XSrc, YSrc, RasterOp_AndRop); {PSa}
              Result := BitBlt(DestDc, X, Y, Width, Height, tempDC, XSrc, YSrc, RasterOp_CopyROP);
            except
              Result := False;
            end;
            QPainter_destroy(tempDC);
          except
            Result := False;
          end;
        end;

      PATCOPY:
        Result := PatternPaint(DestDC, X, Y, Width, Height, RasterOp_CopyROP);

      PATINVERT:
        Result := PatternPaint(DestDC, X, Y, Width, Height, RasterOp_XorROP);

      PATPAINT:
        begin  // DPSnoo   = PDSnoo
          Result := BitBlt(DestDC, X, Y, Width, Height, SrcDC, XSrc, YSrc,
                           RasterOp_NotOrRop); // DSno
          if Result then
            Result := PatternPaint(DestDC, X, Y, Width, Height, RasterOp_XOrROP);
        end;

      ROP_DSPDxax:
        begin
          TempDC := CreateCompatibleDC(DestDC, Width, Height);
          try
            // copy DestDC to pixmap
            BitBlt(TempDC, 0, 0, Width, Height, DestDC, X, Y,  RasterOp_XorROP);
            BitBlt(TempDC, 0, 0, Width, Height, TempDC, 0, 0, PATINVERT);  // PDx
            BitBlt(TempDC, 0, 0, Width, Height, SrcDC, XSrc, YSrc, RasterOp_AndROP); // SPDxa
            Result := BitBlt(DestDC, X, Y, Width, Height, TempDC, 0, 0, RasterOp_XorROP); // DSPDxax
          except
            Result := False;
          end;
          DeleteObject(TempDC);
        end;
    else
      Result := False;
    end;
  end
end;

function BitBlt(DestDC: QPainterH; X, Y, Width, Height: Integer; SrcDC: QPainterH;
  XSrc, YSrc: Integer; Rop: RasterOp; IgnoreMask: Boolean): LongBool;
var
  d_dx, d_dy, d_sx, d_sy, d_sw, d_sh, d_dw, d_dh: Integer;
begin
  if (DestDC = nil) or (SrcDC = nil) then
    Result := False
  else
  begin
    Result := True;
    try
     // Windows's BitBlt uses logical units
      d_dx := X;d_dy := Y;d_dw := Width;d_dh := Height;
      d_sx := XSrc; d_sy := YSrc;d_sw := Width; d_sh := Height;

      MapPainterLP(DestDC, d_dx, d_dy);
      MapPainterLPwh(DestDC, d_dw, d_dh);
      MapPainterLP(SrcDC, d_sx, d_sy);
      MapPainterLPwh(SrcDC, d_sw, d_sh);
      
      if (d_dw = d_sw) and (d_dh = d_sh) then // device bitBlt possible
        Qt.bitBlt(QPainter_device(DestDC), d_dx, d_dy, QPainter_device(SrcDC),
          d_sx, d_sy, d_sw, d_sh, Rop,
          IgnoreMask) // ignore the Mask because Windows's BitBlt does not use Masks
      else
        StretchBlt(DestDC, X, Y, Width, Height, SrcDC, XSrc, YSrc, Width, Height,
          Rop, IgnoreMask);
    except
      Result := False;
    end;
  end;
end;

function PainterOffset(Canvas: TCanvas): TPoint;
var
  aControl: TControl;
begin
  Result.X := 0;
  Result.Y := 0;
  if Canvas is TControlCanvas then
  begin
    AControl := TControlCanvas(Canvas).Control;
    if AControl = nil then
      Exit;
    if not (AControl is TWidgetControl) then
    begin
      Result.X := aControl.Left;
      Result.Y := aControl.Top;
    end;
  end;
end;

function BitBlt(DestCanvas: TCanvas; X, Y, Width, Height: Integer; SrcCanvas: TCanvas;
  XSrc, YSrc: Integer; WinRop: Cardinal; IgnoreMask: boolean): LongBool;
begin
  DestCanvas.Start;
  SrcCanvas.Start;
  Result := BitBlt(DestCanvas.Handle, X, Y , Width, Height, SrcCanvas.Handle,
    XSrc, YSrc, WinRop, IgnoreMask);
  SrcCanvas.Stop;
  DestCanvas.Stop;
end;

const
  CopyModeToRasterOp: array[TCopyMode] of RasterOp = (
    {cmBlackness}   RasterOp_ClearROP,    {cmDstInvert}  RasterOp_NotROP,
    {cmMergeCopy}   RasterOp_AndROP,      {cmMergePaint} RasterOP_NotOrROP,
    {cmNotSrcCopy}  RasterOp_NotCopyROP,  {cmNotSrcErase}RasterOp_NorROP,
    {cmPatCopy}     RasterOp_NopROP,      {cmPatInvert}  RasterOp_NopROP,
    {cmPatPaint}    RasterOp_NotOrROP,    {cmSrcAnd}     RasterOp_AndROP,
    {cmSrcCopy}     RasterOp_CopyROP,     {cmSrcErase}   RasterOp_AndNotROP,
    {cmSrcInvert}   RasterOp_XorROP,      {cmSrcPaint}   RasterOP_OrROP,
    {cmWhiteness}   RasterOp_SetROP,      {cmCreateMask} RasterOp_NopROP);


procedure CopyRect(DstCanvas: TCanvas; const Dest: TRect; Canvas: TCanvas;
  const Source: TRect);
begin
  StretchBlt(DstCanvas, Dest.Left, Dest.Top,
    Dest.Right - Dest.Left, Dest.Bottom - Dest.Top,
    Canvas, Source.Left, Source.Top,
    Source.Right - Source.Left, Source.Bottom - Source.Top,
    RasterOpToWinRop(CopyModeToRasterOp[DstCanvas.CopyMode]));
end;

procedure BrushCopy(DstCanvas: TCanvas; const Dest: TRect; Bitmap: TBitmap;
  const Source: TRect; Color: TColor);
var
  Bmp: TBitmap;
  X, Y: integer;
begin
  Bmp := TBitmap.Create;
  with Bmp do
  begin
    Width := Source.Right - Source.Left;
    Height := Source.Bottom - Source.Top;
    Canvas.Start;
    Canvas.Draw( -Source.Left, -Source.Top, Bitmap);
    TransparentColor := Color;
    Transparent := True;
    Canvas.Stop;
  end;
  with DstCanvas do
  begin
    Start;
    FillRect(Dest);
    X := Dest.Left;
    while X < Dest.Right do
    begin
      Y := Dest.Top;
      while Y < Dest.Bottom do
      begin
        Draw(X, Y, Bmp);
        Y := Y + Bmp.Height;
      end;
      X := X + Bmp.Width;
    end;
    Stop;
  end;
  Bmp.Free;
end;

function PatBlt(Handle: QPainterH; X, Y, Width, Height: Integer; WinRop: Cardinal): LongBool;
begin
  Result := BitBlt(Handle, X, Y, Width, Height, Handle, X, Y, WinRop);
end;

function PatBlt(Canvas: TCanvas; X, Y, Width, Height: Integer; WinRop: Cardinal): LongBool;
begin
  Canvas.Start;
  Result := BitBlt(Canvas.Handle, X, Y, Width, Height, Canvas.Handle, X, Y, WinRop);
  Canvas.Stop;
end;

function StretchBlt(DestDC: QPainterH; dx, dy, dw, dh: Integer;
  SrcDC: QPainterH; sx, sy, sw, sh: Integer; WinRop: Cardinal;
  IgnoreMask: Boolean): LongBool;
var
  Bmp1, Bmp2: QPixmapH;
  Painter : QPainterH;
  d_sx, d_sy, d_sw, d_sh: Integer;
  d_dx, d_dy, d_dw, d_dh: Integer;
begin
  Result := False;
  if (DestDC = nil) and (QPainter_isActive(DestDC)) then
    Exit;

 // Windows's StretchBlt uses logical units
  d_sx := sx;d_sy := sy;d_sw := sw;d_sh := sh;
  d_dx := dx;d_dy := dy;d_dw := dw;d_dh := dh;

  MapPainterLP(DestDC, d_dx, d_dy);
  MapPainterLPwh(DestDC, d_dw, d_dh);
  MapPainterLP(SrcDC, d_sx, d_sy);
  MapPainterLPwh(SrcDC, d_sw, d_sh);

  if (d_dw = d_sw) and (d_dh = d_sh) then // device bitBlt possible
    Result := BitBlt(DestDC, dx, dy, dw, dh, SrcDC, sx, sy, WinRop, IgnoreMask)
  else
  begin
    if not QPainter_isActive(SrcDC) then
      Exit;
    try
      Bmp1 := nil;
      Bmp2 := nil;
      try
       // temporary bitmaps are in device units
        Bmp1 := CreateCompatibleBitmap(SrcDC, d_sw, d_sh);
        Bmp2 := CreateCompatibleBitmap(DestDC, d_dw, d_dh);
        Qt.bitBlt(Bmp1, 0, 0, QPainter_device(SrcDC), d_sx, d_sy, d_sw, d_sh,
          RasterOp_CopyROP, IgnoreMask); // use device units
        Painter := QPainter_create(Bmp2);
        QPainter_save(Painter);
        QPainter_scale(Painter, d_dw/d_sw, d_dh/d_sh);
        QPainter_drawPixmap(Painter, 0, 0, Bmp1, 0, 0, d_sw, d_sh);
        QPainter_restore(Painter);
        Result := BitBlt(DestDC, dx, dy, dw, dh, Painter, 0, 0, WinRop, IgnoreMask); // maps logical units
        QPainter_destroy(Painter);
      finally
        if Assigned(Bmp1) then
          QPixmap_destroy(Bmp1);
        if Assigned(Bmp2) then
          QPixmap_destroy(Bmp2);
      end;
    except
      Result := False;
    end;
  end;
end;

function StretchBlt(DestDC: QPainterH; dx, dy, dw, dh: Integer;
  SrcDC: QPainterH; sx, sy, sw, sh: Integer; Rop: RasterOp; IgnoreMask: Boolean): LongBool;
begin
  Result := StretchBlt(DestDC, dx, dy, dw, dh, SrcDC, sx, sy, sw, sh,
    RasterOpToWinRop(Rop), IgnoreMask);
end;

function StretchBlt(DestCanvas: TCanvas; dx, dy, dw, dh: Integer;
  SrcCanvas: TCanvas; sx, sy, sw, sh: Integer; WinRop: Cardinal; IgnoreMask: Boolean): LongBool;
//var
//  d,s :TPoint;
begin
  DestCanvas.Start;
  SrcCanvas.Start;
//  d := PainterOffset(DestCanvas);
//  s := PainterOffset(SrcCanvas);
//  Result := StretchBlt(DestCanvas.Handle, dx + d.x, dy + d.y, dw, dh, SrcCanvas.Handle,
//    sx + s.x, sy + s.y, sw, sh, WinRop,  IgnoreMask);
  Result := StretchBlt(DestCanvas.Handle, dx, dy, dw, dh, SrcCanvas.Handle,
    sx, sy, sw, sh, WinRop,  IgnoreMask);
  SrcCanvas.Stop;
  DestCanvas.Stop;
end;

function GetStretchBltMode(DC: QPainterH): TStretchMode;
var
  P: PPainterInfo;
begin
  if DC <> nil then
  begin
    if GetPainterInfo(DC, P) then
      Result := P.StetchBltMode
    else
      Result := STRETCH_DELETESCANS;
  end
  else
    Result := STRETCH_DELETESCANS;
end;

function SetStretchBltMode(DC: QPainterH; StretchMode: TStretchMode): TStretchMode;
begin
  try
    Result := GetStretchBltMode(DC);
    SetPainterInfo(DC).StetchBltMode := StretchMode;
  except
    Result := STRETCH_DELETESCANS;
  end;
end;

function ScrollDC(Handle: QPainterH; dx, dy: Integer; var Scroll, Clip: TRect;
  Rgn: QRegionH; Update: PRect): LongBool;
var
  R1, R2: TRect;
  rg1, rg2: QRegionH;
begin
  // assume device units = pixels
  IntersectRect(R2, Scroll, Clip); // clipped source rectangle
  OffsetRect(R2, dx, dy);
  IntersectRect(R2, R2, Clip);  // R2: clipped destination rectangle
  if not isRectEmpty(R2) then
  begin
    R1 := R2;
    OffsetRect(R1, -dx, -dy); // R1: adjusted source rectangle
    Result := BitBlt(Handle, R2.Left, R2.Top, R2.Right-R2.Left, R2.Bottom-R2.Top,
           Handle, R1.Left, R1.Top, SRCCOPY);
  end
  else
    Result := False;    // asn: or True ?
  if (Rgn <> nil) or  (Update <> nil) then
  begin
    rg1 := CreateRectRgnIndirect(Scroll);
    rg2 := CreateRectRgnIndirect(R2);
    CombineRgn(rg2, rg1, rg2, RGN_DIFF);
    if Rgn <> nil then
      CombineRgn(Rgn, Rg2, Rg2, RGN_OR);
    if Update <> nil then
      QRegion_boundingRect(rg2, Update);
    QRegion_destroy(rg2);
    QRegion_destroy(rg1);
  end;
end;

function SetROP2(Handle: QPainterH; Rop: Integer): Integer;
var
  rop2: RasterOp;
begin
  case Rop of
    R2_BLACK      : rop2 := RasterOp_ClearROP;
    R2_WHITE      : rop2 := RasterOp_SetROP;
    R2_NOP        : rop2 := RasterOp_NopROP;
    R2_NOT        : rop2 := RasterOp_NotROP;
    R2_COPYPEN    : rop2 := RasterOp_CopyROP;
    R2_NOTCOPYPEN : rop2 := RasterOp_NotCopyROP;
    R2_MERGEPENNOT: rop2 := RasterOp_OrNotROP;
    R2_MASKPENNOT : rop2 := RasterOp_AndNotROP;
    R2_MERGEPEN   : rop2 := RasterOp_OrROP;
    R2_NOTMERGEPEN: rop2 := RasterOp_NorROP;
    R2_MASKPEN    : rop2 := RasterOp_AndROP;
    R2_NOTMASKPEN : rop2 := RasterOp_NandROP;
    R2_XORPEN     : rop2 := RasterOp_XorROP;
    R2_NOTXORPEN  : rop2 := RasterOp_NotXorROP;
    R2_MASKNOTPEN : rop2 := RasterOp_NotAndROP;
    R2_MERGENOTPEN: rop2 := RasterOp_NotOrROP;
  else
    Result := -1;
    Exit;
  end;
  Result := GetROP2(Handle);
  QPainter_setRasterOp(Handle, rop2);
end;

function GetROP2(Handle: QPainterH): Integer;
var
  rop2: RasterOp;
begin
  rop2 := QPainter_rasterOp(Handle);
  case rop2 of
    RasterOp_ClearROP  : Result := R2_BLACK;
    RasterOp_SetROP    : Result := R2_WHITE;
    RasterOp_NopROP    : Result := R2_NOP;
    RasterOp_NotROP    : Result := R2_NOT;
    RasterOp_CopyROP   : Result := R2_COPYPEN;
    RasterOp_NotCopyROP: Result := R2_NOTCOPYPEN;
    RasterOp_OrNotROP  : Result := R2_MERGEPENNOT;
    RasterOp_AndNotROP : Result := R2_MASKPENNOT;
    RasterOp_OrROP     : Result := R2_MERGEPEN;
    RasterOp_NorROP    : Result := R2_NOTMERGEPEN;
    RasterOp_AndROP    : Result := R2_MASKPEN;
    RasterOp_NandROP   : Result := R2_NOTMASKPEN;
    RasterOp_XorROP    : Result := R2_XORPEN;
    RasterOp_NotXorROP : Result := R2_NOTXORPEN;
    RasterOp_NotAndROP : Result := R2_MASKNOTPEN;
    RasterOp_NotOrROP  : Result := R2_MERGENOTPEN;
  else
    Result := -1;
  end;
end;

function SetForegroundWindow(Handle: QWidgetH): LongBool;
begin
  try
    Result := QWidget_isTopLevel(Handle);
    if Result then
      QWidget_raise(Handle);
  except
    Result := False;
  end;
end;

function BringWindowToTop(Handle: QWidgetH): LongBool;
begin
  try
    while not QWidget_isTopLevel(Handle) do
      Handle := QWidget_parentWidget(Handle);
    Result := Handle <> nil;
    if Result then
    begin
      QWidget_show(Handle);
      QWidget_raise(Handle);
    end;
  except
    Result := False;
  end;
end;

function SwitchToThisWindow(Handle: QWidgetH; Restore: Boolean): LongBool;
begin
  try
    Result := QWidget_isTopLevel(Handle);
    if Result then
    begin
      if Restore then
        QWidget_show(Handle);
      QWidget_setActiveWindow(Handle);
    end;
  except
    Result:= True;
  end;
end;

function CloseWindow(Handle: QWidgetH): LongBool;
begin
  try
    Result := QWidget_isTopLevel(Handle);
    if Result then
      QWidget_close(Handle)
  except
    Result := False;
  end;
end;

function DestroyWindow(Handle: QWidgetH): LongBool;
begin
  try
    Result := QWidget_isTopLevel(Handle);
    if Result then
      QWidget_destroy(Handle);
  except
    Result := False;
  end;
end;

function WindowFromDC(Handle: QPaintDeviceH): QWidgetH;
var
  WidgetList: QObjectListH;
  Widget: QWidgetH;
  I: integer;
begin
  Result := nil;
  WidgetList := QObject_queryList(Application.AppWidget, 'QWidget','*', true, true);
  for I := 0 to QObjectList_count(WidgetList) - 1  do
  begin
    Widget := QWidgetH(QObjectList_at(WidgetList, I));
    if QWidget_isVisible(Widget) and (QWidget_to_QPaintDevice(Widget) = Handle) then
    begin
      Result := Widget;
      break;
    end;
  end;
  QObjectList_destroy(WidgetList);
end;

function WindowFromDC(Handle: QPainterH): QWidgetH;
begin
  Result := nil;
  if QPainter_isActive(Handle) then
    Result := WindowFromDC(QPainter_device(Handle));
end;


function ChildWindowFromPoint(hWndParent: QWidgetH; Point: TPoint): QWidgetH;
begin
  try
    Result := QApplication_widgetAt(@Point, True);
  except
    Result := nil;
  end;
end;

function WindowFromPoint(Point: TPoint): QWidgetH;
begin
  try
    Result := QApplication_widgetAt(@Point, False);
  except
    Result := nil;
  end;
end;

function FindCLXWindow(const Point: TPoint): TWidgetControl;
var
  Handle: QWidgetH;
begin
  Handle := WindowFromPoint(Point);
  Result := nil;
  while Handle <> nil do
  begin
    Result := FindControl(Handle);
    if Result <> nil
    then
      Exit;
    Handle := GetParent(Handle);
  end;
end;

function FindVCLWindow(const Point: TPoint): TWidgetControl;
begin
  Result := FindCLXWindow(Point);
end;

function GetClassName(Handle: QWidgetH; Buffer: PChar; MaxCount: Integer): Integer;
begin
  Result := 0;
  if Handle <> nil then
  begin
    Result := Length(QObject_className(Handle));
    if Buffer <> nil then
      StrLCopy(Buffer, QObject_className(Handle), MaxCount);
  end;
end;

function IsIconic(Handle: QWidgetH): LongBool;
begin
  Result := False;
  if Handle = nil then
    Exit;
  try
    Result := QWidget_isMinimized(Handle);
  except
    Result := False;
  end;
end;

function ClientToScreen(Handle: QWidgetH; var Point: TPoint): LongBool;
begin
  try
    QWidget_mapToGlobal(Handle, @Point, @Point);
    Result := True;
  except
    Result := False;
  end;
end;

function ScreenToClient(Handle: QWidgetH; var Point: TPoint): LongBool;
begin
  try
    QWidget_mapFromGlobal(Handle, @Point, @Point);
    Result := True;
  except
    Result := False;
  end;
end;

function SmallPointToPoint(const P: TSmallPoint): TPoint;
begin
  Result := Point(P.x, P.y);
end;

function PointToSmallPoint(const P: TPoint): TSmallPoint;
begin
  Result.x := SmallInt(P.X);
  Result.y := SmallInt(P.Y);
end;

function MapWindowPoints(WidgetTo, WidgetFrom: QWidgetH; var Points; nr: Cardinal): Integer;
var
  i: Integer;
  p1: PPoint;
  p2: TPoint;
begin
  p1 := @Points;
  try
    if (IsChild(WidgetTo, WidgetFrom)) and (nr > 0) then
    begin
      QWidget_mapTo(WidgetFrom, p1, WidgetTo, @p2);
      TSmallPoint(Result).x := p2.X - p1.X;
      TSmallPoint(Result).y := p2.Y - p1.Y;
      for i:= 0 to nr - 1 do
      begin
        QWidget_mapTo(WidgetFrom, p1, WidgetTo, p1);
        Inc(p1);
      end;
    end
    else
      Result := 0;
  except
    Result := 0;
  end;
end;

function InvalidateRect(Handle: QWidgetH; R: PRect; EraseBackground: Boolean): LongBool;
var
  Control: TWidgetControl;
begin
  Result := False;
  if Handle = nil then
    Exit;
  try
    Control := FindControl(Handle);
    if Control <> nil then
      Control.InvalidateRect(R^, EraseBackGround);
    Result := True;
  except
    Result := False;
  end;
end;

function ValidateRect(hWnd: QWidgetH; R: PRect): LongBool;
var
  Event: QPaintEventH;
begin
  Event := QPaintEvent_create(R, false);
  try
    Result := QApplication_sendEvent(hWnd, QEventH(Event));
  finally
    QPaintEvent_destroy(Event);
  end;
end;

function UpdateWindow(Handle: QWidgetH): LongBool;
begin
  Result := False;
  if Handle <> nil then
    Exit;
  try
    QWidget_update(Handle);
    Result := True;
  except
    Result := False;
  end;
end;

function IsChild(ParentHandle, ChildHandle: QWidgetH): LongBool;
var
  ParentH: QWidgetH;
begin
  Result := False;
  ParentH := QWidget_parentWidget(ChildHandle);
  while (ParentH <> nil) and (not Result) do
  begin
    Result := ParentH = ParentHandle;
    ParentH := QWidget_parentWidget(ParentH);
  end;
end;

function MessageBox(parent: QWidgetH; Text, Caption: WideString; WinFlags: Cardinal): Integer; overload;
var
  Button0, Button1, Button2: Integer;
const
  ButtonOk = 1;
  ButtonCancel = 2;
  ButtonYes = 3;
  ButtonNo = 4;
  ButtonAbort = 5;
  ButtonRetry = 6;
  ButtonIgnore = 7;
  ButtonDefault = $100;
  ButtonEscape = $200;
begin
  case (WinFlags and $7) of
    MB_OKCANCEL:
      begin
        Button0 := ButtonOk;
        Button1 := ButtonCancel or ButtonEscape;
        Button2 := 0;
      end;
    MB_ABORTRETRYIGNORE:
      begin
        Button0 := ButtonAbort;
        Button1 := ButtonRetry or ButtonDefault;
        Button2 := ButtonIgnore;
      end;
    MB_YESNOCANCEL:
      begin
        Button0 := ButtonYes;
        Button1 := ButtonNo;
        Button2 := ButtonCancel or ButtonEscape;
      end;
    MB_YESNO:
      begin
        Button0 := ButtonYes;
        Button1 := ButtonNo or ButtonEscape;
        Button2 := 0;
      end;
    MB_RETRYCANCEL:
      begin
        Button0 := ButtonRetry;
        Button1 := ButtonCancel or ButtonEscape;
        Button2 := 0;
      end;
  else     // MB_OK and non supported
    begin
      Button0 := ButtonOk or ButtonEscape;
      Button1 := 0;
      Button2 := 0;
    end;
  end;
  case (WinFlags and $300) of
    MB_DEFBUTTON2: Button1 := Button1 or ButtonDefault;
    MB_DEFBUTTON3: Button2 := Button2 or ButtonDefault;
  else
  // MB_DEFBUTTON1:
    Button0 := Button0 or ButtonDefault;
  end;
  case (WinFlags and $F0) of
    MB_ICONINFORMATION:
      Result := QMessageBox_information(parent, @caption, @text,
                                        button0, button1, button2);
    MB_ICONWARNING:
      Result := QMessageBox_warning(parent, @caption, @text,
                                        button0, button1, button2);
    MB_ICONQUESTION:
      Result := QMessageBox_information(parent, @caption, @text,
                                        button0, button1, button2);
  else
//  MB_ICONSTOP:
    Result := QMessageBox_critical(parent, @caption, @text,
                                      button0, button1, button2);
  end;
end;

function MessageBox(parent: QWidgetH; pText, pCaption: PChar; WinFlags: Cardinal): Integer;
var
  wsText, wsCaption: WideString;
begin
  wsText := pText;
  wsCaption := pCaption;
  Result := MessageBox(parent, wsText, wsCaption, WinFlags);
end;

function MessageBox(parent: QWidgetH; Text, Caption: String; WinFlags: Cardinal): Integer; overload;
begin
  Result := MessageBox(parent, Text, Caption, WinFlags);
end;

function MessageBoxW(parent: QWidgetH; pText, pCaption: PWideChar; WinFlags: Cardinal): Integer;
var
  wsText, wsCaption: WideString;
begin
  wsText := pText;
  wsCaption := pCaption;
  Result := MessageBox(parent, wsText, wsCaption, WinFlags);
end;

function SelectObject(Handle: QPainterH; Font: QFontH): QFontH;
begin
  Result := QPainter_font(Handle);
  QPainter_setFont(Handle, Font);
end;

function SelectObject(Handle: QPainterH; Brush: QBrushH): QBrushH;
begin
  Result := QPainter_brush(Handle);
  QPainter_setBrush(Handle, Brush);
end;

function SelectObject(Handle: QPainterH; Pen: QPenH): QPenH;
begin
  Result := QPainter_pen(Handle);
  QPainter_setPen(Handle, Pen);
end;

function SelectObject(Handle: QPainterH; Bitmap: QPixmapH): QPixmapH;
var
  P: PPainterInfo;
begin
  if GetPainterInfo(Handle, P) and (P.IsCompatibleDC) then
  begin
    Result := QPixmapH(QPainter_device(Handle)); // IsCompatibleDC -> device is QPixmapH
    if QPainter_isActive(Handle) then
      QPainter_end(Handle);

    QPainter_begin(Handle, Bitmap);
  end
  else
    //Result := nil;
    raise Exception.Create('SelectObject(HBITMAP) is limited to CreateCompatibleDC handles');
end;

function GetRegionType(rgn: QRegionH): Integer;
var
  R: TRect;
begin
  try
    if QRegion_isEmpty(rgn) then
      Result := NULLREGION
    else
    begin
      QRegion_boundingRect(rgn, @R);
      if QRegion_contains(rgn, PRect(@R)) then
        Result := SIMPLEREGION
      else
        Result := COMPLEXREGION;
    end;
  except
    Result := RGN_ERROR;
  end;
end;

function CreateEllipticRgn(Left, Top, Right, Bottom: Integer): QRegionH;
begin
  Result := QRegion_create(Left, Top, Right - Left, Bottom - Top, QRegionRegionType_Ellipse);
end;

function CreateEllipticRgnIndirect(Rect: TRect): QRegionH;
begin
  Result := QRegion_create(@Rect, QRegionRegionType_Ellipse);
end;

function CreateRectRgn(Left, Top, Right, Bottom: Integer): QRegionH;
var
  R: TRect;
begin
  SetRect(R, Left, Top, Right, Bottom);
  Result := QRegion_create(@R, QRegionRegionType_Rectangle);
end;

function CreateRectRgnIndirect(Rect: TRect): QRegionH;
begin
  Result := QRegion_create(@Rect, QRegionRegionType_Rectangle);
end;

function CreateRoundRectRgn(x1, y1, x2, y2, WidthEllipse, HeightEllipse: Integer): QRegionH;
var
  Bmp: QBitmapH;
  Painter: QPainterH;
begin
  Bmp := QBitmap_create(x2-x1+1, y2-y1+1, True, QPixmapOptimization_DefaultOptim);
  Painter := QPainter_create(Bmp);
  QPainter_setBrush(Painter, QPen_color(QPainter_pen(painter)));
  QPainter_drawRoundRect(Painter, 0, 0, x2-x1, y2-y1, WidthEllipse, HeightEllipse);
  QPainter_destroy(Painter);
  Result := QRegion_create(Bmp);
  QBitmap_destroy(Bmp);
  QRegion_translate(Result, x1, y1);
end;

function CreatePolygonRgn(const Points; Count, FillMode: Integer): QRegionH;
var
  pts: TPointArray;
  i: Integer;
  p: PPoint;
begin
  SetLength(pts, Count);
  p := PPoint(@Points);
  for i := 0 to Count - 1 do
  begin
    pts[i].X := p.X;
    pts[i].Y := p.Y;
    Inc(p);
  end;
  Result := QRegion_create(@pts[0], Fillmode = WINDING);
end;

function SelectClipRgn(Handle: QPainterH; Region: QRegionH): Integer;
var
  Clipping: Boolean;
begin
  Result := RGN_ERROR;
  if Handle = nil then
    Exit;
  try
    Clipping := Region <> nil;
    if Clipping then
    begin
      Region := CreateMappedRegion(Handle, Region);
      try
        QPainter_setClipRegion(Handle, Region);
        Result := GetRegionType(Region);
      finally
        QRegion_destroy(Region);
      end;
    end
    else
      Result := NULLREGION;
    QPainter_setClipping(Handle, Clipping);
  except
    Result := RGN_ERROR;
  end;
end;

function SelectClipRgn(Handle: QPainterH; Region: Integer): Integer;
begin
  Result := SelectClipRgn(Handle, QRegionH(Region));
end;

function ExcludeClipRect(Handle: QPainterH; X1, Y1, X2, Y2: Integer): Integer;
var
  ExcludeRgn, Rgn: QRegionH;
begin
  MapPainterLP(Handle, X1, Y1, X2, Y2);
  ExcludeRgn := QRegion_create(X1, Y1, X2 - X1, Y2 - Y1, QRegionRegionType_Rectangle);
  try
    Rgn := QPainter_clipRegion(Handle);
    QRegion_subtract(Rgn, Rgn, ExcludeRgn);
    QPainter_setClipRegion(Handle, Rgn); // otherwide the new clip region is not accepter
    QPainter_setClipping(Handle, True);
    Result := GetRegionType(Rgn);
  except
    Result := RGN_ERROR;
  end;
  QRegion_destroy(ExcludeRgn);
end;

function ExcludeClipRect(Handle: QPainterH; const R: TRect): Integer;
begin
  with R do
    Result := ExcludeClipRect(Handle, Left, Top, Right, Bottom);
end;

function IntersectClipRect(Handle: QPainterH; X1, Y1, X2, Y2: Integer): Integer;
var
  IntersectRgn, Rgn: QRegionH;
begin
  MapPainterLP(Handle, X1, Y1, X2, Y2);
  IntersectRgn := QRegion_create(X1, Y1, X2 - X1, Y2 - Y1, QRegionRegionType_Rectangle);
  try
    if QPainter_hasClipping(Handle) then
    begin
      Rgn := QPainter_clipRegion(Handle);
      if QRegion_isNull(Rgn) then
        QRegion_unite(Rgn, Rgn, IntersectRgn)
      else
        QRegion_intersect(Rgn, Rgn, IntersectRgn);
    end
    else
    begin
      QPainter_setClipRegion(Handle, InterSectRgn);
      Rgn := QPainter_clipRegion(Handle);
    end;
    QPainter_setClipping(Handle, True);
    Result := GetRegionType(Rgn);
  except
    Result := RGN_ERROR;
  end;
  QRegion_destroy(IntersectRgn);
end;

function IntersectClipRect(Handle: QPainterH; const R: TRect): Integer;
begin
  with R do
    Result := IntersectClipRect(Handle, Left, Top, Right, Bottom);
end;

function SetRectRgn(Rgn: QRegionH; X1, Y1, X2, Y2: Integer): LongBool;
var
  rgn2: QRegionH;
  R: TRect;
begin
  SetRect(R, X1, Y1, X2, Y2);
  rgn2 := QRegion_create(@R, QRegionRegionType_Rectangle);
  try
    QRegion_unite(rgn2, rgn, rgn2);
    Result := True;
  except
    Result := False;
  end;
  QRegion_destroy(rgn2);
end;

function EqualRgn(Rgn1, Rgn2: QRegionH): LongBool;
var
  tmpRgn: QRegionH;
begin
  tmpRgn := QRegion_create;
  try
    Result := CombineRgn(tmpRgn, Rgn1, Rgn2, RGN_XOR) = NULLREGION
  except
    Result := False;
  end;
  QRegion_destroy(tmpRgn);
end;

function GetClipRgn(Handle: QPainterH; rgn: QRegionH): Integer;
begin
  if QPainter_hasClipping(Handle)
  then
  begin
    QRegion_unite(QPainter_clipRegion(Handle), rgn, QPainter_clipRegion(Handle));
    Result := GetRegionType(rgn);
  end
  else
    Result := NULLREGION;
end;

function CombineRgn(DestRgn, Source1, Source2: QRegionH;
  Operation: TCombineMode): Integer;
begin
  try
    case Operation of
      RGN_OR:
        QRegion_unite(Source1, DestRgn, Source2);
      RGN_AND:
        QRegion_intersect(Source1, DestRgn, Source2);
      // RGN_DIFF Subtracts Source2 from Source1
      RGN_DIFF:
        QRegion_subtract(Source1, DestRgn, Source2);
      // RGN_XOR creates the union of two combined regions except for any
      // overlapping areas.
      RGN_XOR:
        QRegion_eor(Source1, DestRgn, Source2);
      // RGN_COPY: Creates a copy of the region identified by Source1.
      RGN_COPY:
        QRegion_unite(Source1, DestRgn, Source1)
    else
      Result := RGN_ERROR;
      Exit;
    end;
    Result := GetRegionType(DestRgn);
  except
    Result := RGN_ERROR;
  end;
end;

function OffsetRgn(Region: QRegionH; X, Y:Integer): Integer;
begin
  QRegion_translate(Region, X, Y);
  Result := GetRegionType(Region);
end;

function OffsetClipRgn(Handle: QPainterH; X, Y: Integer): Integer;
begin
  try
    if QPainter_hasClipping(Handle) then
    begin
      OffsetRgn(QPainter_clipRegion(Handle), X, Y);
      Result := GetRegionType(QPainter_clipRegion(Handle));
    end
    else
      Result := RGN_ERROR;
  except
    Result := RGN_ERROR;
  end;
end;

function InvertRgn(Handle: QPainterH; Region: QRegionH): LongBool;
var
  Rgn: QRegionH;
  R: TRect;
begin
  try
    QPainter_window(Handle, @R);
    OffsetRect(R, -R.Left, -R.Top);
    rgn := QRegion_create(@R, QRegionRegionType_Rectangle);
    try
      QRegion_subtract(rgn, Region, Region);
      Result := True;
    except
      Result := False;
    end;
    QRegion_destroy(rgn);
  except
    Result := False;
  end;
end;

function FillRgn(Handle: QPainterH; Region: QRegionH; Brush: QBrushH): LongBool;
var
  OldRgn: QRegionH;
  R: TRect;
  hasClipping: Boolean;
begin
  OldRgn := nil;
  Result := False;
  QPainter_save(Handle);
  try
    hasClipping := QPainter_hasClipping(Handle);
    if hasClipping then
      OldRgn := QPainter_clipRegion(Handle);
    if SelectClipRgn(Handle, Region) <> RGN_ERROR then
    begin
      QRegion_boundingRect(Region, @R);
      QPainter_fillRect(Handle, @R, Brush);
      if hasClipping then
        SelectClipRgn(Handle, OldRgn);
      Result := True;
    end;
  finally
    QPainter_restore(Handle);
  end;
end;

function FrameRgn(Handle: QPainterH; Region: QRegionH; Brush: QBrushH; Width, Height: integer): LongBool;
var
  R: TRect;
  X, Y: integer;
  Pen: QPenH;

  function IsBorderPoint(X, Y: integer): Boolean;
  var
    I, J, K: integer;
  begin
    Result := False;
    if PtInRegion(Region, X, Y) then
    begin
      K := 0;
      For I := -Width to Width do
        For J := -Height to Height do
        begin
          If not PtInRegion(Region, X + I , Y + J) then
          begin
            Inc(K);
            if K > 1 then  // 2 points required windows uses 1 point
            begin
              Result := True;
              exit;
            end;
          end;
        end
    end;
  end;
begin
//  Result := false;
  QPainter_save(Handle);
  try
    QRegion_boundingRect(Region, @R);
    Pen := QPen_create(QBrush_color(Brush), 1, PenStyle_SolidLine);
    try
      QPainter_setPen(Handle, Pen);
    finally
      QPen_destroy(Pen);
    end;
    for X := R.Left to R.Right do
      for Y := R.Top to R.Bottom do
        if IsBorderPoint(X, Y) then
          QPainter_drawPoint(Handle, X, Y);
    Result := True;
  finally
    QPainter_restore(Handle);
  end;
end;

function DeleteObject(Region: QRegionH): LongBool;
begin
  try
//    if not TStockObjectList.ReleaseStockObject(Region) then
      QRegion_destroy(Region);
    Result := True;
  except
    Result := False;
  end;
end;

function PtInRegion(Rgn: QRegionH; X, Y: Integer): Boolean;
var
  P :TPoint;
begin
  P.X := X;
  P.Y := Y;
  Result := QRegion_contains(Rgn, PPoint(@P));
end;

function RectInRegion(Rgn: QRegionH; const Rect: TRect): LongBool;
begin
  try
    Result := QRegion_contains(Rgn, PRect(@Rect));
  except
    Result := False;
  end;
end;

function SetWindowRgn(Handle: QWidgetH; Region: QRegionH; Redraw: LongBool): Integer;
begin
  Result := 0;
  if Handle <> nil then
  try
    if Region <> nil then
    begin
      QWidget_setMask(Handle, Region);
      DeleteObject(Region); // Windows owns the window region
    end
    else
      QWidget_clearMask(Handle);
    if Redraw then
      UpdateWindow(Handle);
    Result := 1;
  except
    Result := 0;
  end;
end;

function GetWindowRgn(Handle: QWidgetH; Region: QRegionH): Integer;
begin
  if (Region <> nil) and (Handle <> nil) then
  begin
    try
      // there is no QWidget_mask() function
      // asn: note region without windows/X11 decoration
      QWidget_childrenRegion(Handle, Region);
      Result := GetRegionType(Region);
    except
      Result := ERROR;
    end;
  end
  else
    Result := ERROR;
end;

function LPtoDP(Handle: QPainterH; var Points; Count: Integer): LongBool;
var
  P: PPoint;
begin
  Result := True;
  try
    P := @Points;
    while Count > 0 do
    begin
      Dec(Count);
      QPainter_xForm(Handle, P, P);
      Inc(P);
    end;
  except
    Result := False;
  end;
end;

function DPtoLP(Handle: QPainterH; var Points; Count: Integer): LongBool;
var
  P: PPoint;
begin
  Result := True;
  try
    P := @Points;
    while Count > 0 do
    begin
      Dec(Count);
      QPainter_xFormDev(Handle, P, P);
      Inc(P);
    end;
  except
    Result := False;
  end;
end;

function SetViewPortOrgEx(Handle: QPainterH; X, Y: Integer; OldOrg: PPoint): LongBool;
var
  R :TRect;
begin
  try
    QPainter_viewport(Handle, @R);
    if OldOrg <> nil then
    begin
      OldOrg.X := R.Left;
      OldOrg.Y := R.Top;
    end;
    QPainter_setViewport(Handle, X, Y, R.Right - R.Left, R.Bottom - R.Top);
    Result := True;
  except
    Result := False;
  end;
end;

function SetViewportExtEx(Handle: QPainterH; XExt, YExt: Integer; Size: PSize): LongBool;
var
  R :TRect;
begin
  Result := True;
  try
    QPainter_viewport(Handle, @R);
    if size <> nil then
    begin
      Size.cx := R.Right - R.Left;
      Size.cy := R.Bottom - R.Top;
    end;
    QPainter_setViewport(Handle, R.Left, R.Top, XExt, YExt);
  except
    Result := False;
  end;
end;

function GetViewportExtEx(Handle: QPainterH; Size: PSize): LongBool;
var
  R :TRect;
begin
  Result := True;
  try
    QPainter_viewport(Handle, @R);
    Size.cx := R.Right - R.Left;
    Size.cy := R.Bottom - R.Top;
  except
    Result := False;
  end;
end;

function GetWindowOrgEx(Handle: QPainterH; Org: PPoint): LongBool;
var
  R :TRect;
begin
  try
    QPainter_window(Handle, @R);
    Org.X := R.Left;
    Org.Y := R.Top;
    Result := True;
  except
    Result := False;
  end;
end;

function GetWindowOrgEx(Handle: QPainterH; var Org: TPoint): LongBool;
begin
  Result := GetWindowOrgEx(Handle, @Org);
end;

function SetWindowOrgEx(Handle: QPainterH; X, Y: Integer; OldOrg: PPoint): LongBool;
var
  R :TRect;
begin
  try
    QPainter_window(Handle, @R);
    with R do
    begin
      if OldOrg <> nil then
      begin
        OldOrg.X := Left;
        OldOrg.Y := Top;
      end;
      QPainter_setWindow(Handle, X, Y, Right - Left, Bottom - Top);
    end;
    Result := True;
  except
    Result := False;
  end;
end;

procedure CopyMemory(Dest: Pointer; Src: Pointer; Len: Cardinal);
begin
  Move(Src^, Dest^, Len);
end;

procedure FillMemory(Dest: Pointer; Len: Cardinal; Fill: Byte);
begin
  FillChar(Dest^, Len, Fill);
end;

procedure MoveMemory(Dest: Pointer; Src: Pointer; Len: Cardinal);
begin
  Move(Src^, Dest^, Len);
end;

procedure ZeroMemory(Dest: Pointer; Len: Cardinal);
begin
  FillChar(Dest^, Len, 0);
end;

function GetDoubleClickTime: Cardinal;
begin
  Result := QApplication_doubleClickInterval;
end;

function SetDoubleClickTime(Interval: Cardinal): LongBool;
begin
  try
    QApplication_setDoubleClickInterval(Interval);
    Result := True;
  except
    Result := False;
  end;
end;

function ReleaseCapture: LongBool;
var
  Handle: QWidgetH;
begin
  Handle := QWidget_mouseGrabber;
  if Handle <> nil then
  begin
    QWidget_releaseMouse(Handle);
    SetMouseGrabControl(nil);  // inform CLX
    Result := True;
  end
  else
    Result := False;
end;

function SetCapture(Widget: QWidgetH): QWidgetH;
begin
  Result := QWidget_mouseGrabber;
  ReleaseCapture;
  if Widget <> nil then
    QWidget_grabMouse(Widget);
end;

function GetCapture: QWidgetH;
begin
  Result := QWidget_mouseGrabber;
end;

function SetCursor(Handle: QCursorH; Save: Boolean): QCursorH;
begin
  Result := QApplication_overrideCursor;
  if Handle <> nil then
    QApplication_setOverrideCursor(Handle, Save)
  else
    QApplication_restoreOverrideCursor;
end;

// limited implementation of
function GetSystemMetrics(PropItem: TSysMetrics): Integer;
var
  size: TSize;
begin
  case PropItem of
    SM_CXVSCROLL, SM_CXHSCROLL:
      begin
        QStyle_scrollBarExtent(QApplication_Style, @size);
        Result := size.cx;
      end;
    SM_CYVSCROLL, SM_CYHSCROLL:
      begin
        QStyle_scrollBarExtent(QApplication_Style, @size);
        Result := size.cy;
      end;
    SM_CXSMICON, SM_CYSMICON:
      Result := 16;
    SM_CXICON, SM_CYICON:
      Result := 32;
    SM_CXSCREEN:
      Result := QWidget_width(QApplication_desktop);
    SM_CYSCREEN:
      Result := QWidget_height(QApplication_desktop);
    SM_CXBORDER, SM_CYBORDER:
      Result := 1;
        // (ahuser) Windows returns "1"
        //QStyle_DefaultFrameWidth(QApplication_style); // (probably) wrong ?
    SM_CXFRAME, SM_CYFRAME, SM_CXDLGFRAME, SM_CYDLGFRAME:
      Result := QStyle_DefaultFrameWidth(QApplication_style); // or this one
    SM_CYCAPTION:
      Result := 19;
  else
    raise Exception.Create('GetSystemMetrics: unsupported property')
  end;
end;

{ limited implementation of}

function GetDeviceCaps(Handle: QPainterH; devcap: TDeviceCap): Integer;
begin
  Result := GetDeviceCaps(QPainter_device(Handle), devcap);
end;

function GetDeviceCaps(Handle: QPaintDeviceH; devcap: TDeviceCap): Integer;
var
  pdm:  QPaintDeviceMetricsH;
begin
  Result := 0;
  pdm := QPaintDeviceMetrics_create(Handle);
  if pdm <> nil then
  begin
    try
      case devcap of
        HORZSIZE:
          Result := QPaintDeviceMetrics_widthMM(pdm);
        VERTSIZE:
          Result := QPaintDeviceMetrics_heightMM(pdm);
        PHYSICALWIDTH, HORZRES:
          Result := QPaintDeviceMetrics_width(pdm); // Horizontal width in pixels
        BITSPIXEL:
          Result := QPaintDeviceMetrics_Depth(pdm); // Number of bits per pixel
        PLANES:
          Result := 1;
        NUMCOLORS:
          Result := QPaintDeviceMetrics_numColors(pdm);
        LOGPIXELSX:
          Result := QPaintDeviceMetrics_logicalDpiX(pdm); // Logical pixelsinch in X
        LOGPIXELSY:
          Result := QPaintDeviceMetrics_logicalDpiY(pdm); // Logical pixelsinch in Y
        PHYSICALOFFSETX:
          Result := 0;
        PHYSICALOFFSETY:
          Result := 0;
        PHYSICALHEIGHT, VERTRES:
          Result := QPaintDeviceMetrics_height(pdm); // Vertical height in pixels
      else
        raise Exception.Create('QWindows.GetDeviceCaps: unsupported capability');
      end;
    finally
      QPaintDeviceMetrics_destroy(pdm);
    end;
  end;
end;

function pfDevice: TPixelFormat;
var
  DC: QPaintDeviceH;
begin
  DC := QWidget_to_QPaintDevice(QApplication_desktop);
  case GetDeviceCaps(DC, BITSPIXEL) of
     1: Result := pf1bit;
     8: Result := pf8bit;
    16: Result := pf16bit;
    24: Result := pf24bit;
    32: Result := pf32bit;
  else
    Result := pfCustom;
  end;
end;

{ a very limited implementation of }
function GetTextMetrics(Handle: QPainterH; var tt: TTextMetric): Integer;
var
  fm: QFontMetricsH;
  fi: QFontInfoH;
begin
  FillChar(tt, SizeOf(tt), 0);
  with tt do
  begin
    fm := QFontMetrics_create(QPainter_font(Handle));
    try
      tmHeight := QFontMetrics_height(fm);
      tmAscent := QFontMetrics_ascent(fm);
      tmDescent := QFontMetrics_descent(fm);
      tmAveCharWidth := QFontMetrics_width(fm, 'x');
      tmMaxCharWidth := QFontMetrics_maxWidth(fm);
      //tmInternalLeading := 0;
      tmExternalLeading := QFontMetrics_leading(fm);
      //tmOverhang := 0;
    finally
      QFontMetrics_destroy(fm);
    end;

    fi := QFontInfo_create(QPainter_font(Handle));
    try
      QPainter_fontInfo(Handle, fi);
      case QFontInfo_weight(fi) of
        25: // Light
          tmWeight := 300;
        50: // Normal:
          tmWeight := 400;
        63: // DemiBold
          tmWeight := 600;
        75: // Bold
          tmWeight := 700;
        87: // Black
          tmWeight := 900;
      else
        tmWeight := Round(QFontInfo_weight(fi) * 9.5);
      end;

      tmItalic := Ord(QFontInfo_italic(fi));
      tmUnderlined := Ord(QFontInfo_underline(fi));
      tmStruckOut := Ord(QFontInfo_strikeOut(fi));
      if QFontInfo_fixedPitch(fi) then
        tmPitchAndFamily := FIXED_PITCH
      else
        tmPitchAndFamily := VARIABLE_PITCH;
      tmCharSet := DEFAULT_CHARSET;
    finally
      QFontInfo_destroy(fi);
    end;
  end;
  Result := 0;
end;

function ColorToRGB(Color: TColor; Instance: TWidgetControl = nil): TColor;
var
  FColor: QColorH;
  FColorGroup: QPaletteColorGroup;

  FColorRole: QColorGroupColorRole;
  FPalette: QPaletteH;

  function GetPaletteHandle(Widget: TWidgetControl): QPaletteH;
  begin
    if Widget = nil then
      Result := Application.Palette.Handle
    else
    begin
      Result := THackedWidgetControl(Widget).Palette.Handle;
      while (Result = nil) and (Widget.Parent <> nil) do
      begin
        Widget := Widget.Parent;
        Result := THackedWidgetControl(Widget).Palette.Handle;
      end;
      if Result = nil then
        Result := Application.Palette.Handle;
    end;
  end;

begin
  case Color of
  clColorTo..clForeground:
    begin
      if assigned(Instance) then
        if not Instance.Enabled then
          FColorGroup := QPaletteColorGroup_Disabled
        else
          if Instance.Focused then
            FColorGroup := QPaletteColorGroup_Active
          else
            FColorGroup := QPaletteColorGroup_InActive
      else
        FColorGroup := QPaletteColorGroup_InActive ;
    end;
  clActiveColorTo..clActiveForeground,
  clNormalColorTo..clNormalForeground,
  clDisabledColorTo..clDisabledForeground:
      FColorGroup := ColorGroup(Color);
  else
    Result := Color;
    Exit;
  end;
  FColorRole := ColorRole(Color); {1..15}
  FPalette := GetPaletteHandle(Instance);
  FColor := QPalette_color(FPalette, FColorGroup, FColorRole);
  Result := QColorColor(FColor);
//  QColor_destroy(FColor);  {not owned}
end;


function RGB(Red, Green, Blue: Integer): TColorRef;
begin
  Result := (Blue shl 16) or (Green shl 8) or Red;
end;

function GetBValue(Col: TColorRef): Byte;
begin
  Result := Byte((Col shr 16) and $FF);
end;

function GetGValue(Col: TColorRef): Byte;
begin
  Result := Byte((Col shr 8) and $FF);
end;

function GetRValue(Col: TColorRef): Byte;
begin
  Result := Byte(Col and $FF);
end;

function SetRect(var R: TRect; Left, Top, Right, Bottom: Integer): LongBool;
begin
  R := Rect(Left, Top, Right, Bottom);
  Result := True;
end;

function CopyRect(var Dst: TRect; const Src: TRect): LongBool;
begin
  Dst := Src;
  Result := True;
end;

function UnionRect(var Dst: TRect; R1, R2: TRect): LongBool;
begin
  Result := True;
  if IsRectEmpty(R1) then
  begin
    if IsRectEmpty(R2) then
      Result := False  // both empty
    else
    begin
      Dst := R2;
      Result := True;
    end;
  end
  else if IsRectEmpty(R2) then
    Dst := R1
  else
    with Dst do
    begin
      Left := Min(R1.Left, R2.Left);
      Top := Min(R1.Top, R2.Top);
      Right := Max(R1.Right, R2.Right);
      Bottom := Max(R1.Bottom, R2.Bottom);
    end;
end;

function IsRectEmpty(R: TRect): LongBool;
begin
  with R do
    Result := (Right <= Left) or (Bottom <= Top);
end;

function EqualRect(R1, R2: TRect): LongBool;
begin
  Result := (R1.Left = R2.Left) and (R1.Right = R2.Right) and
            (R1.Top = R2.Top) and (R1.Bottom = R2.Bottom)
end;

function EqualPoints(const P1: TPoint; const P2: TPoint): Boolean;
begin
  Result := (P1.X = P2.X) and (P1.Y = P2.Y);
end;

function CenterRect(InnerRect, OuterRect: TRect): TRect;
var
  w,h : Integer;
begin
  w := InnerRect.Right - InnerRect.Left;
  h := InnerRect.Bottom - InnerRect.Top;
  Result.Left := (OuterRect.Right + OuterRect.Left - w)div 2;
  Result.Top := (OuterRect.Bottom + OuterRect.Top - h)div 2;
  Result := Bounds( Result.Left, Result.Top, w, h );
end;

function SubtractRect(var dR: TRect; const R1, R2: TRect): LongBool;
var
  R3: TRect;
begin
  try
    dR := R1;
    if IntersectRect(R3, R1, R2) then
    begin
      if EqualPoints(R3.BottomRight, R1.BottomRight) then
      begin
        if R3.Top = R1.Top
        then
          dR.Right := R3.Left
        else if R3.Left = R1.Left
        then
          dR.Bottom := R3.Top
      end
      else
      if EqualPoints(R3.TopLeft, R1.TopLeft) then
      begin
        if R3.Bottom = R1.Bottom
        then
          dR.Left := R3.Right
        else if R3.Right = R1.Right
        then
          dR.Bottom := R3.Top;
      end;
    end;
    Result := True;
  except
    Result := False;
  end;
end;

function IntersectRect(var R: TRect; const R1, R2: TRect): LongBool;
begin
  Result := Types.IntersectRect(R, R1, R2);
end;

function PtInRect(const R: TRect; X, Y: integer): LongBool;
begin
  with R do
    Result := (X >= Left) and (X <= Right) and
              (Y >= Top) and (Y <= Bottom);
end;

function PtInRect(const R: TRect; pt: TPoint): LongBool;
begin
  Result := PtInRect(R, pt.X, Pt.Y);
end;

function PtInEllipse(const R: TRect; pt: TPoint): LongBool;
begin
  Result := PointInEllipse(pt, R);
end;

function PointInEllipse(pt: TPoint; BoundingRect: TRect): boolean;
var
  p, q, r, s: integer;
begin
  with BoundingRect do
  begin
    p := 2 * pt.X - (Left + Right);
    p := p * p;
    q := 2 * pt.Y - (Top + Bottom);
    q := q * q;
    r := Right - Left;
    r := r * r;
    s := Bottom - Top;
    s := s * s;
    Result := p * s + q * r <=  s * r ;
 end;
end;

procedure TextOutAngle(Handle: QPainterH; Angle, Left, Top: Integer; Text: WideString);
{ deprecated use DrawText instead }
begin
  try
    QPainter_save(Handle);
    QPainter_translate(Handle, Left, Top);
    QPainter_rotate(Handle, -Angle);
    QPainter_drawText(Handle, 0, 0, @Text, -1);
  finally
    QPainter_restore(Handle);
  end;
end;

procedure RequiredState(ACanvas: TCanvas; State: TCanvasState);
begin
  THackCanvas(Acanvas).RequiredState(State);
end;

procedure TextOutAngle(ACanvas: TCanvas; Angle, Left, Top: Integer; Text: WideString);
{ deprecated use DrawText instead }
begin
  ACanvas.Start;
  RequiredState(ACanvas, [csHandleValid, csFontValid, csBrushValid]);
  TextOutAngle(ACanvas.Handle, Angle, Left, Top, Text);
  ACanvas.Stop;
end;

function TextWidth(Handle: QPainterH; Caption: WideString;
  QtFlags: Integer = 0): Integer;
var
  R :TRect;
begin
  QPainter_boundingRect(Handle, @R, @R, QtFlags, PWideString(@Caption), -1, nil);
  Result := R.Right - R.Left;
end;

function TextHeight(Handle: QPainterH; Caption: WideString; R: TRect;
  QtFlags: Integer = 0): Integer;
var
  R1, R2: TRect;
begin
  R1 := R;
  R1.Bottom := MaxInt;
  QPainter_boundingRect(Handle, @R1, @R2, QtFlags, PWideString(@Caption), -1, nil);
  Result := R2.Bottom - R2.Top;
end;

function GetTextExtentPoint32(Handle: QPainterH; const Text: WideString; Len: Integer;
  var Size: TSize): LongBool;
var
  R: TRect;
begin
  try
    QPainter_boundingRect(Handle, @R, @R, 0, @Text, Len, nil);
    with R do
    begin
      Size.cx := Right - Left;
      Size.cy := Bottom - Top;
    end;
    Result := True;
  except
    Result := False;
  end;
end;

function GetTextExtentPoint32(Handle: QPainterH; pText: PChar; Len: Integer;
  var Size: TSize): LongBool;
var
  Text: WideString;
begin
  Text := pText;
  Result := GetTextExtentPoint32(Handle, Text, Len, Size);
end;

function GetTextExtentPoint32(Canvas: TCanvas; const Text: WideString; Len: Integer;
  var Size: TSize): LongBool;
begin
  Canvas.Start;
  RequiredState(Canvas, [csHandleValid, csFontValid, csBrushValid]);
  Result := GetTextExtentPoint32W(Canvas.Handle, PWideChar(Text), Len, Size);
  Canvas.Stop;
end;

function GetTextExtentPoint32W(Handle: QPainterH; pText: PWideChar; Len: Integer;
  var Size :TSize): LongBool;
var
  Text: WideString;
begin
  Text := pText;
  Result := GetTextExtentPoint32(Handle, Text, Len, Size);
end;

function TextExtent(Handle: QPainterH; const Caption: WideString; R: TRect;
  QtFlags: Integer): TRect;
var
  R2: TRect;
begin
  R2 := R;
  R2.Bottom := MaxInt;
  QPainter_boundingRect(Handle, @R2, @Result, QtFlags, PWideString(@Caption), -1, nil);

//  QPainter_boundingRect(Handle, @Result, @Result, Flags, PWideString(@Caption), -1, nil);
end;

const
  Ellipses = '...';

function NameEllipsis(const Name: WideString; Handle: QPainterH;
  MaxLen: Integer; QtFlags: integer = 0): WideString;
var
  I: Integer;
begin
  if TextWidth(Handle, Name, QtFlags) > MaxLen then
  begin
    Result := Ellipses;
    I := 0;
    while TextWidth(Handle, Result, QtFlags) <= MaxLen do
    begin
      Inc(I);
      Result := LeftStr(Name, I) + Ellipses;
    end;
    if I <> 0 then
      Result := LeftStr(Name, I-1) + Ellipses;
  end
  else
    Result := name;
end;

function WordEllipsis(Words: WideString; Handle: QPainterH; const R: TRect;
  QtFlags: Integer = 0): WideString;
var
  R2, R1: TRect;
  ShortedText: WideString;
  I: Integer;

  function RectInsideRect(const R1, R2: TRect): Boolean;
  begin
    with R1 do
      Result := (Left >= R2.Left) and (Right  <= R2.Right) and
                (Top  >= R2.Top)  and (Bottom <= R2.Bottom);
  end;

begin
  Result := ShortedText;
  R1 := R;
  R1.Bottom := MaxInt;
  QPainter_boundingRect(Handle, @R1, @R2, QtFlags, PWideString(@Result), -1, nil);
  if not RectInsideRect(R2, R) then
  begin
    I := 1;
    ShortedText := '';
    while RectInsideRect(R2, R) and (I <= Length(Words)) do
    begin
      repeat                 // one more word
        ShortedText := LeftStr(Words, I);
        if Words[I] = ' ' then
          Break;
        Inc(I);
      until I > Length(Words);
      Result := ShortedText + '...';
      QPainter_boundingRect(Handle, @R1, @R2, QtFlags, PWideString(@Result), -1, nil);
    end;
    While not RectInsideRect(R2, R) and (I > 0) do
    begin
      repeat // one word less
        Dec(I);
        ShortedText := LeftStr(Words, I);
        if ShortedText[I] = ' ' then
          Break;
      until I <= 1;
      Result := ShortedText + Ellipses;
      QPainter_boundingRect(Handle, @R1, @R2, QtFlags, PWideString(@Result), -1, nil);
    end;
  end;
end;

function FileEllipsis(const FilePath: AnsiString; Handle: QPainterH; MaxLen: Integer): string;
var
  Paths: TStrings;
  k, i, Start: Integer;
  CurPath, F: AnsiString;
begin
  if TextWidth(Handle, FilePath, SingleLine) <= MaxLen then
    Result := FilePath
  else
  begin    // FilePath too long
    F := FilePath;
    {$IFDEF LINUX}
    CurPath := IncludeTrailingPathDelimiter(GetEnvironmentVariable('HOME'));
    if AnsiStartsStr(CurPath, FilePath) then
    begin
      F := '~/' + AnsiRightStr(FilePath, Length(FilePath) - Length(CurPath));
      if TextWidth(Handle, F, SingleLine) <= MaxLen then
      begin
        Result := F;
        Exit;
      end
    end;
    {$ENDIF LINUX}
    Paths := TStringList.Create;
    try
      Paths.Delimiter := PathDelim;
      Paths.DelimitedText := F; // splits the filepath
      if Paths[0] = '' then
        Start := 1     // absolute path
      else
        Start := 0;    // relative path
      for k := Start to Paths.Count - 2 do
      begin
        CurPath := Paths[k];
        if Length(CurPath) > 2 then   // this excludes '~' '..'
        begin
          Paths[k] := CurPath; // replace with ellipses
          I := Length(CurPath);
          while (I > 0) and (TextWidth(Handle, Paths.DelimitedText, SingleLine) > MaxLen) do
          begin
            Dec(I);
            Paths[k] := LeftStr(CurPath, I) + Ellipses;// remove a character
          end;
          if TextWidth(Handle, Paths.DelimitedText, SingleLine) <= MaxLen then
          begin
            Result := Paths.DelimitedText;
            Exit;
          end;
        end
      end;
      // not succeeded.
      // replace /.../.../.../<filename> with .../<filename>
      // before starting to minimize filename
      for k := Paths.Count - 2 downto 1 do
        Paths.Delete(k);
      Paths[0] := Ellipses;
      if TextWidth(Handle, Paths.DelimitedText, SingleLine) > MaxLen then
      begin
        CurPath := Paths[1];
        Paths[1] := Ellipses; // replace with ellipses
        //I := 1;
        //Paths[1] := CurPath; // replace with ellipses
        I:= Length(CurPath);
        while (I > 0)  and (TextWidth(Handle, Paths.DelimitedText, SingleLine) > MaxLen) do
        begin
          Dec(I);
          Paths[I] := LeftStr(CurPath, I) + Ellipses;// remove a character
        end;
      end;
      Result := Paths.DelimitedText;    // will be something .../Progr...
    finally
      Paths.Free;
    end;
  end;
end;

function TruncatePath(const FilePath: string; Canvas: TCanvas; MaxLen: Integer): string;
begin
  Canvas.Start;
  try
    Result := FileEllipsis(FilePath, Canvas.Handle, MaxLen);
  finally
    Canvas.Stop;
  end;
end;

function TruncateName(const Name: WideString; Canvas: TCanvas; MaxLen: Integer; QtFlags: integer = 0): WideString;
begin
  Canvas.Start;
  try
    Result := NameEllipsis(Name, Canvas.Handle, MaxLen, QtFlags);
  finally
    Canvas.Stop;
  end;
end;

function DrawText2(Handle: QPainterH; var Text: WideString; Len: Integer;
  var R: TRect; WinFlags: Integer): Integer;
var
  Flags: Integer;
  R2: TRect;  // bliep bliep bl...
  Caption: WideString;
  FontSaved, FontSet: QFontH;

  function HidePrefix(const Text: WideString): WideString;
  var
    i, Len: Integer;
  begin
    Result := Text;
    Len := Length(Result);
    i := 1;
    while i <= Len do
    begin
      if (Result[i] = '&') then
      begin
        Delete(Result, i, 1);
        Dec(Len);
        if (Result[i] = '&') and (Result[i + 1] = '&') then
        begin
          Delete(Result, i, 1);
          Dec(Len);
        end;
      end;
      Inc(i);
    end;
  end;

  function OnlyPrefix(const Text: WideString): WideString;
  var
    i, Len: Integer;
  begin
    Result := Text;
    Len := Length(Result);
    i := 1;
    while i <= Len do
    begin
      if (Result[i] = '&') then
      begin
        Delete(Result, i, 1);
        Dec(Len);
        if (Result[i] = '&') and (Result[i + 1] = '&') then
        begin
          Delete(Result, i, 1);
          Dec(Len);
        end;
        Result[i] := '&';
      end
      else
        Result[i] := ' ';
      Inc(i);
    end;
  end;

  function CheckTabStop(WinFlags: Integer): Integer;
  var
    Size: Integer;
  begin
    if WinFlags and DT_TABSTOP <> 0 then
    begin
      Size := WinFlags and $FF00;
      WinFlags := WinFlags - Size;
      Size := (Size shr 8) and $FF;
      QPainter_setTabStops(Handle, Size);
    end;
    Result := WinFlags;
  end;

begin
  FontSaved := nil;
  FontSet := nil;
  if len > 0 then
    Caption := LeftStr(Text, len)
  else
    Caption := Text;
  if WinFlags and DT_INTERNAL <> 0 then
  begin
    FontSaved := QPainter_Font(Handle);
    QApplication_font(FontSet, nil);
    QPainter_setFont(Handle, FontSet);
  end;
  Flags := Win2QtAlign(CheckTabStop(WinFlags));
  if WinFlags and DT_PREFIXONLY <> 0 then
  begin
    Flags := Flags or ShowPrefix;
    Caption := OnlyPrefix(Caption);
  end
  else if WinFlags and DT_HIDEPREFIX <> 0 then
  begin
    Flags := Flags and not ShowPrefix;
    Caption := HidePrefix(Caption);
  end;
  if WinFlags and DT_CALCRECT = 0 then
  begin
    if Flags and ClipName <> 0 then
      Caption := NameEllipsis(Caption, Handle, R.Right - R.Left, Flags)
    else if Flags and ClipPath <> 0 then
      Caption := FileEllipsis(Caption, Handle, R.Right - R.Left)
    else if Flags and ClipToWord <> 0 then
      Caption := WordEllipsis(Caption, Handle, R, Flags);
    QPainter_save(Handle);
    if Flags and DontClip = 0 then // clipping
      IntersectClipRect(Handle, R); // QPainter::drawText() does not clip left/top border
    QPainter_DrawText(Handle, @R, Flags, PWideString(@Caption), -1, @R2, nil);
    QPainter_restore(Handle);
    if ModifyString and Flags <> 0 then
    begin
      if len > 0 then
        Caption := Caption + RightStr(Text, Length(Text)-len);
      Text := Caption;
    end;
    Result := R2.Bottom - R2.Top;
  end
  else
  begin
    R2.Left := R.Left;
    R2.Top := R.Top;
    QPainter_boundingRect(Handle, @R, @R, Flags and not $3F{Alignment},
                          PWideString(@Caption), -1, nil);
    if R.Left <> R2.Left then
      OffsetRect(R, R2.Left, 0);
    if R.Top <> R2.Top then
      OffsetRect(R, 0, R2.Top);
//    QPainter_boundingRect(Handle, @R, @R, Flags and not $3F{Alignment},
//                          @Caption, -1, nil);
    Result := R.Bottom - R.Top;
  end;
  if WinFlags and DT_INTERNAL <> 0 then
    QPainter_setFont(Handle, FontSaved);
end;

function DrawText(Handle :QPainterH; Text: PAnsiChar; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: Integer = 0): Integer;
var
  WText: WideString;
  AText: string;
begin
  WText := Text;
  Result := DrawTextW(Handle, PWideChar(WText), Len, R, WinFlags, 0);
  if (DT_MODIFYSTRING and WinFlags <> 0) and (Text <> nil) then
  begin
    AText := WText;
    StrCopy(Text, PChar(AText));
  end;
end;

function DrawText(Handle: QPainterH; var Text: WideString; Len: Integer;
  x,y, w, h: Integer; WinFlags: Integer; Angle: Integer): Integer;
var
  R2: TRect;
begin
  R2 := Bounds(x,y,w,h);
  Result := DrawTextW(Handle,  PWideChar(Text), Len, R2, WinFlags, Angle);
end;

function DrawTextW(Handle :QPainterH; Text: PWideChar; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: integer = 0): Integer;
var
  WText: WideString;
  R2: TRect;
begin
  WText := Text;

  R2:= R;
  OffsetRect(R2, -R.Left, -R.Top);
  try
    QPainter_save(Handle);
    QPainter_translate(Handle, R.Left, R.Top);
    QPainter_rotate(Handle, -Angle);
  Result := DrawText2(Handle, WText, Len, R2, WinFlags);
  finally
    QPainter_restore(Handle);
  end;
  OffsetRect(R2, R.Left, R.Top);
  R := R2;
  if (DT_MODIFYSTRING and WinFlags <> 0) and (Text <> nil) then
  begin
    Move(WText[1], Text^, Length(WText) * SizeOf(WideChar));
    //WStrCopy(Text, PChar(AText));
  end;
end;

function DrawTextW(Canvas :TCanvas; Text: PWideChar; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: integer = 0): Integer;
begin
  with Canvas do
  begin
    Start;
    RequiredState(Canvas, [csHandleValid, csBrushValid, csFontValid]);
    Result := DrawTextW(Handle, Text, Len, R, WinFlags, Angle);
    Stop;
  end;
end;

function DrawText(Canvas :TCanvas; Text: PAnsiChar; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: Integer = 0): Integer;
begin
  with Canvas do
  begin
    Start;
    RequiredState(Canvas, [csHandleValid, csBrushValid, csFontValid]);
    Result := DrawText(Handle, Text, Len, R, WinFlags, Angle);
    Stop;
  end;
end;

function DrawText(Handle: QPainterH; var Text: WideString; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: Integer = 0): Integer;
var
  R2: TRect;
begin
  R2:= R;
  OffsetRect(R2, -R.Left, -R.Top);
  try
    QPainter_save(Handle);
    QPainter_translate(Handle, R.Left, R.Top);
    QPainter_rotate(Handle, -Angle);
    Result := DrawText2(Handle, Text, Len, R2, WinFlags);
  finally
    QPainter_restore(Handle);
  end;
  OffsetRect(R2, R.Left, R.Top);
  R := R2;
end;

function DrawText(Canvas: TCanvas; Text: TCaption; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: integer = 0): Integer;
begin
  with Canvas do
  begin
    Start;
    RequiredState(Canvas, [csHandleValid, csBrushValid, csFontValid]);
    Result := DrawTextW(Handle, PWideChar(Text), Len, R, WinFlags, Angle);
    Stop;
  end;
end;

function DrawText(Handle: QPainterH; Text: TCaption; Len: Integer;
  var R: TRect; WinFlags: Integer; Angle: Integer = 0): Integer; overload;
begin
  Result := DrawTextW(Handle, PWideChar(Text), Len, R, WinFlags, Angle);
end;

function DrawTextEx(Handle: QPainterH; var Text: WideString; Len: Integer;
  var R: TRect; WinFlags: Integer; DTParams: Pointer): Integer;
begin
  Result := DrawTextW(Handle, PWideChar(Text), Len, R, WinFlags);
end;

function DrawTextEx(Handle: QPainterH; Text: PChar; Len: Integer;
  var R: TRect; WinFlags: Integer; DTParams: Pointer): Integer;
begin
  Result := DrawText(Handle, Text, Len, R, WinFlags);
end;

function ExtTextOut(Handle: QPainterH; X, Y: Integer; WinFlags: Cardinal;
  R: PRect; const Text: WideString; Len: Integer; lpDx: Pointer): LongBool;
var
  WS: WideString;
  Index, Width: Integer;
  Dx: PInteger;
  RR{, CellRect}: TRect;
  TextLen: Integer;
  Canvas: TCanvas;
  TextFlags: Integer;
  CursorPos: TPoint;
begin
  Result := False;
  if (Text = '') then
    Exit;
  if (WinFlags and ETO_CLIPPED <> 0) and (R = nil) then
    WinFlags := WinFlags and not ETO_CLIPPED;

  TextFlags := GetTextAlign(Handle);

  QPainter_save(Handle);
  Canvas := TCanvas.Create;
  try
    Canvas.Handle := Handle;
    Canvas.Start(False);
    with Canvas do
    begin
      Result := True;
      if WinFlags and ETO_OPAQUE <> 0 then
      begin
        if Brush.Style <> bsSolid then
          Brush.Style := bsSolid;
        if R <> nil then
          FillRect(R^);
      end
      else
        if Brush.Style = bsSolid then
          Brush.Style := bsClear;

      if lpDx = nil then
      begin
        if (WinFlags and ETO_CLIPPED <> 0) then
          TextRect(R^, X, Y, Text, TextFlags  and $0FFF)
        else
          TextOut(X, Y, Text);
      end
      else
      begin
       // put each char into its cell
        TextLen := Length(Text);
        if (WinFlags and ETO_OPAQUE <> 0) and (R = nil) then
        begin
          Dx := lpDx;
          Width := 0;
          for Index := 1 to TextLen do
          begin
            Inc(Width, Dx^);
            Inc(Dx);
          end;
          RR.Left := X;
          RR.Right := X + Width;
          RR.Top := Y;
          RR.Bottom := Y + TextHeight(Text);
          FillRect(RR);
        end;

        Dx := lpDx;
        SetLength(WS, 1);
        for Index := 1 to TextLen do
        begin
          if (R <> nil) and (X >= R^.Right) then
            Break;

          WS[1] := Text[Index];
          if WinFlags and ETO_CLIPPED <> 0 then
          begin
            {CellRect.Left := X;
            CellRect.Right := X + Dx^;
            CellRect.Top := R^.Top;
            CellRect.Bottom := R^.Bottom;
            if CellRect.Right > R^.Right then
              CellRect.Right := R^.Right;}
            TextRect(RR, X, Y, WS, TextFlags and $0FFF);
          end
          else
            TextOut(X, Y, WS);

          if Index = TextLen then
            Break;

          Inc(X, Dx^);
          Inc(Dx);
        end;
      end;
    end;
  finally
    Canvas.Stop;
    Canvas.Free;
    QPainter_pos(Handle, @CursorPos);
    QPainter_restore(Handle);
    if WinFlags and TA_UPDATECP <> 0 then
      QPainter_moveTo(Handle, @CursorPos);
  end;
end;

function ExtTextOut(Handle: QPainterH; X, Y: Integer; WinFlags: Cardinal;
  R: PRect; pText: PChar; Len: Integer; lpDx: Pointer): LongBool;
var
  ws: WideString;
begin
  ws := pText;
  Result := ExtTextOut(Handle, X, Y, WinFlags, R, ws, Len, lpDx);
end;

function ExtTextOutW(Handle: QPainterH; X, Y: Integer; WinFlags: Cardinal;
  R: PRect; pText: PWideChar; Len: Integer; lpDx: Pointer): LongBool;
var
  ws: WideString;
begin
  ws := pText;
  Result := ExtTextOut(Handle, X, Y, WinFlags, R, ws, Len, lpDx);
end;

function GetTextAlign(Handle: QPainterH): Cardinal;
var
  P: PPainterInfo;
begin
  if GetPainterInfo(Handle, P) then
    Result := P.TextAlignment
  else
    Result := TA_LEFT or TA_TOP;
end;

function SetTextAlign(Handle: QPainterH; Mode: Cardinal): Cardinal;
begin
  Result := GetTextAlign(Handle);
  if Result <> Mode then
    SetPainterInfo(Handle).TextAlignment := Mode;
end;

function FillRect(Handle: QPainterH; const R: TRect; Brush: QBrushH): LongBool;
begin
  try
    QPainter_fillRect(Handle, @R, Brush);
    Result := True;
  except
    Result := False;
  end;
end;

function DrawIcon(Handle: QPainterH; X, Y: Integer; hIcon: QPixmapH): LongBool;
var
  Pt: TPoint;
begin
  Pt.X := X;
  Pt.Y := Y;
  try
    QPainter_drawPixmap(Handle, @Pt, hIcon);
    Result := True;
  except
    Result := False;
  end;
end;

function DrawIconEx(Handle: QPainterH; X, Y: Integer; hIcon: QPixmapH; W, H: Integer;
  istepIfAniCur: Integer; hbrFlickerFreeDraw: QBrushH; diFlags: Cardinal): LongBool;
var
  TempDC: QPainterH;
  R: TRect;
begin
  if diFlags = DI_DEFAULTSIZE then
  begin
    if W = 0 then
    begin
      W := GetSystemMetrics(SM_CYICON);
      istepIfAniCur := 0;
    end;
    if H = 0 then
      H := GetSystemMetrics(SM_CXICON);
  end
  else
  begin         // DI_NORMAL / DI_IMAGE / DI_MASK
    if W = 0 then
    begin
      W := QPixmap_width(hIcon);
      istepIfAniCur := 0;
    end;
    if H = 0 then
      H := QPixmap_height(hIcon);
    if (DiFlags and DI_MASK) = 0 then    // DI_NORMAL / DT_IMAGE
      QPixmap_setMask(hIcon, nil);
  end;

  if QPixmap_width(hIcon) < ((istepIfAniCur + 1) * W) then
    istepIfAniCur := 0;

  if hbrFlickerFreeDraw <> nil then
  begin
    R := Bounds(0, 0, W, H);
    try
      TempDC := CreateCompatibleDC(Handle, W, H);
      try
        FillRect(TempDC, R, hbrFlickerFreeDraw);
        QPainter_drawPixmap(TempDC, 0, 0, hIcon, istepIfAniCur * W, 0, W, H);
        BitBlt(Handle, X, Y, W, H, TempDC, 0, 0, RasterOp_CopyRop);
        Result := True;
      except
        Result := False;
      end;
      DeleteObject(TempDC);
    except
      Result := False;
    end;
  end
  else
  begin
    try
      QPainter_drawPixmap(Handle, X, Y, hIcon, istepIfAniCur * W, 0, W, H);
      Result := True;
    except
      Result := False;
    end;
  end;
end;

function InvertRect(Handle: QPainterH; const R: TRect): LongBool;
begin
  with R do
    Result := BitBlt(Handle, Left, Top, Right - Left, Bottom-Top,
                     Handle, Left, Top, DSTINVERT);
end;

function Rectangle(Handle: QPainterH; Left, Top, Right, Bottom: Integer): LongBool;
begin
  try
    QPainter_drawRect(Handle, Left, Top, Right, Bottom);
    Result := True;
  except
    Result := False;
  end;
end;

function RoundRect(Handle: QPainterH; Left, Top, Right, Bottom, X3, Y3: Integer): LongBool;
begin
  try
    QPainter_drawRoundRect(Handle, Left, Top, Right, Bottom, X3, Y3);
    Result := True;
  except
    Result := False;
  end;
end;

function Ellipse(Handle: QPainterH; Left, Top, Right, Bottom: Integer): LongBool;
begin
  try
    QPainter_drawEllipse(Handle, Left, Top, Right, Bottom);
    Result := True;
  except
    Result := False;
  end;
end;

function FrameRect(Handle: QPainterH; const R: TRect; Brush: QBrushH): LongBool;
var
  Pen: QPenH;
begin
  Result := False;
  if (Handle = nil) or (R.Right - R.Left <= 0) or (R.Bottom - R.Top <= 0) or
     (Brush = nil) then
    Exit;
  try
    Pen := nil;
    QPainter_save(Handle);
    try
      Pen := QPen_create(QBrush_color(Brush), 1, PenStyle_SolidLine);
      QPainter_setPen(Handle, Pen);
      QPainter_setBrush(Handle, BrushStyle_NoBrush);
      QPainter_drawRect(Handle, @R);
    finally
      if Assigned(Pen) then
        QPen_destroy(Pen);
      QPainter_restore(Handle);
    end;
    Result := True;
  except
    Result := False;
  end;
end;

procedure FrameRect(Canvas: TCanvas; const R: TRect);
begin
  Canvas.Start;
  try
    FrameRect(Canvas.Handle, R, Canvas.Brush.Handle);
  finally
    Canvas.Stop;
  end;
end;

function DrawFocusRect(Handle: QPainterH; const R: TRect): LongBool;
begin
  try
    QPainter_drawWinFocusRect(Handle, @R);
    Result := True;
  except
    Result := False;
  end;
end;

function DrawFrameControl(Handle: QPainterH; const Rect: TRect; uType, uState: Longword): LongBool;

  function GetColorGroup(uState: LongWord): QColorGroupH;
  begin
    if uState and DFCS_INACTIVE <> 0 then
      Result := Application.Palette.ColorGroup(cgDisabled)
    else if uState and DFCS_HOT <> 0 then
      Result := Application.Palette.ColorGroup(cgActive)
    else
      Result := Application.Palette.ColorGroup(cgInActive);
  end;

const
  Mask = $00FF;
var
  InnerRect, R: TRect;
  Brush: QBrushH;
  Pen: QPenH;
  Font: QFontH;
  Size: TSize;
  QC: QColorH;
  oBkMode: Integer;
  MaskPainter, Painter: QPainterH;
  MaskBitmap: QBitmapH;
  Pixmap: QPixmapH;
//  FInstance: TControl;
//  FObject: TObject;
begin
  Result := False;
  if (Handle = nil) or (not QPainter_isActive(Handle)) then
    Exit;

  QPainter_save(Handle);
  try
    if uState and DFCS_TRANSPARENT <> 0 then
    begin
      Brush := nil;
      oBkMode := SetBkMode(Handle, TRANSPARENT);
    end
    else
    begin
      oBkMode := SetBkMode(Handle, OPAQUE);
      Brush := QPainter_brush(Handle);

      if uState and DFCS_INACTIVE <> 0 then
        QC := QColor(clDisabledButton)
      else if uState and DFCS_HOT <> 0 then
        QC := QColor(clActiveButton)
      else
        QC := QColor(clNormalButton);
      QPainter_setBackgroundColor(Handle, QC);
      QBrush_setColor(Brush, QC);
      QColor_destroy(QC);
      QPainter_eraseRect(Handle, @Rect);
    end;
    try
      R := Rect;
      case uType of
        DFC_CAPTION:
          begin
            // draw button
            Result := DrawFrameControl(Handle, Rect, DFC_BUTTON,
              DFCS_BUTTONPUSH or (uState and not Mask));
            if Result then
            begin
              // draw image
              Pen := CreatePen(PS_SOLID, 1, clBlack);
              QPainter_setPen(Handle, Pen);
              QPen_destroy(Pen);
              SetBkMode(Handle, TRANSPARENT);
              case uState and Mask of
                DFCS_CAPTIONCLOSE:
                  begin
                    SetRect(R, 0, 0, 6, 6);
                    R := CenterRect(R, Rect);
                    if (uState and DFCS_PUSHED) = 0 then
                      OffsetRect(R, -1, -1);
                    QPainter_moveTo(Handle, R.Left , R.Top);
                    QPainter_lineTo(Handle, R.Right, R.Bottom);
                    QPainter_moveTo(Handle, R.Left , R.Bottom);
                    QPainter_lineTo(Handle, R.Right, R.Top);
                    OffsetRect(R, 1, 0);
                    QPainter_moveTo(Handle, R.Left , R.Top);
                    QPainter_lineTo(Handle, R.Right, R.Bottom);
                    QPainter_moveTo(Handle, R.Left , R.Bottom);
                    QPainter_lineTo(Handle, R.Right, R.Top);
                  end;
                DFCS_CAPTIONMIN:
                  begin
                    SetRect(R, 0, 0, 9, 9);
                    R := CenterRect(R, Rect);
                    if (uState and DFCS_PUSHED) <> 0 then
                      OffsetRect(R, 1, 1);
//                    Inc(R.Left, 4);
//                    Dec(R.Right, 6);
//                    Dec(R.Bottom, 4);
                    QPainter_moveTo(Handle, R.Left , R.Bottom - 1);
                    QPainter_lineTo(Handle, R.Right, R.Bottom - 1);
                    QPainter_moveTo(Handle, R.Left , R.Bottom );
                    QPainter_lineTo(Handle, R.Right, R.Bottom );
                  end;
                DFCS_CAPTIONMAX:
                  begin
                    {$IFDEF MSWINDOWS}
                 //   InflateRect(R, -4, -4);
                    {$ENDIF MSWINDOWS}
                    {$IFDEF LINUX}
                 //   InflateRect(R, -3, -2);
                    {$ENDIF LINUX}
                    SetRect(R, 0, 0, 9, 9);
                    R := CenterRect(R, Rect);
                    if (uState and DFCS_PUSHED) <> 0 then
                      OffsetRect(R, 1, 1);
                    QPainter_drawRect(Handle, @R);
                    QPainter_moveTo(Handle, R.Left, R.Top + 1);
                    QPainter_lineTo(Handle, R.Right - 1, R.Top + 1);
                  end;
                DFCS_CAPTIONRESTORE:
                  begin
                    QPainter_save(Handle);
                    SetRect(R, 0, 0, 6, 6);
                    R := CenterRect(R, Rect);
                    if (uState and DFCS_PUSHED) <> 0 then
                      OffsetRect(R, 1, 1);
                    OffsetRect(R, -2, 1);
                    ExcludeClipRect(Handle, R.Left, R.Top, R.Right, R.Bottom);
                    OffsetRect(R, 2, -3);
                    QPainter_drawRect(Handle, @R);
                    QPainter_moveTo(Handle, R.Left + 1, R.Top + 1);
                    QPainter_lineTo(Handle, R.Right - 1, R.Top + 1);
                    QPainter_restore(Handle);

                    OffsetRect(R, -2, 3);
                    QPainter_drawRect(Handle, @R);
                    QPainter_moveTo(Handle, R.Left + 1, R.Top + 1);
                    QPainter_lineTo(Handle, R.Right - 1, R.Top + 1);
                    QPainter_restore(Handle);
                  end;
                DFCS_CAPTIONHELP:
                  begin
                    Font := QFont_create(Application.Font.Handle);
                    QFont_setBold(Font, True);
                    QPainter_setFont(Handle, Font);
                    QFont_destroy(Font);
                    if (uState and DFCS_PUSHED) = 0 then
                      OffsetRect(R, -1, -1);
                    OffsetRect(R, -1, 0);
                    DrawText(Handle, '?', 1, R, DT_CENTER or DT_VCENTER or DT_SINGLELINE);
                  end;
              end; // case of
            end;
          end; // DFC_CAPTION

        DFC_MENU:
          begin
            // white background color. Windows paints it so we must paint it, too.
            QC := QColor(clWhite);
            QPainter_setBrush(Handle, QC);
            QColor_destroy(QC);

            case uState and Mask of
              DFCS_MENUARROW: // (ahuser) this is the submenu arrow that points left-to-right !
                begin
                  QStyle_drawArrow(Application.Style.Handle, Handle,
                                   ArrowType_RightArrow,
                                   uState and DFCS_PUSHED <> 0,
                                   R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
                                   GetColorGroup(uState),
                                   uState and DFCS_INACTIVE = 0,
                                   Brush);
                  Result := True;
                end;
              DFCS_MENUARROWRIGHT: // (ahuser) this is the right submenu arrow that points right-to-left !
                begin
                  QStyle_drawArrow(Application.Style.Handle, Handle,
                                   ArrowType_LeftArrow,
                                   uState and DFCS_PUSHED <> 0,
                                   R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
                                   GetColorGroup(uState),
                                   uState and DFCS_INACTIVE = 0,
                                   Brush);
                  Result := True;
                end;
              DFCS_MENUCHECK:
                begin
                  QPainter_fillRect(Handle, @R, QPainter_brush(Handle));
                  QStyle_drawCheckMark(Application.Style.Handle, Handle,
                                       R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
                                       GetColorGroup(uState),
                                       uState and DFCS_CHECKED <> 0,
                                       uState and DFCS_INACTIVE <> 0
                                       );
                  Result := True;
                end;
              DFCS_MENUBULLET:
                begin
                  QPainter_fillRect(Handle, @R, QPainter_brush(Handle));
                  R := Types.Rect(0, 0, 7, 7);
                  OffsetRect(R,
                       ((Rect.Right - Rect.Left) - R.Right) div 2 + Rect.Left,
                       ((Rect.Bottom - Rect.Top) - R.Bottom) div 2 + Rect.Top);
                  SetDCBrushColor(Handle, clBlack);
                  SetDCPenColor(Handle, clBlack);
                  QPainter_drawEllipse(Handle, @R);
                  Result := True;
                end;
            end;
          end; // DFC_MENU

        DFC_SCROLL:
          begin
            DrawFrameControl(Handle, Rect, DFC_BUTTON, DFCS_BUTTONPUSH or (uState and not Mask));
            InflateRect(R, -2,-2);
            case uState and Mask of
              DFCS_SCROLLUP:
                begin
                  QStyle_drawArrow(Application.Style.Handle, Handle,
                                   ArrowType_UpArrow,
                                   uState and DFCS_PUSHED <> 0,
                                   R.Left, R.Top, R.Right-R.Left, R.Bottom-R.Top,
                                   GetColorGroup(uState),
                                   uState and DFCS_INACTIVE = 0,
                                   Brush);
                  Result := True;
                end;
              DFCS_SCROLLCOMBOBOX, // looks equal to DFCS_SCROLLDOWN
              DFCS_SCROLLDOWN:
                begin
                  QStyle_drawArrow(Application.Style.Handle, Handle,
                                   ArrowType_DownArrow,
                                   uState and DFCS_PUSHED <> 0,
                                   R.Left, R.Top, R.Right-R.Left, R.Bottom-R.Top,
                                   GetColorGroup(uState),
                                   uState and DFCS_INACTIVE = 0,
                                   Brush);
                  Result := True;
                end;
              DFCS_SCROLLLEFT:
                begin
                  QStyle_drawArrow(Application.Style.Handle, Handle,
                                   ArrowType_LeftArrow,
                                   uState and DFCS_PUSHED <> 0,
                                   R.Left, R.Top, R.Right-R.Left, R.Bottom-R.Top,
                                   GetColorGroup(uState),
                                   uState and DFCS_INACTIVE = 0,
                                   Brush);
                  Result := True;
                end;
              DFCS_SCROLLRIGHT:
                begin
                  QStyle_drawArrow(Application.Style.Handle, Handle,
                                   ArrowType_RightArrow,
                                   uState and DFCS_PUSHED <> 0,
                                   R.Left, R.Top, R.Right-R.Left, R.Bottom-R.Top,
                                   GetColorGroup(uState),
                                   uState and DFCS_INACTIVE = 0,
                                   Brush);
                   Result := True;
                end;
            else
              raise Exception.Create('not implemented');
            end;
          end; // DFC_SCROLL

        DFC_BUTTON:
          case uState and Mask of
            DFCS_BUTTONRADIO:
              begin
                QStyle_exclusiveIndicatorSize(Application.Style.Handle, @Size);
                OffsetRect(R, (R.Right - R.Left - Size.cx) div 2,
                              (R.Bottom - R.Top - Size.cy) div 2);
                Pixmap := CreateCompatibleBitmap(Handle, R.Right - R.Left, R.Bottom - R.Top);
                try
                  MaskBitmap := QBitmap_create(R.Right - R.Left, R.Bottom - R.Top,
                    False, QPixmapOptimization_DefaultOptim);
                  try
                    QC := QColor(clBlack);
                    QPixmap_fill(MaskBitmap, QC);
                    QColor_destroy(QC);
                    MaskPainter := QPainter_create(MaskBitmap);
                    QStyle_drawExclusiveIndicatorMask(Application.Style.Handle, MaskPainter,
                      0, 0, QPixmap_width(MaskBitmap), QPixmap_height(MaskBitmap),
                      uState and DFCS_CHECKED <> 0);
                    QPainter_destroy(MaskPainter);
                    QPixmap_setMask(Pixmap, MaskBitmap);
                  finally
                    QBitmap_destroy(MaskBitmap);
                  end;

                  Painter := QPainter_create(Pixmap);
                  QStyle_drawExclusiveIndicator(
                       Application.Style.Handle, Painter,
                       0, 0, R.Right - R.Left, R.Bottom - R.Top,
                       GetColorGroup(uState),
                       uState and DFCS_CHECKED <> 0,
                       uState and DFCS_INACTIVE <> 0,
                       True);
                  QPainter_destroy(Painter);
                  QPainter_drawPixmap(Handle, R.Left, R.Top, Pixmap, 0, 0,
                    QPixmap_width(Pixmap), QPixmap_height(Pixmap));
                finally
                  DeleteObject(Pixmap);
                end;
                Result := True;
              end;
            DFCS_BUTTONCHECK:
              begin
                QStyle_drawIndicatorMask(Application.Style.Handle, Handle,
                   R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top, 0);

                if uState and DFCS_INACTIVE = 0  then
                  QStyle_drawIndicator(Application.Style.Handle, Handle,
                     R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
                     Application.Palette.ColorGroup(cgActive), //GetColorGroup(cgInActive),
                     0, False, True)
                else
                  QStyle_drawIndicator(Application.Style.Handle, Handle,
                     R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
                     Application.Palette.ColorGroup(cgActive), //GetColorGroup(cgInActive),
                     0, True, True);
                InflateRect(R, -2, -2);
                if uState and DFCS_CHECKED	<> 0 then
                  DrawFrameControl(Handle, R, DFC_MENU, DFCS_MENUCHECK or (uState and not Mask));
                Result := True;
              end;
            DFCS_BUTTONPUSH:
              begin
                R := Rect;
                InnerRect := Rect;
                InflateRect(InnerRect, -2, -2);
                if uState and DFCS_ADJUSTRECT <> 0 then
                  PRect(@Rect)^ := InnerRect;
                if uState and DFCS_FLAT <> 0 then
                begin
                  if uState and (DFCS_PUSHED or DFCS_HOT) <> 0 then
                  begin
                    QStyle_drawButton(Application.Style.Handle, Handle,
                        R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
                        GetColorGroup(uState),
                        uState and DFCS_PUSHED <> 0,
                        Brush
                        );
                   {QStyle_drawPanel(Application.Style.Handle, Handle,
                        R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
                        GetColorGroup(uState),
                        uState and DFCS_PUSHED <> 0,
                        1,
                        Brush);}
                    InflateRect(R, -1, -1);
                  end;
                  Result := True;
                end
                else if uState and DFCS_MONO = 0 then
                begin
                  QStyle_drawButton(Application.Style.Handle, Handle,
                      R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
                      GetColorGroup(uState),
                      uState and DFCS_PUSHED <> 0,
                      Brush);
                  InflateRect(R, -2, -2);
                  Result := True;
                end
                else
                begin
                  SetDCPenColor(Handle, clBlack);
                  QPainter_drawRect(Handle, @R);
                  InflateRect(R, -1, -1);
                  Result := True;
                end;
              end;
          else
              // not implemented
            raise Exception.Create('QWindows.DrawFrameControl: not implemented');
          end;

        DFC_POPUPMENU:
          begin
          //
            QStyle_drawPopupPanel(Application.Style.Handle, Handle,
                R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
                GetColorGroup(uState), 2, Brush);
          end;
      end;
    finally
      SetBkMode(Handle, oBkMode);
    end;
  finally
    QPainter_restore(Handle);
  end;
end;

function DrawFrameControl(Canvas: TCanvas; const Rect: TRect; uType, uState: Longword): LongBool;
begin
  with Canvas do
  begin
    Start;
    RequiredState(Canvas, [csHandleValid, csBrushValid, csPenValid]);
    Result := DrawFrameControl(Canvas.Handle, Rect, uType, uState);
    Stop;
  end;
end;


function DrawEdge(Handle: QPainterH; var Rect: TRect; Edge: Cardinal;
  Flags: Cardinal): LongBool;
var
  Brush: QBrushH;
  ColorDark, ColorLight: TColor;
  ClientRect: TRect;

  procedure DrawLine(X1, Y1, X2, Y2: Integer);
  begin
    QPainter_moveTo(Handle, X1, Y1);
    QPainter_lineTo(Handle, X2, Y2);
  end;

  procedure DoDrawEdge(Outer: Boolean; const R: TRect);
  var
    X1, Y1, X2, Y2: Integer;
    ColorLeftTop, ColorRightBottom: TColor;
  begin
    X1 := R.Left;
    Y1 := R.Top;
    X2 := R.Right;
    Y2 := R.Bottom;
    ColorLeftTop := clNone;
    ColorRightBottom := clNone;

    if Outer then
    begin
      if Edge and BDR_RAISEDOUTER <> 0 then
      begin
        ColorLeftTop := ColorLight;
        ColorRightBottom := ColorDark;
      end
      else if Edge and BDR_SUNKENOUTER <> 0 then
      begin
        ColorLeftTop := ColorDark;
        ColorRightBottom := ColorLight;
      end;
    end
    else
    begin
      if Edge and BDR_RAISEDINNER <> 0 then
      begin
        ColorLeftTop := ColorLight;
        ColorRightBottom := ColorDark;
      end
      else if Edge and BDR_SUNKENINNER <> 0 then
      begin
        ColorLeftTop := ColorDark;
        ColorRightBottom := ColorLight;
      end;
    end;

    if Flags and BF_DIAGONAL = 0 then
    begin
      SetDCPenColor(Handle, ColorLeftTop);
      if Flags and BF_LEFT <> 0 then
        DrawLine(X1, Y1, X1, Y2);
      if Flags and BF_TOP <> 0 then
        DrawLine(X1, Y1, X2, Y1);

      SetDCPenColor(Handle, ColorRightBottom);
      if Flags and BF_RIGHT <> 0 then
        DrawLine(X2, Y1, X2, Y2);
      if Flags and BF_BOTTOM <> 0 then
        DrawLine(X1, Y2, X2, Y2);
    end
    else
    begin
      // diagonal (does not really work properly with Qt's line algorithm)
      SetDCPenColor(Handle, ColorLeftTop);
      if (Flags and BF_DIAGONAL_ENDTOPLEFT = BF_DIAGONAL_ENDTOPLEFT) or
         (Flags and BF_DIAGONAL_ENDBOTTOMRIGHT = BF_DIAGONAL_ENDBOTTOMRIGHT) then
        DrawLine(X1, Y1, X2, Y2)
      else
      {if (Flags and BF_DIAGONAL_ENDBOTTOMLEFT = BF_DIAGONAL_ENDBOTTOMLEFT) or
         (Flags and BF_DIAGONAL_ENDTOPRIGHT = BF_DIAGONAL_ENDTOPRIGHT) then} // default
        DrawLine(X1, Y2, X2, Y1);
    end;
  end;

begin
  Result := False;
  if Handle = nil then
    Exit;
  try
    ClientRect := Rect;
    QPainter_save(Handle);
    try
      ColorDark := ColorToRGB(clDark);
      ColorLight := ColorToRGB(clBtnHighlight);
      if Flags and BF_FLAT <> 0 then
        ColorLight := clSilver;
      if Flags and BF_MONO <> 0 then
      begin
        ColorDark := clBlack;
        ColorLight := clWhite;
      end;
      try
        if Edge and (BDR_SUNKENOUTER or BDR_RAISEDOUTER) <> 0 then
          DoDrawEdge(True, Rect); // outer
        InflateRect(ClientRect, -1, -1); // remove outer rect
        if Flags and BF_MONO = 0 then
          ColorDark := ColorToRGB(clMid);
        if Edge and (BDR_SUNKENINNER or BDR_RAISEDINNER) <> 0 then
        begin
          DoDrawEdge(False, ClientRect); // inner
          InflateRect(ClientRect, -1, -1); // remove inner rect
        end;
      finally

      end;

      if Flags and BF_MIDDLE <> 0 then
      begin
       // fill interior rect
        Brush := CreateSolidBrush(clButton);
        try
          FillRect(Handle, ClientRect, Brush);
        finally
          DeleteObject(Brush);
        end;
      end;

      if Flags and BF_ADJUST <> 0 then
        Rect := ClientRect;

      Result := True;
    finally
      QPainter_restore(Handle);
    end;
  except
    Result := False;
  end;
end;

function GetCurrentPositionEx(Handle: QPainterH; pos: PPoint): LongBool;
begin
  try
    QPainter_pos(Handle, pos);
    Result := True;
  except
    Result := False;
  end;
end;

function LineTo(Handle: QPainterH; X, Y:Integer): LongBool;
begin
  try
    QPainter_lineTo(Handle, X, Y);
    Result := True;
  except
    Result := False;
  end;
end;

function MoveToEx(Handle: QPainterH; X, Y:Integer; Point: PPoint): LongBool;
begin
  try
    if Point <> nil then
      QPainter_pos(Handle, Point);
    QPainter_moveTo(Handle, X, Y);
    Result := True;
  except
    Result := False;
  end;
end;

function GetDC(Handle: QWidgetH): QPainterH;
var
  PaintDevice: QPaintDeviceH;
begin
  try
    if Handle = nil then
      Handle := QApplication_desktop;
    PaintDevice := QWidget_to_QPaintDevice(Handle);
    Result := QPainter_create(PaintDevice, Handle);
    if not QPainter_isActive(Result) then
      QPainter_begin(Result, PaintDevice, Handle);
  except
    Result := nil;
  end;
end;

function GetDC(Handle: Integer): QPainterH;
begin
  Result := GetDC(QWidgetH(Handle));
end;

function GetWindowDC(Handle: QWidgetH): QPainterH;
begin
  Result := GetDC(Handle);
end;

function ReleaseDC(wdgtH: QWidgetH; Handle: QPainterH): Integer;
begin
  try
    // asn: wdgtH ignored
    QPainter_end(Handle);
    QPainter_destroy(Handle);
    Result := 1;
  except
    Result := 0;
  end;
end;

function ReleaseDC(wdgtH: Integer; Handle: QPainterH): Integer;
begin
  Result := ReleaseDC(QWidgetH(wdgtH), Handle);
end;

function DeleteDC(Handle: QPainterH): LongBool;
var
  P: PPainterInfo;
begin
  if GetPainterInfo(Handle, P) and P.IsCompatibleDC then
    Result := DeleteObject(Handle)
  else
    Result := ReleaseDC(0, Handle) = 1;
end;

function CreateCompatibleDC(Handle: QPainterH; Width: Integer = 1; Height: Integer = 1): QPainterH;
var
  Pixmap: QPixmapH;
  DesktopPainter: Boolean;
begin
  Result := nil;
  try
    if Handle = nil then
    begin
      Handle := GetDC(0);
      DesktopPainter := True;
    end
    else
      DesktopPainter := False;
    try
      Pixmap := CreateCompatibleBitmap(Handle, Width, Height);
      if Pixmap = nil then
        Exit;
      Result := QPainter_create(Pixmap);
      try
        SetPainterInfo(Result).IsCompatibleDC := True;
        QPainter_setPen(Result, QPainter_pen(Handle));
        QPainter_setBackgroundColor(Result, QPainter_BackgroundColor(Handle));
        QPainter_setFont(Result, QPainter_Font(Handle));

        if not QPainter_isActive(Result) then
          QPainter_begin(Result, QPainter_device(Result));
      except
        DeleteObject(Result);
        Result := nil;
      end;
    finally
      if DesktopPainter then
        ReleaseDC(0, Handle);
    end;
  except
    Result := nil;
  end;
end;

function CreateCompatibleBitmap(Handle: QPainterH; Width, Height: Integer): QPixmapH;
var
  pdm: QPaintDeviceMetricsH;
  DesktopPainter: Boolean;
begin
  Result := nil;
  if (Width <= 0) or (Height <= 0) then
    Exit;
  if Handle = nil then
  begin
    Handle := GetDC(0);
    DesktopPainter := True;
  end
  else
    DesktopPainter := False;
  try
    if QPainter_device(Handle) <> nil then
    begin
      try
        pdm := QPaintDeviceMetrics_create(QPainter_device(Handle));
        Result := QPixmap_create(Width, Height, QPaintDeviceMetrics_depth(pdm),
          QPixmapOptimization_DefaultOptim);
        QPaintDeviceMetrics_destroy(pdm);
      except
        Result := nil;
      end;
    end
    else
    begin
      try
        Result := QPixmap_create(Width, Height, -1, QPixmapOptimization_DefaultOptim);
      except
        Result := nil;
      end;
    end;
  finally
    if DesktopPainter then
      ReleaseDC(0, Handle);
  end;
end;

function Convert24To32(Bits: PByte; PixelCount: Cardinal): PByte;
var
  i: Integer;
  P: PByte;
begin
  GetMem(Result, PixelCount * 4);
  P := Result;
  for i := 0 to PixelCount - 1 do
  begin
    P^ := PByte(Bits)^;
    Inc(Bits);
    Inc(P);
    P^ := PByte(Bits)^;
    Inc(Bits);
    Inc(P);
    P^ := PByte(Bits)^;
    Inc(Bits);
    Inc(P);
    P^ := 0;
    Inc(P);
  end;
end;

function CreateBitmap(Width, Height: Integer; Planes, BitCount: Longint; Bits: Pointer): QPixmapH;
var
  Image: QImageH;
  Data: PByte;
begin
  if (Width <= 0) or (Height <= 0) or (Planes <= 0) or (BitCount <= 0) then
    Result := nil
  else
  begin
    try
      Data := PByte(Bits);
      if BitCount = 24 then
      begin
        BitCount := 32;
        if Bits <> nil then
          // convert InitBits
          Data := Convert24To32(Bits, Width * Height);
      end;
      try
        if Data = nil then
          Result := QPixmap_create(Width, Height, BitCount, QPixmapOptimization_DefaultOptim)
        else
        begin
          Image := QImage_create(Width, Height, BitCount, 0, QImageEndian_IgnoreEndian);
          try
            Move(Data^, QImage_bits(Image)^, (Width * Height * BitCount + 7) div 8);
            Result := QPixmap_create;
            try
              QPixmap_convertFromImage(Result, Image, QPixmapColorMode_Auto);
            except
              QPixmap_destroy(Result);
              Result := nil;
            end;
          finally
            QImage_destroy(Image);
          end;
        end;
      finally
        if Data <> Bits then
          FreeMem(Data);
      end;
    except
      Result := nil;
    end;
  end;
end;

function CreateDIBitmap(Handle: QPainterH; var InfoHeader: TBitmapInfoHeader;
  dwUsage: Longword; InitBits: PChar; var InitInfo: TBitmapInfo; wUsage: Cardinal): QPixmapH;
var
  Image: QImageH;
  Data: PByte;
  NumColors: Integer;
begin
  with InfoHeader do
  begin
    if (biWidth <= 0) or (biHeight <= 0) or (biPlanes <> 1) or (biBitCount <= 0) then
      Result := nil
    else
    begin
      Data := PByte(InitBits);
      if biBitCount = 24 then
      begin
        biBitCount := 32;
        if (InitBits <> nil) and (dwUsage = CBM_INIT) then
          // convert InitBits
          Data := Convert24To32(PByte(InitBits), biWidth * biHeight);
      end;
      try
        try
          case biBitCount of
            1: NumColors := 1;
            4: NumColors := 16; // (ahuser) is this supported by Qt ?
            8: NumColors := 256;
          else
            NumColors := 0;
          end;
          Image := QImage_create(biWidth, biHeight, biBitCount, NumColors, QImageEndian_IgnoreEndian);
          try
            if (dwUsage = CBM_INIT) then
            begin
              if (InitBits <> nil) then
                Move(Data^, QImage_bits(Image)^, (biWidth * biHeight * biBitCount + 7) div 8);
              case biBitCount of
                1: Move(InitInfo.bmiColors[0], QImage_colorTable(Image)^, 1 * SizeOf(QRgb));
                4: Move(InitInfo.bmiColors[0], QImage_colorTable(Image)^, 16 * SizeOf(QRgb)); // (ahuser) is this supported by Qt ?
                8: Move(InitInfo.bmiColors[0], QImage_colorTable(Image)^, 256 * SizeOf(QRgb));
              end;
            end;

            Result := QPixmap_create;
            try
              QPixmap_convertFromImage(Result, Image, QPixmapColorMode_Auto);
            except
              QPixmap_destroy(Result);
              Result := nil;
            end;
          finally
            QImage_destroy(Image);
          end;
        except
          Result := nil;
        end;
      finally
        if Data <> PByte(InitBits) then
          FreeMem(Data);
      end;
    end;
  end;
end;

function GetBitmapBits(Bitmap: QPixmapH; Count: Longint; Bits: Pointer): Longint;
var
  Image: QImageH;
begin
  Result := 0;
  if (Bitmap = nil) or (Count <= 0) then
    Exit;
  try
    Image := QImage_create;
    try
      QPixmap_convertToImage(Bitmap, Image);
      Result := (QImage_width(Image) * QImage_height(Image) * QImage_depth(Image) + 7) div 8;
      if Count < Result then
        Result := Count;
      if Result > 0 then
        Move(QImage_bits(Image)^, Bits^, Result);
    finally
      QImage_destroy(Image);
    end;
  except
    Result := 0;
  end;
end;

function SetBitmapBits(Bitmap: QPixmapH; Count: Longint; Bits: Pointer): Longint;
var
  Image: QImageH;
begin
  Result := 0;
  if (Bitmap = nil) or (Count <= 0) then
    Exit;
  try
    Image := QImage_create;
    try
      QPixmap_convertToImage(Bitmap, Image);
      Result := (QImage_width(Image) * QImage_height(Image) * QImage_depth(Image) + 7) div 8;
      if Count < Result then
        Result := Count;
      if Result > 0 then
        Move(Bits^, QImage_bits(Image)^, Result);
      QPixmap_convertFromImage(Bitmap, Image, QPixmapColorMode_Auto);
    finally
      QImage_destroy(Image);
    end;
  except
    Result := 0;
  end;
end;

function GetObject(Handle: QPixmapH; Size: Cardinal; Data: PtagBITMAP): Boolean;
begin
  Result := False;
  if (Handle <> nil) and (Size > 0) and (Data <> nil) then
  begin
    try
      Data.bmWidth := QPixmap_width(Handle);
      Data.bmHeight := QPixmap_height(Handle);
      Data.bmBitsPixel := QPixmap_depth(Handle);
      Result := True;
    except
      Result := False;
    end;
  end;
end;

function GetObject(Handle: QPenH; Size: Cardinal; Data: PLogPen): Boolean;
begin
  Result := False;
  if (Handle <> nil) and (Size > 0) and (Data <> nil) then
  begin
    try
      Data.lopnStyle := Cardinal(QPen_style(Handle));
      Data.lopnWidth := Point(QPen_width(Handle), 0);
      Data.lopnColor := QColorColor(QPen_color(Handle));
      Result := True;
    except
      Result := False;
    end;
  end;
end;

function SetPixel(Handle: QPainterH; X, Y: Integer; Color: TColor): TColorRef;
var
  Brush: QBrushH;
  OldRop: RasterOp;
  R: TRect;
begin
  R := Bounds(X, Y, 1, 1);
  Brush := CreateSolidBrush(Color);
  OldRop := QPainter_rasterOp(Handle);
  if OldRop <> RasterOp_CopyROP then
    QPainter_setRasterOp(Handle, RasterOp_CopyROP);
  FillRect(Handle, R, Brush);
  if OldRop <> RasterOp_CopyROP then
    QPainter_setRasterOp(Handle, OldRop);
  QBrush_destroy(Brush);
  Result := GetPixel(Handle, X, Y);
end;

function GetPixel(Handle: QPainterH; X, Y: Integer): TColorRef;
var
  depth: Integer;
  pixmap: QPixmapH;
  pdm: QPaintDeviceMetricsH;
  tempDC: QPainterH;
  img: QImageH;
begin
  try
    pdm := QPaintDeviceMetrics_create(QPainter_device(Handle));
    depth := QPaintDeviceMetrics_depth(pdm);
    QPaintDeviceMetrics_destroy(pdm);
    img := nil;
    tempdc := nil;
    pixmap := nil;
    try
      pixmap := QPixmap_create(2, 2, depth, QPixmapOptimization_NoOptim);
      tempDC := QPainter_create(pixmap);
      BitBlt(tempDC, 0, 0, 2, 2, Handle, X, Y, SRCCOPY);
      img := QImage_create;
      QPixmap_convertToImage(pixmap, img);
      Result := QImage_pixelIndex(img, 0, 0);
    finally
      if Assigned(img) then
        QImage_destroy(img);
      if Assigned(tempdc) then
        QPainter_destroy(tempdc);
      if Assigned(pixmap) then
        QPixmap_destroy(pixmap);
    end;
  except
    Result := 0;
  end;
end;

function DeleteObject(Handle: QPainterH): LongBool;
var
  Pixmap: QPaintDeviceH;
  P: PPainterInfo;
  IsCompatible: Boolean;
begin
  if Handle = nil then
    Result := False
  else
  try
    Pixmap := QPainter_device(Handle); // get paintdevice
    if QPainter_isActive(Handle) then
      QPainter_end(Handle);

    IsCompatible := GetPainterInfo(Handle, P) and (P.IsCompatibleDC);
    if P <> nil then
      DeletePainterInfo(Handle);
    QPainter_destroy(Handle);  // destroy painter
    if IsCompatible then
      QPixmap_destroy(QPixmapH(Pixmap)); // destroy pixmap paintdevice
    Result := True;
  except
    Result := False;
  end;
end;

function DeleteObject(Handle: QPixmapH): LongBool;
begin
  try
//    if not TStockObjectList.ReleaseStockObject(Handle) then
      QPixmap_destroy(Handle);
    Result := True;
  except
    Result := False;
  end;
end;

function SaveDC(Handle: QPainterH): Integer;
begin
  try
    QPainter_save(Handle);
    Result := -1;
  except
    Result := 0;
  end;
end;

{ only negative and zero values of nSaveDC are supported }
function RestoreDC(Handle: QPainterH; nSavedDC: Integer): LongBool;
var
  i: Integer;
begin
  if nSavedDC < 0 then
  begin
    try
      for i:= nSavedDC - 1 to 0 do // nSavedDC
        QPainter_restore(Handle);
      Result := True;
    except
      Result := False;
    end;
  end
  else // limited implementation
    Result := True;
end;

function HWND_DESKTOP: QWidgetH;
begin
  Result := QApplication_desktop;
end;

function GetDesktopWindow: QWidgetH;
begin
  Result := HWND_DESKTOP;
end;

function GetActiveWindow: QWidgetH;
begin
  Result := QApplication_activeWindow(Application.Handle);
end;

function GetForegroundWindow: QWidgetH;
begin
  // is this correct ?
  Result := QApplication_focusWidget(Application.Handle);
end;

procedure SetActiveWindow(Handle: QWidgetH);
begin
  QWidget_setActiveWindow(Handle);
end;

// maps DT_ alignment flags to Qt (extended) alignment flags
function Win2QtAlign(Flags: Integer): Integer;
begin
  Result := 0;
  // Singleline & multiline
  if Flags and DT_SINGLELINE <> 0 then
     Result := SingleLine
  // multiline:
  else if Flags and DT_WORDBREAK <> 0 then
    Result := Result or WordBreak;
//  else
//    Result := Result or BreakAnywhere;
  // <tab> and '&' prefix
  if Flags and DT_EXPANDTABS <> 0 then
    Result := Result or ExpandTabs;
  if Flags and DT_NOPREFIX = 0 then
    Result := Result or ShowPrefix;
  // Horizontal alignment
  if Flags and DT_RIGHT <> 0 then
    Result := Result or AlignRight
  else if Flags and DT_CENTER <> 0 then
    Result := Result or AlignHCenter
  else
    Result := Result or AlignLeft; // default
  // vertical alignment
  if Flags and DT_BOTTOM <> 0 then
    Result := Result or AlignTop
  else if Flags and DT_VCENTER <> 0 then
    Result := Result or AlignVCenter
  else
    Result := Result or AlignTop;  // default
  // extended Qt alignments
  if Flags and DT_CALCRECT <> 0 then
    Result := Result or CalcRect
  else
  begin
    if Flags and DT_ELLIPSIS <> 0 then
      Result := Result or ClipName or SingleLine
    else if Flags and DT_PATH_ELLIPSIS <> 0 then
      Result := Result or ClipPath or SingleLine
    else if Flags and DT_WORD_ELLIPSIS <> 0 then
      Result := Result or ClipToWord;
    if Flags and DT_MODIFYSTRING <> 0 then
      Result := Result or ModifyString;
  end;
  if Flags and DT_NOCLIP <> 0 then
    Result := Result or DontClip;
end;

{ strips Qt extended alignment from flags }
function QtStdAlign(Flags: Integer): Word;
begin
  Result := Word(Flags and QtAlignMask);
end;


function IsCharAlpha(Ch: Char): LongBool;
begin
  {$IFDEF MSWINDOWS}
  Result := Windows.IsCharAlpha(Ch);
  {$ENDIF MSWINDOWS}
  {$IFDEF LINUX}
  Result := IsAlpha(cardinal(ch)) <> 0 ;
  {$ENDIF LINUX}
end;

function IsCharAlphaNumeric(Ch: Char): LongBool;
begin
  Result := (Ch in ['0'..'9']) or IsCharAlpha(Ch);
end;

{ IP Address edit control }

function MAKEIPRANGE(low, high: Byte): integer;
begin
  Result := high;
  Result := (Result shl 8) + low;
end;

function MAKEIPADDRESS(b1, b2, b3, b4: cardinal): integer;
begin
  Result := (b1 shl 24) + (b2 shl 16) + (b3 shl 8) + b4;
end;

function FIRST_IPADDRESS(x: cardinal): cardinal;
begin
  Result := (x shr 24) and $FF;
end;

function SECOND_IPADDRESS(x: cardinal): cardinal;
begin
  Result := (x shr 16) and $FF;
end;

function THIRD_IPADDRESS(x: cardinal): cardinal;
begin
  Result := (x shr 8) and $FF;
end;

function FOURTH_IPADDRESS(x: cardinal): cardinal;
begin
  Result := x and $FF;
end;

{$IFDEF LINUX}
function FileGetAttr(const FileName: string): Integer;
var
  sr: TSearchRec;
  valid: Boolean;
begin
  Result := 0;
  valid := FindFirst(FileName, faAnyFile, sr) = 0;
  if valid then
  begin
    Result := sr.attr;
    FindClose(sr);
  end;
end;

function FileGetSize(const FileName: string): Cardinal;
var
  sr: TSearchRec;
  valid: Boolean;
begin
  Result := 0;
  valid := FindFirst(FileName, faAnyFile, sr) = 0;
  if valid then
  begin
    Result := sr.size;
    FindClose(sr);
  end;
end;

function FileGetTime(const FileName: string): Integer;
var
  sr: TSearchRec;
  valid: Boolean;
begin
  Result := 0;
  valid := FindFirst(FileName, faAnyFile, sr) = 0;
  if valid then
  begin
    Result := sr.time;
    FindClose(sr);
  end;
end;

function CopyFile(const Source, Destination: string; FailIfExists: Boolean): LongBool;
const
  ChunkSize = 8192;
var
  CopyBuffer: Pointer;
  Src, Dest: Integer;
  {FSize,} BytesCopied {, TotalCopied}: Longint;
  DestName: string;
begin
  Result := False;
  if DirectoryExists(Destination) then
    DestName := IncludeTrailingPathDelimiter(Destination) + ExtractFileName(Source)
  else
    DestName := Destination;
  if FailIfExists and FileExists(DestName) then
    Exit;
  Result := ForceDirectories(ExtractFilePath(Destination));
  if Result then
  begin
    GetMem(CopyBuffer, ChunkSize);
    try
      Dest := FileCreate(DestName);
      if Dest < 0 then
        raise EFCreateError.CreateFmt(SFCreateError, [DestName]);
      try
        // TotalCopied := 0;
        Src := FileOpen(source, fmShareDenyWrite);
        if Src < 0 then
          raise EFOpenError.CreateFmt(SFOpenError, [source]);
        try
          //FSize := GetFileSize(source);
          repeat
            BytesCopied := FileRead(Src, CopyBuffer^, ChunkSize);
            if BytesCopied = -1 then
              raise EReadError.Create(SReadError);
            // TotalCopied := TotalCopied + BytesCopied;
            if BytesCopied > 0 then
            begin
              if FileWrite(Dest, CopyBuffer^, BytesCopied) = -1 then
                raise EWriteError.Create(SWriteError);
            end;
          until BytesCopied < ChunkSize;
          FileSetDate(DestName, FileGetDate(Src));
          Result := True;
        finally
          FileClose(Src);
        end;
      finally
        FileClose(Dest);
      end;
    finally
      FreeMem(CopyBuffer, ChunkSize);
    end;
  end;
end;

function CopyFile(lpExistingFileName, lpNewFileName: PChar;
  bFailIfExists: LongBool): LongBool;
var
  EF, NF: string;
begin
  EF := lpExistingFileName;
  NF := lpNewFilename;
  Result := CopyFile(EF, NF, Boolean(bFailIfExists));
end;

function CopyFileA(lpExistingFileName, lpNewFileName: PAnsiChar;
  bFailIfExists: LongBool): LongBool;
var
  EF, NF: string;
begin
  EF := lpExistingFileName;
  NF := lpNewFilename;
  Result := CopyFile(EF, NF, Boolean(bFailIfExists));
end;

function CopyFileW(lpExistingFileName, lpNewFileName: PWideChar;
  bFailIfExists: LongBool): LongBool;
var
  EF, NF: string;
begin
  EF := lpExistingFileName;
  NF := lpNewFilename;
  Result := CopyFile(EF, NF, bFailIfExists);
end;

function GetComputerName(Buffer: PChar; var Size: Cardinal): LongBool;
var
  S: string;
begin
  Result := True;
  try
    SetLength(S, 255);
    if gethostname(PChar(S), Length(S)) <> -1 then
    begin
      SetLength(S, StrLen(PChar(S)));
      Size := Length(S) + 1;
      Result := S <> '';
      if Result and (Buffer <> nil) then
        StrLCopy(Buffer, PChar(S), Size - 1);
    end;
  except
    Result := False;
  end;
end;

function GetUserName(Buffer: PChar; var Size: Cardinal): LongBool;
var
  S: string;
  psswrd: PPasswordRecord;
begin
  Result := False;
  try
    psswrd :=  getpwuid(getuid); // static no need to free
    if psswrd <> nil then
    begin
      S := psswrd.pw_gecos; //  user's real name? or pwd.pw_name
      Size := Length(S) + 1;
      Result := S <> '';
      if Result and (Buffer <> nil) then
        StrLCopy(Buffer, PChar(S), Size - 1);
    end;
  except
    Result := False;
  end;
end;

function MakeIntResource(Value: Integer): PChar;
begin
  Result := PChar(Value and $0000ffff);
end;

function MakeWord(A, B: Byte): Word;
begin
  Result := A or B shl 8;
end;

function MakeLong(A, B: Word): Longint;
begin
  Result := A or B shl 16;
end;

function HiWord(L: DWORD): Word;
begin
  Result := L shr 16;
end;

function HiByte(W: Word): Byte;
begin
  Result := W shr 8;
end;

procedure MessageBeep(Value: Integer);
begin
  QApplication_beep;
end;

procedure OutputDebugString(OutputString: AnsiString);
begin
  WriteLn(ErrOutput, Format('%s %s (%d)', [OutputString, ExtractFilename(Application.ExeName), GetCurrentThreadID]));
end;

procedure OutputDebugString(lpOutputString: PAnsiChar);
begin
  OutputDebugString(string(lpOutputString));
end;

function GetCurrentProcess: THandle;
begin
  Result := THandle(0);
end;

function CheckThreadError(ErrCode: Integer): Integer;
begin
  if ErrCode <> 0 then
    raise EThread.CreateResFmt(@SQThreadError, [SysErrorMessage(ErrCode), ErrCode]);
  Result := ErrCode;
end;

function TerminateThread(ThreadID: TThreadID; RetVal: Integer): LongBool;
begin
  case RetVal of
    0:
      Result := CheckThreadError(pthread_kill(ThreadID, SIGQUIT)) = 0;
    130:
      Result := CheckThreadError(pthread_kill(ThreadID, SIGABRT)) = 0; /// CTRL_C
  else
    Result := CheckThreadError(pthread_kill(ThreadID, SIGKILL))= 0; // unmaskable
  end;
end;

function SuspendThread(ThreadID: TThreadID): LongBool;
begin
  Result := CheckThreadError(pthread_kill(ThreadID, SIGSTOP)) = 0;
end;

function ResumeThread(ThreadID: TThreadID): LongBool;
begin
  Result := CheckThreadError(pthread_kill(ThreadID, SIGCONT)) = 0;
end;

function GetThreadPolicy(ThreadID: TThreadID): Integer;
var
  SP: TSchedParam;
begin
  CheckThreadError(pthread_getschedparam(ThreadID, Result, SP));
end;

procedure SetThreadPolicy(ThreadID: TThreadID; value: Integer);
var
  SP: TSchedParam;
begin
  if Value <> GetThreadPolicy(ThreadID) then
  begin
    SP.sched_priority := GetThreadPriority(ThreadID);
    CheckThreadError(pthread_setschedparam(ThreadID, Value, @SP));
  end;
end;

function GetThreadPriority(ThreadID: TThreadID): TThreadPriority;
var
  P: Integer;
  SP: TSchedParam;
begin
  if CheckThreadError(pthread_getschedparam(ThreadID, P, SP)) <> 0
  then
    Result := THREAD_PRIORITY_ERROR_RETURN
  else
    Result := SP.sched_priority;
end;

function SetThreadPriority(ThreadID: TThreadID; priority: Integer): LongBool; 	// handle to the thread
var
  SP: TSchedParam;
  P: Integer;
begin
  if priority <> GetThreadPriority(ThreadID) then
  begin
    SP.sched_priority := priority;
    P:= GetThreadPolicy(ThreadID);
    CheckThreadError(pthread_setschedparam(ThreadID, P, @SP));
    Result := errno = 0;
  end
  else
    Result := True;
end;

function VirtualProtect(lpAddress: Pointer; dwSize, flNewProtect: Cardinal;
  lpflOldProtect: Pointer): LongBool; overload;
var
  AlignedAddress: Cardinal;
  PageSize, ProtectSize: Cardinal;
begin
  if lpflOldProtect <> nil then
  begin
    // (ahuser) I have not found a Libc function for that
    PCardinal(lpflOldProtect)^ := PAGE_EXECUTE_READWRITE;
  end;

  PageSize := Cardinal(Libc.getpagesize);
  AlignedAddress := Cardinal(lpAddress) and not (PageSize - 1); // start memory page
  // get the number of needed memory pages
  ProtectSize := PageSize;
  while Cardinal(lpAddress) + dwSize > AlignedAddress + ProtectSize do
    Inc(ProtectSize, PageSize);
  Result := mprotect(Pointer(AlignedAddress), ProtectSize, flNewProtect) = 0;
end;

function VirtualProtect(lpAddress: Pointer; dwSize, flNewProtect: Cardinal;
  var OldProtect: Cardinal): LongBool; overload;
begin
  Result := VirtualProtect(lpAddress, dwSize, flNewProtect, @OldProtect);
end;

function ReadProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer;
  lpBuffer: Pointer; nSize: LongWord; var lpNumberOfBytesRead: Cardinal): LongBool;
var
  OldProt, Dummy: Cardinal;
begin
  Result := False;
  lpNumberOfBytesRead := 0;
  if (hProcess = GetCurrentProcess) and (lpBuffer <> nil) then
  begin
    if nSize = 0 then
      Result := True
    else
    if VirtualProtect(lpBaseAddress, nSize, PAGE_EXECUTE_READWRITE, OldProt) then
    begin
      try
        Move(lpBaseAddress^, lpBuffer^, nSize);
        lpNumberOfBytesRead := nSize;
        Result := True;
      except
        Result := False;
      end;
      VirtualProtect(lpBaseAddress, nSize, OldProt, Dummy);
    end;
  end;
end;

function WriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer;
  lpBuffer: Pointer; nSize: LongWord; var lpNumberOfBytesWritten: Longword): LongBool;
var
  OldProt, Dummy: Cardinal;
begin
  Result := False;
  lpNumberOfBytesWritten := 0;
  if (hProcess = GetCurrentProcess) and (lpBuffer <> nil) then
  begin
    if nSize = 0 then
      Result := True
    else
    if VirtualProtect(lpBaseAddress, nSize, PAGE_EXECUTE_READWRITE, OldProt) then
    begin
      try
        Move(lpBuffer^, lpBaseAddress^, nSize);
        lpNumberOfBytesWritten := nSize;
        Result := True;
      except
        Result := False;
      end;
      VirtualProtect(lpBaseAddress, nSize, OldProt, Dummy);
    end;
  end;
end;

procedure FlushInstructionCache(PID: cardinal; OrgCalProc: Pointer; size: Integer);
asm
        JMP     @@Exit
// 64 Bytes:
        DD      0, 0, 0, 0, 0, 0, 0, 0
        DD      0, 0, 0, 0, 0, 0, 0, 0
@@Exit:
end;

function GetKeyState(nVirtKey: Integer): SmallInt;
begin
  Result := 0;
  case nVirtKey of
    Key_Shift:
      if ssShift in Application.KeyState  then
        Result := -32768;  // = $8000
    Key_Control:
      if ssCtrl in Application.KeyState then
        Result := -32768;
    Key_Menu:
      if ssAlt in Application.KeyState then
        Result := -32768;
  end;
end;

function GetAsyncKeyState(vKey: Integer): SmallInt;
var
  Root: Window;
  Child: Window;
  RootX, RootY, WinX, WinY: Longint;
  Mask: Cardinal;
begin
  XQueryPointer(Application.Display,
    XRootWindow(Application.Display, XDefaultScreen(Application.Display)),
    @Root, @Child, @RootX, @RootY, @WinX, @WinY, @Mask);
  Result := 0;
  case vKey of
    VK_SHIFT:
      if Mask and ShiftMask <> 0 then
        Result := -32768;  // = $8000
    VK_CONTROL:
      if Mask and ControlMask <> 0 then
        Result := -32768;
    VK_MENU:
      if Mask and Mod1Mask <> 0 then
        Result := -32768;
  end;
end;


// Handle-Values and IPC
type
  THandleObjectList = class;

  THandleObject = class(TObject)
  private
    FRefCount: Integer;
    FName: string;
    FList: THandleObjectList;
  public
    constructor Create(AList: THandleObjectList; const AName: string);
    destructor Destroy; override;
    procedure AddRef;
    procedure Release;

    property Name: string read FName;
    property List: THandleObjectList read FList;
  end;

  TWaitObject = class(THandleObject)
    constructor Create(const AName: string);
    function WaitFor(Timeout: Longword): Cardinal; virtual; abstract;
  end;

  THandleObjectList = class(TObjectList)
  private
    FLockHandle: TSemaphore;
    function GetItems(Index: Integer): THandleObject;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Enter;
    procedure Leave;
    function Find(const AName: string): THandleObject;
    property Items[Index: Integer]: THandleObject read GetItems;
  end;

  TSemaphoreWaitObject = class(TWaitObject)
  private
    FOwnSem: Boolean;
    FSemId: Integer;
  public
    constructor Create(InitialCount, Max: Integer; const AName: string; Open: Boolean);
    destructor Destroy; override;
    function WaitFor(Timeout: Longword): Cardinal; override;
    function ReleaseSemaphore(ReleaseCount: Integer; PreviousCount: PInteger): Boolean;
  end;

  TEventWaitObject = class(TWaitObject)
  private
    FManualReset: Boolean;
    FEvent: TEvent;
    FSignaled: Boolean;
  public
    constructor Create(EventAttributes: PSecurityAttributes;
      ManualReset, InitialState: LongBool; const AName: string);
    destructor Destroy; override;
    function WaitFor(Timeout: Longword): Cardinal; override;
    function SetEvent: Boolean;
    function ResetEvent: Boolean;
  end;

  TEventTimeoutThread = class(TThread)
  private
    FStopped: Boolean;
    FEvent: TEventWaitObject;
    FTimeout: Integer;
  protected
    procedure Execute; override;
  public
    constructor Create(AEvent: TEventWaitObject; ATimeout: Integer);
    property Stopped: Boolean read FStopped write FStopped;
  end;

  TMutexWaitObject = class(TSemaphoreWaitObject)
  private
    FOwnerThreadId: Cardinal;
    FThreadLocks: Integer;
    FCritSect: TRTLCriticalSection;
  public
    constructor Create(const AName: string; Open: Boolean);
    destructor Destroy; override;
    function WaitFor(Timeout: Longword): Cardinal; override;
    function ReleaseMutex: Boolean;
  end;

var
  WaitObjectList: THandleObjectList;

{ THandleObject }

constructor THandleObject.Create(AList: THandleObjectList; const AName: string);
begin
  inherited Create;
  FList := AList;
  FName := AName;
  FRefCount := 0;
  if Assigned(FList) then
    FList.Add(Self);
  AddRef;
end;

destructor THandleObject.Destroy;
begin
  if Assigned(FList) then
    FList.Extract(Self);
  inherited Destroy;
end;

procedure THandleObject.AddRef;
begin
  Inc(FRefCount);
end;

procedure THandleObject.Release;
begin
  Dec(FRefCount);
  if FRefCount <= 0 then
    Free;
end;

{ TWaitObject }

constructor TWaitObject.Create(const AName: string);
begin
  inherited Create(WaitObjectList, AName);
end;

{ THandleObjectList }

constructor THandleObjectList.Create;
begin
  inherited Create;
  sem_init(FLockHandle, False, 1);
end;

destructor THandleObjectList.Destroy;
begin
  sem_destroy(FLockHandle);
  inherited Destroy;
end;

procedure THandleObjectList.Enter;
begin
  sem_wait(FLockHandle);
end;

procedure THandleObjectList.Leave;
begin
  sem_post(FLockHandle);
end;

function THandleObjectList.GetItems(Index: Integer): THandleObject;
begin
  Result := THandleObject(inherited Items[Index]);
end;

function THandleObjectList.Find(const AName: string): THandleObject;
var
  I: Integer;
begin
  if AName <> '' then
  begin
    for I := 0 to Count - 1 do
    begin
      Result := Items[I];
      if Result.Name = AName then
        Exit;
    end;
  end;
  Result := nil;
end;

{ TSemaphoreWaitObject }

// asn: documented, but (afaics) not in libc.so.6
//function semtimedop; external libcmodulename name 'semtimedop';

function semtimedop(semid: Integer; sops: PSemaphoreBuffer;
  nsops: size_t;timeout: PTimeSpec): Integer;
var
  sem: TSemaphoreBuffer;
  psem: PSemaphoreBuffer;
  i: Integer;
  WaitTicks, StartTicks: cardinal;
begin
  if timeout = nil then
    Result := semop(semid, sops, nsops)
  else
  begin
    Result := 0; // incase nsops = 0
    WaitTicks := 1000 * timeout.tv_sec  + timeout.tv_nsec div 1000000;
    psem := sops;
    StartTicks := GetTickCount ;
    try
      for i:= 0 to nsops-1 do
      begin
        sem := psem^ ;
        sem.sem_flg := sem.sem_flg OR IPC_NOWAIT;

        // process one sem
        while (GetTickCount - StartTicks) <= WaitTicks do
        begin
          Result := semop(semid, @sem, 1);
          if Result <> -1 then
          begin
            inc(psem);  // succes, next semaphore
            break;
          end
          else
          begin
            if (errno = EAGAIN) and ((psem^.sem_flg and IPC_NOWAIT) = 0)
            then
              Sleep(10) // try again
            else
              Exit;    // no wait allowed or other error
          end;
        end; // while

        if (Result = -1)  and (errno <> EAGAIN) then
          break;
      end;  // for i:= 0 to ..
    except
      Result := -1;
      // errno := EFAULT;
    end;
  end;
end;

function GetIPCKey(const AName: string; What: Integer): Integer;
var
  Filename: string;
begin
  if AName = '' then
    Result := IPC_PRIVATE
  else
  begin
    Filename := IpcDirectory + PathDelim + AName;
    ForceDirectories(IpcDirectory);
    if not FileExists(Filename) then
      FileClose(FileCreate(Filename));
    Result := ftok(PChar(Filename), What);
  end;
end;

type
  TSemUnion = record
    case Integer of
      0: (val: Integer);
      1: (buf: PSemaphoreIdDescriptor);
      2: (ary: PWord);
      3: (__buf: PSemaphoreInfo);
  end;

constructor TSemaphoreWaitObject.Create(InitialCount, Max: Integer; const AName: string;
  Open: Boolean);
const
  AccessMode = S_IREAD or S_IWRITE or S_IRGRP or S_IWGRP;
var
  Arg: TSemUnion;
  IPCKey: Integer;
begin
  inherited Create(AName);
  IPCKey := GetIPCKey(Name, 1);
  if not Open then
    FSemId := semget(IPCKey, 1, IPC_CREAT or IPC_EXCL or AccessMode)
  else
    FSemId := -1; // open

  if FSemId = -1 then
  begin
    // open sempahore
    FOwnSem := False;
    FSemId := semget(IPCKey, 0, SEM_UNDO);
    if FSemId = -1 then
      RaiseLastOSError;
  end
  else
  begin
    FOwnSem := True;
    Arg.val := Max - InitialCount;
    if semctl(FSemId, 0, SETVAL, Arg) = -1 then
      RaiseLastOSError;
  end;
end;

destructor TSemaphoreWaitObject.Destroy;
begin
  if FOwnSem then
  begin
    semctl(FSemId, 0, IPC_RMID);
    if Name <> '' then
      DeleteFile(IpcDirectory + PathDelim + Name); // only if allowed
  end;
  inherited Destroy;
end;

function TSemaphoreWaitObject.WaitFor(Timeout: Longword): Cardinal;
var
  Buf: TSemaphoreBuffer;
  RetValue: Integer;
  timespec: TTimeSpec;
begin
  Buf.sem_num := 0;
  Buf.sem_op := -1;
  Buf.sem_flg := SEM_UNDO;
  if Timeout = INFINITE then
//    RetValue := semop(FSemId, @Buf, 1)
    Timeout := 2000000;
//  else
  if Timeout = 0 then
  begin
    Buf.sem_flg := Buf.sem_flg or IPC_NOWAIT;
    RetValue := semop(FSemId, @Buf, 1);
  end
  else
  begin
    timespec.tv_sec := Timeout div 1000;
    timespec.tv_nsec := (Timeout mod 1000) * 1000000;
    RetValue := semtimedop(FSemId, @Buf, 1, @timespec); // Timeout=0 -> INFINTE
  end;

  if RetValue = -1 then
  begin
    if errno = EAGAIN then
      Result := WAIT_TIMEOUT
    else
      Result := WAIT_FAILED;
  end
  else
    Result := WAIT_OBJECT_0;
end;

function TSemaphoreWaitObject.ReleaseSemaphore(ReleaseCount: Integer; PreviousCount: PInteger): Boolean;
var
  Buf: TSemaphoreBuffer;
  Arg: TSemUnion;
begin
  Result := False;
  if ReleaseCount >= 0 then
  begin
    if PreviousCount <> nil then
    begin
      Result := semctl(FSemId, 0, GETVAL, @Arg) = 0;
      PreviousCount^ := Arg.val;
    end;
    if ReleaseCount > 0 then
    begin
      Buf.sem_num := 0;
      Buf.sem_op := ReleaseCount;
      Buf.sem_flg := SEM_UNDO;
      Result := semop(FSemId, @Buf, 1) = 0;
    end;
  end
end;

{ TEventTimeoutThread }

constructor TEventTimeoutThread.Create(AEvent: TEventWaitObject; ATimeout: Integer);
begin
  FEvent := AEvent;
  FTimeout := ATimeout;
  FStopped := False;
  inherited Create(False);
end;

procedure TEventTimeoutThread.Execute;
var
  StartTime, CurrentTime: Int64;
begin
  StartTime := GetTickCount;
  while not FStopped do
  begin
    CurrentTime := GetTickCount;
    if CurrentTime < StartTime then
      Inc(CurrentTime, $100000000);
    if CurrentTime - StartTime > FTimeout then
    begin
      FStopped := True;
      FEvent.SetEvent;
      Break;
    end;
    Sleep(10);
  end;
end;

{ TEventWaitObject }

type
  TPrivateEvent = class(TEvent)
  protected
    FEvent: TSemaphore;
    {...}
  end;

constructor TEventWaitObject.Create(EventAttributes: PSecurityAttributes;
  ManualReset, InitialState: LongBool; const AName: string);
begin
  inherited Create(AName);
  FManualReset := ManualReset;
  FEvent := TEvent.Create(EventAttributes,
    False, // ManualReset: handled by this class
    InitialState, AName);
  FSignaled := False;
end;

destructor TEventWaitObject.Destroy;
begin
  sem_destroy(TPrivateEvent(FEvent).FEvent);
  FEvent.Free;
  inherited Destroy;
end;

function TEventWaitObject.WaitFor(Timeout: Longword): Cardinal;
var
  TimeoutThread: TEventTimeoutThread;
begin
  Result := WAIT_FAILED;
  TimeoutThread := nil;
  if Timeout <> INFINITE then
    { POSIX semaphores do not support a timeout value. Here we use a
      second thread that produces a timeout by releasing the semaphore. }
    TimeoutThread := TEventTimeoutThread.Create(Self, Integer(Timeout));
  try
    case FEvent.WaitFor(INFINITE) of
      wrSignaled:
        Result := WAIT_OBJECT_0;
      wrTimeout:
        Result := WAIT_TIMEOUT; // POSIX semaphores do not have a timeout
      wrAbandoned:
        Result := WAIT_ABANDONED; // for events ?
    end;
  finally
    if Assigned(TimeoutThread) then
    begin
      if TimeoutThread.Stopped then
        Result := WAIT_TIMEOUT;
      TimeoutThread.Stopped := True;
      TimeoutThread.WaitFor;
      TimeoutThread.Free;
    end;
    if FManualReset then
    begin
      FSignaled := True;
      SetEvent; // do not auto-reset
    end
    else
      FSignaled := False;
  end;
end;

function TEventWaitObject.SetEvent: Boolean;
begin
  FEvent.SetEvent;
  Result := True;
end;

function TEventWaitObject.ResetEvent: Boolean;
begin
  if FSignaled then
  begin
    FSignaled := False;
    WaitFor(INFINITE); // auto-reset
  end;
  FEvent.ResetEvent;
  Result := True;
end;

{ TMutexWaitObject }

constructor TMutexWaitObject.Create(const AName: string; Open: Boolean);
begin
  inherited Create(0, 1, AName, Open);
  FOwnerThreadId := 0;
  FThreadLocks := 0;
  InitializeCriticalSection(FCritSect);
end;

destructor TMutexWaitObject.Destroy;
begin
  if FOwnerThreadId <> 0 then
    ReleaseSemaphore(1, nil);
  DeleteCriticalSection(FCritSect);
  inherited Destroy;
end;

function TMutexWaitObject.WaitFor(Timeout: Longword): Cardinal;
var
  CurThreadId: Cardinal;
begin
  CurThreadId := GetCurrentThreadID;
  if CurThreadId = FOwnerThreadId then
  begin
    InterlockedIncrement(FThreadLocks);
    Result := WAIT_OBJECT_0;
  end
  else
  begin
    Result := inherited WaitFor(Timeout);
    if Result = WAIT_OBJECT_0 then
    begin
      EnterCriticalSection(FCritSect);
      try
        FOwnerThreadId := CurThreadId;
        InterlockedIncrement(FThreadLocks);
      finally
        LeaveCriticalSection(FCritSect);
      end;
    end;
  end;
end;

function TMutexWaitObject.ReleaseMutex: Boolean;
begin
  if GetCurrentThreadId = FOwnerThreadId then
  begin
    EnterCriticalSection(FCritSect);
    try
      InterlockedDecrement(FThreadLocks);
      if FThreadLocks <= 0 then
      begin
        Result := ReleaseSemaphore(1, nil);
        FOwnerThreadId := 0;
        FThreadLocks := 0;
      end
      else
        Result := True;
    finally
      LeaveCriticalSection(FCritSect);
    end;
  end
  else
    Result := False;
end;

// ======= IPC API functions =======

function CreateEvent(EventAttributes: PSecurityAttributes;
  ManualReset, InitialState: LongBool; Name: PChar): THandle;
begin
  WaitObjectList.Enter;
  try
    Result := THandle(WaitObjectList.Find(Name));
    if Result <> 0 then
    begin
      if THandleObject(Result) is TEventWaitObject then
        THandleObject(Result).AddRef
      else
        Result := 0;
    end
    else
      Result := THandle(TEventWaitObject.Create(EventAttributes, ManualReset,
        InitialState, Name));
  finally
    WaitObjectList.Leave;
  end;
end;

function OpenEvent(DesiredAccess: Longword; InheritHandle: LongBool;
  Name: PChar): THandle;
begin
  WaitObjectList.Enter;
  try
    Result := THandle(WaitObjectList.Find(Name));
    if (Result <> 0) and (THandleObject(Result) is TEventWaitObject) then
      THandleObject(Result).AddRef
    else
      Result := 0;
  finally
    WaitObjectList.Leave;
  end;
end;

function SetEvent(Event: THandle): LongBool;
begin
  WaitObjectList.Enter;
  try
    try
      Result := (Event <> 0) and (THandleObject(Event) is TEventWaitObject);
      if Result then
        TEventWaitObject(Event).SetEvent;
    except
      Result := False;
    end;
  finally
    WaitObjectList.Leave;
  end;
end;

function ResetEvent(Event: THandle): LongBool;
begin
  WaitObjectList.Enter;
  try
    try
      Result := (Event <> 0) and (THandleObject(Event) is TEventWaitObject);
      if Result then
        TEventWaitObject(Event).ResetEvent;
    except
      Result := False;
    end;
  finally
    WaitObjectList.Leave;
  end;
end;

function PulseEvent(Event: THandle): LongBool;
begin
 // not implemented
  Result := SetEvent(Event);
end;

function CreateMutex(MutexAttributes: PSecurityAttributes; InitialOwner: LongBool;
  Name: PChar): THandle;
begin
  WaitObjectList.Enter;
  try
    Result := THandle(WaitObjectList.Find(Name));
    if Result <> 0 then
    begin
      if THandleObject(Result) is TMutexWaitObject then
        THandleObject(Result).AddRef
      else
        Result := 0; // no mutex
    end
    else
    begin
      try
        Result := THandle(TMutexWaitObject.Create(Name, False));
      except
        Result := 0;
      end;
    end;
  finally
    WaitObjectList.Leave;
  end;

  if (Result <> 0) and InitialOwner then
    WaitForSingleObject(Result, INFINITE);
end;

function OpenMutex(DesiredAccess: Longword; InheritHandle: Boolean;
  Name: PChar): THandle;
begin
  WaitObjectList.Enter;
  try
    Result := THandle(WaitObjectList.Find(Name));
    if (Result <> 0) and (THandleObject(Result).ClassType = TMutexWaitObject) then
      THandleObject(Result).AddRef
    else
    begin
      try
        Result := THandle(TMutexWaitObject.Create(Name, True));
      except
        Result := 0;
      end;
    end;
  finally
    WaitObjectList.Leave;
  end;
end;

function ReleaseMutex(Mutex: THandle): LongBool;
begin
  WaitObjectList.Enter;
  try
    try
      Result := (Mutex <> 0) and (THandleObject(Mutex).ClassType = TMutexWaitObject);
      if Result then
        TMutexWaitObject(Mutex).ReleaseMutex;
    except
      Result := False;
    end;
  finally
    WaitObjectList.Leave;
  end;
end;

function CreateSemaphore(SemaphoreAttributes: PSecurityAttributes;
  InitialCount, MaximumCount: Longint; Name: PChar): THandle;
begin
  WaitObjectList.Enter;
  try
    Result := THandle(WaitObjectList.Find(Name));
    if Result <> 0 then
    begin
      if THandleObject(Result).ClassType = TSemaphoreWaitObject then
        THandleObject(Result).AddRef
      else
        Result := 0; // no semaphore
    end
    else
    begin
      if (InitialCount < 0) or (MaximumCount <= 0) or (InitialCount > MaximumCount) then
        Result := 0 // invalid
      else
      begin
        try
          Result := THandle(TSemaphoreWaitObject.Create(InitialCount, MaximumCount,
                                                        Name, False));
        except
          Result := 0;
        end;
      end;
    end;
  finally
    WaitObjectList.Leave;
  end;
end;

function OpenSemaphore(DesiredAccess: Longword; InheritHandle: LongBool;
  Name: PChar): THandle;
begin
  WaitObjectList.Enter;
  try
    Result := THandle(WaitObjectList.Find(Name));
    if (Result <> 0) and (THandleObject(Result).ClassType = TSemaphoreWaitObject) then
      THandleObject(Result).AddRef
    else
    begin
      try
        Result := THandle(TSemaphoreWaitObject.Create(0, 0, Name, True));
      except
        Result := 0;
      end;
    end;
  finally
    WaitObjectList.Leave;
  end;
end;

function ReleaseSemaphore(Semaphore: THandle; ReleaseCount: Longint;
  PreviousCount: PInteger): LongBool;
begin
  WaitObjectList.Enter;
  try
    try
      Result := (Semaphore <> 0) and (THandleObject(Semaphore).ClassType = TSemaphoreWaitObject);
      if Result then
        TSemaphoreWaitObject(Semaphore).ReleaseSemaphore(ReleaseCount, PreviousCount);
    except
      Result := False;
    end;
  finally
    WaitObjectList.Leave;
  end;
end;

// common handle functions

function WaitForSingleObject(Handle: THandle; Milliseconds: Cardinal): Cardinal;
begin
  Result := WAIT_FAILED;
  try
    if (Handle <> 0) and (THandleObject(Handle) is TWaitObject) then
    begin
      TWaitObject(Handle).AddRef;
      try
        Result := TWaitObject(Handle).WaitFor(Milliseconds);
      finally
        TWaitObject(Handle).Release;
      end;
    end;
  except
    Result := WAIT_FAILED;
  end;
end;

// The WaitForMultipleObjects function returns when one of the following occurs:
//
// ·	Either any one or all of the specified objects are in the signaled state.
// ·	The time-out interval elapses.
function WaitForMultipleObjects(Count: Cardinal; Handles: PWOHandleArray;
  WaitAll: LongBool; Milliseconds: Cardinal): Cardinal;
var
  i: Integer;
  startticks: int64;
  ticks: Integer;
begin
  startticks := GetTickCount;
  Result := WAIT_OBJECT_0;
  if WaitAll then
  begin
    for i := 0 to Count - 1  do
    begin
      ticks :=  Milliseconds - (GetTickCount - StartTicks);
      if ticks < 0 then
      begin
        Result := WAIT_TIMEOUT;
        Exit;
      end
      else
      begin
        Result := WaitForSingleObject(Handles[i], Ticks);
        if Result <> WAIT_OBJECT_0 then
        begin
          Inc(Result, i);
          Exit;
        end;
      end;
    end;
  end
  else
  begin  //
    while True do
    begin
      for i := 0 to Count-1 do
      begin
        Result := WaitForSingleObject(Handles[i], 0);
        case Result of
          WAIT_FAILED, WAIT_ABANDONED, WAIT_OBJECT_0:
            begin
              Inc(Result, i);
              Exit;
            end;
        else
          if (startticks - GetTickCount) > MilliSeconds then
          begin
            Result := WAIT_TIMEOUT;
            Exit;
          end;
        end;
      end;
      Sleep(5);
    end;
  end;
end;

// all Handles are THandleObject derived classes
function CloseHandle(hObject: THandle): LongBool;
begin
  WaitObjectList.Enter;
  try
    try
      if (hObject <> 0) then
        THandleObject(hObject).Release;
      Result := True;
    except
      Result := False;
    end;
  finally
    WaitObjectList.Leave;
  end;
end;

function GlobalAllocPtr(Flags: Integer; Bytes: Longint): Pointer;
begin
  Result := GlobalLock(GlobalAlloc(Flags, Bytes));
end;

function GlobalReAllocPtr(P: Pointer; Bytes: Longint; Flags: Integer): Pointer;
var
  hMem: Cardinal;
begin
  hMem := GlobalHandle(P);
  GlobalUnlock(hMem);
  Result := GlobalLock(GlobalReAlloc(hMem, Bytes, Flags));
end;

function GlobalFreePtr(P: Pointer): THandle;
var
  hMem: Cardinal;
begin
  hMem := GlobalHandle(P);
  GlobalUnlock(hMem);
  Result := GlobalFree(hMem);
end;

type
  PGlobalBlock = ^TGlobalBlock;
  TGlobalBlock = packed record
    Start: Pointer;
    Size: Longword;
  end;

function GlobalAlloc(uFlags: Cardinal; dwBytes: Longword): Cardinal;
var
  Info: PGlobalBlock;
  Start, P: PByte;
begin
  Result := 0;
  if dwBytes > 0 then
  begin
    GetMem(P, SizeOf(TGlobalBlock) + dwBytes + 16);
    Start := P;
    Inc(P, SizeOf(TGlobalBlock) + $0F);
    P := Pointer(Cardinal(P) and not $0F);
    Info := Pointer(Cardinal(P) - SizeOf(TGlobalBlock));
    Info^.Start := Start;
    Info^.Size := dwBytes;

    if uFlags and GMEM_ZEROINIT <> 0 then
      FillChar(P^, dwBytes, 0);

    Result := Cardinal(P);
  end;
end;

function GlobalReAlloc(hMem: Cardinal; dwBytes: Longword; uFlags: Cardinal): Cardinal;
var
  CurSize: Longword;
  Offset: Cardinal;
  Start: Pointer;
  Info: PGlobalBlock;
  P: PChar;
begin
  if dwBytes = 0 then
  begin
    GlobalFree(hMem);
    Result := 0;
    Exit;
  end;
  if hMem = 0 then
    Result := GlobalAlloc(uFlags, dwBytes)
  else
  begin
    CurSize := GlobalSize(hMem);
    Start := PGlobalBlock(hMem - SizeOf(TGlobalBlock))^.Start;
    Offset := hMem - Cardinal(Start);
    ReallocMem(Start, SizeOf(TGlobalBlock) + dwBytes + 16);
    hMem := Cardinal(Start) + Offset;
    P := Pointer(hMem);

    if hMem and $0F <> 0 then
    begin
      P := Start;
      Inc(P, SizeOf(TGlobalBlock) + $0F);
      P := Pointer(Cardinal(P) and not $0F);
      Info := Pointer(Cardinal(P) - SizeOf(TGlobalBlock));
      Move(Pointer(hMem)^, P^, CurSize); // move data
      hMem := Cardinal(P);
      Info^.Start := Start;
      Info^.Size := dwBytes;
    end;

    PGlobalBlock(hMem - SizeOf(TGlobalBlock))^.Size := dwBytes;
    if uFlags and GMEM_ZEROINIT <> 0 then
      if CurSize < dwBytes then
        FillChar(P[CurSize], dwBytes - CurSize, 0);
    Result := hMem;
  end;
end;

function GlobalSize(hMem: Cardinal): Longword;
begin
  if hMem > 0 then
    Result := PGlobalBlock(hMem - SizeOf(TGlobalBlock))^.Size
  else
    Result := 0;
end;

function GlobalLock(hMem: Cardinal): Pointer;
begin
  Result := Pointer(hMem);
end;

function GlobalHandle(Mem: Pointer): Cardinal;
begin
  Result := Cardinal(Mem);
end;

function GlobalUnlock(hMem: Cardinal): LongBool;
begin
  Result := hMem <> 0;
end;

function GlobalFree(hMem: Cardinal): Cardinal;
begin
  if hMem <> 0 then
  begin
    FreeMem(PGlobalBlock(hMem - SizeOf(TGlobalBlock))^.Start);
    Result := 0;
  end
  else
    Result := GMEM_INVALID_HANDLE;
end;


var
  StartTimeVal: TTimeVal;

// linux systems tend to run for months,
// rolls over after 49.7 days since application start
// predictable !
// return value: number of milliseconds since application start

function GetTickCount: Cardinal;
var
  TimeVal: TTimeVal;
begin
  gettimeofday(TimeVal, nil);
  Result := 1000 * (TimeVal.tv_sec - StartTimeVal.tv_sec) +
    (TimeVal.tv_usec - StartTimeVal.tv_usec) div 1000;
end;

procedure InitGetTickCount;
begin
  gettimeofday(StartTimeVal, nil);
end;

function QueryPerformanceCounter(var PerformanceCount: int64): LongBool;
var
  TimeVal: TTimeVal;
begin
  gettimeofday(TimeVal, nil);
  PerformanceCount := CLOCKS_PER_SEC * TimeVal.tv_sec + Timeval.tv_usec;
  Result := true;
end;

function QueryPerformanceFrequency(var Frequency: int64): LongBool;
begin
  Frequency := CLOCKS_PER_SEC; // 1 Mhz resolution gettimeofday
  Result := True;
end;

procedure GetLocalTime(var st: TSystemTime);
var
  dt: TDateTime;
begin
  dt := Now;
  DecodeDateTime(dt, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute,
    st.wSecond, st.wMilliseconds);
  st.wDayOfWeek := DayOfTheWeek(dt);
end;

// Provider helpers

function Succeeded(Res: HResult): Boolean;
begin
  Result := Res and $80000000 = 0;
end;

function Failed(Res: HResult): Boolean;
begin
  Result := Res and $80000000 <> 0;
end;

function ResultCode(Res: HResult): Integer;
begin
  Result := Res and $0000FFFF;
end;

function CoCreateGUID(out Guid: TGUID): HResult;
begin
  Result := CreateGuid(Guid);
end;

{$ENDIF LINUX}

// for ShellExecute(0, ..
function ShellExecute(Handle: Integer; Operation, FileName, Parameters,
  Directory: PChar; ShowCmd: Integer): THandle;
begin
  Result := ShellExecute(QWidgetH(Handle), Operation, FileName,
                         Parameters, Directory, ShowCmd);
end;

function ShellExecute(Handle: QWidgetH; Operation, FileName, Parameters,
  Directory: PChar; ShowCmd: Integer): THandle;
var
  Name: string;
  Dir: string;
  Par: string;
begin
  if Directory <> nil then
    Dir := Directory;
  if Parameters <> nil then
    Par := Parameters;
  if Filename <> nil then
    Name := FileName;
  Result := ShellExecute(Handle, Operation, Name, Par, Dir, ShowCmd);
end;

function ShellExecute(Handle: QWidgetH; const Operation, FileName, Parameters,
  Directory: string; ShowCmd: Integer): THandle;
var
  {$IFDEF MSWINDOWS}
  WinId: Integer;
  {$ENDIF MSWINDOWS}
  {$IFDEF LINUX}
  Line: string;
  {$ENDIF LINUX}
begin
  {$IFDEF MSWINDOWS}
  if Handle = nil then
    WinId := 0
  else
    WinId := QWidget_winID(Handle);
  Result := ShellAPI.ShellExecute(WinId, PChar(Operation),
                         PChar(FileName), PChar(Parameters),
                         PChar(Directory), ShowCmd);
  {$ENDIF MSWINDOWS}
  {$IFDEF LINUX}
  if (Operation = 'open') or (Operation = '') then
    Line := Format('%s "%s" %s',[Shell, Filename, Parameters])
  else
  if Operation = 'browse' then
    Line := Format('%s "%s" %s',
      [GetEnvironmentVariable('BROWSER'), Filename, Parameters])
  else
  begin
    Result := THandle(HINSTANCE_ERROR);
    Exit;
  end;
  Line := Trim(Line)+ '&';
  if Directory <> '' then
    Line := Format('cd "%s";', [Directory]) + Line;
  if Libc.system(PChar(Line)) <> -1 then
    Result := THandle(HINSTANCE_OK)
  else
    Result := THandle(HINSTANCE_ERROR)
  {$ENDIF LINUX}
end;

function InterlockedIncrement(var I: Integer): Integer;
begin
  {$IFDEF MSWINDOWS}
  Result := Windows.InterlockedIncrement(I);
  {$ENDIF MSWINDOWS}
  {$IFDEF LINUX}
  Result := SysUtils.InterlockedIncrement(I);
  {$ENDIF LINUX}
end;

function InterlockedDecrement(var I: Integer): Integer;
begin
  {$IFDEF MSWINDOWS}
  Result := Windows.InterlockedDecrement(I);
  {$ENDIF MSWINDOWS}
  {$IFDEF LINUX}
  Result := SysUtils.InterlockedDecrement(I);
  {$ENDIF LINUX}
end;

function InterlockedExchange(var A: Integer; B: Integer): Integer;
begin
  {$IFDEF MSWINDOWS}
  Result := Windows.InterlockedExchange(A, B);
  {$ENDIF MSWINDOWS}
  {$IFDEF LINUX}
  Result := SysUtils.InterlockedExchange(A, B);
  {$ENDIF LINUX}
end;

function InterlockedExchangeAdd(var A: Integer; B: Integer): Integer;
begin
  {$IFDEF MSWINDOWS}
  Result := Windows.InterlockedExchangeAdd(A, B);
  {$ENDIF MSWINDOWS}
  {$IFDEF LINUX}
  Result := SysUtils.InterlockedExchangeAdd(A, B);
  {$ENDIF LINUX}
end;

{$IFDEF MSWINDOWS}
{ wrappers to windows}

function CopyFile(lpExistingFileName, lpNewFileName: PChar;
  bFailIfExists: LongBool): LongBool;
begin
  Result := Windows.CopyFile(lpExistingFileName, lpNewFileName, bFailIfExists);
end;

function CopyFileA(lpExistingFileName, lpNewFileName: PAnsiChar;
  bFailIfExists: LongBool): LongBool;
begin
  Result := Windows.CopyFileA(lpExistingFileName, lpNewFileName, bFailIfExists);
end;

function CopyFileW(lpExistingFileName, lpNewFileName: PWideChar;
  bFailIfExists: LongBool): LongBool;
begin
  Result := Windows.CopyFileW(lpExistingFileName, lpNewFileName, bFailIfExists);
end;

function GetUserName(Buffer: PChar; var Size: Cardinal): LongBool;
begin
  Result := Windows.GetUserName(Buffer,Size);
end;

function GetComputerName(Buffer: PChar; var Size: Cardinal): LongBool;
begin
  Result := Windows.GetComputerName(Buffer,Size);
end;

function GetTickCount: Cardinal;
begin
  Result := Windows.GetTickCount;
end;

function QueryPerformanceCounter(var PerformanceCount: int64): LongBool;
begin
  Result := Windows.QueryPerformanceCounter(PerformanceCount);
end;

function QueryPerformanceFrequency(var Frequency: int64): LongBool;
begin
  Result := Windows.QueryPerformanceFrequency(Frequency);
end;

function SetEvent(Event: THandle): LongBool;
begin
  Result := Windows.SetEvent(Event);
end;

function ResetEvent(Event: THandle): LongBool;
begin
  Result := Windows.ResetEvent(Event);
end;

function PulseEvent(Event: THandle): LongBool;
begin
  Result := Windows.PulseEvent(Event);
end;

procedure OutputDebugString(OutputString: AnsiString);
begin
  Windows.OutputDebugString(PAnsiChar(OutputString));
end;

procedure OutputDebugString(lpOutputString: PAnsiChar);
begin
  Windows.OutputDebugString(lpOutputString);
end;

function GetKeyState(nVirtKey: Integer): SmallInt;
begin
  Result := Windows.GetKeyState(nVirtKey);
end;

//
// Taken from QDialogs.
//
type
  PTaskWindow = ^TTaskWindow;
  TTaskWindow = record
    Next: PTaskWindow;
    Window: Windows.HWnd;
  end;

var
  TaskActiveWindow: Windows.HWnd = 0;
  TaskFirstWindow: Windows.HWnd = 0;
  TaskFirstTopMost: Windows.HWnd = 0;
  TaskWindowList: PTaskWindow = nil;

function DoDisableWindow(Window: Windows.HWnd; Data: Longint): Bool; stdcall;
var
  P: PTaskWindow;
begin
  if (Window <> TaskActiveWindow) and Windows.IsWindowVisible(Window) and
    Windows.IsWindowEnabled(Window) then
  begin
    New(P);
    P^.Next := TaskWindowList;
    P^.Window := Window;
    TaskWindowList := P;
    Windows.EnableWindow(Window, False);
  end;
  Result := True;
end;

procedure EnableTaskWindows(WindowList: Pointer);
var
  P: PTaskWindow;
begin
  while WindowList <> nil do
  begin
    P := WindowList;
    if Windows.IsWindow(P^.Window) then Windows.EnableWindow(P^.Window, True);
    WindowList := P^.Next;
    Dispose(P);
  end;
end;

function DisableTaskWindows(ActiveWindow: Windows.HWnd): Pointer;
var
  SaveActiveWindow: Windows.HWND;
  SaveWindowList: Pointer;
begin
  Result := nil;
  SaveActiveWindow := TaskActiveWindow;
  SaveWindowList := TaskWindowList;
  TaskActiveWindow := ActiveWindow;
  TaskWindowList := nil;
  try
    try
      EnumThreadWindows(GetCurrentThreadID, @DoDisableWindow, 0);
      Result := TaskWindowList;
    except
      EnableTaskWindows(TaskWindowList);
      raise;
    end;
  finally
    TaskWindowList := SaveWindowList;
    TaskActiveWindow := SaveActiveWindow;
  end;
end;
{$ENDIF MSWINDOWS}

function IgnoreMouseEvents(Handle: QObjectH; Event: QEventH): boolean;
begin
  case QEvent_type(Event) of
    QEventType_MouseButtonPress,
    QEventType_MouseButtonRelease,
    QEventType_MouseButtonDblClick,
    QEventType_MouseMove,
    QEventType_Enter,
    QEventType_Leave,
    QEventType_Wheel:
      Result := true;
  else
    Result := false;
  end;
end;

function GetCursorPos(var P: TPoint): LongBool;
begin
  Result := True;
  try
    QCursor_pos(@P);
  except
    Result := False;
  end;
end;

procedure SetCursorPos(X, Y: integer);
var
  Value: TPoint;
begin
  Value.X := X;
  Value.Y := Y;
  QCursor_setPos(@Value);
end;

{ ------------ Caret -------------- }
type
  TEmulatedCaret = class(TComponent)
  private
    FTimer: TTimer;
    FWndId: Cardinal;
    FWidget: QWidgetH;
    FPixmap: QPixmapH;
    FWidth, FHeight: Integer;
    FPos: TPoint;
    FVisible: Boolean;
    FShown: Boolean;
    FCritSect: TRTLCriticalSection;
    procedure SetPos(const Value: TPoint);
  protected
    procedure DoTimer(Sender: TObject);
    procedure DrawCaret; virtual;
    function CreateColorPixmap(Color: Cardinal): QPixmapH;
    procedure SetWidget(AWidget: QWidgetH);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure Lock;
    procedure Unlock;

    function CreateCaret(AWidget: QWidgetH; Pixmap: QPixmapH; Width, Height: Integer): Boolean;
    function DestroyCaret: Boolean;

    function IsValid: Boolean;

    function Show(AWidget: QWidgetH): Boolean;
    function Hide: Boolean;

    property Timer: TTimer read FTimer;
    property Pos: TPoint read FPos write SetPos;
  end;

var
  GlobalCaret: TEmulatedCaret = nil ;

procedure GlobalCaretNeeded;
begin
  if GlobalCaret = nil then
  begin
    GlobalCaret := TEmulatedCaret.Create(nil);
    OutputDebugString('Global caret created.');
  end;
end;

function CreateCaret(Widget: QWidgetH; Pixmap: QPixmapH; Width, Height: Integer): Boolean;
begin
  GlobalCaretNeeded;
  GlobalCaret.Lock;
  try
    Result := GlobalCaret.CreateCaret(Widget, Pixmap, Width, Height);
  finally
    GlobalCaret.Unlock;
  end;
end;

function CreateCaret(Widget: QWidgetH; ColorCaret: Cardinal; Width, Height: Integer): Boolean;
begin
  Result := CreateCaret(Widget, QPixmapH(ColorCaret), Width, Height);
end;

function GetCaretBlinkTime: Cardinal;
begin
  Result := QApplication_cursorFlashTime;
end;

function SetCaretBlinkTime(uMSeconds: Cardinal): LongBool;
begin
  Result := True;
  try
    QApplication_setCursorFlashTime(uMSeconds);
    if assigned(GlobalCaret) then
    begin
      GlobalCaret.Lock;
      try
        GlobalCaret.Timer.Interval := GetCaretBlinkTime;
      finally
        GlobalCaret.Unlock;
      end;
    end;
  except
    Result := False;
  end;
end;

function HideCaret(Widget: QWidgetH): Boolean;
begin
  GlobalCaretNeeded;
  if Assigned(GlobalCaret) then
  begin
    GlobalCaret.Lock;
    try
      Result := GlobalCaret.Hide;
    finally
      GlobalCaret.Unlock;
    end;
  end
  else
    Result := false;
end;

function ShowCaret(Widget: QWidgetH): Boolean;
begin
  GlobalCaretNeeded;
  GlobalCaret.Lock;
  try
    Result := GlobalCaret.Show(Widget);
  finally
    GlobalCaret.Unlock;
  end;
end;

function SetCaretPos(X, Y: Integer): Boolean;
begin
  Result := True;
  GlobalCaretNeeded;
  GlobalCaret.Lock;
  try
    GlobalCaret.Pos := Point(X, Y);
  finally
    GlobalCaret.Unlock;
  end;
end;

function GetCaretPos(var Pt: TPoint): Boolean;
begin
  Result := True;
  GlobalCaretNeeded;
  GlobalCaret.Lock;
  try
    Pt := GlobalCaret.Pos;
  finally
    GlobalCaret.Unlock;
  end;
end;

function DestroyCaret: Boolean;
begin
  if Assigned(GlobalCaret) then
  begin
    GlobalCaret.Lock;
    try
      Result := GlobalCaret.DestroyCaret;
    finally
      GlobalCaret.Unlock;
    end;
  end
  else
    Result := False;
end;

{ TEmulatedCaret }

constructor TEmulatedCaret.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  InitializeCriticalSection(FCritSect);

  FTimer := TTimer.Create(self);
  FTimer.Enabled := False;
  FTimer.Interval := GetCaretBlinkTime;
  FTimer.OnTimer := DoTimer;
end;

destructor TEmulatedCaret.Destroy;
begin
  DestroyCaret;
  DeleteCriticalSection(FCritSect);
  inherited Destroy;
end;

function TEmulatedCaret.CreateCaret(AWidget: QWidgetH; Pixmap: QPixmapH;
  Width, Height: Integer): Boolean;
begin
  DestroyCaret;
  SetWidget(AWidget);
  FWidth := Width;
  FHeight := Height;
  if Cardinal(Pixmap) > $FFFF then
    FPixmap := QPixmap_create(Pixmap)
  else
    FPixmap := CreateColorPixmap(Integer(Pixmap));

  Result := IsValid;
end;

function TEmulatedCaret.DestroyCaret: Boolean;
begin
  Hide;
  if Assigned(FPixmap) then
    QPixmap_destroy(FPixmap);
  FWidget := nil;
  FPixmap := nil;
  FWidth := 0;
  FHeight := 0;
  Result := not IsValid;
end;

procedure TEmulatedCaret.DrawCaret;
var
  DestDev: QPaintDeviceH;
  R: TRect;
begin
  if IsValid then
  begin

    DestDev := QWidget_to_QPaintDevice(FWidget);
    R := Rect(0, 0, QPixmap_width(FPixmap), QPixmap_height(FPixmap));

    Qt.bitBlt(DestDev, @FPos, FPixmap, @R, RasterOp_CopyROP);
    FShown := not FShown;
  end;
end;

function TEmulatedCaret.Show(AWidget: QWidgetH): Boolean;
begin
  if FWidget <> AWidget then
    Hide;
  SetWidget(AWidget);
  Result := IsValid;
  if Result then
  begin
    FVisible := True;
    FTimer.Enabled := True;
    DrawCaret;
  end;
end;

function TEmulatedCaret.Hide: Boolean;
begin
  Result := IsValid;
  if Result then
  begin
    FVisible := False;
    FTimer.Enabled := False;
    if FShown then
      DrawCaret;
    FShown := False;
  end;
end;

procedure TEmulatedCaret.SetPos(const Value: TPoint);
begin
  if FVisible then
  begin
    Hide;
    try
      FPos := Value;
    finally
      Show(FWidget);
    end;
  end
  else
    FPos := Value;
end;

procedure TEmulatedCaret.DoTimer(Sender: TObject);
begin
  DrawCaret;
end;

procedure TEmulatedCaret.Lock;
begin
  EnterCriticalSection(FCritSect);
end;

procedure TEmulatedCaret.Unlock;
begin
  LeaveCriticalSection(FCritSect);
end;

function TEmulatedCaret.CreateColorPixmap(Color: Cardinal): QPixmapH;
var
  QC: QColorH;
begin
  if (FWidth <= 0) or (FHeight <= 0) then
    Result := nil
  else
  begin
    case Color of
      0: QC := QColor(clBlack);
      1: QC := QColor(clGray);
    else
      Result := nil;
      Exit;
    end;
    try
      Result := QPixmap_create(FWidth, FHeight, -1, QPixmapOptimization_MemoryOptim);
      try
        QPixmap_fill(Result, QC);
      except
        QPixmap_destroy(Result);
        Result := nil;
      end;
    finally
      QColor_destroy(QC);
    end;
  end;
end;

function TEmulatedCaret.IsValid: Boolean;
begin
  Result := (FWidget <> nil) and (FPixmap <> nil) and
    (QWidget_find(FWndId) <> nil);
end;

procedure TEmulatedCaret.SetWidget(AWidget: QWidgetH);
begin
  FWidget := AWidget;
  if FWidget <> nil then
    FWndId := QWidget_winId(FWidget)
  else
    FWndId := 0;
end;


type
  TCriticalSections = class(TComponent)
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

constructor TCriticalSections.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  InitializeCriticalSection(StockObjectListCritSect);
end;

destructor TCriticalSections.Destroy;
begin
  DeleteCriticalSection(StockObjectListCritSect);
  inherited Destroy;
end;

function Perform(Control: TControl; Msg: Cardinal; WPar, LPar: Longint): Longint;
var
  Mesg: TMessage;
begin
  Mesg.Msg := Msg;
  Mesg.WParam := WPar;
  Mesg.LParam := LPar;
  Mesg.Result := 0;
  Control.Dispatch(Mesg);
  Result := Mesg.Result;
end;

function SendMessage(Receiver: QWidgetH; MsgId: Integer; WPar, LPar: Longint): Integer;
var
  Event: QCustomEventH;
  Mesg: TMessage;
begin
  AppEventHookNeeded;
  with Mesg do
  begin
    Msg := MsgId;
    wParam := WPar;
    lParam := LPar;
    Result := 0;
  end;
  Event := QCustomEvent_create(QEventType_Message, @Mesg);
  QApplication_sendEvent(Receiver, Event);
  Result := Mesg.Result;
  QEvent_destroy(Event);
end;

function SendMessage(AControl: TWidgetControl; MsgId: Integer; WPar, LPar: Longint): Integer;
begin
//  OutputDebugString(Pchar(Format('%s: %s Sended message %x', [AControl.Name, AControl.ClassName, MsgId ])));
  Result := SendMessage(AControl.Handle, MsgId, WPar, LPar);
end;

type
  TCustomMsg = packed record
    Msg: integer;
    WParam: integer;
    LParam: integer;
    Result: integer;
    Pt: TPoint;
  end;

function PostMessage(Receiver: QWidgetH; MsgId: Integer; WPar, LPar: Longint): LongBool;
var
  Mesg: PMessage;
  Event: QCustomEventH;
begin
  AppEventHookNeeded;
  New(Mesg);
  with Mesg^ do
  begin
    Msg := MsgId;
    WParam := WPar;
    LParam := LPar;
    Result := 0; //or GetTickCount?;
  end;
  Event := QCustomEvent_Create(QEventType_Message, Mesg);
  try
    QApplication_postEvent(Receiver, QEventH(Event));
    Result := true;
  except
    QCustomEvent_Destroy(Event);
    Result := false;
  end;
end;

function PostMessage(AControl: TWidgetControl; MsgId: Integer; WPar, LPar: Longint): LongBool;
begin
//  OutputDebugString(Pchar(Format('%s: %s Posted message %x', [AControl.Name, AControl.ClassName, MsgId ])));
  Result := PostMessage(AControl.Handle, MsgId, WPar, LPar);
end;

{
  implements
  - WMTimer dispatch
  - Handles messages posted through QCustomEvent_message
}

type
  TWinTimer = class(TComponent)
  private
    FWMTimer: Cardinal;
    FQtTimer: Cardinal;
    FTimerProc: TTimerProc;
  public
    constructor Create(AOwner: TComponent); override;
    class function CreateTimer(AOwner: TWinControl; WMTimerId: Cardinal;
      Elapse: Cardinal; Proc: TTimerProc): TWinTimer;
    destructor Destroy; override;
    property WMTimer: Cardinal read FWMTimer;
    property QtTimer: Cardinal read FQtTimer;
    property TimerProc: TTimerProc read FTimerProc write FTimerProc;
  end;

constructor TWinTimer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FWMTimer := 0;
  FQtTimer := 0;
  FTimerProc := nil;
end;

class function TWinTimer.CreateTimer(AOwner: TWinControl; WMTimerId: Cardinal;
      Elapse: Cardinal; Proc: TTimerProc): TWinTimer;
begin
  AppEventHookNeeded;
  Result := Create(AOwner);
  with Result do
  begin
    FWMTimer := WMTimerId;
    FTimerProc := Proc;
    FQtTimer := QObject_startTimer(AOwner.Handle, Elapse);
  end;
end;

destructor TWinTimer.Destroy;
begin
  QObject_killTimer(TWinControl(Owner).Handle, FQtTimer);
  inherited Destroy;
end;

function FindTimer(Receiver: QWidgetH; QtTimerID: Cardinal): TWinTimer;
var
  I: Integer;
  Instance: TWinControl;
begin
  Result := nil;
  Instance := FindControl(Receiver);
  if Assigned(Instance) then
    with Instance do
      for I := 0 to ComponentCount - 1 do
        if (Components[I] is TWinTimer) and
           (TWinTimer(Components[I]).QtTimer = QtTimerID) then
        begin
          Result := TWinTimer(Components[I]);
          Exit;
        end;
end;

function FindWMTimer(Receiver: QWidgetH; WinTimerID: Longword): TWinTimer;
var
  I: Integer;
  Instance: TComponent;
begin
  Result := nil;
  Instance := FindControl(Receiver);
  if Assigned(Instance) then
    with Instance do
      for I := 0 to ComponentCount - 1 do
        if (Components[I] is TWinTimer) and
           (TWinTimer(Components[I]).WMTimer = WinTimerID) then
        begin
          Result := TWinTimer(Components[I]);
          Exit;
        end;
end;

function SetTimer(Instance: TWidgetControl; WMTimerID, Elapse: Cardinal;
  TimerFunc: TTimerProc): Cardinal;
var
  FWinTimer: TWinTimer;
begin
  if Assigned(AppEventHook) then
  begin
    FWinTimer := FindWMTimer(Instance.Handle, WMTimerId);
    if Assigned(FWinTimer) then
      FWinTimer.Destroy;
  end
  else
    AppEventHookNeeded;

  FWinTimer := TWinTimer.CreateTimer(Instance, WMTimerID, Elapse, TimerFunc);
  Result := FWinTimer.WMTimer;
end;

function SetTimer(Wnd: QWidgetH; WMTimerID, Elapse: Cardinal;
  TimerFunc: TTimerProc): Cardinal;
var
  Instance: TWidgetControl;
begin
  Instance := FindControl(Wnd);
  if assigned(Instance) then
    Result := SetTimer(Instance, WMTimerID, Elapse, TimerFunc)
  else
    Result := 0;
end;

function KillTimer(Instance: TWidgetControl; WMTimerId: Cardinal): LongBool;
begin
  Result := KillTimer(Instance.Handle, WMTimerId);
end;

function KillTimer(Wnd: QWidgetH; WMTimerId: Cardinal): LongBool;
var
  WinTimer: TWinTimer;
begin
  WinTimer := FindWMTimer(Wnd, WMTimerId);
  if Assigned(WinTimer) then
  begin
    WinTimer.Destroy;
    Result := true;
  end
  else
    Result := false;
end;

function TAppEventHook.EventFilter(Receiver: QObjectH; Event: QEventH): Boolean;
var
  WinTimer: TWinTimer;
  Mesg: TMessage;
  Id: Integer;
  Instance: TWidgetControl;
begin
  Result := false;
  case QEvent_Type(Event) of

  QEventType_Message:
    begin
      Instance := FindControl(QWidgetH(Receiver));
      if Assigned(Instance)  and not (csDestroying in Instance.ComponentState) then
      begin
        Mesg := TMessage(QCustomEvent_data(QCustomEventH(Event))^);
        Mesg.Result := 0;
        Instance.Dispatch(Mesg);
      end;
      Result := True;
    end;

  QEventType_Timer:
    begin
      if not QObject_isWidgetType(Receiver) then
        Exit;
      Id := QTimerEvent_timerId(QTimerEventH(Event));
      WinTimer := FindTimer(QWidgetH(Receiver), Id );
      if Assigned(WinTimer) then
        with WinTimer do
        begin
          if Assigned(TimerProc) then
            TimerProc(QWidgetH(Receiver), WM_TIMER, WMTimer, GetTickCount);
          with Mesg do
          begin
            Mesg.Msg := WM_TIMER;
            Mesg.WParam := WMTimer;
            Mesg.LParam := Integer(@TimerProc);
            Mesg.Result := 0;
            WinTimer.Owner.Dispatch(Mesg);
          end;
          Result := True;
        end;
    end;

  end;       // case EventType of
end;

function InstallApplicationEventHook(EventFilter: TEventFilterMethod): QApplication_hookH;
var
  Method: TMethod;
begin
  Result := QApplication_hook_create(Application.Handle);
  TEventFilterMethod(Method) := EventFilter;
  Qt_hook_hook_events(Result, Method);
end;

constructor TAppEventHook.Create(AOwner: TComponent);
var
  Method: TMethod;
begin
  inherited Create(AOwner);
  FHook := QApplication_hook_create(Application.Handle);
  TEventFilterMethod(Method) := EventFilter;
  Qt_hook_hook_events(FHook, Method);
end;

destructor TAppEventHook.Destroy;
begin
  if Assigned(FHook) then
  begin
    QApplication_hook_destroy(FHook);
  end;
  inherited Destroy;
end;

initialization
  //OutputDebugString('Loading QWindows.pas');
  {$IFDEF LINUX}
  InitGetTickCount;
  WaitObjectList := THandleObjectList.Create;
  {$ENDIF LINUX}
//  TCriticalSections.Create(Application);

finalization
  {$IFDEF LINUX}
  WaitObjectList.Free;
  {$ENDIF LINUX}
  AppEventHook.Free;
  GlobalCaret.Free;
  //OutputDebugString('Unloaded QWindows.pas');
end.



