forked from enlightenment/efl
257 lines
5.2 KiB
C
257 lines
5.2 KiB
C
#include <Eina.h>
|
|
#include <Ecore.h>
|
|
#include <Ecore_Con.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
enum
|
|
{
|
|
MODE_NONE,
|
|
MODE_GLX
|
|
};
|
|
|
|
int _vsync_init_glx(void);
|
|
double _vsync_wait_glx(void);
|
|
|
|
static void _svr_broadcast_time(double t);
|
|
|
|
static int _vsync_mode = MODE_NONE;
|
|
|
|
static int
|
|
_vsync_init(void)
|
|
{
|
|
if (_vsync_init_glx()) _vsync_mode = MODE_GLX;
|
|
else return 0;
|
|
return 1;
|
|
}
|
|
|
|
static double
|
|
_vsync_wait(void)
|
|
{
|
|
if (_vsync_mode == MODE_GLX) return _vsync_wait_glx();
|
|
return 0.0;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
Eina_Thread_Queue_Msg head;
|
|
char val;
|
|
} Msg;
|
|
|
|
static int tick = 0;
|
|
static Eina_Thread_Queue *thq = NULL;
|
|
|
|
static void
|
|
_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread)
|
|
{
|
|
Msg *msg;
|
|
void *ref;
|
|
|
|
for (;;)
|
|
{
|
|
if (!tick)
|
|
{
|
|
msg = eina_thread_queue_wait(thq, &ref);
|
|
if (msg)
|
|
{
|
|
tick = msg->val;
|
|
eina_thread_queue_wait_done(thq, ref);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
again:
|
|
msg = eina_thread_queue_poll(thq, &ref);
|
|
if (msg)
|
|
{
|
|
tick = msg->val;
|
|
eina_thread_queue_wait_done(thq, ref);
|
|
}
|
|
if (msg) goto again;
|
|
}
|
|
if (tick == -1) exit(0);
|
|
if (tick)
|
|
{
|
|
double *t;
|
|
|
|
t = malloc(sizeof(*t));
|
|
if (t)
|
|
{
|
|
*t = _vsync_wait();
|
|
ecore_thread_feedback(thread, t);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_tick_notify(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED, void *msg)
|
|
{
|
|
double *t = msg;
|
|
|
|
if (t)
|
|
{
|
|
_svr_broadcast_time(*t);
|
|
free(t);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_tick_init(void)
|
|
{
|
|
thq = eina_thread_queue_new();
|
|
ecore_thread_feedback_run(_tick_core, _tick_notify,
|
|
NULL, NULL, NULL, EINA_TRUE);
|
|
}
|
|
|
|
static void
|
|
_tick_send(char val)
|
|
{
|
|
Msg *msg;
|
|
void *ref;
|
|
msg = eina_thread_queue_send(thq, sizeof(Msg), &ref);
|
|
msg->val = val;
|
|
eina_thread_queue_send_done(thq, ref);
|
|
}
|
|
|
|
static void
|
|
_tick_start(void)
|
|
{
|
|
tick++;
|
|
if (tick > 1) return;
|
|
_tick_send(1);
|
|
}
|
|
|
|
static void
|
|
_tick_end(void)
|
|
{
|
|
tick--;
|
|
if (tick > 0) return;
|
|
_tick_send(0);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
typedef struct
|
|
{
|
|
Ecore_Con_Client *client;
|
|
Eina_Bool enabled : 1;
|
|
} Clientdata;
|
|
|
|
static Ecore_Con_Server *svr = NULL;
|
|
static Eina_List *clients = NULL;
|
|
|
|
static void
|
|
_svr_broadcast_time(double t)
|
|
{
|
|
Eina_List *l;
|
|
Clientdata *cdat;
|
|
|
|
EINA_LIST_FOREACH(clients, l, cdat)
|
|
{
|
|
ecore_con_client_send(cdat->client, &t, sizeof(t));
|
|
}
|
|
}
|
|
|
|
static Eina_Bool
|
|
_svr_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
|
|
{
|
|
Ecore_Con_Event_Client_Add *ev = event;
|
|
if (svr != ecore_con_client_server_get(ev->client)) return EINA_TRUE;
|
|
Clientdata *cdat = calloc(1, sizeof(Clientdata));
|
|
if (cdat)
|
|
{
|
|
cdat->client = ev->client;
|
|
clients = eina_list_append(clients, cdat);
|
|
ecore_con_client_data_set(ev->client, cdat);
|
|
}
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_svr_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
|
|
{
|
|
Ecore_Con_Event_Client_Del *ev = event;
|
|
if (svr != ecore_con_client_server_get(ev->client)) return EINA_TRUE;
|
|
Clientdata *cdat = ecore_con_client_data_get(ev->client);
|
|
if (cdat)
|
|
{
|
|
clients = eina_list_remove(clients, cdat);
|
|
if (cdat->enabled) _tick_end();
|
|
free(cdat);
|
|
}
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_svr_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
|
|
{
|
|
Ecore_Con_Event_Client_Data *ev = event;
|
|
if (svr != ecore_con_client_server_get(ev->client)) return EINA_TRUE;
|
|
Clientdata *cdat = ecore_con_client_data_get(ev->client);
|
|
if (cdat)
|
|
{
|
|
char *dat = ev->data;
|
|
|
|
if (ev->size > 0)
|
|
{
|
|
if (dat[ev->size - 1])
|
|
{
|
|
if (!cdat->enabled)
|
|
{
|
|
_tick_start();
|
|
cdat->enabled = EINA_TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (cdat->enabled)
|
|
{
|
|
_tick_end();
|
|
cdat->enabled = EINA_FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
static void
|
|
_svr_init(void)
|
|
{
|
|
char buf[4096], *disp, *s;
|
|
|
|
disp = getenv("DISPLAY");
|
|
if (disp) disp = ":0";
|
|
snprintf(buf, sizeof(buf), "ecore-x-vsync-%s", disp);
|
|
for (s = buf; *s; s++)
|
|
{
|
|
if (*s == ':') *s = '=';
|
|
}
|
|
svr = ecore_con_server_add(ECORE_CON_LOCAL_USER, buf, 1, NULL);
|
|
if (!svr) exit(0);
|
|
ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, _svr_add, NULL);
|
|
ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, _svr_del, NULL);
|
|
ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, _svr_data, NULL);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
int
|
|
main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
|
|
{
|
|
eina_init();
|
|
ecore_app_no_system_modules();
|
|
ecore_init();
|
|
ecore_con_init();
|
|
|
|
if (!_vsync_init()) return 7;
|
|
_svr_init();
|
|
_tick_init();
|
|
|
|
ecore_main_loop_begin();
|
|
_tick_send(-1);
|
|
pause();
|
|
return 0;
|
|
}
|