1

To demonstrate what I mean, I wrote up this code without most of the gtk mess:

//more gtk declaration stuff above
int access;
access = 0;

int tries;
tries = 0;

string input;
input = "";

string code;
code = "";

while(access != 1 && tries < 4){
    directions((gpointer)lbl); //change label to "type 'finger'"
    cin >> input;

    if(input.compare("finger") = 0){
        while(code.compare("1") != 0 && tries < 4){
            fpcheck((gpointer)lbl); //change label "Enter the secret code ('1')"
            cin >> code;
            if(code.compare("1") != 0){
                retry((gpointer) lbl);//change label "Try again!"
                tries ++;       
            }
            else{
                fprecog((gpointer) lbl); //change label "Recognized!"
                access = 1;
            }
        }
    }
}
if(access = 1)
    //change label "Access Granted!"
else
    //change label "No access."

gtk_main();
return 0;

Clearly this won't exactly work, since gtk_main() isn't called to the end. The console stuff will run fine, but the window won't pop up until the very end so the user won't know what to do, and if I put gtk_main() early on, the program is stuck in the gtk_main() loop so nothing will happen.

How is this sort of flow typically accomplished in GTK? I've tried some gtk_thread stuff to break out of main, but that's apparently deprecated so I'm trying not to use that.

The input has to be read by a thread that's not gtk_main(), since the input isn't coming from the GUI. In reality, it'll be a device plugged into a beaglebone black, but I think this is a simpler similar situation.

The actual input methods that will be used are 1) a finger print sensor that does actions based on sent and received bytes through a UART channel, and 2) a usb camera and facial recognition scripts using OpenCV methods on a BeagleBone Black running Debian, networked to a laptop to do the intensive opencv stuff. For the moment I'm just trying to get it going with the FP sensor. With our interface, we can call an FP sensor method, which returns an int, and do something depending on that int.

I need to be able to change the GTK label depending on what int is returned, then call another method after the label displays.

Here's a snippet of what the code I'm trying to integrate with looks like:

while(key != 'x')
    {
        imshow("main_display", welcome);
        key = waitKey(1);  //poll keyboard at active screen

        //key = getkey();  //TODO: poll from TFT instead

        switch(key)
        {
            case 'i': //Identify User
                imshow("main_display", press_finger);
                waitKey(1);
                printf("\n---IDENTIFY USER---\n");
                post_log(1, 0);

                do_reg = true;
                Ret = GT_LED_On(LS);
                printf("\nPress Finger");

                //something to force console text before loop starts...?

                Timer.InitTimer();
                while(GT_IsPressFinger(LS) == 0 && ((Timer.ElapsedTime_ms() < TIMEOUT))) {}
                if(Timer.ElapsedTime_ms() >= TIMEOUT)
                {
                    printf("\nCapture TIMEOUT\n");
                    Ret = GT_LED_Off(LS);
                    post_log(6, user_id);
                    imshow("main_display", fps_timeout);
                    waitKey(1000);
                    do_reg = false;
                    break;  //??????????????????????????? GOTO???
                }
                printf("\nCapturing...Standby...\n");
                imshow("main_display", hold_finger);
                waitKey(1);
                Ret = GT_CaptureFinger(LS, 0);

Basically instead of the imshow() we're trying to use an actual GUI framework, and since the device already has GTK going due to OpenCV, it would be nice to stick with GTK. This console question is trying to figure out how to replace imshow() with a label change of a gtk window in a simple context.

Will
  • 13
  • 3
  • What's the point of the CLI data entry for a GUI program? – oldtechaa Apr 11 '16 at 20:56
  • The CLI here is just testing for a more robust set up - I glossed over it in the original question to simplify things but I'll add more about it. – Will Apr 11 '16 at 21:59

2 Answers2

1

I think what you're looking for is Glib IO Channel. If you tie this to the standard input file descriptor, the signal gets fired when the user hits enter. Then you should be able to use cin to get the text.

If your intent is to get some type of password you might instead consider using a dialog to capture user input.

Community
  • 1
  • 1
Blake
  • 368
  • 1
  • 11
  • Maybe that will work, but to clarify, the actual input methods that will be used are 1) a finger print sensor that does actions based on sent and received bytes through a UART channel, and 2) a usb camera and facial recognition scripts using OpenCV methods on a BeagleBone Black running Debian, networked to a laptop to do the intensive opencv stuff. For the moment I'm just trying to get it going with the FP sensor. With our interface, we can call an FP sensor method, which returns an int, and do something depending on that int. Does glibIO seem suitable for that? – Will Apr 11 '16 at 22:06
  • That seems exactly like what the Glib IO Channel stuff is for. If you wrap the UART's file descriptor in a Glib IO channel you should get a signal when you get any data on the UART. The fact that it seems you've wrapped the UART device around standard input/output doesn't change anything other than the value of the file descriptor. I recommend checking out [this example](http://stackoverflow.com/questions/9513327/gio-socket-server-client-example) where someone did the same thing with a TCP socket. – Blake Apr 12 '16 at 20:03
  • Could you clarify "tie this to the standard input file descriptor"? I'm trying to work with the console example first, using [this as a resource](http://www.linuxjournal.com/node/8545/print), but I don't know how to get the fd in this case. – Will Apr 14 '16 at 17:55
  • I'm assuming you're on linux, so you should be able to use [STDIN_FILENO](https://en.wikipedia.org/wiki/File_descriptor) to get the file descriptor for standard input. That should be what gets passed as the argument to g_io_channel_unix_new. – Blake Apr 14 '16 at 18:19
  • Thanks, I think I got it to recognize cin stuff and callback using an io_watch. However, the problem still persists that I can't change the label within a loop (like the one counting tries), since it doesn't go to gtk_main(). Based on [this thread](http://stackoverflow.com/questions/19973720/how-do-i-change-a-label-in-gtk-while-the-program-is-running-from-a-seperate-thr) I've tried using gtk_main_context_invoke() rather than directly calling the label update function, but that didn't update either. Here's a [pastebin](http://pastebin.com/7jk4smAF) of the full code. – Will Apr 14 '16 at 18:49
  • You shouldn't need a loop directly. You should be able to count failures in denied(), and take action if they get too high. – Blake Apr 14 '16 at 19:07
0

Alright, with the help of Blake I think I found a solution, but I don't know if its the best one.

In order to get the input while gtk_main() was happening, and call a function when that happens, I added a glib io call on the standard input file descriptor to detect cin style input. I used my other code as the callback function. Thanks Blake for the help with this part.

Then, in order to actually update the text in this new mini-thread, I made an update() function to call main_iteration(), while loops through gtk_main() once. Here's documentation on that. I don't know if this is safe usage or if there is a nicer solution, but the program now does what I wanted it to do.

Here's the full code for future reference.

#include <gtk/gtk.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <glib.h>


using namespace std;

void update(){
while (gtk_events_pending ())
gtk_main_iteration ();}

void fpcheck(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window) {
    gchar const *text = "<span font='32' weight='bold' color='#DDDDDD'>Enter the Secret\nCode. ('1')</span>";
    gtk_label_set_markup(GTK_LABEL(window), text);
}

void fprecog(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window) {
    gchar const *text2 = "<span font='32' weight='bold' color='#DDDDDD'>Fingerprint Recognized!</span>";
    gtk_label_set_markup(GTK_LABEL(window), text2);
}

void directions(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window){
    gchar const *text3 = "<span font='32' weight='bold' color='#DDDDDD'>Type 'finger'.</span>";
    gtk_label_set_markup(GTK_LABEL(window), text3);
}

void retry(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window){
    gchar const *text4 = "<span font='32' weight='bold' color='#DDDDDD'>Try Again.</span>";
    gtk_label_set_markup(GTK_LABEL(window), text4);
}

void accessed(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window){
    gchar const *text5 = "<span font='32' weight='bold' color='#DDDDDD'>Access Granted!</span>";
    gtk_label_set_markup(GTK_LABEL(window), text5);
}

void denied(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window){
    gchar const *text6 = "<span font='32' weight='bold' color='#DDDDDD'>Access Denied.</span>";
    gtk_label_set_markup(GTK_LABEL(window), text6);
}


gboolean callback(GIOChannel *gio, GIOCondition condition, gpointer lbl){
    int access;
    access = 0;

    int tries;
    tries = 0;

    string input;
    input = "";

    string code;
    code = "";

    while(access != 1 && tries < 4){
        directions((gpointer)lbl); //change label to "type 'finger'"
        update();
        cin >> input;

        if(input.compare("finger") == 0){
            while(code.compare("1") != 0 && tries < 4){
                fpcheck((gpointer)lbl); //change label "Enter the secret code ('1')"
                update();
                cin >> code;
                if(code.compare("1") != 0){
                    retry((gpointer) lbl);//change label "Try again!"
                    update();
                    tries ++;       
                }
                else{
                    fprecog((gpointer) lbl); //change label "Recognized!"
                    update();
                    access = 1;
                }
            }
        }
    }
    if(access == 1)
        accessed((gpointer)lbl);
        //change label "Access Granted!"
    else
        denied((gpointer)lbl);
        //change label "No access."
}


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

    GtkWidget *window; //main window
    GtkWidget *lbl; //text
    GdkColor color = {0, 0x0, 0x0, 0x0}; //window color

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL); //init window
    //gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); //window pos on screen
    gtk_window_set_resizable(GTK_WINDOW(window), FALSE); //user cant resize //doesnt work
    //gtk_window_set_default_size(GTK_WINDOW(window), 800, 480); //window size

    gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color); //set color to window
    gtk_window_set_decorated(GTK_WINDOW(window), FALSE); //borderless
    gtk_widget_show(window);

    lbl = gtk_label_new(NULL); //label init
    gtk_container_add(GTK_CONTAINER(window), lbl);
    gtk_widget_set_size_request(lbl,800,480); //sets area that text can be //breaks alignment
    gtk_misc_set_alignment(GTK_MISC(lbl), .5, .5); //alignment
    gtk_label_set_line_wrap_mode(GTK_LABEL(lbl), PANGO_WRAP_WORD_CHAR); //sets line wrap on

    gchar const *str = "<span font='32' weight='bold' color='#DDDDDD'>Press Enter to begin.</span>"; //label text, uses pango markup
    gtk_label_set_markup(GTK_LABEL(lbl), str); //add pango str to label
    gtk_label_set_angle(GTK_LABEL(lbl), -90);

    gtk_widget_show(lbl);

    //fpcheck((gpointer)lbl);
    //g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(fpcheck), (gpointer) lbl); //calls fpcheck to change label 
    //g_signal_connect(G_OBJECT(window), "key-release-event", G_CALLBACK(fprecog), (gpointer) lbl);     
    //fprecog((gpointer)lbl);

    g_signal_connect(G_OBJECT(window), "destroy",
    G_CALLBACK(gtk_main_quit), NULL);

    //gtk_widget_show_all(window); //build the window all at once

    //label says "Ready"

    GIOChannel *gio;
    gio = g_io_channel_unix_new(STDIN_FILENO);
    guint ret;
    ret = g_io_add_watch(gio, G_IO_IN, callback, (gpointer)lbl);

    gtk_main();

    return 0;
}
Will
  • 13
  • 3