comparison android/dw.cpp @ 2631:e9f4f0d2e5da

Android: Implement an event queue that will be handled by dw_main() and friends... since the threaded event handling might not actually happen in the order the events occurred due to the thread sheduler. This should be more light weight and hopefully as stable as the thread system. The threaded event handling can be reenabled with #define _DW_EVENT_THREADING
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Mon, 02 Aug 2021 20:37:56 +0000
parents 401a3b9f21ba
children 04d5c8147e33
comparison
equal deleted inserted replaced
2630:7534466688da 2631:e9f4f0d2e5da
39 /* Define this to enable threading for events... 39 /* Define this to enable threading for events...
40 * most Android events don't handle return values, so 40 * most Android events don't handle return values, so
41 * we can launch a new thread to handle the event. 41 * we can launch a new thread to handle the event.
42 * #define _DW_EVENT_THREADING 42 * #define _DW_EVENT_THREADING
43 */ 43 */
44 #define _DW_EVENT_THREADING 44 /* #define _DW_EVENT_THREADING */
45 #define DW_CLASS_NAME "org/dbsoft/dwindows/DWindows" 45 #define DW_CLASS_NAME "org/dbsoft/dwindows/DWindows"
46 46
47 /* Dynamic Windows internal variables */ 47 /* Dynamic Windows internal variables */
48 static char _dw_app_id[_DW_APP_ID_SIZE+1]= {0}; 48 static char _dw_app_id[_DW_APP_ID_SIZE+1]= {0};
49 static char _dw_app_name[_DW_APP_ID_SIZE+1]= {0}; 49 static char _dw_app_name[_DW_APP_ID_SIZE+1]= {0};
458 free(params); 458 free(params);
459 #endif 459 #endif
460 return retval; 460 return retval;
461 } 461 }
462 462
463 int _dw_event_handler(jobject object, void **params) { 463 /* If we aren't using threading, we create a queue of events...
464 * the oldest event indexed by _dw_event_head, the newest by
465 * _dw_event_tail.
466 */
467 #ifndef _DW_EVENT_THREADING
468 #define _DW_EVENT_QUEUE_LENGTH 10
469 void *_dw_event_queue[_DW_EVENT_QUEUE_LENGTH][_DW_EVENT_PARAM_SIZE];
470 int _dw_event_head = -1, _dw_event_tail = -1, _dw_main_active = TRUE;
471 HMTX _dw_event_mutex = nullptr;
472 DWTID _dw_main_thread = -1;
473
474 /* Add a new event to the queue if there is space.
475 * This will be handled in the thread running dw_main()
476 */
477 int _dw_queue_event(void **params)
478 {
479 int newtail = _dw_event_tail + 1;
480 int retval = FALSE;
481
482 /* Initialize the mutex if necessary... return on failure. */
483 if(!_dw_event_mutex && !(_dw_event_mutex = dw_mutex_new()))
484 return retval;
485 /* Protect the queue in a mutex... hold for as short as possible */
486 dw_mutex_lock(_dw_event_mutex);
487 /* If we are at the end of the queue, loop back to the start. */
488 if(newtail >= _DW_EVENT_QUEUE_LENGTH)
489 newtail = 0;
490 /* If the new tail will be at the head, the event queue
491 * if full... drop the event.
492 */
493 if(newtail != _dw_event_head)
494 {
495 /* If the queue was empty, head and tail will be the same. */
496 if (_dw_event_head == -1)
497 _dw_event_head = newtail;
498 /* Copy the new event from the stack into the event queue. */
499 memcpy(&_dw_event_queue[newtail], params, _DW_EVENT_PARAM_SIZE * sizeof(void *));
500 /* Update the tail index */
501 _dw_event_tail = newtail;
502 /* Successfully queued event */
503 retval = TRUE;
504 }
505 dw_mutex_unlock(_dw_event_mutex);
506 return retval;
507 }
508
509 /* If there is an event waiting, pop it off the queue,
510 * advance the head and return TRUE.
511 * If there are no events waiting return FALSE
512 */
513 int _dw_dequeue_event(void **params)
514 {
515 int retval = FALSE;
516
517 /* Initialize the mutex if necessary... return FALSE on failure. */
518 if(!_dw_event_mutex && !(_dw_event_mutex = dw_mutex_new()))
519 return retval;
520 dw_mutex_lock(_dw_event_mutex);
521 if(_dw_event_head != -1)
522 {
523 /* Copy the params out of the queue so it can be filled in by new events */
524 memcpy(params, &_dw_event_queue[_dw_event_head], _DW_EVENT_PARAM_SIZE * sizeof(void *));
525
526 /* If the head is the same as the tail...
527 * there was only one event... so set the
528 * head and tail to -1 to indicate empty.
529 */
530 if(_dw_event_head == _dw_event_tail)
531 _dw_event_head = _dw_event_tail = -1;
532 else
533 {
534 /* Advance the head */
535 _dw_event_head++;
536
537 /* If we are at the end of the queue, loop back to the start. */
538 if(_dw_event_head >= _DW_EVENT_QUEUE_LENGTH)
539 _dw_event_head = 0;
540 }
541 /* Successfully dequeued event */
542 retval = TRUE;
543 /* Notify dw_main() that there is an event to handle */
544 dw_event_post(_dw_main_event);
545 }
546 dw_mutex_unlock(_dw_event_mutex);
547 return retval;
548 }
549 #endif
550
551 int _dw_event_handler(jobject object, void **params)
552 {
464 DWSignalHandler *handler = _dw_get_handler(object, DW_POINTER_TO_INT(params[8])); 553 DWSignalHandler *handler = _dw_get_handler(object, DW_POINTER_TO_INT(params[8]));
465 554
466 if (handler) 555 if (handler)
467 { 556 {
468 params[9] = (void *)handler; 557 params[9] = (void *)handler;
469 558
470 #ifdef _DW_EVENT_THREADING 559 /* We have to handle draw events in the main thread...
471 /* We can't launch a thread for draw events it won't work */ 560 * If it isn't a draw event, either queue the event
561 * or launch a new thread to handle it.
562 */
472 if(DW_POINTER_TO_INT(params[8]) != 7) 563 if(DW_POINTER_TO_INT(params[8]) != 7)
473 { 564 {
565 #ifdef _DW_EVENT_THREADING
474 /* Make a copy of the params so it isn't allocated from the stack */ 566 /* Make a copy of the params so it isn't allocated from the stack */
475 void *newparams = calloc(_DW_EVENT_PARAM_SIZE, sizeof(void *)); 567 void *newparams = calloc(_DW_EVENT_PARAM_SIZE, sizeof(void *));
476 568
477 memcpy(newparams, params, _DW_EVENT_PARAM_SIZE * sizeof(void *)); 569 memcpy(newparams, params, _DW_EVENT_PARAM_SIZE * sizeof(void *));
478 dw_thread_new((void *) _dw_event_handler2, newparams, 0); 570 dw_thread_new((void *) _dw_event_handler2, newparams, 0);
571 #else
572 /* Push the new event onto the queue if it fits */
573 _dw_queue_event(params);
574 #endif
479 } 575 }
480 else 576 else
481 #endif 577 return _dw_event_handler2(params);
482 return _dw_event_handler2(params);
483 578
484 } 579 }
485 return 0; 580 return 0;
486 } 581 }
487 582
507 return _dw_event_handler(obj1, params); 602 return _dw_event_handler(obj1, params);
508 } 603 }
509 604
510 /* A more simple method for quicker calls */ 605 /* A more simple method for quicker calls */
511 JNIEXPORT void JNICALL 606 JNIEXPORT void JNICALL
512 Java_org_dbsoft_dwindows_DWindows_eventHandlerSimple(JNIEnv* env, jobject obj, jobject obj1, jint message) { 607 Java_org_dbsoft_dwindows_DWindows_eventHandlerSimple(JNIEnv* env, jobject obj, jobject obj1, jint message)
608 {
513 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr }; 609 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr };
514 610
515 params[8] = DW_INT_TO_POINTER(message); 611 params[8] = DW_INT_TO_POINTER(message);
516 _dw_event_handler(obj1, params); 612 _dw_event_handler(obj1, params);
517 } 613 }
518 614
519 /* Handler for notebook page changes */ 615 /* Handler for notebook page changes */
520 JNIEXPORT void JNICALL 616 JNIEXPORT void JNICALL
521 Java_org_dbsoft_dwindows_DWindows_eventHandlerNotebook(JNIEnv* env, jobject obj, jobject obj1, jint message, jlong pageID) { 617 Java_org_dbsoft_dwindows_DWindows_eventHandlerNotebook(JNIEnv* env, jobject obj, jobject obj1, jint message, jlong pageID)
618 {
522 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr }; 619 void *params[_DW_EVENT_PARAM_SIZE] = { nullptr };
523 620
524 params[3] = DW_INT_TO_POINTER(pageID); 621 params[3] = DW_INT_TO_POINTER(pageID);
525 params[8] = DW_INT_TO_POINTER(message); 622 params[8] = DW_INT_TO_POINTER(message);
526 _dw_event_handler(obj1, params); 623 _dw_event_handler(obj1, params);
781 // Call the method on the object 878 // Call the method on the object
782 env->CallVoidMethod(_dw_obj, dwMain); 879 env->CallVoidMethod(_dw_obj, dwMain);
783 _dw_jni_check_exception(env); 880 _dw_jni_check_exception(env);
784 } 881 }
785 882
883 #ifdef _DW_EVENT_THREADING
786 /* We don't actually run a loop here, 884 /* We don't actually run a loop here,
787 * we launched a new thread to run the loop there. 885 * we launched a new thread to run the loop there.
788 * Just wait for dw_main_quit() on the DWMainEvent. 886 * Just wait for dw_main_quit() on the DWMainEvent.
789 */ 887 */
790 dw_event_wait(_dw_main_event, DW_TIMEOUT_INFINITE); 888 dw_event_wait(_dw_main_event, DW_TIMEOUT_INFINITE);
889 #else
890
891 /* Save our thread ID, so we know if we should handle
892 * events in callback dw_main_sleep/iteration() calls.
893 */
894 _dw_main_thread = dw_thread_id();
895
896 do
897 {
898 void *params[_DW_EVENT_PARAM_SIZE];
899
900 dw_event_reset(_dw_main_event);
901
902 /* Dequeue and handle any pending events */
903 while(_dw_dequeue_event(params))
904 _dw_event_handler2(params);
905
906 /* Wait for something to wake us up,
907 * either a posted event, or dw_main_quit()
908 */
909 dw_event_wait(_dw_main_event, 100);
910
911 } while(_dw_main_active);
912 _dw_main_thread = -1;
913 #endif
791 } 914 }
792 915
793 /* 916 /*
794 * Causes running dw_main() to return. 917 * Causes running dw_main() to return.
795 */ 918 */
796 void API dw_main_quit(void) 919 void API dw_main_quit(void)
797 { 920 {
921 #ifndef _DW_EVENT_THREADING
922 _dw_main_active = FALSE;
923 #endif
798 dw_event_post(_dw_main_event); 924 dw_event_post(_dw_main_event);
799 } 925 }
800 926
801 /* 927 /*
802 * Runs a message loop for Dynamic Windows, for a period of milliseconds. 928 * Runs a message loop for Dynamic Windows, for a period of milliseconds.
805 */ 931 */
806 void API dw_main_sleep(int milliseconds) 932 void API dw_main_sleep(int milliseconds)
807 { 933 {
808 JNIEnv *env; 934 JNIEnv *env;
809 935
936 #ifndef _DW_EVENT_THREADING
937 /* If we are in an event callback from dw_main() ...
938 * we need to continue handling events from the UI.
939 */
940 if(_dw_main_thread == dw_thread_id())
941 {
942 struct timeval tv, start;
943 /* The time left to wait from the start */
944 int difference = milliseconds;
945
946 gettimeofday(&start, NULL);
947
948 do
949 {
950 void *params[_DW_EVENT_PARAM_SIZE];
951
952 dw_event_reset(_dw_main_event);
953
954 /* Dequeue and handle any pending events */
955 while(_dw_dequeue_event(params))
956 _dw_event_handler2(params);
957
958 /* Wait for something to wake us up,
959 * either a posted event, or dw_main_quit()
960 */
961 dw_event_wait(_dw_main_event, difference);
962
963 gettimeofday(&tv, NULL);
964
965 } while(_dw_main_active && (difference = ((tv.tv_sec - start.tv_sec)*1000) + ((tv.tv_usec - start.tv_usec)/1000)) <= milliseconds);
966 }
967 else
968 #endif
810 if((env = (JNIEnv *)pthread_getspecific(_dw_env_key))) 969 if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
811 { 970 {
812 // First get the class that contains the method you need to call 971 // First get the class that contains the method you need to call
813 jclass clazz = _dw_find_class(env, DW_CLASS_NAME); 972 jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
814 // Get the method that you want to call 973 // Get the method that you want to call
823 /* 982 /*
824 * Processes a single message iteration and returns. 983 * Processes a single message iteration and returns.
825 */ 984 */
826 void API dw_main_iteration(void) 985 void API dw_main_iteration(void)
827 { 986 {
987 #ifndef _DW_EVENT_THREADING
988 if(_dw_main_thread == dw_thread_id())
989 {
990 void *params[_DW_EVENT_PARAM_SIZE];
991
992 /* Dequeue a single pending event */
993 if (_dw_dequeue_event(params))
994 _dw_event_handler2(params);
995 }
996 else
997 #endif
828 /* If we sleep for 0 milliseconds... we will drop out 998 /* If we sleep for 0 milliseconds... we will drop out
829 * of the loop at the first idle moment 999 * of the loop at the first idle moment
830 */ 1000 */
831 dw_main_sleep(0); 1001 dw_main_sleep(0);
832 } 1002 }