From 1ad6cf828cb390ffdfc59d630b6627bf33fffa14 Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Wed, 21 Mar 2012 11:17:28 +0000 Subject: [PATCH] Patch from Guiliano Colla for a new painting model no LCL-CustomDrawn-X11 and advances the implementation for shift states in this backend git-svn-id: trunk@36189 - --- .../customdrawn/customdrawndefines.inc | 7 +++ lcl/interfaces/customdrawn/customdrawnint.pas | 13 +++- .../customdrawn/customdrawnlclintf_x11.inc | 2 + .../customdrawn/customdrawnobject_x11.inc | 58 ++++++++++++++++- .../customdrawn/customdrawnwinapi_x11.inc | 17 +++-- .../customdrawn/customdrawnwinapih.inc | 4 +- .../customdrawn/customdrawnwsforms.pp | 1 + .../customdrawn/customdrawnwsforms_x11.inc | 62 +++++++++++++++---- 8 files changed, 143 insertions(+), 21 deletions(-) diff --git a/lcl/interfaces/customdrawn/customdrawndefines.inc b/lcl/interfaces/customdrawn/customdrawndefines.inc index 3f16b4c0f0..12e32dd044 100644 --- a/lcl/interfaces/customdrawn/customdrawndefines.inc +++ b/lcl/interfaces/customdrawn/customdrawndefines.inc @@ -48,10 +48,17 @@ {$define CD_BufferControlImages} // for all wincontrols except the form { $define CD_BufferFormImage} // for the form itself (excluding child wincontrols) + +// ================== +// X11 options +// ================== +{$define CD_X11_NewNativePaint} + // ================== // Debug options // ================== {.$define VerboseCDPaintProfiler} {.$define VerboseCDDrawing} {.$define VerboseCDBitmap} +{ $define VerboseCDForms} diff --git a/lcl/interfaces/customdrawn/customdrawnint.pas b/lcl/interfaces/customdrawn/customdrawnint.pas index 0c32a053a0..ec5d38a4bf 100644 --- a/lcl/interfaces/customdrawn/customdrawnint.pas +++ b/lcl/interfaces/customdrawn/customdrawnint.pas @@ -36,7 +36,7 @@ uses // Platform specific {$ifdef CD_Windows}Windows, customdrawn_WinProc,{$endif} {$ifdef CD_Cocoa}MacOSAll, CocoaAll, customdrawn_cocoaproc, CocoaGDIObjects,{$endif} - {$ifdef CD_X11}X, XLib, XUtil, BaseUnix, customdrawn_x11proc,{$ifdef CD_UseNativeText}xft, fontconfig,{$endif}{$endif} + {$ifdef CD_X11}X, XLib, XUtil, BaseUnix, customdrawn_x11proc, contnrs,{$ifdef CD_UseNativeText}xft, fontconfig,{$endif}{$endif} {$ifdef CD_Android} customdrawn_androidproc, jni, bitmap, log, keycodes, {$endif} @@ -150,6 +150,7 @@ type FWMProtocols: TAtom; // Atom for "WM_PROTOCOLS" FWMDeleteWindow: TAtom; // Atom for "WM_DELETE_WINDOW" FWMHints: TAtom; // Atom for "_MOTIF_WM_HINTS" + FWMPaint: TAtom; // Atom for "WM_PAINT" // For composing character events ComposeBuffer: string; @@ -159,12 +160,21 @@ type LastKeySym: TKeySym; // Used for KeyRelease event LastKey: Word; // Used for KeyRelease event + ShiftState: TShiftState; // Keeps ShiftState from X + // XConnections list XConnections: TFPList; + // Windows Info List + XWindowList: TStringList; + + // Functions to keep track of windows needing repaint + function CheckInvalidateWindowForX(XWIndowID: X.TWindow): Boolean; + procedure WindowUpdated(XWIndowID: X.TWindow); function FindWindowByXID(XWindowID: X.TWindow; out AWindowInfo: TX11WindowInfo): TWinControl; procedure AppProcessMessage; procedure AppProcessInvalidates; + function XStateToLCLState(XKeyState: cuint): TShiftState; {$endif} {$ifdef CD_Android} CombiningAccent: Cardinal; @@ -411,6 +421,7 @@ const {$ifdef CD_X11} const CDBackendNativeHandle = nhtX11TWindow; + {$define CD_HasNativeFormHandle} {$endif} {$ifdef CD_Cocoa} diff --git a/lcl/interfaces/customdrawn/customdrawnlclintf_x11.inc b/lcl/interfaces/customdrawn/customdrawnlclintf_x11.inc index 66ea60a7ea..0f395607ba 100644 --- a/lcl/interfaces/customdrawn/customdrawnlclintf_x11.inc +++ b/lcl/interfaces/customdrawn/customdrawnlclintf_x11.inc @@ -132,6 +132,7 @@ function TCDWidgetSet.PromptUser(const DialogCaption : string; DefaultIndex : LongInt; EscapeResult : LongInt) : LongInt; begin + Result := -1; end; {------------------------------------------------------------------------------ @@ -166,6 +167,7 @@ end; procedure TCDWidgetset.ShowVirtualKeyboard(); begin + end; //##apiwiz##eps## // Do not remove, no wizard declaration after this line diff --git a/lcl/interfaces/customdrawn/customdrawnobject_x11.inc b/lcl/interfaces/customdrawn/customdrawnobject_x11.inc index b3fdb48bd5..a8c197c62b 100644 --- a/lcl/interfaces/customdrawn/customdrawnobject_x11.inc +++ b/lcl/interfaces/customdrawn/customdrawnobject_x11.inc @@ -30,6 +30,38 @@ begin else CDWidgetset.XConnections.Remove(Pointer(fd)); end; +function TCDWidgetSet.CheckInvalidateWindowForX(XWIndowID: X.TWindow): Boolean; +var + I: integer; + AWindowInfo: TX11WindowInfo; +begin + Result:= False; + for I:= 0 to XWindowList.Count -1 do begin + AWindowInfo:= TX11WindowInfo(XWindowList.Objects[I]); + if AWindowInfo.Window = XWIndowID then begin + if XWindowList.Strings[I] <> 'Paint' then begin + XWindowList.Strings[I] := 'Paint'; + Result:= True; + Exit; + end; + end; + end; +end; + +procedure TCDWidgetSet.WindowUpdated(XWIndowID: X.TWindow); +var + I: integer; + AWindowInfo: TX11WindowInfo; +begin + for I:= 0 to XWindowList.Count -1 do begin + AWindowInfo:= TX11WindowInfo(XWindowList.Objects[I]); + if AWindowInfo.Window = XWIndowID then begin + XWindowList.Strings[I] := 'Done'; + Exit; + end; + end; +end; + function TCDWidgetSet.FindWindowByXID(XWindowID: X.TWindow; out AWindowInfo: TX11WindowInfo): TWinControl; var i: Integer; @@ -80,6 +112,7 @@ begin ScreenDC := TLazCanvas.Create(ScreenImage); XConnections := TFPList.Create; + XWindowList := TStringList.Create; end; {------------------------------------------------------------------------------ @@ -90,8 +123,13 @@ end; destructor for the class. ------------------------------------------------------------------------------} procedure TCDWidgetSet.BackendDestroy; +var + I: Integer; begin XConnections.Free; + for I:= 0 to XWindowList.Count -1 do + XWindowList.Objects[I].Free; + XWindowList.Free; { Release the screen DC and Image } ScreenDC.Free; @@ -303,6 +341,7 @@ end; procedure TCDWidgetSet.AppProcessMessage; var XEvent: TXEvent; + XClientEvent: TXClientMessageEvent absolute XEvent ; WindowEntry: TWinControl; Sum: Integer; NewEvent: TXEvent; @@ -395,7 +434,15 @@ begin end; X.ClientMessage: begin - TCDWSCustomForm.EvClientMessage(WindowEntry, CurWindowInfo, XEvent.xclient); + if XClientEvent.message_type = CDWidgetSet.FWMPaint then begin + {$ifdef VerboseCDEvents} + DebugLn(Format('X11 event WM_PAINT - Window %d',[CurWindowInfo.Window])); + {$endif} + TCDWSCustomForm.EvPaintEx(WindowEntry, CurWindowInfo); + WindowUpdated(CurWindowInfo.Window); + end + else + TCDWSCustomForm.EvClientMessage(WindowEntry, CurWindowInfo, XEvent.xclient); end; else DebugLn('LCL-CustomDrawn-X11: Unhandled X11 event received: ', GetXEventName(XEvent._type)); @@ -423,6 +470,15 @@ begin end; end; +function TCDWidgetSet.XStateToLCLState(XKeyState: cuint): TShiftState; +begin + Result:= []; + if (XKeyState and X.ShiftMask) <> 0 then Include(Result,ssShift); + if (XKeyState and X.ControlMask) <> 0 then Include(Result,ssCtrl); + if (XKeyState and X.Mod1Mask) <> 0 then Include(Result,ssAlt); + if (XKeyState and X.Mod5Mask) <> 0 then Include(Result,ssAltGr); +end; + function TCDWidgetSet.GetAppHandle: THandle; begin Result := THandle(FDisplay); diff --git a/lcl/interfaces/customdrawn/customdrawnwinapi_x11.inc b/lcl/interfaces/customdrawn/customdrawnwinapi_x11.inc index c66740b64c..f547e165a2 100644 --- a/lcl/interfaces/customdrawn/customdrawnwinapi_x11.inc +++ b/lcl/interfaces/customdrawn/customdrawnwinapi_x11.inc @@ -2861,8 +2861,9 @@ begin {$endif} end; end; +*) -function TQtWidgetSet.GetKeyState(nVirtKey: Integer): Smallint; +function TCDWidgetSet.GetKeyState(nVirtKey: Integer): Smallint; const StateDown = SmallInt($FF80); {StateToggled = SmallInt($0001);} @@ -2871,14 +2872,16 @@ begin case nVirtKey of VK_LSHIFT: nVirtKey := VK_SHIFT; + VK_RSHIFT: nVirtKey := VK_SHIFT; VK_LCONTROL: nVirtKey := VK_CONTROL; + VK_RCONTROL: nVirtKey := VK_CONTROL; VK_LMENU: nVirtKey := VK_MENU; end; // where to track toggle state? case nVirtKey of - VK_LBUTTON: +(* VK_LBUTTON: if (QApplication_mouseButtons and QtLeftButton) > 0 then Result := Result or StateDown; VK_RBUTTON: @@ -2896,22 +2899,24 @@ begin VK_MENU: if (QApplication_keyboardModifiers and QtAltModifier) > 0 then Result := Result or StateDown; +*) VK_SHIFT: - if (QApplication_keyboardModifiers and QtShiftModifier) > 0 then + if ssShift in ShiftState then Result := Result or StateDown; VK_CONTROL: - if (QApplication_keyboardModifiers and QtControlModifier) > 0 then + if ssCtrl in ShiftState then Result := Result or StateDown; - VK_LWIN, VK_RWIN: +(* VK_LWIN, VK_RWIN: if (QApplication_keyboardModifiers and QtMetaModifier) > 0 then Result := Result or StateDown; {$ifdef VerboseQtWinAPI} else DebugLn('TQtWidgetSet.GetKeyState TODO ', DbgSVKCode(Word(nVirtkey))); - {$endif} + {$endif} *) end; end; +(* function TQtWidgetSet.GetMapMode(DC: HDC): Integer; begin if IsValidDC(DC) then diff --git a/lcl/interfaces/customdrawn/customdrawnwinapih.inc b/lcl/interfaces/customdrawn/customdrawnwinapih.inc index 474895cd1f..097b983791 100644 --- a/lcl/interfaces/customdrawn/customdrawnwinapih.inc +++ b/lcl/interfaces/customdrawn/customdrawnwinapih.inc @@ -122,9 +122,9 @@ function GetDeviceCaps(DC: HDC; Index: Integer): Integer; override; (*function GetDIBits(DC: HDC; Bitmap: HBitmap; StartScan, NumScans: UINT; Bits: Pointer; var BitInfo: BitmapInfo; Usage: UINT): Integer; Override; function GetDoubleClickTime: UINT; override;*) function GetFocus: HWND; override; -(*function GetForegroundWindow: HWND; override; +(*function GetForegroundWindow: HWND; override;*) function GetKeyState(nVirtKey: Integer): Smallint; override; -function GetMapMode(DC: HDC): Integer; override; +(*function GetMapMode(DC: HDC): Integer; override; function GetMonitorInfo(Monitor: HMONITOR; lpmi: PMonitorInfo): Boolean; override; function GetObject(GDIObj: HGDIOBJ; BufSize: Integer; Buf: Pointer): Integer; override; function GetParent(Handle : HWND): HWND; override;*) diff --git a/lcl/interfaces/customdrawn/customdrawnwsforms.pp b/lcl/interfaces/customdrawn/customdrawnwsforms.pp index b4ada1766c..3307da928b 100644 --- a/lcl/interfaces/customdrawn/customdrawnwsforms.pp +++ b/lcl/interfaces/customdrawn/customdrawnwsforms.pp @@ -124,6 +124,7 @@ type class procedure EvFocusIn(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo); class procedure EvFocusOut(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo); class procedure EvPaint(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo); + class procedure EvPaintEx(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo); class procedure EvConfigureNotify(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo; var Event: TXConfigureEvent); class procedure EvClientMessage(const AWinControl: TWinControl; diff --git a/lcl/interfaces/customdrawn/customdrawnwsforms_x11.inc b/lcl/interfaces/customdrawn/customdrawnwsforms_x11.inc index f18b026ed5..5a45b46eb1 100644 --- a/lcl/interfaces/customdrawn/customdrawnwsforms_x11.inc +++ b/lcl/interfaces/customdrawn/customdrawnwsforms_x11.inc @@ -499,6 +499,7 @@ begin lKey := X11KeyToLCLKey(KeySym); CDWidgetset.LastKeySym := KeySym; CDWidgetset.LastKey := lKey; + CDWidgetSet.ShiftState := CDWidgetSet.XStateToLCLState(Event.state); CallbackKeyDown(lForm, lKey); @@ -527,6 +528,7 @@ begin lForm := TCDForm(AWinControl.Handle); lKey := CDWidgetset.LastKey; + CDWidgetSet.ShiftState := CDWidgetSet.XStateToLCLState(Event.state); CallbackKeyUp(lForm, lKey); // Do not call EndComposing, as this would generate duplicate KeyChar events!} @@ -624,6 +626,8 @@ var lWidth, lHeight: Integer; lBitmap, lMask: HBITMAP; lRawImage: TRawImage; + Event: TXClientMessageEvent; + reslt: Integer; {$IFDEF VerboseCDPaintProfiler} lTimeStart, lCDTimeEnd, lNativeTimeStart: TDateTime; {$ENDIF} @@ -662,9 +666,25 @@ begin lNativeTimeStart := NowUTC(); {$ENDIF} + {$ifdef CD_X11_NewNativePaint} + // if not already done, send a message to X + if CDWidgetSet.CheckInvalidateWindowForX(AWindowInfo.Window) then + begin + FillChar(Event,sizeof(Event),0); + Event._type:= ClientMessage; + Event.display:=CDWidgetSet.FDisplay; + Event.window:=AWindowInfo.Window; + Event.message_type:= CDWidgetSet.FWMPaint; + Event.format:= 32; // Must hold a culong for TXID + Event.data.l[0]:= AWindowInfo.Window; + reslt := XSendEvent(CDWidgetSet.FDisplay,AWindowInfo.Window,{Propagate=}True,0,@Event); + // Painting will carried out from main event loop + end; + {$else} // Now render it into the control AWindowInfo.Image.GetRawImage(lRawImage); DrawRawImageToGC(lRawImage, AWindowInfo, 0, 0, lWidth, lHeight); + {$endif} {$IFDEF VerboseCDPaintProfiler} DebugLn(Format('[TCDWSCustomForm.EvPaint] Total Paint duration: %d ms of this CustomDrawn: %d ms Native: %d', @@ -675,6 +695,18 @@ begin {$ENDIF} end; +class procedure TCDWSCustomForm.EvPaintEx(const AWinControl: TWinControl; + AWindowInfo: TX11WindowInfo); +var + lWidth, lHeight: Integer; + lRawImage: TRawImage; +begin + lWidth := Round(AWinControl.width); + lHeight := Round(AWinControl.height); + AWindowInfo.Image.GetRawImage(lRawImage); + DrawRawImageToGC(lRawImage, AWindowInfo, 0, 0, lWidth, lHeight); +end; + class procedure TCDWSCustomForm.EvConfigureNotify(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo; var Event: TXConfigureEvent); begin @@ -1777,9 +1809,9 @@ begin 0xfd1d U0000 f # 3270_PrintScreen 0xfd1e U0000 f # 3270_Enter 0xfe01 U0000 f # ISO_Lock - 0xfe02 U0000 f # ISO_Level2_Latch - 0xfe03 U0000 f # ISO_Level3_Shift - 0xfe04 U0000 f # ISO_Level3_Latch + 0xfe02 U0000 f # ISO_Level2_Latch} + $FE03: Result := VK_RMENU; // ISO_Level3_Shift + {0xfe04 U0000 f # ISO_Level3_Latch 0xfe05 U0000 f # ISO_Level3_Lock 0xfe06 U0000 f # ISO_Group_Latch 0xfe07 U0000 f # ISO_Group_Lock @@ -1922,8 +1954,8 @@ begin $FF54: Result := VK_DOWN; $FF55: Result := VK_PRIOR; $FF56: Result := VK_NEXT; -{ 0xff57 U0000 f # End - 0xff58 U0000 f # Begin + $ff57: Result := VK_END; +{ 0xff58 U0000 f # Begin 0xff60 U0000 f # Select 0xff61 U0000 f # Print 0xff62 U0000 f # Execute @@ -2015,15 +2047,15 @@ begin { 0xffe5 U0000 f # Caps_Lock 0xffe6 U0000 f # Shift_Lock 0xffe7 U0000 f # Meta_L - 0xffe8 U0000 f # Meta_R - 0xffe9 U0000 f # Alt_L - 0xffea U0000 f # Alt_R + 0xffe8 U0000 f # Meta_R} + $FFE9: Result := VK_LMENU; + {0xffea U0000 f # Alt_R 0xffeb U0000 f # Super_L 0xffec U0000 f # Super_R 0xffed U0000 f # Hyper_L 0xffee U0000 f # Hyper_R - 0xffff U0000 f # Delete - $FFFF: Result := VK_DEL; } + 0xffff U0000 f # Delete } + $FFFF: Result := VK_DELETE; { 0xffffff U0000 f # VoidSymbol # Various XFree86 extensions since X11R6.4 @@ -2443,7 +2475,6 @@ begin else Result := 0; end; - if Result = 0 then DebugLn('[X11KeyToLCLKey] Unknown KeySym: $' + IntToHex(AX11Key, 4)); end; @@ -2569,6 +2600,11 @@ begin CDWidgetSet.FWMProtocols := XInternAtom(CDWidgetSet.FDisplay, 'WM_PROTOCOLS', False); if CDWidgetSet.FWMDeleteWindow = 0 then CDWidgetSet.FWMDeleteWindow := XInternAtom(CDWidgetSet.FDisplay, 'WM_DELETE_WINDOW', False); + {$ifdef CD_X11_NewNativePaint} + // Client Message for Paint Event + if CDWidgetSet.FWMPaint = 0 then + CDWidgetSet.FWMPaint := XInternAtom(CDWidgetSet.FDisplay, 'WM_PAINT', False); + {$endif} // send close event instead of quitting the whole application... XSetWMProtocols(CDWidgetSet.FDisplay, lWindow, @CDWidgetSet.FWMDeleteWindow, 1); @@ -2592,6 +2628,10 @@ begin CreateX11Canvas(lWindowInfo); Result := TLCLIntfHandle(lWindowInfo); + {$ifdef CD_X11_NewNativePaint} + CDWidgetSet.XWindowList.AddObject('New',TObject(lWindowInfo)); + {$endif} + {$ifdef VerboseCDForms} DebugLn(Format(':<[TCDWSCustomForm.CreateHandle] Result=%x', [Result]));