Mercurial > dwindows
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 } |