-1

更新: これは GtkEntry に固有のものではないと思いますが、キーボード入力自体がプログラムに送信されていません (キー イベントはトリガーされなくなりました)。

私はディスプレイマネージャーに取り組んでいます。Arch Linux でテストしています。これは、ユーザーが資格情報を入力して Enter キーを押すと、ディスプレイ マネージャーが fork し、で指定されたウィンドウ マネージャーを起動するという考え方です~/.xinitrc。ウィンドウマネージャーとしてAwesome WMでテストしています。ユーザーがウィンドウ マネージャーを終了すると、ユーザーが再度ログインできるように、ディスプレイ マネージャーが制御を取り戻す必要があります。

問題は、ユーザーがウィンドウ マネージャーを終了した後、ディスプレイ マネージャーが表示されますが、GtkEntry ボックスに入力できなくなることです。テキストを強調表示したり、右クリックしてカット アンド ペーストしたりすることはできますが、入力することはできません。以下に簡単な例を作成しました。ウィンドウマネージャーを起動する代わりに、sleepコマンドのようなものを起動すると、すべて正常に動作することに注意してください。

#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;
}

コードをコンパイルする方法は次のとおりです。

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

このコードをテストするには、まず次を実行します。

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

これにより、テストに使用できるウィンドウで X サーバーが起動します。次に、コードを開始します

DISPLAY=:1 ./test

Xephyrウィンドウで起動します。ディスプレイ マネージャーを終了すると (Awesome では、右クリックして [終了] をクリックできます)、テキスト ボックスに入力できなくなります。

4

1 に答える 1

0

スレッドとフォークを混在させるべきではないと思います。threads-and-fork-think-twice-before-using-them を参照

私はあなたのコードを次のように修正しました:

#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;
}

ご覧のとおり、スレッドを削除しました。これで、Awesome からログアウトすると、gtk エントリを入力できるようになりました。

于 2015-02-07T20:38:05.553 に答える