aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil Hodgson <nyamatongwe@gmail.com>2014-07-15 12:04:54 +1000
committerNeil Hodgson <nyamatongwe@gmail.com>2014-07-15 12:04:54 +1000
commitbaf2d31068737bf24102cee6a7fed33e0d00d1f3 (patch)
treef814f1a39637d7711ab0ce709fef0b2468fbb270
parent7b7865ca3062d57ebe990468a9275180f0d60569 (diff)
downloadscintilla-mirror-baf2d31068737bf24102cee6a7fed33e0d00d1f3.tar.gz
Implement separate timers for each type of periodic activity and turn them on and off
as required. This saves power as there are fewer wake ups. A tolerance value is provided so that platforms that support coalescing timers, Windows 8+ and OS X 10.9+, can use them. The previous global 100 millisecond timer may still be used by non-core platforms.
-rw-r--r--cocoa/ScintillaCocoa.h7
-rw-r--r--cocoa/ScintillaCocoa.mm109
-rw-r--r--doc/ScintillaHistory.html8
-rw-r--r--gtk/ScintillaGTK.cxx57
-rw-r--r--qt/ScintillaEditBase/ScintillaQt.cpp66
-rw-r--r--qt/ScintillaEditBase/ScintillaQt.h10
-rw-r--r--src/Editor.cxx124
-rw-r--r--src/Editor.h8
-rw-r--r--win32/ScintillaWin.cxx65
9 files changed, 359 insertions, 95 deletions
diff --git a/cocoa/ScintillaCocoa.h b/cocoa/ScintillaCocoa.h
index 61d78c449..122df7b44 100644
--- a/cocoa/ScintillaCocoa.h
+++ b/cocoa/ScintillaCocoa.h
@@ -144,7 +144,11 @@ public:
void PaintMargin(NSRect aRect);
virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
- void SetTicking(bool on);
+ void TickFor(TickReason reason);
+ bool FineTickerAvailable();
+ bool FineTickerRunning(TickReason reason);
+ void FineTickerStart(TickReason reason, int millis, int tolerance);
+ void FineTickerCancel(TickReason reason);
bool SetIdle(bool on);
void SetMouseCapture(bool on);
bool HaveMouseCapture();
@@ -181,6 +185,7 @@ public:
static sptr_t DirectFunction(sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam);
+ NSTimer *timers[tickPlatform+1];
void TimerFired(NSTimer* timer);
void IdleTimerFired();
static void UpdateObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *sci);
diff --git a/cocoa/ScintillaCocoa.mm b/cocoa/ScintillaCocoa.mm
index 027bdffbf..f8c53932c 100644
--- a/cocoa/ScintillaCocoa.mm
+++ b/cocoa/ScintillaCocoa.mm
@@ -395,6 +395,10 @@ ScintillaCocoa::ScintillaCocoa(SCIContentView* view, SCIMarginView* viewMargin)
idleTimer = NULL;
observer = NULL;
layerFindIndicator = NULL;
+ for (TickReason tr=tickCaret; tr<=tickPlatform; tr = static_cast<TickReason>(tr+1))
+ {
+ timers[tr] = nil;
+ }
Initialise();
}
@@ -435,7 +439,10 @@ void ScintillaCocoa::Initialise()
void ScintillaCocoa::Finalise()
{
ObserverRemove();
- SetTicking(false);
+ for (TickReason tr=tickCaret; tr<=tickPlatform; tr = static_cast<TickReason>(tr+1))
+ {
+ FineTickerCancel(tr);
+ }
ScintillaBase::Finalise();
}
@@ -862,32 +869,72 @@ sptr_t ScintillaCocoa::DefWndProc(unsigned int, uptr_t, sptr_t)
//--------------------------------------------------------------------------------------------------
/**
- * Enables or disables a timer that can trigger background processing at a regular interval, like
- * drag scrolling or caret blinking.
+ * Handle any ScintillaCocoa-specific ticking or call superclass.
*/
-void ScintillaCocoa::SetTicking(bool on)
+void ScintillaCocoa::TickFor(TickReason reason)
{
- if (timer.ticking != on)
+ if (reason == tickPlatform)
{
- timer.ticking = on;
- if (timer.ticking)
- {
- // Scintilla ticks = milliseconds
- tickTimer = [NSTimer scheduledTimerWithTimeInterval: timer.tickSize / 1000.0
- target: timerTarget
- selector: @selector(timerFired:)
- userInfo: nil
- repeats: YES];
- timer.tickerID = reinterpret_cast<TickerID>(tickTimer);
- }
- else
- if (timer.tickerID != NULL)
- {
- [reinterpret_cast<NSTimer*>(timer.tickerID) invalidate];
- timer.tickerID = 0;
- }
+ DragScroll();
+ }
+ else
+ {
+ Editor::TickFor(reason);
+ }
+}
+
+//--------------------------------------------------------------------------------------------------
+
+/**
+ * Report that this Editor subclass has a working implementation of FineTickerStart.
+ */
+bool ScintillaCocoa::FineTickerAvailable()
+{
+ return true;
+}
+
+//--------------------------------------------------------------------------------------------------
+
+/**
+ * Is a particular timer currently running?
+ */
+bool ScintillaCocoa::FineTickerRunning(TickReason reason)
+{
+ return timers[reason] != nil;
+}
+
+//--------------------------------------------------------------------------------------------------
+
+/**
+ * Start a fine-grained timer.
+ */
+void ScintillaCocoa::FineTickerStart(TickReason reason, int millis, int tolerance)
+{
+ FineTickerCancel(reason);
+ NSTimer *fineTimer = [NSTimer scheduledTimerWithTimeInterval: millis / 1000.0
+ target: timerTarget
+ selector: @selector(timerFired:)
+ userInfo: nil
+ repeats: YES];
+ if (tolerance && [fineTimer respondsToSelector: @selector(setTolerance:)])
+ {
+ [fineTimer setTolerance: tolerance / 1000.0];
+ }
+ timers[reason] = fineTimer;
+}
+
+//--------------------------------------------------------------------------------------------------
+
+/**
+ * Cancel a fine-grained timer.
+ */
+void ScintillaCocoa::FineTickerCancel(TickReason reason)
+{
+ if (timers[reason])
+ {
+ [timers[reason] invalidate];
+ timers[reason] = nil;
}
- timer.ticksToWait = caret.period;
}
//--------------------------------------------------------------------------------------------------
@@ -1175,6 +1222,8 @@ void ScintillaCocoa::StartDrag()
inDragDrop = ddDragging;
+ FineTickerStart(tickPlatform, timer.tickSize, 0);
+
// Put the data to be dragged on the drag pasteboard.
SelectionText selectedText;
NSPasteboard* pasteboard = [NSPasteboard pasteboardWithName: NSDragPboard];
@@ -1336,6 +1385,7 @@ void ScintillaCocoa::StartDrag()
*/
NSDragOperation ScintillaCocoa::DraggingEntered(id <NSDraggingInfo> info)
{
+ FineTickerStart(tickPlatform, timer.tickSize, 0);
return DraggingUpdated(info);
}
@@ -1378,6 +1428,7 @@ void ScintillaCocoa::DraggingExited(id <NSDraggingInfo> info)
{
#pragma unused(info)
SetDragPosition(SelectionPosition(invalidPosition));
+ FineTickerCancel(tickPlatform);
inDragDrop = ddNone;
}
@@ -1822,9 +1873,13 @@ bool ScintillaCocoa::CanRedo()
void ScintillaCocoa::TimerFired(NSTimer* timer)
{
-#pragma unused(timer)
- Tick();
- DragScroll();
+ for (TickReason tr=tickCaret; tr<=tickPlatform; tr = static_cast<TickReason>(tr+1))
+ {
+ if (timers[tr] == timer)
+ {
+ TickFor(tr);
+ }
+ }
}
//--------------------------------------------------------------------------------------------------
@@ -2145,7 +2200,7 @@ void ScintillaCocoa::ActiveStateChanged(bool isActive)
if (!isActive) {
DropCaret();
//SetFocusState( false );
- SetTicking( false );
+ FineTickerCancel(tickCaret);
} else {
ShowCaretAtCurrentPosition();
}
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index 08615b5cf..9dfbe08f0 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -469,6 +469,14 @@
Released 3 July 2014.
</li>
<li>
+ Separate timers are used for each type of periodic activity and they are turned on and off
+ as required. This saves power as there are fewer wake ups.
+ On recent releases of OS X Cocoa and Windows, coalescing timers are used to further
+ save power.
+ <a href="http://sourceforge.net/p/scintilla/bugs/1086/">Bug #1086</a>.
+ <a href="http://sourceforge.net/p/scintilla/bugs/1532/">Bug #1532</a>.
+ </li>
+ <li>
SciTE adds a "Clean" command to the "Tools" menu which is meant to be bound to a command like
"make clean".
</li>
diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx
index 3285967da..be3df5501 100644
--- a/gtk/ScintillaGTK.cxx
+++ b/gtk/ScintillaGTK.cxx
@@ -189,7 +189,17 @@ public: // Public for scintilla_send_message
virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
private:
virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
- virtual void SetTicking(bool on);
+ struct TimeThunk {
+ TickReason reason;
+ ScintillaGTK *scintilla;
+ guint timer;
+ TimeThunk() : reason(tickCaret), scintilla(NULL), timer(0) {}
+ };
+ TimeThunk timers[tickDwell+1];
+ virtual bool FineTickerAvailable();
+ virtual bool FineTickerRunning(TickReason reason);
+ virtual void FineTickerStart(TickReason reason, int millis, int tolerance);
+ virtual void FineTickerCancel(TickReason reason);
virtual bool SetIdle(bool on);
virtual void SetMouseCapture(bool on);
virtual bool HaveMouseCapture();
@@ -303,7 +313,7 @@ private:
gint x, gint y, GtkSelectionData *selection_data, guint info, guint time);
static void DragDataGet(GtkWidget *widget, GdkDragContext *context,
GtkSelectionData *selection_data, guint info, guint time);
- static gboolean TimeOut(ScintillaGTK *sciThis);
+ static gboolean TimeOut(TimeThunk *tt);
static gboolean IdleCallback(ScintillaGTK *sciThis);
static gboolean StyleIdle(ScintillaGTK *sciThis);
virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo);
@@ -832,11 +842,16 @@ void ScintillaGTK::Initialise() {
caret.period = 0;
}
- SetTicking(true);
+ for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
+ timers[tr].reason = tr;
+ timers[tr].scintilla = this;
+ }
}
void ScintillaGTK::Finalise() {
- SetTicking(false);
+ for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
+ FineTickerCancel(tr);
+ }
ScintillaBase::Finalise();
}
@@ -1027,17 +1042,27 @@ sptr_t ScintillaGTK::DefWndProc(unsigned int, uptr_t, sptr_t) {
return 0;
}
-void ScintillaGTK::SetTicking(bool on) {
- if (timer.ticking != on) {
- timer.ticking = on;
- if (timer.ticking) {
- timer.tickerID = reinterpret_cast<TickerID>(g_timeout_add(timer.tickSize,
- reinterpret_cast<GSourceFunc>(TimeOut), this));
- } else {
- g_source_remove(GPOINTER_TO_UINT(timer.tickerID));
- }
+/**
+* Report that this Editor subclass has a working implementation of FineTickerStart.
+*/
+bool ScintillaGTK::FineTickerAvailable() {
+ return true;
+}
+
+bool ScintillaGTK::FineTickerRunning(TickReason reason) {
+ return timers[reason].timer != 0;
+}
+
+void ScintillaGTK::FineTickerStart(TickReason reason, int millis, int /* tolerance */) {
+ FineTickerCancel(reason);
+ timers[reason].timer = g_timeout_add(millis, reinterpret_cast<GSourceFunc>(TimeOut), &timers[reason]);
+}
+
+void ScintillaGTK::FineTickerCancel(TickReason reason) {
+ if (timers[reason].timer) {
+ g_source_remove(timers[reason].timer);
+ timers[reason].timer = 0;
}
- timer.ticksToWait = caret.period;
}
bool ScintillaGTK::SetIdle(bool on) {
@@ -2715,8 +2740,8 @@ void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context,
}
}
-int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) {
- sciThis->Tick();
+int ScintillaGTK::TimeOut(TimeThunk *tt) {
+ tt->scintilla->TickFor(tt->reason);
return 1;
}
diff --git a/qt/ScintillaEditBase/ScintillaQt.cpp b/qt/ScintillaEditBase/ScintillaQt.cpp
index 3d727900b..c2b250a3e 100644
--- a/qt/ScintillaEditBase/ScintillaQt.cpp
+++ b/qt/ScintillaEditBase/ScintillaQt.cpp
@@ -44,19 +44,20 @@ ScintillaQt::ScintillaQt(QAbstractScrollArea *parent)
WndProc(SCI_SETBUFFEREDDRAW, false, 0);
Initialise();
+
+ for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
+ timers[tr] = 0;
+ }
}
ScintillaQt::~ScintillaQt()
{
- SetTicking(false);
+ for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
+ FineTickerCancel(tr);
+ }
SetIdle(false);
}
-void ScintillaQt::tick()
-{
- Tick();
-}
-
void ScintillaQt::execCommand(QAction *action)
{
int command = action->data().toInt();
@@ -148,7 +149,9 @@ void ScintillaQt::Initialise()
void ScintillaQt::Finalise()
{
- SetTicking(false);
+ for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
+ FineTickerCancel(tr);
+ }
ScintillaBase::Finalise();
}
@@ -396,25 +399,31 @@ void ScintillaQt::NotifyParent(SCNotification scn)
emit notifyParent(scn);
}
-void ScintillaQt::SetTicking(bool on)
+/**
+* Report that this Editor subclass has a working implementation of FineTickerStart.
+*/
+bool ScintillaQt::FineTickerAvailable()
{
- QTimer *qTimer;
- if (timer.ticking != on) {
- timer.ticking = on;
- if (timer.ticking) {
- qTimer = new QTimer;
- connect(qTimer, SIGNAL(timeout()), this, SLOT(tick()));
- qTimer->start(timer.tickSize);
- timer.tickerID = qTimer;
- } else {
- qTimer = static_cast<QTimer *>(timer.tickerID);
- qTimer->stop();
- disconnect(qTimer, SIGNAL(timeout()), 0, 0);
- delete qTimer;
- timer.tickerID = 0;
- }
+ return true;
+}
+
+bool ScintillaQt::FineTickerRunning(TickReason reason)
+{
+ return timers[reason] != 0;
+}
+
+void ScintillaQt::FineTickerStart(TickReason reason, int millis, int /* tolerance */)
+{
+ FineTickerCancel(reason);
+ timers[reason] = startTimer(millis);
+}
+
+void ScintillaQt::FineTickerCancel(TickReason reason)
+{
+ if (timers[reason]) {
+ killTimer(timers[reason]);
+ timers[reason] = 0;
}
- timer.ticksToWait = caret.period;
}
void ScintillaQt::onIdle()
@@ -740,3 +749,12 @@ void ScintillaQt::Drop(const Point &point, const QMimeData *data, bool move)
DropAt(movePos, bytes, len, move, rectangular);
}
+
+void ScintillaQt::timerEvent(QTimerEvent *event)
+{
+ for (TickReason tr=tickCaret; tr<=tickDwell; tr = static_cast<TickReason>(tr+1)) {
+ if (timers[tr] == event->timerId()) {
+ TickFor(tr);
+ }
+ }
+}
diff --git a/qt/ScintillaEditBase/ScintillaQt.h b/qt/ScintillaEditBase/ScintillaQt.h
index ff4d65992..16bafbf7c 100644
--- a/qt/ScintillaEditBase/ScintillaQt.h
+++ b/qt/ScintillaEditBase/ScintillaQt.h
@@ -14,6 +14,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+#include <assert.h>
#include <ctype.h>
#include <time.h>
#include <string>
@@ -88,7 +89,6 @@ signals:
void command(uptr_t wParam, sptr_t lParam);
private slots:
- void tick();
void onIdle();
void execCommand(QAction *action);
void SelectionChanged();
@@ -114,7 +114,11 @@ private:
virtual void NotifyChange();
virtual void NotifyFocus(bool focus);
virtual void NotifyParent(SCNotification scn);
- virtual void SetTicking(bool on);
+ int timers[tickDwell+1];
+ virtual bool FineTickerAvailable();
+ virtual bool FineTickerRunning(TickReason reason);
+ virtual void FineTickerStart(TickReason reason, int millis, int tolerance);
+ virtual void FineTickerCancel(TickReason reason);
virtual bool SetIdle(bool on);
virtual void SetMouseCapture(bool on);
virtual bool HaveMouseCapture();
@@ -143,6 +147,8 @@ protected:
void DragLeave();
void Drop(const Point &point, const QMimeData *data, bool move);
+ void timerEvent(QTimerEvent *event);
+
private:
QAbstractScrollArea *scrollArea;
diff --git a/src/Editor.cxx b/src/Editor.cxx
index a23683698..361e82803 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -1311,16 +1311,26 @@ void Editor::ShowCaretAtCurrentPosition() {
if (hasFocus) {
caret.active = true;
caret.on = true;
- SetTicking(true);
+ if (FineTickerAvailable()) {
+ FineTickerCancel(tickCaret);
+ if (caret.period > 0)
+ FineTickerStart(tickCaret, caret.period, caret.period/10);
+ } else {
+ SetTicking(true);
+ }
} else {
caret.active = false;
caret.on = false;
+ if (FineTickerAvailable()) {
+ FineTickerCancel(tickCaret);
+ }
}
InvalidateCaret();
}
void Editor::DropCaret() {
caret.active = false;
+ FineTickerCancel(tickCaret);
InvalidateCaret();
}
@@ -1328,6 +1338,11 @@ void Editor::CaretSetPeriod(int period) {
if (caret.period != period) {
caret.period = period;
caret.on = true;
+ if (FineTickerAvailable()) {
+ FineTickerCancel(tickCaret);
+ if ((caret.active) && (caret.period > 0))
+ FineTickerStart(tickCaret, caret.period, caret.period/10);
+ }
InvalidateCaret();
}
}
@@ -1659,6 +1674,15 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
view.PaintText(surfaceWindow, rcArea, rcClient, *this, vs);
+ if (horizontalScrollBarVisible && trackLineWidth && (view.lineWidthMaxSeen > scrollWidth)) {
+ if (FineTickerAvailable()) {
+ scrollWidth = view.lineWidthMaxSeen;
+ if (!FineTickerRunning(tickWiden)) {
+ FineTickerStart(tickWiden, 50, 5);
+ }
+ }
+ }
+
NotifyPainted();
}
@@ -3809,7 +3833,13 @@ void Editor::SetDragPosition(SelectionPosition newPos) {
}
if (!(posDrag == newPos)) {
caret.on = true;
- SetTicking(true);
+ if (FineTickerAvailable()) {
+ FineTickerCancel(tickCaret);
+ if ((caret.active) && (caret.period > 0) && (newPos.Position() < 0))
+ FineTickerStart(tickCaret, caret.period, caret.period/10);
+ } else {
+ SetTicking(true);
+ }
InvalidateCaret();
posDrag = newPos;
InvalidateCaret();
@@ -4033,6 +4063,12 @@ void Editor::DwellEnd(bool mouseMoved) {
dwelling = false;
NotifyDwelling(ptMouseLast, dwelling);
}
+ if (FineTickerAvailable()) {
+ FineTickerCancel(tickDwell);
+ if (mouseMoved && (dwellDelay < SC_TIME_FOREVER)) {
+ //FineTickerStart(tickDwell, dwellDelay, dwellDelay/10);
+ }
+ }
}
void Editor::MouseLeave() {
@@ -4080,6 +4116,9 @@ void Editor::ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifie
if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {
//Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
SetMouseCapture(true);
+ if (FineTickerAvailable()) {
+ FineTickerStart(tickScroll, 100, 10);
+ }
if (!ctrl || !multipleSelection || (selectionType != selChar && selectionType != selWord))
SetEmptySelection(newPos.Position());
bool doubleClick = false;
@@ -4176,6 +4215,9 @@ void Editor::ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifie
SetDragPosition(SelectionPosition(invalidPosition));
SetMouseCapture(true);
+ if (FineTickerAvailable()) {
+ FineTickerStart(tickScroll, 100, 10);
+ }
} else {
if (PointIsHotspot(pt)) {
NotifyHotSpotClicked(newCharPos.Position(), modifiers);
@@ -4188,6 +4230,9 @@ void Editor::ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifie
inDragDrop = ddNone;
}
SetMouseCapture(true);
+ if (FineTickerAvailable()) {
+ FineTickerStart(tickScroll, 100, 10);
+ }
if (inDragDrop != ddInitial) {
SetDragPosition(SelectionPosition(invalidPosition));
if (!shift) {
@@ -4281,6 +4326,9 @@ void Editor::ButtonMoveWithModifiers(Point pt, int modifiers) {
if (inDragDrop == ddInitial) {
if (DragThreshold(ptMouseLast, pt)) {
SetMouseCapture(false);
+ if (FineTickerAvailable()) {
+ FineTickerCancel(tickScroll);
+ }
SetDragPosition(movePos);
CopySelectionRange(&drag);
StartDrag();
@@ -4289,6 +4337,12 @@ void Editor::ButtonMoveWithModifiers(Point pt, int modifiers) {
}
ptMouseLast = pt;
+ PRectangle rcClient = GetClientRectangle();
+ Point ptOrigin = GetVisibleOriginInMain();
+ rcClient.Move(0, -ptOrigin.y);
+ if (FineTickerAvailable() && (dwellDelay < SC_TIME_FOREVER) && rcClient.Contains(pt)) {
+ FineTickerStart(tickDwell, dwellDelay, dwellDelay/10);
+ }
//Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
if (HaveMouseCapture()) {
@@ -4340,9 +4394,6 @@ void Editor::ButtonMoveWithModifiers(Point pt, int modifiers) {
}
// Autoscroll
- PRectangle rcClient = GetClientRectangle();
- Point ptOrigin = GetVisibleOriginInMain();
- rcClient.Move(0, -ptOrigin.y);
int lineMove = DisplayFromPosition(movePos.Position());
if (pt.y > rcClient.bottom) {
ScrollTo(lineMove - LinesOnScreen() + 1);
@@ -4414,6 +4465,9 @@ void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
}
ptMouseLast = pt;
SetMouseCapture(false);
+ if (FineTickerAvailable()) {
+ FineTickerCancel(tickScroll);
+ }
NotifyIndicatorClick(false, newPos.Position(), 0);
if (inDragDrop == ddDragging) {
SelectionPosition selStart = SelectionStart();
@@ -4530,6 +4584,66 @@ bool Editor::Idle() {
return !idleDone;
}
+void Editor::SetTicking(bool) {
+ // SetTicking is deprecated. In the past it was pure virtual and was overridden in each
+ // derived platform class but fine grained timers should now be implemented.
+ // Either way, execution should not arrive here so assert failure.
+ assert(false);
+}
+
+void Editor::TickFor(TickReason reason) {
+ switch (reason) {
+ case tickCaret:
+ caret.on = !caret.on;
+ if (caret.active) {
+ InvalidateCaret();
+ }
+ break;
+ case tickScroll:
+ // Auto scroll
+ ButtonMove(ptMouseLast);
+ break;
+ case tickWiden:
+ SetScrollBars();
+ FineTickerCancel(tickWiden);
+ break;
+ case tickDwell:
+ if ((!HaveMouseCapture()) &&
+ (ptMouseLast.y >= 0)) {
+ dwelling = true;
+ NotifyDwelling(ptMouseLast, dwelling);
+ }
+ FineTickerCancel(tickDwell);
+ break;
+ default:
+ // tickPlatform handled by subclass
+ break;
+ }
+}
+
+bool Editor::FineTickerAvailable() {
+ return false;
+}
+
+// FineTickerStart is be overridden by subclasses that support fine ticking so
+// this method should never be called.
+bool Editor::FineTickerRunning(TickReason) {
+ assert(false);
+ return false;
+}
+
+// FineTickerStart is be overridden by subclasses that support fine ticking so
+// this method should never be called.
+void Editor::FineTickerStart(TickReason, int, int) {
+ assert(false);
+}
+
+// FineTickerCancel is be overridden by subclasses that support fine ticking so
+// this method should never be called.
+void Editor::FineTickerCancel(TickReason) {
+ assert(false);
+}
+
void Editor::SetFocusState(bool focusState) {
hasFocus = focusState;
NotifyFocus(hasFocus);
diff --git a/src/Editor.h b/src/Editor.h
index 53da90906..d80292a0a 100644
--- a/src/Editor.h
+++ b/src/Editor.h
@@ -500,7 +500,13 @@ protected: // ScintillaBase subclass needs access to much of Editor
void Tick();
bool Idle();
- virtual void SetTicking(bool on) = 0;
+ virtual void SetTicking(bool on);
+ enum TickReason { tickCaret, tickScroll, tickWiden, tickDwell, tickPlatform };
+ virtual void TickFor(TickReason reason);
+ virtual bool FineTickerAvailable();
+ virtual bool FineTickerRunning(TickReason reason);
+ virtual void FineTickerStart(TickReason reason, int millis, int tolerance);
+ virtual void FineTickerCancel(TickReason reason);
virtual bool SetIdle(bool) { return false; }
virtual void SetMouseCapture(bool on) = 0;
virtual bool HaveMouseCapture() = 0;
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx
index e7aae8c3b..67fddd1cb 100644
--- a/win32/ScintillaWin.cxx
+++ b/win32/ScintillaWin.cxx
@@ -103,6 +103,8 @@
#define SC_WIN_IDLE 5001
typedef BOOL (WINAPI *TrackMouseEventSig)(LPTRACKMOUSEEVENT);
+typedef UINT_PTR (WINAPI *SetCoalescableTimerSig)(HWND hwnd, UINT_PTR nIDEvent,
+ UINT uElapse, TIMERPROC lpTimerFunc, ULONG uToleranceDelay);
// GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables.
@@ -183,6 +185,7 @@ class ScintillaWin :
bool capturedMouse;
bool trackedMouseLeave;
TrackMouseEventSig TrackMouseEventFn;
+ SetCoalescableTimerSig SetCoalescableTimerFn;
unsigned int linesPerScroll; ///< Intellimouse support
int wheelDelta; ///< Wheel delta from roll
@@ -227,7 +230,7 @@ class ScintillaWin :
static sptr_t PASCAL CTWndProc(
HWND hWnd, UINT iMessage, WPARAM wParam, sptr_t lParam);
- enum { invalidTimerID, standardTimerID, idleTimerID };
+ enum { invalidTimerID, standardTimerID, idleTimerID, fineTimerStart };
virtual bool DragThreshold(Point ptStart, Point ptNow);
virtual void StartDrag();
@@ -237,7 +240,11 @@ class ScintillaWin :
virtual bool ValidCodePage(int codePage) const;
virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
virtual bool SetIdle(bool on);
- virtual void SetTicking(bool on);
+ UINT_PTR timers[tickDwell+1];
+ virtual bool FineTickerAvailable();
+ virtual bool FineTickerRunning(TickReason reason);
+ virtual void FineTickerStart(TickReason reason, int millis, int tolerance);
+ virtual void FineTickerCancel(TickReason reason);
virtual void SetMouseCapture(bool on);
virtual bool HaveMouseCapture();
virtual void SetTrackMouseLeaveEvent(bool on);
@@ -334,6 +341,7 @@ ScintillaWin::ScintillaWin(HWND hwnd) {
capturedMouse = false;
trackedMouseLeave = false;
TrackMouseEventFn = 0;
+ SetCoalescableTimerFn = 0;
linesPerScroll = 0;
wheelDelta = 0; // Wheel delta from roll
@@ -389,8 +397,10 @@ void ScintillaWin::Initialise() {
// Find TrackMouseEvent which is available on Windows > 95
HMODULE user32 = ::GetModuleHandle(TEXT("user32.dll"));
- if (user32)
+ if (user32) {
TrackMouseEventFn = (TrackMouseEventSig)::GetProcAddress(user32, "TrackMouseEvent");
+ SetCoalescableTimerFn = (SetCoalescableTimerSig)::GetProcAddress(user32, "SetCoalescableTimer");
+ }
if (TrackMouseEventFn == NULL) {
// Windows 95 has an emulation in comctl32.dll:_TrackMouseEvent
if (!commctrl32)
@@ -400,11 +410,16 @@ void ScintillaWin::Initialise() {
::GetProcAddress(commctrl32, "_TrackMouseEvent");
}
}
+ for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
+ timers[tr] = 0;
+ }
}
void ScintillaWin::Finalise() {
ScintillaBase::Finalise();
- SetTicking(false);
+ for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
+ FineTickerCancel(tr);
+ }
SetIdle(false);
#if defined(USE_D2D)
DropRenderTarget();
@@ -912,12 +927,10 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam
return 0;
case WM_TIMER:
- if (wParam == standardTimerID && timer.ticking) {
- Tick();
- } else if (wParam == idleTimerID && idler.state) {
+ if (wParam == idleTimerID && idler.state) {
SendMessage(MainHWND(), SC_WIN_IDLE, 0, 1);
} else {
- return 1;
+ TickFor(static_cast<TickReason>(wParam - fineTimerStart));
}
break;
@@ -1319,20 +1332,34 @@ sptr_t ScintillaWin::DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lPa
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
}
-void ScintillaWin::SetTicking(bool on) {
- if (timer.ticking != on) {
- timer.ticking = on;
- if (timer.ticking) {
- timer.tickerID = ::SetTimer(MainHWND(), standardTimerID, timer.tickSize, NULL)
- ? reinterpret_cast<TickerID>(standardTimerID) : 0;
- } else {
- ::KillTimer(MainHWND(), reinterpret_cast<uptr_t>(timer.tickerID));
- timer.tickerID = 0;
- }
+/**
+* Report that this Editor subclass has a working implementation of FineTickerStart.
+*/
+bool ScintillaWin::FineTickerAvailable() {
+ return true;
+}
+
+bool ScintillaWin::FineTickerRunning(TickReason reason) {
+ return timers[reason] != 0;
+}
+
+void ScintillaWin::FineTickerStart(TickReason reason, int millis, int tolerance) {
+ FineTickerCancel(reason);
+ if (SetCoalescableTimerFn && tolerance) {
+ timers[reason] = SetCoalescableTimerFn(MainHWND(), fineTimerStart + reason, millis, NULL, tolerance);
+ } else {
+ timers[reason] = ::SetTimer(MainHWND(), fineTimerStart + reason, millis, NULL);
}
- timer.ticksToWait = caret.period;
}
+void ScintillaWin::FineTickerCancel(TickReason reason) {
+ if (timers[reason]) {
+ ::KillTimer(MainHWND(), timers[reason]);
+ timers[reason] = 0;
+ }
+}
+
+
bool ScintillaWin::SetIdle(bool on) {
// On Win32 the Idler is implemented as a Timer on the Scintilla window. This
// takes advantage of the fact that WM_TIMER messages are very low priority,