Re: "Lazy" GtkToggleButtons



On Fri, Feb 02, 2007 at 07:30:24PM +0100, Stefan Weber lawo de wrote:
I frequently have the need for GtkToggleButtons that emit a 
"toggled"-signal but do not switch state. The signal handler then should 
send a toggle request to a server via network. After receiving a 
confirmation from the server, I wish to toggle the button from code. I 
have not found a way to do so yet. Activating/Deactivating the button in 
the toggled-signal-handler leads to endless recursion. Has anybody else 
found a way accomplish that?

See the enclosed example.  Note if you want to use other
signals of the button than "toggled", things can get hairy
and I would think about creation of a new widget.

Yeti


--
Whatever.


=============================================================================
#include <gtk/gtk.h>

typedef enum {
    TOGGLE_USER = 0,
    TOGGLE_EVADE,
    TOGGLE_FINISH
} ToggleType;

static GQuark toggle_type_quark = 0;
static GQuark timeout_id_quark = 0;

static gboolean
lazy_button_finish_toggle(gpointer data)
{
    GtkWidget *button = (GtkWidget*)data;

    g_object_set_qdata(G_OBJECT(button), timeout_id_quark, NULL);
    g_object_set_qdata(G_OBJECT(button), toggle_type_quark,
                       GUINT_TO_POINTER(TOGGLE_FINISH));
    gtk_toggle_button_toggled(GTK_TOGGLE_BUTTON(data));

    return FALSE;
}

static void
lazy_button_toggled(GtkWidget *button,
                    gpointer data)
{
    guint id;

    switch (GPOINTER_TO_UINT(g_object_get_qdata(G_OBJECT(button),
                                                toggle_type_quark))) {
        case TOGGLE_EVADE:
        g_signal_stop_emission_by_name(button, "toggled");
        return;

        case TOGGLE_USER:
        gtk_widget_set_sensitive(button, FALSE);
        g_object_set_qdata(G_OBJECT(button), toggle_type_quark,
                           GUINT_TO_POINTER(TOGGLE_EVADE));
        id = g_timeout_add(GPOINTER_TO_INT(data), lazy_button_finish_toggle,
                           button);
        g_object_set_qdata(G_OBJECT(button), timeout_id_quark,
                           GUINT_TO_POINTER(id));
        gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(button), TRUE);
        g_signal_stop_emission_by_name(button, "toggled");
        break;

        case TOGGLE_FINISH:
        gtk_widget_set_sensitive(button, TRUE);
        gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(button), FALSE);
        g_object_set_qdata(G_OBJECT(button), toggle_type_quark,
                           GUINT_TO_POINTER(TOGGLE_USER));
        /* Work around Gtk+ bug */
        gtk_widget_hide(button);
        gtk_widget_show(button);
    }
}

static void
lazy_button_destroy(GtkWidget *button)
{
    guint id;

    if ((id = GPOINTER_TO_UINT(g_object_get_qdata(G_OBJECT(button),
                                                  timeout_id_quark))))
        g_source_remove(id);
}

static GtkWidget*
lazy_button_new_with_mnemonic(const gchar *label,
                              gint laziness)
{
    GtkWidget *button;

    if (!toggle_type_quark)
        toggle_type_quark = g_quark_from_static_string("toggle type");
    if (!timeout_id_quark)
        timeout_id_quark = g_quark_from_static_string("timeout id");

    button = gtk_toggle_button_new_with_label(label);
    g_signal_connect(button, "toggled",
                     G_CALLBACK(lazy_button_toggled),
                     GINT_TO_POINTER(laziness));
    g_signal_connect(button, "destroy",
                     G_CALLBACK(lazy_button_destroy),
                     NULL);

    return button;
}

static void
application_toggled_callback(GtkWidget *button)
{
    g_printerr("Button %p toggled, state is: %d\n",
               button, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
}

int
main(int argc, char *argv[])
{
    GtkWidget *window, *button;

    gtk_init(&argc, &argv);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    button = lazy_button_new_with_mnemonic("I'm so bloody lazy", 2000);
    gtk_container_add(GTK_CONTAINER(window), button);
    g_signal_connect(button, "toggled",
                     G_CALLBACK(application_toggled_callback), NULL);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}




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