diff options
-rw-r--r-- | cocoa/ScintillaCocoa.h | 7 | ||||
-rw-r--r-- | cocoa/ScintillaCocoa.mm | 109 | ||||
-rw-r--r-- | doc/ScintillaHistory.html | 8 | ||||
-rw-r--r-- | gtk/ScintillaGTK.cxx | 57 | ||||
-rw-r--r-- | qt/ScintillaEditBase/ScintillaQt.cpp | 66 | ||||
-rw-r--r-- | qt/ScintillaEditBase/ScintillaQt.h | 10 | ||||
-rw-r--r-- | src/Editor.cxx | 124 | ||||
-rw-r--r-- | src/Editor.h | 8 | ||||
-rw-r--r-- | win32/ScintillaWin.cxx | 65 |
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, |