summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/drivers/Android/Fl_Android_Application.H107
-rw-r--r--src/drivers/Android/Fl_Android_Application.cxx96
-rw-r--r--src/drivers/Android/Fl_Android_Screen_Driver.H42
-rw-r--r--src/drivers/Android/Fl_Android_Screen_Driver.cxx304
4 files changed, 271 insertions, 278 deletions
diff --git a/src/drivers/Android/Fl_Android_Application.H b/src/drivers/Android/Fl_Android_Application.H
index dbc0a4dd9..8489f495c 100644
--- a/src/drivers/Android/Fl_Android_Application.H
+++ b/src/drivers/Android/Fl_Android_Application.H
@@ -40,41 +40,28 @@ extern void (*fl_lock_function)();
#include <android/native_activity.h>
/**
- * Static class that keeps often used data for global access.
+ * Static class that manages all interaction between the Android Native Activity
+ * and the FLTK library. It also keeps often used data for global access.
*
- * This class holds global variables that are needed by the Android
- * drivers.
- *
- * It also contains the interface to the Android Native Activity.
* On launch, it creates a main thread and communication pipe to
* the Activity. All FLTK code will run in that thread. Activity
- * events can be polled from the Screen driver using the provided
- * Android Looper, but must also be forwarded to this class.
- *
- * All other events are handled in Fl_Android_Screen_Driver
+ * events will be polled by the Screen driver using the provided
+ * Android Looper, and will also be routed back to this class as needed.
*
* This code is based on the native activity interface
* provided by <android/native_activity.h>. It is based on a set
* of application-provided callbacks that will be called
* by the Activity's main thread when certain events occur.
*
- * This means that each one of this callbacks _should_ _not_ block, or they
- * risk having the system force-close the application. This programming
- * model is direct, lightweight, but constraining.
- *
- * The 'Fl_Android_Application' interface is used to provide a different
- * execution model where the application can implement its own main event
- * loop in a different thread instead. Here's how it works:
- *
* 1/ The application must provide a function named "int main(argc, argv)" that
* will be called when the activity is created, in a new thread that is
* distinct from the activity's main thread.
*
- * 2/ android_main() receives a pointer to a valid "android_app" structure
+ * 2/ The application has access to a static "Fl_Android_Application" class
* that contains references to other important objects, e.g. the
- * ANativeActivity obejct instance the application is running in.
+ * ANativeActivity object instance the application is running in.
*
- * 3/ the "android_app" object holds an ALooper instance that already
+ * 3/ the "Fl_Android_Application" class holds an ALooper instance that already
* listens to two important things:
*
* - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX
@@ -86,23 +73,8 @@ extern void (*fl_lock_function)();
* ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT,
* respectively.
*
- * Your application can use the same ALooper to listen to additional
- * file-descriptors. They can either be callback based, or with return
- * identifiers starting with LOOPER_ID_USER.
- *
- * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event,
- * the returned data will point to an android_poll_source structure. You
- * can call the process() function on it, and fill in android_app->onAppCmd
- * and android_app->onInputEvent to be called for your own processing
- * of the event.
- *
- * Alternatively, you can call the low-level functions to read and process
- * the data directly... look at the process_cmd() and process_input()
- * implementations in the glue to see how to do this.
- *
- * See the sample named "native-activity" that comes with the NDK with a
- * full usage example. Also look at the JavaDoc of NativeActivity.
-
+ * FLTK will add more items to the looper for timers and file and socket
+ * communication. (fl_add_timeout, Fl::add_fd(), ...
*/
class Fl_Android_Application
{
@@ -125,12 +97,18 @@ public:
* android_poll_source structure. These can be read via the inputQueue
* object of android_app.
*/
- LOOPER_ID_INPUT = 2,
+ LOOPER_ID_INPUT,
+
+ /**
+ * Timer data ID of all timer events coming from the Unix timer_create()
+ * and friends, used in fl_add_timeout() and colleagues.
+ */
+ LOOPER_ID_TIMER,
/**
* Start of user-defined ALooper identifiers.
*/
- LOOPER_ID_USER = 3,
+ LOOPER_ID_USER,
};
/**
@@ -155,67 +133,59 @@ public:
APP_CMD_DESTROY,
};
- /**
- * Data associated with an ALooper fd that will be returned as the "outData"
- * when that source has data ready.
- */
- struct android_poll_source {
- // The identifier of this source. May be LOOPER_ID_MAIN or
- // LOOPER_ID_INPUT.
- int32_t id;
-
- // Function to call to perform the standard processing of data from
- // this source.
- void (*process)(struct android_poll_source* source);
- };
-
-
public:
+ // --- logging
static void log_e(const char *text, ...);
static void log_w(const char *text, ...);
static void log_i(const char *text, ...);
static void log_v(const char *text, ...);
+ // --- application state stuff
static int8_t read_cmd();
static void pre_exec_cmd(int8_t cmd);
static void post_exec_cmd(int8_t cmd);
+ static int destroy_requested() { return pDestroyRequested; }
+
+ // --- event handling
static AInputQueue *input_event_queue() { return pInputQueue; }
+ // --- screen stuff
+ static bool copy_screen();
static inline ANativeWindow *native_window() { return pNativeWindow; }
static inline ANativeWindow_Buffer &graphics_buffer() { return pApplicationWindowBuffer; }
- static int destroy_requested() { return pDestroyRequested; }
- //static void set_on_app_cmd(void (*cmd)(int32_t cmd)) { pOnAppCmd = cmd; }
- //static void set_on_input_event(int32_t (*cmd)(AInputEvent* event)) { pOnInputEvent = cmd; }
- static bool copy_screen();
+ // --- timer stuff
+ static void send_timer_index(uint8_t ix);
+ static uint8_t receive_timer_index();
+
protected:
static void free_saved_state();
static void print_cur_config();
static void destroy();
- static void process_input(struct android_poll_source* source);
- static void process_cmd(struct android_poll_source* source);
static void* thread_entry(void* param);
+ // --- screen handling stuff
static void allocate_screen();
static bool lock_screen();
static void unlock_and_post_screen();
static bool screen_is_locked();
+ // --- timer stuff
+ static void create_timer_handler();
+ static void destroy_timer_handler();
+
static ANativeActivity *pActivity;
static AConfiguration *pConfig;
static void *pSavedState;
static size_t pSavedStateSize;
- static ALooper *pMsgPipeLooper;
- //static ALooper *pRedrawLooper;
+ static ALooper *pAppLooper;
static AInputQueue *pInputQueue;
static ANativeWindow *pNativeWindow;
static ANativeWindow_Buffer pNativeWindowBuffer;
static ANativeWindow_Buffer pApplicationWindowBuffer;
static int pActivityState;
static int pDestroyRequested;
- static void (*pOnAppCmd)(int32_t cmd);
- static int32_t (*pOnInputEvent)(AInputEvent* event);
// ---- no need to make these visible to the outside ----
static pthread_mutex_t pMutex;
@@ -223,15 +193,16 @@ protected:
static int pMsgReadPipe;
static int pMsgWritePipe;
static pthread_t pThread;
- static struct android_poll_source pCmdPollSource;
- static struct android_poll_source pInputPollSource;
static int pRunning;
static int pStateSaved;
static int pDestroyed;
- //static int pRedrawNeeded;
static AInputQueue* pPendingInputQueue;
static ANativeWindow* pPendingWindow;
- //static ARect pPendingContentRect;
+
+ // --- timer variables
+ static int pTimerReadPipe;
+ static int pTimerWritePipe;
+
};
diff --git a/src/drivers/Android/Fl_Android_Application.cxx b/src/drivers/Android/Fl_Android_Application.cxx
index 0d3181b78..ed8be53eb 100644
--- a/src/drivers/Android/Fl_Android_Application.cxx
+++ b/src/drivers/Android/Fl_Android_Application.cxx
@@ -25,6 +25,8 @@
#include "Fl_Android_Application.H"
#include "Fl_Android_Window_Driver.H"
+#include <FL/fl_draw.H>
+
#include <jni.h>
#include <errno.h>
@@ -58,7 +60,7 @@ void* Fl_Android_Application::pSavedState = 0;
size_t Fl_Android_Application::pSavedStateSize = 0;
// The ALooper associated with the app's thread.
-ALooper* Fl_Android_Application::pMsgPipeLooper = 0;
+ALooper* Fl_Android_Application::pAppLooper = 0;
// When non-NULL, this is the input queue from which the app will
// receive user input events.
@@ -79,22 +81,11 @@ int Fl_Android_Application::pActivityState = 0;
// destroyed and waiting for the app thread to complete.
int Fl_Android_Application::pDestroyRequested = 0;
-// Fill this in with the function to process main app commands (APP_CMD_*)
-void (*Fl_Android_Application::pOnAppCmd)(int32_t cmd) = 0;
-
-// Fill this in with the function to process input events. At this point
-// the event has already been pre-dispatched, and it will be finished upon
-// return. Return 1 if you have handled the event, 0 for any default
-// dispatching.
-int32_t (*Fl_Android_Application::pOnInputEvent)(AInputEvent* event) = 0;
-
pthread_mutex_t Fl_Android_Application::pMutex = { 0 };
pthread_cond_t Fl_Android_Application::pCond = { 0 };
int Fl_Android_Application::pMsgReadPipe = 0;
int Fl_Android_Application::pMsgWritePipe = 0;
pthread_t Fl_Android_Application::pThread = 0;
-struct Fl_Android_Application::android_poll_source Fl_Android_Application::pCmdPollSource = { 0 };
-struct Fl_Android_Application::android_poll_source Fl_Android_Application::pInputPollSource = { 0 };
int Fl_Android_Application::pRunning = 0;
int Fl_Android_Application::pStateSaved = 0;
int Fl_Android_Application::pDestroyed = 0;
@@ -103,6 +94,9 @@ AInputQueue *Fl_Android_Application::pPendingInputQueue = 0;
ANativeWindow *Fl_Android_Application::pPendingWindow = 0;
//ARect Fl_Android_Application::pPendingContentRect = { 0 };
+int Fl_Android_Application::pTimerReadPipe = -1;
+int Fl_Android_Application::pTimerWritePipe = -1;
+
void Fl_Android_Application::log_e(const char *text, ...)
@@ -222,9 +216,7 @@ void Fl_Android_Application::pre_exec_cmd(int8_t cmd)
pInputQueue = pPendingInputQueue;
if (pInputQueue != NULL) {
log_v("Attaching input queue to looper");
- AInputQueue_attachLooper(pInputQueue,
- pMsgPipeLooper, LOOPER_ID_INPUT, NULL,
- &pInputPollSource);
+ AInputQueue_attachLooper(pInputQueue, pAppLooper, LOOPER_ID_INPUT, NULL, NULL);
}
pthread_cond_broadcast(&pCond);
pthread_mutex_unlock(&pMutex);
@@ -312,6 +304,43 @@ void Fl_Android_Application::post_exec_cmd(int8_t cmd)
}
+void Fl_Android_Application::create_timer_handler()
+{
+ int msgpipe[2];
+ if (::pipe(msgpipe)) {
+ log_e("could not create timer pipe: %s", strerror(errno));
+ return;
+ }
+ pTimerReadPipe = msgpipe[0];
+ pTimerWritePipe = msgpipe[1];
+ ALooper_addFd(pAppLooper, pTimerReadPipe, LOOPER_ID_TIMER, ALOOPER_EVENT_INPUT, NULL, NULL);
+}
+
+
+void Fl_Android_Application::destroy_timer_handler()
+{
+ ALooper_removeFd(pAppLooper, pTimerReadPipe);
+ ::close(pTimerWritePipe);
+ ::close(pTimerReadPipe);
+}
+
+
+void Fl_Android_Application::send_timer_index(uint8_t ix)
+{
+ if (pTimerWritePipe!=-1)
+ ::write(pTimerWritePipe, &ix, 1);
+}
+
+
+uint8_t Fl_Android_Application::receive_timer_index()
+{
+ uint8_t ix = 0;
+ if (pTimerReadPipe!=-1)
+ ::read(pTimerReadPipe, &ix, 1);
+ return ix;
+}
+
+
void Fl_Android_Application::destroy()
{
log_v("android_app_destroy!");
@@ -320,6 +349,7 @@ void Fl_Android_Application::destroy()
if (pInputQueue != NULL) {
AInputQueue_detachLooper(pInputQueue);
}
+ destroy_timer_handler();
AConfiguration_delete(pConfig);
pDestroyed = 1;
pthread_cond_broadcast(&pCond);
@@ -328,29 +358,6 @@ void Fl_Android_Application::destroy()
}
-void Fl_Android_Application::process_input(struct android_poll_source* source)
-{
- AInputEvent* event = NULL;
- while (AInputQueue_getEvent(pInputQueue, &event) >= 0) {
- if (AInputQueue_preDispatchEvent(pInputQueue, event)) {
- continue;
- }
- int32_t handled = 0;
- if (pOnInputEvent != NULL) handled = pOnInputEvent(event);
- AInputQueue_finishEvent(pInputQueue, event, handled);
- }
-}
-
-
-void Fl_Android_Application::process_cmd(struct android_poll_source* source)
-{
- int8_t cmd = read_cmd();
- pre_exec_cmd(cmd);
- if (pOnAppCmd != NULL) pOnAppCmd(cmd);
- post_exec_cmd(cmd);
-}
-
-
void *Fl_Android_Application::thread_entry(void* param)
{
pConfig = AConfiguration_new();
@@ -358,15 +365,10 @@ void *Fl_Android_Application::thread_entry(void* param)
print_cur_config();
- pCmdPollSource.id = LOOPER_ID_MAIN;
- pCmdPollSource.process = process_cmd;
- pInputPollSource.id = LOOPER_ID_INPUT;
- pInputPollSource.process = process_input;
+ pAppLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+ ALooper_addFd(pAppLooper, pMsgReadPipe, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, NULL);
- ALooper *looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
- ALooper_addFd(looper, pMsgReadPipe, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
- &pCmdPollSource);
- pMsgPipeLooper = looper;
+ create_timer_handler();
pthread_mutex_lock(&pMutex);
pRunning = 1;
@@ -395,8 +397,6 @@ void Fl_Android_Application::allocate_screen() {
}
-#include <FL/fl_draw.H>
-
bool Fl_Android_Application::copy_screen()
{
bool ret = false;
diff --git a/src/drivers/Android/Fl_Android_Screen_Driver.H b/src/drivers/Android/Fl_Android_Screen_Driver.H
index 32ae04899..a63941783 100644
--- a/src/drivers/Android/Fl_Android_Screen_Driver.H
+++ b/src/drivers/Android/Fl_Android_Screen_Driver.H
@@ -45,26 +45,14 @@ private:
int handle_keyboard_event(AInputEvent*);
int handle_mouse_event(AInputEvent*);
-#if 0
-
-protected:
- RECT screens[MAX_SCREENS];
- RECT work_area[MAX_SCREENS];
- float dpi[MAX_SCREENS][2];
- float scale_of_screen[MAX_SCREENS];
-
- static BOOL CALLBACK screen_cb(HMONITOR mon, HDC, LPRECT r, LPARAM);
- BOOL screen_cb(HMONITOR mon, HDC, LPRECT r);
- int get_mouse_unscaled(int &mx, int &my);
-#ifdef FLTK_HIDPI_SUPPORT
- void init_screen_scale_factors();
-#endif
-
-#endif
-
public:
Fl_Android_Screen_Driver() : Fl_Screen_Driver(), pScreenContentChanged(false) { }
+ void add_timeout(double time, Fl_Timeout_Handler cb, void *argp);
+ void repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp);
+ int has_timeout(Fl_Timeout_Handler cb, void *argp);
+ void remove_timeout(Fl_Timeout_Handler cb, void *argp);
+
#if 0
Fl_WinAPI_Screen_Driver() : Fl_Screen_Driver() {
for (int i = 0; i < MAX_SCREENS; i++) scale_of_screen[i] = 1;
@@ -94,10 +82,6 @@ public:
virtual void get_system_colors();
virtual const char *get_system_scheme();
// --- global timers
- virtual void add_timeout(double time, Fl_Timeout_Handler cb, void *argp);
- virtual void repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp);
- virtual int has_timeout(Fl_Timeout_Handler cb, void *argp);
- virtual void remove_timeout(Fl_Timeout_Handler cb, void *argp);
virtual int dnd(int unused);
virtual int compose(int &del);
virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h);
@@ -123,6 +107,22 @@ public:
virtual float desktop_scale_factor();
#endif
+#if 0
+
+ protected:
+ RECT screens[MAX_SCREENS];
+ RECT work_area[MAX_SCREENS];
+ float dpi[MAX_SCREENS][2];
+ float scale_of_screen[MAX_SCREENS];
+
+ static BOOL CALLBACK screen_cb(HMONITOR mon, HDC, LPRECT r, LPARAM);
+ BOOL screen_cb(HMONITOR mon, HDC, LPRECT r);
+ int get_mouse_unscaled(int &mx, int &my);
+#ifdef FLTK_HIDPI_SUPPORT
+ void init_screen_scale_factors();
+#endif
+
+#endif
bool pScreenContentChanged;
};
diff --git a/src/drivers/Android/Fl_Android_Screen_Driver.cxx b/src/drivers/Android/Fl_Android_Screen_Driver.cxx
index 810ccedbf..545d8b979 100644
--- a/src/drivers/Android/Fl_Android_Screen_Driver.cxx
+++ b/src/drivers/Android/Fl_Android_Screen_Driver.cxx
@@ -27,12 +27,17 @@
#include <FL/Fl_RGB_Image.H>
#include <FL/fl_ask.H>
#include <stdio.h>
+#include <errno.h>
+#include <math.h>
static void nothing() {}
void (*fl_unlock_function)() = nothing;
void (*fl_lock_function)() = nothing;
+static void timer_do_callback(int timerIndex);
+
+
#if 0
// these are set by Fl::args() and override any system colors: from Fl_get_system_colors.cxx
@@ -95,7 +100,7 @@ int Fl_Android_Screen_Driver::handle_input_event()
consumed = handle_mouse_event(event);
break;
default:
- // don;t do anything. There may be additional event types in the future
+ // don't do anything. There may be additional event types in the future
break;
}
// TODO: handle all events here
@@ -178,6 +183,9 @@ int Fl_Android_Screen_Driver::handle_queued_events(double time_to_wait)
case Fl_Android_Application::LOOPER_ID_INPUT:
ret = handle_input_event();
break;
+ case Fl_Android_Application::LOOPER_ID_TIMER:
+ timer_do_callback(Fl_Android_Application::receive_timer_index());
+ break;
case -3: return ret;
default: return ret;
}
@@ -186,6 +194,14 @@ int Fl_Android_Screen_Driver::handle_queued_events(double time_to_wait)
}
+// TODO: we need a timout: nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
+// static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs) return secs*1000000000;
+// int timer_create(clockid_t __clock, struct sigevent* __event, timer_t* __timer_ptr);
+// int timer_delete(timer_t __timer);
+// int timer_settime(timer_t __timer, int __flags, const struct itimerspec* __new_value, struct itimerspec* __old_value);
+// int timer_gettime(timer_t __timer, struct itimerspec* __ts);
+// int timer_getoverrun(timer_t __timer);
+
double Fl_Android_Screen_Driver::wait(double time_to_wait)
{
Fl::run_checks();
@@ -514,149 +530,9 @@ const char *Fl_WinAPI_Screen_Driver::get_system_scheme()
}
-// ---- timers
-
-struct Win32Timer
-{
- UINT_PTR handle;
- Fl_Timeout_Handler callback;
- void *data;
-};
-static Win32Timer* win32_timers;
-static int win32_timer_alloc;
-static int win32_timer_used;
-static HWND s_TimerWnd;
-
-
-static void realloc_timers()
-{
- if (win32_timer_alloc == 0) {
- win32_timer_alloc = 8;
- }
- win32_timer_alloc *= 2;
- Win32Timer* new_timers = new Win32Timer[win32_timer_alloc];
- memset(new_timers, 0, sizeof(Win32Timer) * win32_timer_used);
- memcpy(new_timers, win32_timers, sizeof(Win32Timer) * win32_timer_used);
- Win32Timer* delete_me = win32_timers;
- win32_timers = new_timers;
- delete [] delete_me;
-}
-static void delete_timer(Win32Timer& t)
-{
- KillTimer(s_TimerWnd, t.handle);
- memset(&t, 0, sizeof(Win32Timer));
-}
-
-
-static LRESULT CALLBACK s_TimerProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- switch (msg) {
- case WM_TIMER:
- {
- unsigned int id = (unsigned) (wParam - 1);
- if (id < (unsigned int)win32_timer_used && win32_timers[id].handle) {
- Fl_Timeout_Handler cb = win32_timers[id].callback;
- void* data = win32_timers[id].data;
- delete_timer(win32_timers[id]);
- if (cb) {
- (*cb)(data);
- }
- }
- }
- return 0;
-
- default:
- break;
- }
- return DefWindowProc(hwnd, msg, wParam, lParam);
-}
-
-
-void Fl_WinAPI_Screen_Driver::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
-{
- repeat_timeout(time, cb, data);
-}
-
-
-void Fl_WinAPI_Screen_Driver::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data)
-{
- int timer_id = -1;
- for (int i = 0; i < win32_timer_used; ++i) {
- if ( !win32_timers[i].handle ) {
- timer_id = i;
- break;
- }
- }
- if (timer_id == -1) {
- if (win32_timer_used == win32_timer_alloc) {
- realloc_timers();
- }
- timer_id = win32_timer_used++;
- }
- unsigned int elapsed = (unsigned int)(time * 1000);
-
- if ( !s_TimerWnd ) {
- const char* timer_class = "FLTimer";
- WNDCLASSEX wc;
- memset(&wc, 0, sizeof(wc));
- wc.cbSize = sizeof (wc);
- wc.style = CS_CLASSDC;
- wc.lpfnWndProc = (WNDPROC)s_TimerProc;
- wc.hInstance = fl_display;
- wc.lpszClassName = timer_class;
- /*ATOM atom =*/ RegisterClassEx(&wc);
- // create a zero size window to handle timer events
- s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW,
- timer_class, "",
- WS_POPUP,
- 0, 0, 0, 0,
- NULL, NULL, fl_display, NULL);
- // just in case this OS won't let us create a 0x0 size window:
- if (!s_TimerWnd)
- s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW,
- timer_class, "",
- WS_POPUP,
- 0, 0, 1, 1,
- NULL, NULL, fl_display, NULL);
- ShowWindow(s_TimerWnd, SW_SHOWNOACTIVATE);
- }
-
- win32_timers[timer_id].callback = cb;
- win32_timers[timer_id].data = data;
-
- win32_timers[timer_id].handle =
- SetTimer(s_TimerWnd, timer_id + 1, elapsed, NULL);
-}
-
-
-int Fl_WinAPI_Screen_Driver::has_timeout(Fl_Timeout_Handler cb, void* data)
-{
- for (int i = 0; i < win32_timer_used; ++i) {
- Win32Timer& t = win32_timers[i];
- if (t.handle && t.callback == cb && t.data == data) {
- return 1;
- }
- }
- return 0;
-}
-
-
-void Fl_WinAPI_Screen_Driver::remove_timeout(Fl_Timeout_Handler cb, void* data)
-{
- int i;
- for (i = 0; i < win32_timer_used; ++i) {
- Win32Timer& t = win32_timers[i];
- if (t.handle && t.callback == cb &&
- (t.data == data || data == NULL)) {
- delete_timer(t);
- }
- }
-}
-
int Fl_WinAPI_Screen_Driver::compose(int &del) {
unsigned char ascii = (unsigned char)Fl::e_text[0];
int condition = (Fl::e_state & (FL_ALT | FL_META)) && !(ascii & 128) ;
@@ -832,6 +708,152 @@ int Fl_WinAPI_Screen_Driver::screen_num_unscaled(int x, int y)
#endif
+
+// ---- timers
+
+struct TimerData
+{
+ timer_t handle;
+ struct sigevent sigevent;
+ Fl_Timeout_Handler callback;
+ void *data;
+ bool used;
+ bool triggered;
+};
+static TimerData* timerData = 0L;
+static int NTimerData = 0;
+static int nTimerData = 0;
+
+
+static int allocate_more_timers()
+{
+ if (NTimerData == 0) {
+ NTimerData = 8;
+ }
+ if (NTimerData>256) { // out of timers
+ return -1;
+ }
+ NTimerData *= 2;
+ timerData = (TimerData*)realloc(timerData, sizeof(TimerData) * NTimerData);
+ return nTimerData;
+}
+
+
+static void timer_signal_handler(union sigval data)
+{
+ int timerIndex = data.sival_int;
+ Fl_Android_Application::send_timer_index(timerIndex);
+}
+
+
+static void timer_do_callback(int timerIndex)
+{
+ TimerData& t = timerData[timerIndex];
+ t.triggered = false;
+ if (t.callback) {
+ t.callback(t.data);
+ // TODO: should we release the timer at this point?
+ }
+}
+
+
+void Fl_Android_Screen_Driver::add_timeout(double time, Fl_Timeout_Handler cb, void *data)
+{
+ repeat_timeout(time, cb, data);
+}
+
+
+void Fl_Android_Screen_Driver::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data)
+{
+ int ret = -1;
+ int timerIndex = -1;
+
+ // first, find the timer associated with this handler
+ for (int i = 0; i < nTimerData; ++i) {
+ TimerData& t = timerData[i];
+ if ( (t.used) && (t.callback==cb) && (t.data==data) ) {
+ timerIndex = i;
+ break;
+ }
+ }
+
+ // if we did not have a timer yet, find a free slot
+ if (timerIndex==-1) {
+ for (int i = 0; i < nTimerData; ++i) {
+ if (!timerData[i].used)
+ timerIndex = i;
+ break;
+ }
+ }
+
+ // if that didn't work, allocate more timers
+ if (timerIndex==-1) {
+ if (nTimerData==NTimerData)
+ allocate_more_timers();
+ timerIndex = nTimerData++;
+ }
+
+ // if that didn;t work either, we ran out of timers
+ if (timerIndex==-1) {
+ Fl::error("FLTK ran out of timer slots.");
+ return;
+ }
+
+ TimerData& t = timerData[timerIndex];
+ if (!t.used) {
+ t.data = data;
+ t.callback = cb;
+ memset(&t.sigevent, 0, sizeof(struct sigevent));
+ t.sigevent.sigev_notify = SIGEV_THREAD;
+ t.sigevent.sigev_notify_function = timer_signal_handler;
+ t.sigevent.sigev_value.sival_int = timerIndex;
+ ret = timer_create(CLOCK_MONOTONIC, &t.sigevent, &t.handle);
+ if (ret==-1) {
+ Fl_Android_Application::log_e("Can't create timer: %s", strerror(errno));
+ return;
+ }
+ t.used = true;
+ }
+
+ double ff;
+ struct itimerspec timeout = {
+ { 0, 0 },
+ { (time_t)floor(time), (long)(modf(time, &ff)*1000000000) }
+ };
+ ret = timer_settime(t.handle, 0, &timeout, 0L);
+ if (ret==-1) {
+ Fl_Android_Application::log_e("Can't launch timer: %s", strerror(errno));
+ return;
+ }
+ t.triggered = true;
+}
+
+
+int Fl_Android_Screen_Driver::has_timeout(Fl_Timeout_Handler cb, void *data)
+{
+ for (int i = 0; i < nTimerData; ++i) {
+ TimerData& t = timerData[i];
+ if ( (t.used) && (t.callback==cb) && (t.data==data) ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+void Fl_Android_Screen_Driver::remove_timeout(Fl_Timeout_Handler cb, void *data)
+{
+ for (int i = 0; i < nTimerData; ++i) {
+ TimerData& t = timerData[i];
+ if ( t.used && (t.callback==cb) && ( (t.data==data) || (data==NULL) ) ) {
+ if (t.used)
+ timer_delete(t.handle);
+ t.triggered = t.used = false;
+ }
+ }
+}
+
+
//
// End of "$Id$".
//