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 -
This commit is contained in:
sekelsenmat 2012-03-21 11:17:28 +00:00
parent 376af23998
commit 1ad6cf828c
8 changed files with 143 additions and 21 deletions

View File

@ -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}

View File

@ -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}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;*)

View File

@ -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;

View File

@ -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]));