Possible problem with gdk_selection_get_owner()



Attached are two small programs, gtk.c and x11.c. Both are meant to demonstrate how to use a GdkAtom/Atom to determine if an instance of a program is already running (Linux/Unix).

The x11.c code works fine. The gtk.c code always returns NULL when gdk_selection_get_owner() is called, but the SelectionClear event is actually dispatched when gdk_selection_owner_set() is called the second time the program is run.

Am I missing something or is this expected behavior?

How the programs are supposed to be run:

1. Run the first one in the background:
   % ./x11 &

2. When the program is run again, it is supposed to print something about another copy already running and exit:

   % ./x11
--
---------------------------------------------------------------------------
Mark Leisher
Computing Research Lab            A sneer is the weapon of the weak.
New Mexico State University         -- James Russell Lowell (1819-1891)
Box 30001, MSC 3CRL
Las Cruces, NM  88003
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>

static GdkAtom running = 0;

static gboolean
selclear(GtkWidget *w, GdkEventSelection *ev, gpointer data)
{
    gdk_selection_owner_set(w->window, ev->selection, GDK_CURRENT_TIME, FALSE);

    return TRUE;
}

static void
done(GtkWidget *widget, gpointer data)
{
    gdk_selection_owner_set(0, running, GDK_CURRENT_TIME, FALSE);
    gtk_main_quit();
    exit(0);
}

int
main(int argc, char *argv[])
{
    GtkWidget *w, *b;

    gtk_init(&argc, &argv);

    running = gdk_atom_intern("PROG_RUNNING", TRUE);

    if (gdk_selection_owner_get(running) != 0) {
        printf("%s: already running.\n", g_get_prgname());
        gdk_selection_owner_set(0, running, GDK_CURRENT_TIME, TRUE);
        return 1;
    }

    w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(G_OBJECT(w), "selection-clear-event",
                     G_CALLBACK(selclear), 0);

    gtk_window_set_title(GTK_WINDOW(w), "Am I Already Running?");
    g_signal_connect(G_OBJECT(w), "destroy", G_CALLBACK(gtk_main_quit), 0);
    g_signal_connect(G_OBJECT(w), "delete_event", G_CALLBACK(gtk_main_quit),0);

    b = gtk_button_new_with_label("Exit");
    gtk_widget_set_size_request(b, 100, 100);
    g_signal_connect(G_OBJECT(b), "clicked", G_CALLBACK(done), 0);
    gtk_container_add(GTK_CONTAINER(w), b);

    gtk_widget_show_all(w);

    /*
     * Own the selection.
     */
    gdk_selection_owner_set(w->window, running, GDK_CURRENT_TIME, TRUE);

    gtk_main();

    return 0;
}
#include <stdio.h>
#include <X11/Xlib.h>

#define ALLEVENTMASKS (KeyPressMask|KeyReleaseMask|ButtonPressMask|\
                       ButtonReleaseMask|EnterWindowMask|LeaveWindowMask|\
                       PointerMotionMask|PointerMotionHintMask|\
                       Button1MotionMask|Button2MotionMask|Button3MotionMask|\
                       Button4MotionMask|Button5MotionMask|ButtonMotionMask|\
                       KeymapStateMask|ExposureMask|VisibilityChangeMask|\
                       StructureNotifyMask|ResizeRedirectMask|\
                       SubstructureNotifyMask|SubstructureRedirectMask|\
                       FocusChangeMask|PropertyChangeMask|ColormapChangeMask|\
                       OwnerGrabButtonMask)

int
main(void)
{
    int done;
    Display *d;
    Atom running;
    Window win, root;
    XEvent ev;

    d = XOpenDisplay("");

    root = DefaultRootWindow(d);

    win = XCreateWindow(d, root, 10, 10, 100, 100, 2,
                        CopyFromParent, InputOutput, CopyFromParent,
                        0, 0);
    XSelectInput(d, win, ALLEVENTMASKS);
    XMapWindow(d, win);

    running = XInternAtom(d, "PROG_RUNNING", True);

    if (XGetSelectionOwner(d, running) == 0) {
        printf("Owning property.\n");
        XSetSelectionOwner(d, running, win, CurrentTime);
    } else {
        XSetSelectionOwner(d, running, 0, CurrentTime);
        XDestroyWindow(d, win);
        XCloseDisplay(d);
        printf("Another instance is running.\n");
        return 0;
    }

    done = 0;
    while (!done) {
        XNextEvent(d, &ev);
        switch (ev.type) {
          case SelectionClear:
            XSetSelectionOwner(d, running, win, CurrentTime);
            break;
          case KeyReleaseMask:
            done = 1;
            break;
        }
    }

    XSetSelectionOwner(d, running, 0, CurrentTime);
    XCloseDisplay(d);
    return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]