1 #include "CtrlCore.h"
2
3 namespace Upp {
4
5 // #define LOG_QUEUE
6 #define LLOG(x) // LOG(x)
7
8 int MemoryProbeInt;
9
10 struct TimeEvent : public Link<TimeEvent> {
11 dword time;
12 int delay;
13 Event<> cb;
14 void *id;
15 bool rep;
16 };
17
18 static dword sTClick;
19
20 static StaticCriticalSection sTimerLock;
21
22 struct CtrlTimerOwner__ : public LinkOwner<TimeEvent> {
23 CtrlTimerOwner__();
24 ~CtrlTimerOwner__();
25 };
26
tevents()27 static TimeEvent *tevents() {
28 static LinkOwner<TimeEvent> t;
29 return t.GetPtr();
30 }
31
sTimeCallback(dword time,int delay,Event<> cb,void * id)32 static void sTimeCallback(dword time, int delay, Event<> cb, void *id) {
33 TimeEvent *ne = tevents()->InsertPrev();
34 ne->time = time;
35 ne->cb = cb;
36 ne->delay = delay;
37 ne->id = id;
38 ne->rep = false;
39 LLOG("sTimeCalllback " << ne->time << " " << ne->delay << " " << ne->id);
40 }
41
SetTimeCallback(int delay_ms,Function<void ()> cb,void * id)42 void SetTimeCallback(int delay_ms, Function<void ()> cb, void *id) {
43 Mutex::Lock __(sTimerLock);
44 ASSERT(abs(delay_ms) < 0x40000000);
45 LLOG("SetTimeCallback " << delay_ms << " " << id);
46 sTimeCallback(msecs() + abs(delay_ms), delay_ms, Event<> () << cb, id);
47 }
48
KillTimeCallbacks(void * id,void * idlim)49 void KillTimeCallbacks(void *id, void *idlim) {
50 Mutex::Lock __(sTimerLock);
51 TimeEvent *list = tevents();
52 for(TimeEvent *e = list->GetNext(); e != list;)
53 if(e->id >= id && e->id < idlim) {
54 e = e->GetNext();
55 delete e->GetPrev();
56 }
57 else
58 e = e->GetNext();
59 }
60
61 EXITBLOCK
62 {
63 Mutex::Lock __(sTimerLock);
64 while(tevents()->GetNext() != tevents())
65 delete tevents()->GetNext();
66 }
67
68 bool ExistsTimeCallback(void *id) {
69 Mutex::Lock __(sTimerLock);
70 TimeEvent *list = tevents();
71 for(TimeEvent *e = list->GetNext(); e != list; e = e->GetNext())
72 if(e->id == id)
73 return true;
74 return false;
75 }
76
KillTimeCallback(void * id)77 void KillTimeCallback(void *id) {
78 KillTimeCallbacks(id, (byte *)id + 1);
79 }
80
TimerProc(dword time)81 void Ctrl::TimerProc(dword time)
82 {
83 if(IsPanicMode())
84 return;
85 sTimerLock.Enter();
86 TimeEvent *list = tevents();
87 if(time == sTClick) {
88 sTimerLock.Leave();
89 return;
90 }
91 sTClick = time;
92 sTimerLock.Leave();
93 Ctrl::CheckMouseCtrl();
94 Ctrl::SyncCaret();
95 sTimerLock.Enter();
96
97 #ifdef LOG_QUEUE
98 LLOG("--- Timer queue at " << time);
99 for(TimeEvent *e = list->GetNext(); e != list; e = e->GetNext())
100 LLOG("TP " << e->time << " " << e->delay << " " << e->id << " " << e->rep);
101 LLOG("----");
102 #endif
103
104 for(;;) {
105 TimeEvent *todo = NULL;
106 int maxtm = -1;
107 for(TimeEvent *e = list->GetNext(); e != list; e = e->GetNext()) {
108 int tm = (int)(time - e->time);
109 if(!e->rep && tm >= 0 && tm > maxtm) {
110 maxtm = tm;
111 todo = e;
112 }
113 }
114 if(!todo)
115 break;
116 LLOG("Performing " << todo->time << " " << todo->delay << " " << todo->id);
117 Event<> cb = todo->cb;
118 if(todo->delay < 0)
119 todo->rep = true;
120 else
121 delete todo;
122 sTimerLock.Leave();
123 cb();
124 sTimerLock.Enter();
125 }
126 time = msecs();
127 LLOG("--- Rescheduling at " << time);
128 TimeEvent *e = list->GetNext();
129 while(e != list) {
130 TimeEvent *w = e;
131 e = e->GetNext();
132 if(w->rep) {
133 LLOG("Rescheduling " << e->id);
134 sTimeCallback(time - w->delay, w->delay, w->cb, w->id);
135 delete w;
136 }
137 }
138 LLOG("----");
139 sTimerLock.Leave();
140 }
141
InitTimer()142 void Ctrl::InitTimer()
143 {
144 Mutex::Lock __(sTimerLock);
145 tevents();
146 }
147
SetTimeCallback(int delay_ms,Function<void ()> cb,int id)148 void Ctrl::SetTimeCallback(int delay_ms, Function<void ()> cb, int id) {
149 ASSERT(id >= 0 && (size_t)id < (int)sizeof(Ctrl));
150 UPP::SetTimeCallback(delay_ms, cb, (byte *)this + id);
151 }
152
KillTimeCallback(int id)153 void Ctrl::KillTimeCallback(int id) {
154 ASSERT(id >= 0 && (size_t)id < sizeof(Ctrl));
155 UPP::KillTimeCallback((byte *)this + id);
156 }
157
KillSetTimeCallback(int delay_ms,Function<void ()> cb,int id)158 void Ctrl::KillSetTimeCallback(int delay_ms, Function<void ()> cb, int id)
159 {
160 KillTimeCallback(id);
161 SetTimeCallback(delay_ms, cb, id);
162 }
163
PostCallback(Function<void ()> cb,int id)164 void Ctrl::PostCallback(Function<void ()> cb, int id)
165 {
166 SetTimeCallback(0, cb, id);
167 }
168
KillPostCallback(Function<void ()> cb,int id)169 void Ctrl::KillPostCallback(Function<void ()> cb, int id)
170 {
171 KillSetTimeCallback(0, cb, id);
172 }
173
ExistsTimeCallback(int id) const174 bool Ctrl::ExistsTimeCallback(int id) const {
175 ASSERT(id >= 0 && (size_t)id < sizeof(Ctrl));
176 return UPP::ExistsTimeCallback((byte *)this + id);
177 }
178
GetTimeClick()179 dword GetTimeClick()
180 {
181 return sTClick;
182 }
183
184 }
185