libs: backend: Set timer event timestamp correctly
[gfxprim/pasky.git] / libs / backends / GP_Backend.c
blob454cb11e043df6ccf8f467a657d05a5f40008de4
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include <inttypes.h>
24 #include <poll.h>
26 #include "core/GP_Common.h"
27 #include "core/GP_Transform.h"
28 #include "core/GP_Debug.h"
30 #include "input/GP_EventQueue.h"
31 #include "input/GP_TimeStamp.h"
33 #include "backends/GP_Backend.h"
35 void GP_BackendFlip(GP_Backend *backend)
37 if (backend->Flip != NULL)
38 backend->Flip(backend);
41 void GP_BackendUpdateRectXYXY(GP_Backend *backend,
42 GP_Coord x0, GP_Coord y0,
43 GP_Coord x1, GP_Coord y1)
45 if (backend->UpdateRect == NULL)
46 return;
48 GP_TRANSFORM_POINT(backend->context, x0, y0);
49 GP_TRANSFORM_POINT(backend->context, x1, y1);
51 if (x1 < x0)
52 GP_SWAP(x0, x1);
54 if (y1 < y0)
55 GP_SWAP(y0, y1);
57 if (x0 < 0) {
58 GP_WARN("Negative x coordinate %i, clipping to 0", x0);
59 x0 = 0;
62 if (y0 < 0) {
63 GP_WARN("Negative y coordinate %i, clipping to 0", y0);
64 y0 = 0;
67 GP_Coord w = backend->context->w;
69 if (x1 >= w) {
70 GP_WARN("Too large x coordinate %i, clipping to %u", x1, w - 1);
71 x1 = w - 1;
74 GP_Coord h = backend->context->h;
76 if (y1 >= h) {
77 GP_WARN("Too large y coordinate %i, clipping to %u", y1, h - 1);
78 y1 = h - 1;
81 backend->UpdateRect(backend, x0, y0, x1, y1);
85 int GP_BackendResize(GP_Backend *backend, uint32_t w, uint32_t h)
87 if (backend->SetAttributes == NULL)
88 return 1;
90 if (w == 0)
91 w = backend->context->w;
93 if (h == 0)
94 h = backend->context->h;
96 if (backend->context->w == w && backend->context->h == h)
97 return 0;
99 return backend->SetAttributes(backend, w, h, NULL);
102 int GP_BackendResizeAck(GP_Backend *self)
104 GP_DEBUG(2, "Calling backend %s ResizeAck()", self->name);
106 if (self->ResizeAck)
107 return self->ResizeAck(self);
109 return 0;
112 static uint32_t pushevent_callback(GP_Timer *self)
114 GP_Event ev;
116 ev.type = GP_EV_TMR;
117 gettimeofday(&ev.time, NULL);
118 ev.val.tmr = self;
120 GP_EventQueuePut(self->priv, &ev);
122 return 0;
125 void GP_BackendAddTimer(GP_Backend *self, GP_Timer *timer)
127 if (timer->Callback == NULL) {
128 timer->Callback = pushevent_callback;
129 timer->priv = &self->event_queue;
132 GP_TimerQueueInsert(&self->timers, GP_GetTimeStamp(), timer);
135 void GP_BackendRemTimer(GP_Backend *self, GP_Timer *timer)
137 GP_TimerQueueRemove(&self->timers, timer);
140 void GP_BackendPoll(GP_Backend *self)
142 self->Poll(self);
144 if (self->timers)
145 GP_TimerQueueProcess(&self->timers, GP_GetTimeStamp());
148 static void wait_timers_fd(GP_Backend *self, uint64_t now)
150 int timeout;
152 timeout = self->timers->expires - now;
154 struct pollfd fd = {.fd = self->fd, .events = POLLIN, fd.revents = 0};
156 if (poll(&fd, 1, timeout))
157 self->Poll(self);
159 now = GP_GetTimeStamp();
161 GP_TimerQueueProcess(&self->timers, now);
165 * Polling for backends that does not expose FD to wait on (namely SDL).
167 static void wait_timers_poll(GP_Backend *self)
169 for (;;) {
170 uint64_t now = GP_GetTimeStamp();
172 if (GP_TimerQueueProcess(&self->timers, now))
173 return;
175 self->Poll(self);
177 if (GP_BackendEventsQueued(self))
178 return;
180 usleep(10000);
184 void GP_BackendWait(GP_Backend *self)
186 if (self->timers) {
187 uint64_t now = GP_GetTimeStamp();
189 /* Get rid of possibly expired timers */
190 if (GP_TimerQueueProcess(&self->timers, now))
191 return;
193 /* Wait for events or timer expiration */
194 if (self->fd != -1)
195 wait_timers_fd(self, now);
196 else
197 wait_timers_poll(self);
199 return;
202 self->Wait(self);
205 int GP_BackendWaitEvent(GP_Backend *self, GP_Event *ev)
207 int ret;
209 for (;;) {
210 if ((ret = GP_BackendGetEvent(self, ev)))
211 return ret;
213 GP_BackendWait(self);
217 int GP_BackendPollEvent(GP_Backend *self, GP_Event *ev)
219 int ret;
221 if ((ret = GP_BackendGetEvent(self, ev)))
222 return ret;
224 GP_BackendPoll(self);
226 if ((ret = GP_BackendGetEvent(self, ev)))
227 return ret;
229 return 0;