Initial community commit

This commit is contained in:
Jef 2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit fc06254474
16440 changed files with 4239995 additions and 2 deletions

View file

@ -0,0 +1,47 @@
#ifndef __TIMER_API_H
#define __TIMER_API_H
// Under linux, the Timer API requires the Linux API
#include <bfc/dispatch.h>
#include <bfc/platform/platform.h>
class TimerClient;
#ifdef _WIN32
typedef UINT_PTR TimerToken ;
#elif defined(__APPLE__)
typedef EventLoopTimerRef TimerToken;
#else
#error port me!
#endif
class timer_api : public Dispatchable
{
public:
TimerToken timer_add(TimerClient *client, intptr_t id, int ms);
void timer_remove(TimerClient *client, TimerToken token);
enum {
TIMER_API_ADD = 1,
TIMER_API_REMOVE = 11,
};
};
inline TimerToken timer_api::timer_add(TimerClient *client, intptr_t id, int ms)
{
return _call(TIMER_API_ADD, (TimerToken)0, client, id, ms);
}
inline void timer_api::timer_remove(TimerClient *client, TimerToken token)
{
_voidcall(TIMER_API_REMOVE, client, token);
}
// {3130D81C-AE1F-4954-9765-698473B627B0}
static const GUID timerApiServiceGuid =
{ 0x3130d81c, 0xae1f, 0x4954, { 0x97, 0x65, 0x69, 0x84, 0x73, 0xb6, 0x27, 0xb0 } };
extern timer_api *timerApi;
#endif

View file

@ -0,0 +1,38 @@
#include "osx_timer.h"
#include <api/timer/timerclient.h>
timer_api *timerApi = NULL;
TimerApi::TimerApi()
{
mainEventLoop = GetMainEventLoop();
}
static void WasabiTimerProc(EventLoopTimerRef inTimer, void * inUserData)
{
TimerClient *client = (TimerClient *)inUserData;
if (client)
client->timerclient_timerCallback(inTimer);
}
TimerToken TimerApi::timer_add(TimerClient *client, int id, int ms)
{
EventLoopTimerRef token;
OSStatus err = InstallEventLoopTimer(mainEventLoop,
(float)ms/1000.0f,
(float)ms/1000.0f,
WasabiTimerProc,
client,
&token);
if (err == noErr)
return token;
else
return 0;
}
void TimerApi::timer_remove(TimerClient *client, TimerToken token)
{
RemoveEventLoopTimer(token);
}

View file

@ -0,0 +1,17 @@
#ifndef NULLSOFT_WASABI_OSX_TIMER_H
#define NULLSOFT_WASABI_OSX_TIMER_H
#include <api/timer/api_timer.h>
class TimerApi : public timer_apiI
{
public:
TimerApi();
TimerToken timer_add(TimerClient *client, int id, int ms);
void timer_remove(TimerClient *client, TimerToken);
private:
EventLoopRef mainEventLoop;
};
#endif

View file

@ -0,0 +1,108 @@
#include "api.h"
#include <api/timer/api_timer.h>
#include <api/timer/timerclient.h>
#define CBCLASS TimerClientI
START_DISPATCH;
// this one doesn't map directly so that we can catch deferredcb timers
VCB(TIMERCLIENT_TIMERCALLBACK, timerclient_handleDeferredCallback);
CB(TIMERCLIENT_GETMASTERCLIENT, timerclient_getMasterClient);
VCB(TIMERCLIENT_ONMASTERMUX, timerclient_onMasterClientMultiplex);
CB(TIMERCLIENT_GETDEPPTR, timerclient_getDependencyPtr);
CB(TIMERCLIENT_GETSKIPPED, timerclient_getSkipped);
VCB(TIMERCLIENT_SETSKIPPED, timerclient_setSkipped);
VCB(TIMERCLIENT_POSTDEFERREDCB , timerclient_postDeferredCallback);
CB(TIMERCLIENT_ONDEFERREDCB , timerclient_onDeferredCallback);
CB(TIMERCLIENT_GETNAME, timerclient_getName);
END_DISPATCH;
TimerClientI::TimerClientI()
: skipped(0), timerdelay(0), disallowset(0)
{ }
TimerClientI::~TimerClientI()
{
disallowset = 1;
if (cbs.getNumItems() > 0)
{
TimerToken token;
if (tokens.reverseGetItem(DEFERREDCB_TIMERID, &token)) // TODO: it would be nice to have a combo get/del, so we don't have to search twice
{
WASABI_API_TIMER->timer_remove(this, token);
tokens.delItem(token);
}
}
cbs.deleteAll();
}
int TimerClientI::timerclient_setTimer(intptr_t id, int ms)
{
if (disallowset) return 0;
ASSERTPR(id > 0, "A timer id cannot be <= 0");
ASSERTPR(id != DEFERREDCB_TIMERID, "please chose another timer id");
TimerToken token = WASABI_API_TIMER->timer_add(this, id, ms);
tokens.addItem(token, id);
return 1;
}
int TimerClientI::timerclient_killTimer(intptr_t id)
{
TimerToken token;
if (tokens.reverseGetItem(id, &token)) // TODO: it would be nice to have a combo get/del, so we don't have to search twice
{
WASABI_API_TIMER->timer_remove(this, token);
tokens.delItem(token);
}
return 1;
}
void TimerClientI::timerclient_postDeferredCallback(intptr_t param1, intptr_t param2, int mindelay)
{
if (disallowset) return ;
for (int i = 0;i < cbs.getNumItems();i++)
{
deferred_callback *cb = cbs.enumItem(i);
if (cb->param1 == param1 && cb->param2 == param2)
{
cbs.removeByPos(i);
break;
}
}
deferred_callback *c = new deferred_callback;
c->origin = this;
c->param1 = param1;
c->param2 = param2;
cbs.addItem(c);
TimerToken token = WASABI_API_TIMER->timer_add(this, DEFERREDCB_TIMERID, MAX(1, mindelay));
tokens.addItem(token, DEFERREDCB_TIMERID);
}
void TimerClientI::timerclient_handleDeferredCallback(TimerToken token)
{
// let deriving class handle it. note we call into here even if
// it's the deferred cb id, since older versions did that too,
// expecting the user to call down on the method.
#ifdef WIN64
LPARAM id;
#else
intptr_t id;
#endif
if (tokens.getItem(token, &id))
{
timerclient_timerCallback((int)id);
// process our deferred cb id
if (id == DEFERREDCB_TIMERID)
{
WASABI_API_TIMER->timer_remove(this, token);
PtrList<deferred_callback> temp(cbs);
cbs.removeAll();
foreach(temp)
deferred_callback *c = temp.getfor();
c->origin->timerclient_onDeferredCallback(c->param1, c->param2);
delete c;
endfor
}
}
}

View file

@ -0,0 +1,183 @@
#ifndef __TIMER_CLIENT_H
#define __TIMER_CLIENT_H
#include <bfc/dispatch.h>
#include <bfc/common.h>
#include <bfc/depend.h>
#include <map>
#define DEFERREDCB_TIMERID -2
class TimerClient;
#ifdef _WIN32
typedef UINT_PTR TimerToken ;
#elif defined(__APPLE__)
typedef EventLoopTimerRef TimerToken;
#else
#error port me!
#endif
typedef struct {
TimerClient *origin;
intptr_t param1;
intptr_t param2;
} deferred_callback;
class NOVTABLE TimerClient : public Dispatchable
{
protected:
TimerClient() { }
public:
int timerclient_setTimer(int id, int ms);
int timerclient_killTimer(int id);
void timerclient_postDeferredCallback(intptr_t param1, intptr_t param2=0, int mindelay=0);
int timerclient_onDeferredCallback(intptr_t param1, intptr_t param2);
void timerclient_timerCallback(TimerToken token);
TimerClient *timerclient_getMasterClient();
void timerclient_onMasterClientMultiplex();
api_dependent *timerclient_getDependencyPtr();
void timerclient_setSkipped(int s);
int timerclient_getSkipped();
void timerclient_setTimerDelay(int td);
int timerclient_getTimerDelay();
const wchar_t *timerclient_getName();
enum {
TIMERCLIENT_TIMERCALLBACK = 101,
TIMERCLIENT_SETTIMER = 110,
TIMERCLIENT_KILLTIMER = 120,
TIMERCLIENT_GETMASTERCLIENT = 130,
TIMERCLIENT_ONMASTERMUX = 140,
TIMERCLIENT_GETDEPPTR = 150,
TIMERCLIENT_SETSKIPPED = 160,
TIMERCLIENT_GETSKIPPED = 170,
TIMERCLIENT_SETTIMERDELAY = 180,
TIMERCLIENT_GETTIMERDELAY = 190,
TIMERCLIENT_POSTDEFERREDCB = 200,
TIMERCLIENT_ONDEFERREDCB = 210,
TIMERCLIENT_GETNAME = 220,
};
};
inline void TimerClient::timerclient_timerCallback(TimerToken token) {
_voidcall(TIMERCLIENT_TIMERCALLBACK, token);
}
inline int TimerClient::timerclient_setTimer(int id, int ms) {
return _call(TIMERCLIENT_SETTIMER, 0, id, ms);
}
inline int TimerClient::timerclient_killTimer(int id) {
return _call(TIMERCLIENT_KILLTIMER, 0, id);
}
inline TimerClient *TimerClient::timerclient_getMasterClient() {
return _call(TIMERCLIENT_GETMASTERCLIENT, (TimerClient *)NULL);
}
inline void TimerClient::timerclient_onMasterClientMultiplex() {
_voidcall(TIMERCLIENT_ONMASTERMUX);
}
inline api_dependent *TimerClient::timerclient_getDependencyPtr() {
return _call(TIMERCLIENT_GETDEPPTR, (api_dependent *)NULL);
}
inline void TimerClient::timerclient_setSkipped(int s) {
_voidcall(TIMERCLIENT_SETSKIPPED, s);
}
inline int TimerClient::timerclient_getSkipped() {
return _call(TIMERCLIENT_GETSKIPPED, 0);
}
inline void TimerClient::timerclient_setTimerDelay(int td) {
_voidcall(TIMERCLIENT_SETTIMERDELAY, td);
}
inline int TimerClient::timerclient_getTimerDelay() {
return _call(TIMERCLIENT_GETTIMERDELAY, 0);
}
inline void TimerClient::timerclient_postDeferredCallback(intptr_t param1, intptr_t param2, int mindelay) {
_voidcall(TIMERCLIENT_POSTDEFERREDCB, param1, param2, mindelay);
}
inline int TimerClient::timerclient_onDeferredCallback(intptr_t param1, intptr_t param2) {
return _call(TIMERCLIENT_ONDEFERREDCB, 0, param1, param2);
}
inline const wchar_t *TimerClient::timerclient_getName() {
return _call(TIMERCLIENT_GETNAME, (const wchar_t *)NULL);
}
class NOVTABLE TimerClientI : public TimerClient {
protected:
TimerClientI();
public:
virtual ~TimerClientI();
virtual int timerclient_setTimer(intptr_t id, int ms);
virtual int timerclient_killTimer(intptr_t id);
// override this to catch your timer events
virtual void timerclient_timerCallback(int id) { }
virtual TimerClient *timerclient_getMasterClient() { return NULL; }
virtual void timerclient_onMasterClientMultiplex() { };
virtual api_dependent *timerclient_getDependencyPtr()=0;
virtual void timerclient_setSkipped(int s) { skipped = s; }
virtual int timerclient_getSkipped() { return skipped; }
virtual void timerclient_setTimerDelay(int td) { timerdelay = td; }
virtual int timerclient_getTimerDelay() { return timerdelay; }
virtual void timerclient_postDeferredCallback(intptr_t param1, intptr_t param2=0, int mindelay=0);
virtual int timerclient_onDeferredCallback(intptr_t param1, intptr_t param2) { return 1; };
virtual const wchar_t *timerclient_getName() { return NULL; }
protected:
RECVS_DISPATCH;
private:
virtual void timerclient_handleDeferredCallback(TimerToken token);
int skipped;
int timerdelay;
int disallowset;
PtrList<deferred_callback> cbs;
#ifdef _WIN32
class TokenMap
{
public:
void delItem(TimerToken) {}
bool reverseGetItem(intptr_t id, TimerToken *token)
{
*token = id;
return true;
}
bool getItem(TimerToken token, intptr_t *id)
{
*id = token;
return true;
}
void addItem(TimerToken, intptr_t) {}
};
#else
typedef std::map<TimerToken, intptr_t> TokenMap;
#endif
TokenMap tokens;
};
class NOVTABLE TimerClientDI : public TimerClientI, public DependentI {
protected:
TimerClientDI() { }
public:
api_dependent *timerclient_getDependencyPtr() { return this; }
};
#endif

View file

@ -0,0 +1,62 @@
#include "precomp.h"
#include "timeslicer.h"
#define TIMER_SLICE 0x7816
TimeSlicer::TimeSlicer(int percent_cpu_usage/* =50 */, int slice_duration/* =-1 */) {
max_cpu_usage = MIN((float)percent_cpu_usage, 99.0f) / 100.0f;
duration = slice_duration;
started = 0;
slicecount = 0;
firstslicetime = -1;
}
TimeSlicer::~TimeSlicer() {
}
void TimeSlicer::startSlicer() {
if (started) return;
started = 1;
timerclient_setTimer(TIMER_SLICE, duration);
onSlicerStart();
timerclient_timerCallback(TIMER_SLICE);
}
void TimeSlicer::stopSlicer() {
if (!started) return;
started = 0;
timerclient_killTimer(TIMER_SLICE);
onSlicerStop();
firstslicetime = -1;
}
void TimeSlicer::onSlicerStop() {
}
void TimeSlicer::onSlicerStart() {
}
int TimeSlicer::isSlicerStarted() {
return started;
}
void TimeSlicer::timerclient_timerCallback(int id) {
if (id == TIMER_SLICE) {
DWORD now = Std::getTickCount();
runSlice(now, now + (int)((float)duration * max_cpu_usage));
} else
TimerClient::timerclient_timerCallback(id);
}
void TimeSlicer::runSlice(DWORD start, DWORD stopwhen) {
DWORD now = Std::getTickCount();
slicecount = 0;
onBeginSliceBatch();
if (slicecount == 0 && firstslicetime != -1) stopwhen = now + firstslicetime;
while (Std::getTickCount() < stopwhen) {
onSlice();
slicecount++;
if (!started) break; // got aborted
}
onEndSliceBatch();
}

View file

@ -0,0 +1,64 @@
#ifndef __TIMESLICER_H
#define __TIMESLICER_H
// TimeSlicer allows you to create a background job to perform while not blocking
// the main GUI thread. You give it the max percentage of CPU it should use, call star()
// and it'll start calling onSlice as many times as it can without using more cpu than requested
//
// To use this class, you need to break down your job into multiple tiny chunks that
// you perform in onSlice. Typical uses include adding files to or filtering entries from
// the database, driving state machines, etc.
//
// onSlice will be called multiple times per timer.
#include "timerclient.h"
enum {
GRANULARITY_EXTRALOW = 20,
GRANULARITY_LOW = 50,
GRANULARITY_MEDIUM = 100,
GRANULARITY_HIGH = 250,
GRANULARITY_EXTRAHIGH = 1000,
};
class TimeSlicer : public TimerClientI {
public:
TimeSlicer(int percent_cpu_usage=25, int slice_duration=GRANULARITY_LOW);
virtual ~TimeSlicer();
virtual void timerclient_timerCallback(int id);
void startSlicer();
void stopSlicer();
int isSlicerStarted();
virtual void onSlicerStart();
virtual void onSlicerStop();
virtual void onBeginSliceBatch() {}
virtual void onEndSliceBatch() {}
api_dependent *timerclient_getDependencyPtr() { return timeslicer_getDependencyPtr(); }
virtual api_dependent *timeslicer_getDependencyPtr()=0;
virtual void setFirstSliceMinTime(int ms) { firstslicetime = ms; }
virtual int getSliceCount() { return slicecount; }
// override this to do your work
virtual void onSlice() { }
private:
virtual void runSlice(DWORD start, DWORD stopwhen);
float max_cpu_usage;
int duration;
int started;
int firstslicetime;
int slicecount;
};
class TimeSlicerD : public TimeSlicer, public DependentI {
public:
virtual api_dependent *timeslicer_getDependencyPtr() { return this; }
};
#endif