mirror of https://github.com/buggins/dlangui.git
timers support part 1 - for win32 platform
This commit is contained in:
parent
016a958a17
commit
1377556d92
|
@ -66,7 +66,7 @@
|
||||||
<debuglevel>0</debuglevel>
|
<debuglevel>0</debuglevel>
|
||||||
<debugids>DebugFocus</debugids>
|
<debugids>DebugFocus</debugids>
|
||||||
<versionlevel>0</versionlevel>
|
<versionlevel>0</versionlevel>
|
||||||
<versionids>EmbedStandardResources Unicode USE_SDL USE_FREETYPE</versionids>
|
<versionids>EmbedStandardResources Unicode</versionids>
|
||||||
<dump_source>0</dump_source>
|
<dump_source>0</dump_source>
|
||||||
<mapverbosity>0</mapverbosity>
|
<mapverbosity>0</mapverbosity>
|
||||||
<createImplib>1</createImplib>
|
<createImplib>1</createImplib>
|
||||||
|
|
|
@ -117,19 +117,38 @@ class TimerInfo {
|
||||||
@property long nextTimestamp() { return _nextTimestamp; }
|
@property long nextTimestamp() { return _nextTimestamp; }
|
||||||
/// widget to route timer event to
|
/// widget to route timer event to
|
||||||
@property Widget targetWidget() { return _targetWidget; }
|
@property Widget targetWidget() { return _targetWidget; }
|
||||||
|
/// return true if timer is not yet cancelled
|
||||||
|
@property bool valid() { return _targetWidget !is null; }
|
||||||
|
|
||||||
protected ulong _id;
|
protected ulong _id;
|
||||||
protected long _interval;
|
protected long _interval;
|
||||||
protected long _nextTimestamp;
|
protected long _nextTimestamp;
|
||||||
protected Widget _targetWidget;
|
protected Widget _targetWidget;
|
||||||
|
|
||||||
|
override bool opEquals(Object obj) {
|
||||||
|
TimerInfo b = cast(TimerInfo)obj;
|
||||||
|
if (!b)
|
||||||
|
return false;
|
||||||
|
return b._nextTimestamp == _nextTimestamp;
|
||||||
|
}
|
||||||
|
override int opCmp(Object obj) {
|
||||||
|
TimerInfo b = cast(TimerInfo)obj;
|
||||||
|
if (!b)
|
||||||
|
return false;
|
||||||
|
if (valid && !b.valid)
|
||||||
|
return -1;
|
||||||
|
if (!valid && b.valid)
|
||||||
|
return 1;
|
||||||
|
if (!valid && !b.valid)
|
||||||
|
return 0;
|
||||||
|
if (_nextTimestamp < b._nextTimestamp)
|
||||||
|
return -1;
|
||||||
|
if (_nextTimestamp > b._nextTimestamp)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimerQueue {
|
|
||||||
protected TimerInfo[] _queue;
|
|
||||||
void add(TimerInfo event) {
|
|
||||||
int len = cast(int)_queue.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Window abstraction layer. Widgets can be shown only inside window.
|
* Window abstraction layer. Widgets can be shown only inside window.
|
||||||
|
@ -261,6 +280,7 @@ class Window {
|
||||||
|
|
||||||
this() {
|
this() {
|
||||||
_eventList = new EventList();
|
_eventList = new EventList();
|
||||||
|
_timerQueue = new TimerQueue();
|
||||||
_backgroundColor = 0xFFFFFF;
|
_backgroundColor = 0xFFFFFF;
|
||||||
}
|
}
|
||||||
~this() {
|
~this() {
|
||||||
|
@ -272,6 +292,7 @@ class Window {
|
||||||
_mainWidget = null;
|
_mainWidget = null;
|
||||||
}
|
}
|
||||||
destroy(_eventList);
|
destroy(_eventList);
|
||||||
|
destroy(_timerQueue);
|
||||||
_eventList = null;
|
_eventList = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -818,6 +839,124 @@ class Window {
|
||||||
dlg.show();
|
dlg.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected TimerQueue _timerQueue;
|
||||||
|
|
||||||
|
|
||||||
|
/// schedule timer for interval in milliseconds - call window.onTimer when finished
|
||||||
|
protected void scheduleSystemTimer(long intervalMillis) {
|
||||||
|
Log.d("override scheduleSystemTimer to support timers");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// system timer interval expired - notify queue
|
||||||
|
protected void onTimer() {
|
||||||
|
bool res = _timerQueue.notify();
|
||||||
|
if (res) {
|
||||||
|
// check if update needed and redraw if so
|
||||||
|
update(false);
|
||||||
|
}
|
||||||
|
long nextInterval = _timerQueue.nextIntervalMillis();
|
||||||
|
if (nextInterval > 0) {
|
||||||
|
scheduleSystemTimer(nextInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// set timer for destination widget - destination.onTimer() will be called after interval expiration; returns timer id
|
||||||
|
ulong setTimer(Widget destination, long intervalMillis) {
|
||||||
|
if (!isChild(destination)) {
|
||||||
|
Log.e("setTimer() is called not for child widget of window");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ulong res = _timerQueue.add(destination, intervalMillis);
|
||||||
|
long nextInterval = _timerQueue.nextIntervalMillis();
|
||||||
|
if (nextInterval > 0) {
|
||||||
|
scheduleSystemTimer(intervalMillis);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// cancel previously scheduled widget timer (for timerId pass value returned from setTimer)
|
||||||
|
void cancelTimer(ulong timerId) {
|
||||||
|
_timerQueue.cancelTimer(timerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// timers queue
|
||||||
|
private class TimerQueue {
|
||||||
|
protected TimerInfo[] _queue;
|
||||||
|
/// add new timer
|
||||||
|
ulong add(Widget destination, long intervalMillis) {
|
||||||
|
TimerInfo item = new TimerInfo(destination, intervalMillis);
|
||||||
|
_queue ~= item;
|
||||||
|
sort(_queue);
|
||||||
|
return item.id;
|
||||||
|
}
|
||||||
|
/// cancel timer
|
||||||
|
void cancelTimer(ulong timerId) {
|
||||||
|
for (size_t i = _queue.length - 1; i >= 0; i--) {
|
||||||
|
if (_queue[i].id == timerId) {
|
||||||
|
_queue[i].cancel();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// returns interval if millis of next scheduled event or -1 if no events queued
|
||||||
|
long nextIntervalMillis() {
|
||||||
|
if (!_queue.length || !_queue[0].valid)
|
||||||
|
return -1;
|
||||||
|
long delta = _queue[0].nextTimestamp - currentTimeMillis;
|
||||||
|
if (delta < 1)
|
||||||
|
delta = 1;
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
private void cleanup() {
|
||||||
|
sort(_queue);
|
||||||
|
size_t newsize = 0;
|
||||||
|
for (size_t i = _queue.length - 1; i >= 0; i--) {
|
||||||
|
if (!_queue[i].valid) {
|
||||||
|
newsize = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_queue.length > newsize)
|
||||||
|
_queue.length = newsize;
|
||||||
|
}
|
||||||
|
private TimerInfo[] expired() {
|
||||||
|
long ts = currentTimeMillis;
|
||||||
|
TimerInfo[] res;
|
||||||
|
for (int i = 0; i < _queue.length; i++) {
|
||||||
|
if (_queue[i].nextTimestamp <= ts)
|
||||||
|
res ~= _queue[i];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/// returns true if at least one widget was notified
|
||||||
|
bool notify() {
|
||||||
|
bool res = false;
|
||||||
|
checkValidWidgets();
|
||||||
|
TimerInfo[] list = expired();
|
||||||
|
if (list) {
|
||||||
|
for (int i = 0; i < list.length; i++) {
|
||||||
|
Widget w = _queue[i].targetWidget;
|
||||||
|
if (w && !isChild(w))
|
||||||
|
_queue[i].cancel();
|
||||||
|
else {
|
||||||
|
_queue[i].notify();
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cleanup();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
private void checkValidWidgets() {
|
||||||
|
for (int i = 0; i < _queue.length; i++) {
|
||||||
|
Widget w = _queue[i].targetWidget;
|
||||||
|
if (w && !isChild(w))
|
||||||
|
_queue[i].cancel();
|
||||||
|
}
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -318,6 +318,27 @@ class Win32Window : Window {
|
||||||
PostMessageW(_hwnd, CUSTOM_MESSAGE_ID, 0, event.uniqueId);
|
PostMessageW(_hwnd, CUSTOM_MESSAGE_ID, 0, event.uniqueId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long _nextExpectedTimerTs;
|
||||||
|
private UINT_PTR _timerId;
|
||||||
|
|
||||||
|
/// schedule timer for interval in milliseconds - call window.onTimer when finished
|
||||||
|
override protected void scheduleSystemTimer(long intervalMillis) {
|
||||||
|
if (intervalMillis < 10)
|
||||||
|
intervalMillis = 10;
|
||||||
|
long nextts = currentTimeMillis + intervalMillis;
|
||||||
|
if (_timerId && _nextExpectedTimerTs && _nextExpectedTimerTs < nextts + 10)
|
||||||
|
return; // don't reschedule timer, timer event will be received soon
|
||||||
|
if (_hwnd) {
|
||||||
|
_timerId = SetTimer(_hwnd, _timerId, cast(uint)intervalMillis, null);
|
||||||
|
_nextExpectedTimerTs = nextts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleTimer(UINT_PTR timerId) {
|
||||||
|
onTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Win32ColorDrawBuf getDrawBuf() {
|
Win32ColorDrawBuf getDrawBuf() {
|
||||||
//RECT rect;
|
//RECT rect;
|
||||||
//GetClientRect(_hwnd, &rect);
|
//GetClientRect(_hwnd, &rect);
|
||||||
|
@ -1062,6 +1083,12 @@ LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case WM_TIMER:
|
||||||
|
if (window !is null) {
|
||||||
|
window.handleTimer(wParam);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case WM_GETMINMAXINFO:
|
case WM_GETMINMAXINFO:
|
||||||
case WM_NCCREATE:
|
case WM_NCCREATE:
|
||||||
case WM_NCCALCSIZE:
|
case WM_NCCALCSIZE:
|
||||||
|
|
|
@ -923,9 +923,21 @@ class Widget {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// set new timer to call onTimer() after specified interval (for recurred notifications, return true from onTimer)
|
||||||
|
ulong setTimer(long intervalMillis) {
|
||||||
|
return window.setTimer(this, intervalMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// cancel timer - pass value returned from setTimer() as timerId parameter
|
||||||
|
void cancelTimer(ulong timerId) {
|
||||||
|
window.cancelTimer(timerId);
|
||||||
|
}
|
||||||
|
|
||||||
/// handle timer; return true to repeat timer event after next interval, false cancel timer
|
/// handle timer; return true to repeat timer event after next interval, false cancel timer
|
||||||
bool onTimer(ulong id) {
|
bool onTimer(ulong id) {
|
||||||
// override to do something useful
|
// override to do something useful
|
||||||
|
// return true to repeat after the same interval, false to stop timer
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue