Onscreen Keyboard integration with GTK+3 application

Hi Nicola,

It seems that Onboard is already available on Ubuntu18.04. If you use GIO you can get your window id and not need to start Onboard before your app. Looked interesting so I gave it a try. A lot that can be improved here also.

Eric


/*
   Test getting an onboard keyboard as a plug in a socket.

   gcc -Wall onboard_socket1.c -o onboard_socket1 `pkg-config --cflags --libs gtk+-3.0`

   Tested on Ubuntu18.04 and GTK3.22
*/

#include<gtk/gtk.h>
#include<gtk/gtkx.h>
#include<stdlib.h>

static GPid child_pid=0;

static void plug_added(GtkSocket *socket, gpointer data);
static void add_plug(GtkWidget *widget, gpointer *data);
static gboolean watch_out_channel(GIOChannel *channel, GIOCondition cond, gpointer *data);
static void quit_program(GtkWidget *widget, gpointer data);

int main(int argc, char *argv[])
  {
    gtk_init(&argc, &argv);

    GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Socket");
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 300);
    g_signal_connect(window, "destroy", G_CALLBACK(quit_program), NULL);

    GtkWidget *entry=gtk_entry_new();
    gtk_widget_set_hexpand(entry, TRUE);

    GtkWidget *socket=gtk_socket_new();
    gtk_widget_set_size_request(socket, 500, 200);
    gtk_widget_set_hexpand(socket, TRUE);
    gtk_widget_set_vexpand(socket, TRUE);
    g_signal_connect(socket, "plug-added", G_CALLBACK(plug_added), NULL);

    GtkWidget *expander=gtk_expander_new("Keyboard");
    gtk_container_add(GTK_CONTAINER(expander), socket);

    GtkWidget *button=gtk_button_new_with_label("Get Keyboard");
    gtk_widget_set_hexpand(button, TRUE);
    gpointer data[]={button, socket, entry, expander};
    g_signal_connect(button, "clicked", G_CALLBACK(add_plug), data);

    GtkWidget *grid=gtk_grid_new();
    gtk_container_add(GTK_CONTAINER(window), grid);
    gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1);
    gtk_grid_attach(GTK_GRID(grid), entry, 0, 1, 1, 1);
    gtk_grid_attach(GTK_GRID(grid), expander, 0, 2, 1, 1);

    gtk_widget_show_all(window);

    gtk_main();

    return 0;   
  }
static void plug_added(GtkSocket *socket, gpointer data)
  {
    g_print("Keyboard Added\n");
  }
static void add_plug(GtkWidget *widget, gpointer *data)
  {
    g_print("Add Plug\n");
    gboolean retval;
    gchar *cmd=g_strdup("onboard -e -l Phone -t ModelM -s 400x300");
    gchar **arg_v = NULL;
    gint std_out=0;
    GError *error=NULL;
    GIOChannel *std_out_ch;

    g_shell_parse_argv(cmd, NULL, &arg_v, NULL);
    retval=g_spawn_async_with_pipes(NULL, arg_v, NULL, G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH, NULL, NULL, &child_pid, NULL, &std_out, NULL, &error);

    g_strfreev(arg_v);

    if(retval)
      {
        gtk_widget_set_sensitive(widget, FALSE);
        std_out_ch=g_io_channel_unix_new(std_out);
        g_io_add_watch(std_out_ch, G_IO_IN | G_IO_HUP, (GIOFunc)watch_out_channel, data);
        g_print("Channel Added\n");
      }
    else 
      {
        g_print("Couldn't start plug. %s\n", error->message);
        g_error_free(error);
      }
  }
static gboolean watch_out_channel(GIOChannel *channel, GIOCondition cond, gpointer *data)
  {
    g_print("Watch Out\n");
    if(cond==G_IO_HUP)
      {
        g_print("Unreference Channel\n");
        g_io_channel_unref(channel);
        return FALSE;
      } 
    else
      {
        gsize size;
        gchar *string1=NULL;
        g_io_channel_read_line(channel, &string1, &size, NULL, NULL);
        g_print("Window ID %s", string1);
        if(atoi(string1)>0)
          {
            gtk_socket_add_id(GTK_SOCKET(data[1]), (Window)atoi(string1));
            gtk_expander_set_expanded(GTK_EXPANDER(data[3]), TRUE);
            gtk_widget_grab_focus(GTK_WIDGET(data[2]));
          }
        if(g_strcmp0("dis\n", string1)==0)
          {
            gchar *string2=g_strdup_printf("kill %i", (gint)child_pid);
            g_print("%s\n", string2);
            g_spawn_command_line_async(string2, NULL); 
            g_spawn_close_pid(child_pid);
            g_free(string2);
            gtk_widget_set_sensitive(GTK_WIDGET(data[0]), TRUE);
          }
        g_free(string1);
        return TRUE;
      }
  }
static void quit_program(GtkWidget *widget, gpointer data)
  {
    g_print("Pid %i\n", child_pid);
    if(child_pid!=0) 
      {
        gchar *string=g_strdup_printf("kill %i", (gint)child_pid);
        g_print("%s\n", string);
        g_spawn_command_line_async(string, NULL); 
        g_spawn_close_pid(child_pid);
        g_free(string);
      }
    gtk_main_quit();
  }