summaryrefslogtreecommitdiff
path: root/src/drivers/Android/Fl_Android_Screen_Driver.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/Android/Fl_Android_Screen_Driver.cxx')
-rw-r--r--src/drivers/Android/Fl_Android_Screen_Driver.cxx568
1 files changed, 0 insertions, 568 deletions
diff --git a/src/drivers/Android/Fl_Android_Screen_Driver.cxx b/src/drivers/Android/Fl_Android_Screen_Driver.cxx
deleted file mode 100644
index 2d75eb240..000000000
--- a/src/drivers/Android/Fl_Android_Screen_Driver.cxx
+++ /dev/null
@@ -1,568 +0,0 @@
-//
-// Android screen interface for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 1998-2018 by Bill Spitzak and others.
-//
-// This library is free software. Distribution and use rights are outlined in
-// the file "COPYING" which should have been included with this file. If this
-// file is missing or damaged, see the license at:
-//
-// https://www.fltk.org/COPYING.php
-//
-// Please see the following page on how to report bugs and issues:
-//
-// https://www.fltk.org/bugs.php
-//
-
-
-/**
- @cond AndroidDev
- \defgroup AndroidDeveloper Android Developer Documentation
- \{
- */
-
-
-#include <config.h>
-#include "Fl_Android_Screen_Driver.H"
-#include "Fl_Android_Application.H"
-#include "Fl_Android_Graphics_Font.H"
-#include <FL/Fl.H>
-#include <FL/platform.H>
-#include <FL/Fl_Graphics_Driver.H>
-#include <FL/Fl_RGB_Image.H>
-#include <FL/fl_ask.H>
-#include <stdio.h>
-#include <errno.h>
-#include <math.h>
-
-
-/**
- \class Fl_Android_Screen_Driver
-
- Handle Android screen devices.
-
- \todo This class is in an early development stage
- */
-
-
-static void nothing() {}
-void (*fl_unlock_function)() = nothing;
-void (*fl_lock_function)() = nothing;
-
-static void timer_do_callback(int timerIndex);
-
-
-/**
- Creates a driver that manages all Android screen and display related calls.
- */
-Fl_Screen_Driver *Fl_Screen_Driver::newScreenDriver()
-{
- return new Fl_Android_Screen_Driver();
-}
-
-
-extern int fl_send_system_handlers(void *e);
-
-
-/**
- Create the screen driver.
- */
-Fl_Android_Screen_Driver::Fl_Android_Screen_Driver() :
- super(),
- pContentChanged(false),
- pClearDesktop(false)
-{
-}
-
-
-/**
- Call the FLTK System handler with Android specific events.
-
- \return always 1, assuming the event was handled
-
- \see Fl_Android_Platform_Event
- */
-int Fl_Android_Screen_Driver::handle_app_command()
-{
- // get the command
- int8_t cmd = Fl_Android_Application::read_cmd();
-
- // setup the Android glue and prepare all settings for calling into FLTK
- Fl_Android_Application::pre_exec_cmd(cmd);
-
- // call all registered FLTK system handlers
- Fl::e_number = ((uint32_t)(cmd-Fl_Android_Application::APP_CMD_INPUT_CHANGED)) + FL_ANDROID_EVENT_INPUT_CHANGED;
- fl_send_system_handlers(nullptr);
-
- // fixup and finalize application wide command handling
- Fl_Android_Application::post_exec_cmd(cmd);
- return 1;
-}
-
-
-int Fl_Android_Screen_Driver::handle_input_event()
-{
- AInputQueue *queue = Fl_Android_Application::input_event_queue();
- AInputEvent *event = nullptr;
-
- if (AInputQueue_getEvent(queue, &event) >= 0) {
- if (AInputQueue_preDispatchEvent(queue, event)==0) {
- int consumed = 0;
- switch (AInputEvent_getType(event)) {
- case AINPUT_EVENT_TYPE_KEY:
- consumed = handle_keyboard_event(queue, event);
- break;
- case AINPUT_EVENT_TYPE_MOTION:
- consumed = handle_mouse_event(queue, event);
- break;
- default:
- // don't do anything. There may be additional event types in the future
- AInputQueue_finishEvent(queue, event, consumed);
- break;
- }
- // TODO: handle all events here
-// AInputQueue_finishEvent(queue, event, consumed);
- }
- }
- return 0;
-}
-
-
-int Fl_Android_Screen_Driver::handle_mouse_event(AInputQueue *queue, AInputEvent *event)
-{
- int ex = Fl::e_x_root = (int)(AMotionEvent_getX(event, 0) * 600 /
- ANativeWindow_getWidth(Fl_Android_Application::native_window()));
- int ey = Fl::e_y_root = (int)(AMotionEvent_getY(event, 0) * 800 /
- ANativeWindow_getHeight(Fl_Android_Application::native_window()));
-
- // FIXME: find the window in which the event happened
- Fl_Window *win = Fl::grab();
- if (!win) {
- win = Fl::first_window();
- if (win && !win->modal()) {
- while (win) {
- if (ex >= win->x() && ex < win->x() + win->w() && ey >= win->y() &&
- ey < win->y() + win->h())
- break;
- win = Fl::next_window(win);
- }
- }
- }
- if (!win) {
- AInputQueue_finishEvent(queue, event, 0);
- return 0;
- }
-
- if (win) {
- Fl::e_x = ex-win->x();
- Fl::e_y = ey-win->y();
- } else {
- Fl::e_x = ex;
- Fl::e_y = ey;
- }
-
- Fl::e_state = FL_BUTTON1;
- Fl::e_keysym = FL_Button + 1;
- if (AMotionEvent_getAction(event) == AMOTION_EVENT_ACTION_DOWN) {
- AInputQueue_finishEvent(queue, event, 1);
- Fl::e_is_click = 1;
-// Fl_Android_Application::log_i("Mouse push %x %d at %d, %d", win, Fl::event_button(), Fl::event_x(), Fl::event_y());
- if (win) Fl::handle(FL_PUSH, win); // do NOT send a push event into the "Desktop"
- } else if (AMotionEvent_getAction(event) == AMOTION_EVENT_ACTION_MOVE) {
- AInputQueue_finishEvent(queue, event, 1);
-// Fl_Android_Application::log_i("Mouse drag %x %d at %d, %d", win, Fl::event_button(), Fl::event_x(), Fl::event_y());
- if (win) Fl::handle(FL_DRAG, win);
- } else if (AMotionEvent_getAction(event) == AMOTION_EVENT_ACTION_UP) {
- AInputQueue_finishEvent(queue, event, 1);
- Fl::e_state = 0;
-// Fl_Android_Application::log_i("Mouse release %x %d at %d, %d", win, Fl::event_button(), Fl::event_x(), Fl::event_y());
- if (win) Fl::handle(FL_RELEASE, win);
- } else {
- AInputQueue_finishEvent(queue, event, 0);
- }
- return 1;
-}
-
-
-/**
- Handle all events in the even queue.
-
- \todo what should this function return?
-
- \param time_to_wait
- \return we do not know
- */
-int Fl_Android_Screen_Driver::handle_queued_events(double time_to_wait)
-{
- int ret = 0;
- // Read all pending events.
- int ident;
- int events;
- int delay_millis = time_to_wait*1000;
- bool done = false;
-
- int delay = Fl::damage() ? 0 : delay_millis;
- while (!done) {
- ident = ALooper_pollOnce(delay, nullptr, &events, nullptr);
- switch (ident) {
- case Fl_Android_Application::LOOPER_ID_MAIN:
- ret = handle_app_command();
- break;
- 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 ALOOPER_POLL_WAKE:
- Fl_Android_Application::log_e("Someone woke up ALooper_pollOnce.");
- done = true;
- break;
- case ALOOPER_POLL_CALLBACK:
- Fl_Android_Application::log_e(
- "Someone added a callback to ALooper_pollOnce.");
- done = true;
- break;
- case ALOOPER_POLL_TIMEOUT:
- done = true; // timer expired, return to FLTK
- break;
- case ALOOPER_POLL_ERROR:
- Fl_Android_Application::log_e(
- "Something caused an ERROR in ALooper_pollOnce.");
- done = true; // return to the app to find the error
- break;
- default:
- Fl_Android_Application::log_e(
- "Unknown return value from ALooper_pollOnce.");
- done = true; // return to the app, just in case
- break;
- }
- // we need to repeat this as long as there are messages in the queue, or any
- // change in the graphical interface will trigger a redraw immediately. To
- // save time and energy, we want to collect graphics changes and execute
- // them as soon as no more events are pending.
- // Setting delay to zero on the second round makes sure that all events
- // are handled first, and the call returns only when no more
- // events are pending.
- delay = 0;
- }
- return ret;
-}
-
-
-/**
- Wait for a maximum of `time_to_wait` until something happens.
-
- \param time_to_wait in seconds
- \return We really do not know; check other platforms to see what is
- consistent here.
-
- \todo return the remaining time to reach 'time_to_wait'
- */
-double Fl_Android_Screen_Driver::wait(double time_to_wait)
-{
- Fl::run_checks();
- static int in_idle = 0;
- if (Fl::idle) {
- if (!in_idle) {
- in_idle = 1;
- Fl::idle();
- in_idle = 0;
- }
- // the idle function may turn off idle, we can then wait:
- if (Fl::idle) time_to_wait = 0.0;
- }
-
- if (time_to_wait==0.0) {
- // if there is no wait time, handle the event and show the results right away
- fl_unlock_function();
- handle_queued_events(time_to_wait);
- fl_lock_function();
- // FIXME: kludge to erase a window after it was hidden
- if (pClearDesktop && fl_graphics_driver) {
- ((Fl_Android_Graphics_Driver*)fl_graphics_driver)->make_current(nullptr);
- fl_rectf(0, 0, 600, 800, FL_BLACK);
- pClearDesktop = false;
- pContentChanged = true;
- }
- Fl::flush();
- } else {
- // if there is wait time, show the pending changes and then handle the events
- // FIXME: kludge to erase a window after it was hidden
- if (pClearDesktop && fl_graphics_driver) {
- ((Fl_Android_Graphics_Driver*)fl_graphics_driver)->make_current(nullptr);
- fl_rectf(0, 0, 600, 800, FL_BLACK);
- pClearDesktop = false;
- pContentChanged = true;
- }
- Fl::flush();
- if (Fl::idle && !in_idle) // 'idle' may have been set within flush()
- time_to_wait = 0.0;
- fl_unlock_function();
- handle_queued_events(time_to_wait);
- fl_lock_function();
- }
-
- return 0.0;
-}
-
-
-/**
- On Android, we currently write into a memory buffer and copy
- the content to the screen.
-
- \see fl_flush()
- */
-void Fl_Android_Screen_Driver::flush()
-{
- Fl_Screen_Driver::flush();
- // FIXME: do this only if anything actually changed on screen (need to optimize)!
- if (pContentChanged) {
- if (Fl_Android_Application::copy_screen())
- pContentChanged = false;
- }
-}
-
-
-// ---- timers -----------------------------------------------------------------
-
-
-struct TimerData
-{
- timer_t handle;
- struct sigevent sigevent;
- Fl_Timeout_Handler callback;
- void *data;
- bool used;
- bool triggered;
- struct itimerspec timeout;
-};
-static TimerData* timerData = nullptr;
-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;
- t.timeout = {
- { 0, 0 },
- { (time_t)floor(time), (long)(modf(time, &ff)*1000000000) }
- };
- ret = timer_settime(t.handle, 0, &t.timeout, nullptr);
- 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==nullptr) ) ) {
- if (t.used)
- timer_delete(t.handle);
- t.triggered = t.used = false;
- }
- }
-}
-
-
-/**
- Play some system sound.
-
- This function plays some rather arbitrary system sounds.
-
- \param type
-
- \see Fl_Screen_Driver::beep(int)
- \see fl_beep(int)
- */
-void Fl_Android_Screen_Driver::beep(int type)
-{
- int androidSoundID = 93; // default to TONE_CDMA_ALERT_CALL_GUARD
- switch (type) {
- case FL_BEEP_DEFAULT: androidSoundID = 92; break;
- case FL_BEEP_MESSAGE: androidSoundID = 86; break;
- case FL_BEEP_ERROR: androidSoundID = 87; break;
- case FL_BEEP_QUESTION: androidSoundID = 91; break;
- case FL_BEEP_PASSWORD: androidSoundID = 95; break;
- case FL_BEEP_NOTIFICATION: androidSoundID = 93; break;
- }
- Fl_Android_Java java;
- if (java.is_attached()) {
-
- jclass class_tone_generator = java.env()->FindClass("android/media/ToneGenerator");
-
- jmethodID toneGeneratorConstructor = java.env()->GetMethodID(
- class_tone_generator, "<init>",
- "(II)V");
-
- jobject toneGeneratorObj = java.env()->NewObject(
- class_tone_generator, toneGeneratorConstructor,
- 4, // STREAM_ALARM
- 100); // volume
-
- jmethodID method_start_tone = java.env()->GetMethodID(
- class_tone_generator,
- "startTone",
- "(II)Z");
-
- java.env()->CallBooleanMethod(
- toneGeneratorObj, method_start_tone,
- androidSoundID,
- 1000);
-
- java.env()->DeleteLocalRef(class_tone_generator);
- java.env()->DeleteLocalRef(toneGeneratorObj);
- }
-
-}
-
-
-/**
- Get the current mouse coordinates.
-
- This is used, among other things, to position the FLTK standard dialogs in
- a way that makes it easy to click the most common button. For an Android
- touch screen, this makes no sense at all, which is why we return the center
- of the screen for now.
-
- \todo rethink the dialog positioning scheme for touch devices.
-
- \todo this method assumes a fixed screen resolution
-
- \param [out] x
- \param [out] y
- \return
- */
-int Fl_Android_Screen_Driver::get_mouse(int &x, int &y)
-{
- x = 600/2;
- y = 800/2;
- return 1;
-}
-
-
-void Fl_Android_Screen_Driver::grab(Fl_Window* win)
-{
- if (win) {
- if (!Fl::grab_) {
- // TODO: will we need to fix any focus and/or direct the input stream to a window
- }
- Fl::grab_ = win;
- } else {
- if (Fl::grab_) {
- Fl::grab_ = 0;
- }
- }
-}
-
-
-/**
- \}
- \endcond
- */