-1

Update: I believe this isn't specific to GtkEntry, but more that the keyboard input itself isn't being sent to the program (key events are no longer triggered).

I'm working on a display manager. I'm testing on Arch Linux. The idea is that when the user types in their credentials and hit enter, the display manager forks and launches the window manager specified in their ~/.xinitrc. I'm testing with Awesome WM as the window manager. When the user exits the window manager, the display manager should then get back control so the user can log in again.

The issue is that after the user exits the window manager, the display manager is shown but I can't type into the GtkEntry box anymore. I can highlight the text and even right click and cut and paste, but I can't type. I've made a simplified example below. Note that if instead of launching the window manager I launch something like the sleep command, everything works fine.

#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

#include <gtk/gtk.h>

#define ENTER_KEY    65293

static pthread_t login_thread;

static void* login_func(void *data) {
    pid_t child_pid = fork();
    if (child_pid == 0) {
        execl("/bin/bash", "/bin/bash", "--login", "/home/gulshan/.xinitrc", NULL); // This doesn't work
        // execl("/usr/bin/awesome", "/usr/bin/awesome", NULL); // This doesn't work
        // execl("/usr/bin/sleep", "/usr/bin/sleep", "5", NULL); // This works
        printf("exec error");
        exit(1);
    }

    // Wait for child process to finish
    int status;
    waitpid(child_pid, &status, 0);

    printf("Returning from login_func\n");
    return NULL;
}

static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
    if (event->keyval == ENTER_KEY) {
        pthread_create(&login_thread, NULL, login_func, (void*) widget);
    }
    return FALSE;
}

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

    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    gtk_container_add(GTK_CONTAINER(window), gtk_entry_new());
    gtk_widget_show_all(window);

    g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
    gtk_main();

    return 0;
}

Here's how I compile the code:

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

To test this code, I start by running:

Xephyr -ac -br -noreset -screen 800x600 :1

This starts an X server in a window that I can use for testing. Then I start the code with

DISPLAY=:1 ./test

Which starts it in the Xephyr window. If you quit out of the display manager (in Awesome, you can right click and click "quit"), you'll see that you can't type in the text box anymore.

gsgx
  • 12,020
  • 25
  • 98
  • 149
  • Downvoters on questions like this anger me. Making a simple example took a lot of time. I explained what I'm trying to do, gave the simple example, and gave detailed instructions on how to run it and what the expected and actual output are, and yet I get downvotes. SO is not the nice place it used to be. – gsgx Apr 23 '15 at 02:12

1 Answers1

0

I think that you shouldn't mix threads and fork see threads-and-fork-think-twice-before-using-them

I have modified your code like this:

#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

#include <gtk/gtk.h>

#define ENTER_KEY    65293

static pthread_t login_thread;

static void* login_func(void *data) {
    pid_t child_pid = fork();
    if (child_pid == 0) {
        execl("/usr/bin/awesome", "/usr/bin/awesome", NULL); // This doesn't work
        printf("exec error");
        exit(1);
    }

    // Wait for child process to finish
    int status;
    waitpid(child_pid, &status, 0);

    printf("Returning from login_func\n");
    return NULL;
}

static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
    if (event->keyval == ENTER_KEY) {
      login_func((void *) widget);
    }
    return FALSE;
}

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

    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    gtk_container_add(GTK_CONTAINER(window), gtk_entry_new());
    gtk_widget_show_all(window);

    g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
    gtk_main();

    return 0;
}

As you can see I have just removed the thread. Now when I logout from Awesome, I am able to type in the gtk entry.

cedlemo
  • 3,205
  • 3
  • 32
  • 50
  • I have to use threads. In the simplified example, the window stays visible when the window manager starts. In an actual display manager, the window will have to be hidden. If you don't use threads, you block the `key_event` callback, and then functions like `gtk_widget_hide` don't work and you can't hide the window manager. – gsgx Feb 17 '15 at 03:51