changeset 2481:94f0d61d6953

Android: Initial commit of signal handlers, connecting buttons to the new system.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Mon, 26 Apr 2021 11:01:58 +0000
parents 878d36588aaa
children 4888503c3e3e
files android/DWindows.kt android/dw.cpp
diffstat 2 files changed, 409 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/android/DWindows.kt	Sun Apr 25 23:33:53 2021 +0000
+++ b/android/DWindows.kt	Mon Apr 26 11:01:58 2021 +0000
@@ -129,6 +129,7 @@
     {
         val button = Button(this)
         button.text = text
+        button.setOnClickListener { eventHandler(button, button, 8, "", "", 0, 0, 0, 0) }
         return button
     }
 
@@ -146,6 +147,7 @@
     {
         val radiobutton = RadioButton(this)
         radiobutton.text = text
+        radiobutton.setOnClickListener { eventHandler(radiobutton, radiobutton, 8, "", "", 0, 0, 0, 0) }
         return radiobutton
     }
 
@@ -168,6 +170,7 @@
      * which is packaged with this application.
      */
     external fun dwindowsInit(dataDir: String): String
+    external fun eventHandler(obj1: Any, obj2: Any, message: Int, str1: String, str2: String, int1: Int, int2: Int, int3: Int, int4: Int): Int
 
     companion object
     {
--- a/android/dw.cpp	Sun Apr 25 23:33:53 2021 +0000
+++ b/android/dw.cpp	Mon Apr 26 11:01:58 2021 +0000
@@ -107,6 +107,303 @@
     return env->NewStringUTF("Hello from JNI!");
 }
 
+typedef struct _sighandler
+{
+    struct _sighandler   *next;
+    ULONG message;
+    HWND window;
+    int id;
+    void *signalfunction;
+    void *discfunction;
+    void *data;
+
+} SignalHandler;
+
+static SignalHandler *DWRoot = NULL;
+
+SignalHandler *_dw_get_handler(HWND window, int messageid)
+{
+    SignalHandler *tmp = DWRoot;
+
+    /* Find any callbacks for this function */
+    while(tmp)
+    {
+        if(tmp->message == messageid && window == tmp->window)
+        {
+            return tmp;
+        }
+        tmp = tmp->next;
+    }
+    return NULL;
+}
+
+typedef struct
+{
+    ULONG message;
+    char name[30];
+
+} DWSignalList;
+
+/* List of signals */
+#define SIGNALMAX 19
+
+static DWSignalList DWSignalTranslate[SIGNALMAX] = {
+        { 1,    DW_SIGNAL_CONFIGURE },
+        { 2,    DW_SIGNAL_KEY_PRESS },
+        { 3,    DW_SIGNAL_BUTTON_PRESS },
+        { 4,    DW_SIGNAL_BUTTON_RELEASE },
+        { 5,    DW_SIGNAL_MOTION_NOTIFY },
+        { 6,    DW_SIGNAL_DELETE },
+        { 7,    DW_SIGNAL_EXPOSE },
+        { 8,    DW_SIGNAL_CLICKED },
+        { 9,    DW_SIGNAL_ITEM_ENTER },
+        { 10,   DW_SIGNAL_ITEM_CONTEXT },
+        { 11,   DW_SIGNAL_LIST_SELECT },
+        { 12,   DW_SIGNAL_ITEM_SELECT },
+        { 13,   DW_SIGNAL_SET_FOCUS },
+        { 14,   DW_SIGNAL_VALUE_CHANGED },
+        { 15,   DW_SIGNAL_SWITCH_PAGE },
+        { 16,   DW_SIGNAL_TREE_EXPAND },
+        { 17,   DW_SIGNAL_COLUMN_CLICK },
+        { 18,   DW_SIGNAL_HTML_RESULT },
+        { 19,   DW_SIGNAL_HTML_CHANGED }
+};
+
+int _dw_event_handler(jobject object, void **params, int message)
+{
+    SignalHandler *handler = _dw_get_handler(object, message);
+
+    if(handler)
+    {
+        switch(message)
+        {
+            /* Timer event */
+            case 0:
+            {
+                int (*timerfunc)(void *) = (int (* API)(void *))handler->signalfunction;
+
+                if(!timerfunc(handler->data))
+                    dw_timer_disconnect(handler->id);
+                return 0;
+            }
+                /* Configure/Resize event */
+            case 1:
+            {
+                int (*sizefunc)(HWND, int, int, void *) = (int (* API)(HWND, int, int, void *))handler->signalfunction;
+                int width = DW_POINTER_TO_INT(params[3]);
+                int height = DW_POINTER_TO_INT(params[4]);
+
+                if(width > 0 && height > 0)
+                {
+                    return sizefunc(object, width, height, handler->data);
+                }
+                return 0;
+            }
+            case 2:
+            {
+                int (*keypressfunc)(HWND, char, int, int, void *, char *) = (int (* API)(HWND, char, int, int, void *, char *))handler->signalfunction;
+                char *utf8 = (char *)params[1], ch = utf8 ? utf8[0] : '\0';
+                int vk = 0, special = 0;
+
+                return keypressfunc(handler->window, ch, (int)vk, special, handler->data, utf8);
+            }
+                /* Button press and release event */
+            case 3:
+            case 4:
+            {
+                int (* API buttonfunc)(HWND, int, int, int, void *) = (int (* API)(HWND, int, int, int, void *))handler->signalfunction;
+                int button = 1;
+
+                return buttonfunc(object, DW_POINTER_TO_INT(params[3]), DW_POINTER_TO_INT(params[4]), button, handler->data);
+            }
+            /* Motion notify event */
+            case 5:
+            {
+                int (* API motionfunc)(HWND, int, int, int, void *) = (int (* API)(HWND, int, int, int, void *))handler->signalfunction;
+
+                return motionfunc(object, DW_POINTER_TO_INT(params[3]), DW_POINTER_TO_INT(params[4]), DW_POINTER_TO_INT(params[5]), handler->data);
+            }
+            /* Window close event */
+            case 6:
+            {
+                int (* API closefunc)(HWND, void *) = (int (* API)(HWND, void *))handler->signalfunction;
+                return closefunc(object, handler->data);
+            }
+            /* Window expose/draw event */
+            case 7:
+            {
+                DWExpose exp;
+                int (* API exposefunc)(HWND, DWExpose *, void *) = (int (* API)(HWND, DWExpose *, void *))handler->signalfunction;
+
+                exp.x = DW_POINTER_TO_INT(params[3]);
+                exp.y = DW_POINTER_TO_INT(params[4]);
+                exp.width = DW_POINTER_TO_INT(params[5]);
+                exp.height = DW_POINTER_TO_INT(params[6]);
+                int result = exposefunc(object, &exp, handler->data);
+                return result;
+            }
+                /* Clicked event for buttons and menu items */
+            case 8:
+            {
+                int (* API clickfunc)(HWND, void *) = (int (* API)(HWND, void *))handler->signalfunction;
+
+                return clickfunc(object, handler->data);
+            }
+                /* Container class selection event */
+            case 9:
+            {
+                int (*containerselectfunc)(HWND, char *, void *, void *) =(int (* API)(HWND, char *, void *, void *)) handler->signalfunction;
+
+                return containerselectfunc(handler->window, (char *)params[1], handler->data, params[7]);
+            }
+                /* Container context menu event */
+            case 10:
+            {
+                int (* API containercontextfunc)(HWND, char *, int, int, void *, void *) = (int (* API)(HWND, char *, int, int, void *, void *))handler->signalfunction;
+                char *text = (char *)params[1];
+                void *user = params[7];
+                int x = DW_POINTER_TO_INT(params[3]);
+                int y = DW_POINTER_TO_INT(params[4]);
+
+                return containercontextfunc(handler->window, text, x, y, handler->data, user);
+            }
+                /* Generic selection changed event for several classes */
+            case 11:
+            case 14:
+            {
+                int (* API valuechangedfunc)(HWND, int, void *) = (int (* API)(HWND, int, void *))handler->signalfunction;
+                int selected = DW_POINTER_TO_INT(params[3]);
+
+                return valuechangedfunc(handler->window, selected, handler->data);;
+            }
+                /* Tree class selection event */
+            case 12:
+            {
+                int (* API treeselectfunc)(HWND, HTREEITEM, char *, void *, void *) = (int (* API)(HWND, HTREEITEM, char *, void *, void *))handler->signalfunction;
+                char *text = (char *)params[1];
+                void *user = params[7];
+
+                return treeselectfunc(handler->window, params[0], text, handler->data, user);
+            }
+                /* Set Focus event */
+            case 13:
+            {
+                int (* API setfocusfunc)(HWND, void *) = (int (* API)(HWND, void *))handler->signalfunction;
+
+                return setfocusfunc(handler->window, handler->data);
+            }
+                /* Notebook page change event */
+            case 15:
+            {
+                int (* API switchpagefunc)(HWND, unsigned long, void *) = (int (* API)(HWND, unsigned long, void *))handler->signalfunction;
+                int pageid = DW_POINTER_TO_INT(params[3]);
+
+                return switchpagefunc(handler->window, pageid, handler->data);
+            }
+                /* Tree expand event */
+            case 16:
+            {
+                int (* API treeexpandfunc)(HWND, HTREEITEM, void *) = (int (* API)(HWND, HTREEITEM, void *))handler->signalfunction;
+
+                return treeexpandfunc(handler->window, (HTREEITEM)params[0], handler->data);
+            }
+                /* Column click event */
+            case 17:
+            {
+                int (* API clickcolumnfunc)(HWND, int, void *) = (int (* API)(HWND, int, void *))handler->signalfunction;
+                int column_num = DW_POINTER_TO_INT(params[3]);
+
+                return clickcolumnfunc(handler->window, column_num, handler->data);
+            }
+                /* HTML result event */
+            case 18:
+            {
+                int (* API htmlresultfunc)(HWND, int, char *, void *, void *) = (int (* API)(HWND, int, char *, void *, void *))handler->signalfunction;
+                char *result = (char *)params[1];
+
+                return htmlresultfunc(handler->window, result ? DW_ERROR_NONE : DW_ERROR_UNKNOWN, result, params[7], handler->data);
+            }
+                /* HTML changed event */
+            case 19:
+            {
+                int (* API htmlchangedfunc)(HWND, int, char *, void *) = (int (* API)(HWND, int, char *, void *))handler->signalfunction;
+                char *uri = (char *)params[1];
+
+                return htmlchangedfunc(handler->window, DW_POINTER_TO_INT(params[3]), uri, handler->data);
+            }
+        }
+    }
+    return -1;
+}
+
+/*
+ * Entry location for all event handlers from the Android UI
+ */
+JNIEXPORT jint JNICALL
+Java_org_dbsoft_dwindows_dwtest_DWindows_eventHandler(JNIEnv* env, jobject obj, jobject obj1, jobject obj2,
+                                                      jint message, jstring str1, jstring str2,
+                                                      jint int1, jint int2, jint int3, jint int4) {
+    const char *utf81 = str1 ? env->GetStringUTFChars(str1, NULL) : NULL;
+    const char *utf82 = str2 ? env->GetStringUTFChars(str2, NULL) : NULL;
+    void *params[8] = { (void *)obj2, (void *)utf81, (void *)utf82,
+                        DW_INT_TO_POINTER(int1), DW_INT_TO_POINTER(int2),
+                        DW_INT_TO_POINTER(int3), DW_INT_TO_POINTER(int4), NULL };
+    return _dw_event_handler(obj1, params, message);
+}
+
+/* This function adds a signal handler callback into the linked list.
+ */
+void _dw_new_signal(ULONG message, HWND window, int msgid, void *signalfunction, void *discfunc, void *data)
+{
+    SignalHandler *newsig = (SignalHandler *)malloc(sizeof(SignalHandler));
+
+    newsig->message = message;
+    newsig->window = window;
+    newsig->id = msgid;
+    newsig->signalfunction = signalfunction;
+    newsig->discfunction = discfunc;
+    newsig->data = data;
+    newsig->next = NULL;
+
+    if (!DWRoot)
+        DWRoot = newsig;
+    else
+    {
+        SignalHandler *prev = NULL, *tmp = DWRoot;
+        while(tmp)
+        {
+            if(tmp->message == message &&
+               tmp->window == window &&
+               tmp->id == msgid &&
+               tmp->signalfunction == signalfunction)
+            {
+                tmp->data = data;
+                free(newsig);
+                return;
+            }
+            prev = tmp;
+            tmp = tmp->next;
+        }
+        if(prev)
+            prev->next = newsig;
+        else
+            DWRoot = newsig;
+    }
+}
+
+/* Finds the message number for a given signal name */
+ULONG _dw_findsigmessage(const char *signame)
+{
+    int z;
+
+    for(z=0;z<SIGNALMAX;z++)
+    {
+        if(strcasecmp(signame, DWSignalTranslate[z].name) == 0)
+            return DWSignalTranslate[z].message;
+    }
+    return 0L;
+}
+
 /* Implement these to get and set the Box* pointer on the widget handle */
 void *_dw_window_pointer_get(HWND handle)
 {
@@ -3101,16 +3398,60 @@
  */
 void API dw_signal_connect_data(HWND window, const char *signame, void *sigfunc, void *discfunc, void *data)
 {
+    ULONG message = 0, msgid = 0;
+
+    if(window && signame && sigfunc)
+    {
+        if((message = _dw_findsigmessage(signame)) != 0)
+        {
+            _dw_new_signal(message, window, (int)msgid, sigfunc, discfunc, data);
+        }
+    }
 }
 
 /*
  * Removes callbacks for a given window with given name.
  * Parameters:
  *       window: Window handle of callback to be removed.
- *       signame: Signal name to be matched on window.
  */
 void API dw_signal_disconnect_by_name(HWND window, const char *signame)
 {
+    SignalHandler *prev = NULL, *tmp = DWRoot;
+    ULONG message;
+
+    if(!window || !signame || (message = _dw_findsigmessage(signame)) == 0)
+        return;
+
+    while(tmp)
+    {
+        if(tmp->window == window && tmp->message == message)
+        {
+            void (*discfunc)(HWND, void *) = (void (*)(HWND, void*))tmp->discfunction;
+
+            if(discfunc)
+            {
+                discfunc(tmp->window, tmp->data);
+            }
+
+            if(prev)
+            {
+                prev->next = tmp->next;
+                free(tmp);
+                tmp = prev->next;
+            }
+            else
+            {
+                DWRoot = tmp->next;
+                free(tmp);
+                tmp = DWRoot;
+            }
+        }
+        else
+        {
+            prev = tmp;
+            tmp = tmp->next;
+        }
+    }
 }
 
 /*
@@ -3120,6 +3461,38 @@
  */
 void API dw_signal_disconnect_by_window(HWND window)
 {
+    SignalHandler *prev = NULL, *tmp = DWRoot;
+
+    while(tmp)
+    {
+        if(tmp->window == window)
+        {
+            void (*discfunc)(HWND, void *) = (void (*)(HWND, void*))tmp->discfunction;
+
+            if(discfunc)
+            {
+                discfunc(tmp->window, tmp->data);
+            }
+
+            if(prev)
+            {
+                prev->next = tmp->next;
+                free(tmp);
+                tmp = prev->next;
+            }
+            else
+            {
+                DWRoot = tmp->next;
+                free(tmp);
+                tmp = DWRoot;
+            }
+        }
+        else
+        {
+            prev = tmp;
+            tmp = tmp->next;
+        }
+    }
 }
 
 /*
@@ -3130,6 +3503,38 @@
  */
 void API dw_signal_disconnect_by_data(HWND window, void *data)
 {
+    SignalHandler *prev = NULL, *tmp = DWRoot;
+
+    while(tmp)
+    {
+        if(tmp->window == window && tmp->data == data)
+        {
+            void (*discfunc)(HWND, void *) = (void (*)(HWND, void*))tmp->discfunction;
+
+            if(discfunc)
+            {
+                discfunc(tmp->window, tmp->data);
+            }
+
+            if(prev)
+            {
+                prev->next = tmp->next;
+                free(tmp);
+                tmp = prev->next;
+            }
+            else
+            {
+                DWRoot = tmp->next;
+                free(tmp);
+                tmp = DWRoot;
+            }
+        }
+        else
+        {
+            prev = tmp;
+            tmp = tmp->next;
+        }
+    }
 }
 
 void _dw_strlwr(char *buf)