From eaab533d22b132ff56dc8dcffb8ce07e935c0b7b Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Wed, 21 Dec 2011 16:20:05 +0000 Subject: [PATCH] LCL-CustomDrawn-X11: Improves the timer precision, allows bigger waits when no timers are active and implements AppProcessMessages git-svn-id: trunk@34354 - --- lcl/interfaces/customdrawn/customdrawnint.pas | 1 + .../customdrawn/customdrawnobject_x11.inc | 217 ++++++++++-------- .../customdrawn/customdrawnproc.pas | 17 +- 3 files changed, 134 insertions(+), 101 deletions(-) diff --git a/lcl/interfaces/customdrawn/customdrawnint.pas b/lcl/interfaces/customdrawn/customdrawnint.pas index 910173dc56..93354fa0dc 100644 --- a/lcl/interfaces/customdrawn/customdrawnint.pas +++ b/lcl/interfaces/customdrawn/customdrawnint.pas @@ -193,6 +193,7 @@ type procedure AppRun(const ALoop: TApplicationMainLoop); override; procedure AppWaitMessage; override; procedure AppProcessMessages; override; + procedure AppProcessMessage; procedure AppTerminate; override; procedure AppMinimize; override; procedure AppRestore; override; diff --git a/lcl/interfaces/customdrawn/customdrawnobject_x11.inc b/lcl/interfaces/customdrawn/customdrawnobject_x11.inc index 3efdc67083..9a21a99ee5 100644 --- a/lcl/interfaces/customdrawn/customdrawnobject_x11.inc +++ b/lcl/interfaces/customdrawn/customdrawnobject_x11.inc @@ -142,110 +142,12 @@ end; procedure TCDWidgetSet.AppRun(const ALoop: TApplicationMainLoop); var - XEvent: TXEvent; - WindowEntry: TWinControl; - Sum: Integer; - NewEvent: TXEvent; DoBreakRun: Boolean = False; - CurWindowInfo: TX11WindowInfo; begin while (DoBreakRun = False) do begin AppWaitMessage(); - XNextEvent(FDisplay, @XEvent); - - // According to a comment in X.h, the valid event types start with 2! - if XEvent._type >= 2 then - begin - WindowEntry := FindWindowByXID(XEvent.XAny.Window, CurWindowInfo); - - if not Assigned(WindowEntry) then - begin - DebugLn('LCL-CustomDrawn-X11: Received X event "%s" for unknown window %x', - [GetXEventName(XEvent._type), PtrInt(XEvent.XAny.Window)]); - Continue; - end; - - CurWindowInfo.XEvent := @XEvent; - - case XEvent._type of - X.DestroyNotify: - begin - //WindowList.Delete(lWindowListIndex); - end; - X.KeyPress: - begin - TCDWSCustomForm.EvKeyPressed(WindowEntry, CurWindowInfo, XEvent.xkey); - end; - X.KeyRelease: - begin - TCDWSCustomForm.EvKeyReleased(WindowEntry, CurWindowInfo, XEvent.xkey); - end; - X.ButtonPress: - begin - TCDWSCustomForm.EvMousePressed(WindowEntry, CurWindowInfo, XEvent.xbutton); - end; - X.ButtonRelease: - begin - TCDWSCustomForm.EvMouseReleased(WindowEntry, CurWindowInfo, XEvent.xbutton); - end; - X.EnterNotify: - begin - TCDWSCustomForm.EvMouseEnter(WindowEntry, CurWindowInfo); - end; - X.LeaveNotify: - begin - TCDWSCustomForm.EvMouseLeave(WindowEntry, CurWindowInfo); - end; - X.MotionNotify: - begin - TCDWSCustomForm.EvMouseMove(WindowEntry, CurWindowInfo, XEvent.xmotion); - end; - X.FocusIn: - begin - TCDWSCustomForm.EvFocusIn(WindowEntry, CurWindowInfo); - end; - X.FocusOut: - begin - TCDWSCustomForm.EvFocusOut(WindowEntry, CurWindowInfo); - end; - X.MapNotify: - begin -// WindowEntry.EvShow(); - end; - X.UnmapNotify: - begin -// WindowEntry.EvHide(); - end; - X.ReparentNotify: - begin -// WindowEntry.EvCreate(); - end; - X.Expose: - begin - // This repeat really helps speeding up when maximized for example - repeat - until not XCheckTypedWindowEvent(FDisplay, XEvent.xexpose.window, X.Expose, @XEvent); - // This check for count=0 is a performance tunning documented in - // http://tronche.com/gui/x/xlib/events/exposure/expose.html - if XEvent.xexpose.count = 0 then - begin - TCDWSCustomForm.EvPaint(WindowEntry, CurWindowInfo); - end; - end; - X.ConfigureNotify: - begin - TCDWSCustomForm.EvConfigureNotify(WindowEntry, CurWindowInfo, XEvent.xconfigure); - end; - X.ClientMessage: - begin - TCDWSCustomForm.EvClientMessage(WindowEntry, CurWindowInfo, XEvent.xclient); - end; - else - DebugLn('LCL-CustomDrawn-X11: Unhandled X11 event received: ', GetXEventName(XEvent._type)); - end; - - end; + AppProcessMessage(); DoBreakRun := Application.Terminated; end; @@ -364,7 +266,118 @@ end;*) ------------------------------------------------------------------------------} procedure TCDWidgetSet.AppProcessMessages; begin + while True do + begin + if XPending(FDisplay) <= 0 then Exit; // There are no more X messages to process + AppProcessMessage(); + end; end; + +// Processes 1 X message +procedure TCDWidgetSet.AppProcessMessage; +var + XEvent: TXEvent; + WindowEntry: TWinControl; + Sum: Integer; + NewEvent: TXEvent; + CurWindowInfo: TX11WindowInfo; +begin + XNextEvent(FDisplay, @XEvent); + + // According to a comment in X.h, the valid event types start with 2! + if XEvent._type >= 2 then + begin + WindowEntry := FindWindowByXID(XEvent.XAny.Window, CurWindowInfo); + + if not Assigned(WindowEntry) then + begin + DebugLn('LCL-CustomDrawn-X11: Received X event "%s" for unknown window %x', + [GetXEventName(XEvent._type), PtrInt(XEvent.XAny.Window)]); + Exit; + end; + + CurWindowInfo.XEvent := @XEvent; + + case XEvent._type of + X.DestroyNotify: + begin + //WindowList.Delete(lWindowListIndex); + end; + X.KeyPress: + begin + TCDWSCustomForm.EvKeyPressed(WindowEntry, CurWindowInfo, XEvent.xkey); + end; + X.KeyRelease: + begin + TCDWSCustomForm.EvKeyReleased(WindowEntry, CurWindowInfo, XEvent.xkey); + end; + X.ButtonPress: + begin + TCDWSCustomForm.EvMousePressed(WindowEntry, CurWindowInfo, XEvent.xbutton); + end; + X.ButtonRelease: + begin + TCDWSCustomForm.EvMouseReleased(WindowEntry, CurWindowInfo, XEvent.xbutton); + end; + X.EnterNotify: + begin + TCDWSCustomForm.EvMouseEnter(WindowEntry, CurWindowInfo); + end; + X.LeaveNotify: + begin + TCDWSCustomForm.EvMouseLeave(WindowEntry, CurWindowInfo); + end; + X.MotionNotify: + begin + TCDWSCustomForm.EvMouseMove(WindowEntry, CurWindowInfo, XEvent.xmotion); + end; + X.FocusIn: + begin + TCDWSCustomForm.EvFocusIn(WindowEntry, CurWindowInfo); + end; + X.FocusOut: + begin + TCDWSCustomForm.EvFocusOut(WindowEntry, CurWindowInfo); + end; + X.MapNotify: + begin +// WindowEntry.EvShow(); + end; + X.UnmapNotify: + begin +// WindowEntry.EvHide(); + end; + X.ReparentNotify: + begin +// WindowEntry.EvCreate(); + end; + X.Expose: + begin + // This repeat really helps speeding up when maximized for example + repeat + until not XCheckTypedWindowEvent(FDisplay, XEvent.xexpose.window, X.Expose, @XEvent); + // This check for count=0 is a performance tunning documented in + // http://tronche.com/gui/x/xlib/events/exposure/expose.html + if XEvent.xexpose.count = 0 then + begin + TCDWSCustomForm.EvPaint(WindowEntry, CurWindowInfo); + end; + end; + X.ConfigureNotify: + begin + TCDWSCustomForm.EvConfigureNotify(WindowEntry, CurWindowInfo, XEvent.xconfigure); + end; + X.ClientMessage: + begin + TCDWSCustomForm.EvClientMessage(WindowEntry, CurWindowInfo, XEvent.xclient); + end; + else + DebugLn('LCL-CustomDrawn-X11: Unhandled X11 event received: ', GetXEventName(XEvent._type)); + end; + + end; +end; + (* procedure TWinCEWidgetSet.CheckPipeEvents; var @@ -416,7 +429,11 @@ var i: Integer; begin {$ifndef CD_X11_DISABLETIMERS} - lTimeoutInterval := 50; + lTimeoutInterval := GetSmallestTimerInterval(); + // Limit the maximum interval, even if only to process Application.OnIdle or + // for general safety + if (lTimeoutInterval <= 0) or (lTimeoutInterval >= 1000) then lTimeoutInterval := 1000; + while True do begin xconnnum := XConnectionNumber(FDisplay); diff --git a/lcl/interfaces/customdrawn/customdrawnproc.pas b/lcl/interfaces/customdrawn/customdrawnproc.pas index 98e68740b5..a7ee2cce77 100644 --- a/lcl/interfaces/customdrawn/customdrawnproc.pas +++ b/lcl/interfaces/customdrawn/customdrawnproc.pas @@ -7,7 +7,7 @@ interface uses // rtl+ftl Types, Classes, SysUtils, - fpimage, fpcanvas, + fpimage, fpcanvas, Math, // Custom Drawn Canvas IntfGraphics, lazcanvas, lazregions, // LCL @@ -137,6 +137,7 @@ procedure InitTimersList(); procedure AddTimer(ATimer: TCDTimer); function GetTimer(AIndex: Integer): TCDTimer; function GetTimerCount(): Integer; +function GetSmallestTimerInterval(): Integer; procedure RemoveTimer(ATimer: TCDTimer); function FindTimerWithNativeHandle(ANativeHandle: PtrInt): TCDTimer; @@ -619,6 +620,20 @@ begin Result := TimersList.Count; end; +function GetSmallestTimerInterval: Integer; +var + i: Integer; + lTimer: TCDTimer; +begin + Result := High(Integer); + for i := 0 to GetTimerCount()-1 do + begin + lTimer := GetTimer(i); + Result := Min(Result, lTimer.Interval); + end; + if Result = High(Integer) then Result := -1; +end; + procedure RemoveTimer(ATimer: TCDTimer); begin InitTimersList();