GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Tue Jul 29, 2014 12:36 am

All times are UTC




Post new topic Reply to topic  [ 12 posts ] 
Author Message
 Post subject: a documentation whine
PostPosted: Thu Oct 10, 2013 1:55 pm 
Offline
Familiar Face

Joined: Tue Oct 08, 2013 6:04 pm
Posts: 13
I've been using GTK+ for almost no time at all but I have found the format of the on-line documentation to be REALLY annoying. Under any given object the function calls are listed in seemingly random order when they should be alphabetical. In addition there is scant reference to allied functions as is common in most Linux documentation.

Then there is the layout! It doesn't conform to the GTK+ coding standards. I, like most people, cut and paste from the documentation pages directly into my code and the results are a mess (I have added periods in the quoted text below to illustrate the effect).

Lastly, the explanation of many functions is terse or obscure. In the example I show below the author uses, as a parenthetical explanation, "base 0" which one can only guess a meaning. What on earth is wrong with the words "left" and "right" or a comment that it is like a C string and how about an example! This isn't the end of the world, nor even a failure to raise the debt ceiling, but I shall have to code and play with the function to discover what it actually does.

Quote:
gtk_editable_set_position ()

void...................gtk_editable_set_position....................(GtkEditable *editable,
........................................................gint position);
Sets the cursor position.

editable : a GtkEditable widget.
position : the position of the cursor. The cursor is displayed before the character with the given (base 0) index in the widget. The value must be less than or equal to the number of characters in the widget. A value of -1 indicates that the position should be set after the last character in the entry. Note that this position is in characters, not in bytes.[/size]


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Thu Oct 10, 2013 6:25 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 734
Location: UK
Hello Clive,

The documentation has to be short as there is so much functionality that needs to be documented. They are automatically generated from the source code which is why you may think they are in an odd order. The description is from the comments with some parts generated from the actual code. The function proto type is formatted so that it appears clearer in the documentation and does not follow a programming style.

Generally the functions follow a similar layout with the constructor functions first followed by the functions to set/get attributes. Listed on each Object is the Object hierarchy, known implementations, signals, properties, style properties, etc.

The Object hierarchy and known implementations form your cross referencing. This may seam odd to you if you are used to Unix man pages, but this is due to GTK+ being an Object Orientated tool kit even though it is written in C. Even the QT tool kit has similar documentation.

What could also help you is to check out the tutorials that are listed here or on the Gnome web site.

_________________
E.


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Mon Oct 14, 2013 2:59 pm 
Offline
Familiar Face

Joined: Tue Oct 08, 2013 6:04 pm
Posts: 13
As you say:
Quote:
They are automatically generated from the source code
this should make it easier for the documentation to be sorted in a useful manner, not harder. There is no rocket science to an alphabetical sort. The fact that Qt does not offer better documentation is simply not relevant.

I have read and used many of the tutorials and have the Andrew Kraus book. The on-line tutorials are rather thin and are the only reference for Gtk+3.0.

Here are a couple of particular and practical things:

    All the Boolean properties have default settings but the documentation does not say what the defaults are. gtk_grid_get/set_column_homogeneous() defaults to FALSE but the only way to know that is to try it.

    Functions generally do not initiate a main loop iteration. However, GtkProgressBar (counter-intuitively to me) does not; and it is necessary to place stock piece of code : while(gtk_events_pending()) gtk_main_loop_iteration(); in any progress bar update mechanism. There is no mention or reference to this in the documentation. Cross-referencing related functions really helps for things like this.


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Mon Oct 14, 2013 5:48 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 734
Location: UK
The documentation for GTK is created using DOxygen and the functions are taken in the order they are declare in the source. All I am saying is that the documentation for GTK and QT are similar as they both use DOxygen.

For the properties of each widget all you need to do is look at the "Property Details" and listed are the properties, the ranges, the read/write status and what value is the default.

As for GtkProgressBar nearly everyone gets this one wrong. What most people do is do all the long work and tell the progress bar to update, but do not give control back to the GTK main loop to allow the redraw to occur. As a kludge people use
Code:
while(gtk_events_pending()) gtk_main_loop_iteration();
with-in their long running code to get around this and it does work. But it is not the best way which is why it is not mentioned in the documentation.

Have you got DevHelp installed on your system along with the documentation. This would allow searching for functions, properties, etc.

There are many tutorials out their that still reference GTK v2. Have a look at the list of documentation and tutorials here - http://www.gtkforums.com/viewtopic.php?f=3&t=988

_________________
E.


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Mon Oct 14, 2013 6:44 pm 
Offline
Familiar Face

Joined: Tue Oct 08, 2013 6:04 pm
Posts: 13
That particular code fragment may not be the "best" way but it amounts to the only way to get the progress bar to function if the a Gtk+ GUI is put on top of an existing program. To my mind it would do no harm if any call to the progress bar widget implicitly called for a loop iteration. After all, the only reason the programmer calls for a progress bar update is to show the user what is going on!

Moreover if what you say is true:
Quote:
As for GtkProgressBar nearly everyone gets this one wrong.

then either the documentation is lacking or the function of the code is wrong or nearly everyone else is wrong! Why not change something so that nearly everyone gets this right?

My comment stands. If you have DOxygen create a bunch of stuff that ends up as HTML, which is your sole source of documentation, then it simply needs more processing.

The pre-3.0 tutorials are fine, but if I'm writing new UI code I don't want to find, for example, that the GtkTable widget is deprecated. Old tutorials are next to useless if they haven't been cleaned-up.


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Mon Oct 14, 2013 7:34 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 734
Location: UK
With regards to GtkProgressBar there are many ways that this should be used. One of the better ways is to have the long processing job work in a thread sending messages to the main thread to update the progress bar. You can also use the idle signal to do small sections of your long job. There are many different ways which is why you can not say in the documentation this is the way it must only be done.

Why people get this wrong? They see examples around the internet done by people who write sloppy code and just follow this code. OK I have done this here, but have explained that this should not be used as it has some side effects.

Another example of a function that is often used incorrectly is the function sprinf() as this is often a cause of buffer overflows and used for hacking attacks.

The reason why updates to the display are not done immediately but put in a queue is to optimise screen redraws. If redraws where done on every API call then GTK would be very very slow.

DOxygen works, and has been used for many years. To redo this would be a major job with over 130Mb of data, documentation and source code just for LibGtk.

Note at no point have you said which version of GTK you want to use so that I could help you find the tutorials you want.

_________________
E.


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Mon Oct 14, 2013 11:25 pm 
Offline
Familiar Face

Joined: Tue Oct 08, 2013 6:04 pm
Posts: 13
I'm working with Gtk 3.0 (version 3.6).

I think my point is that if "nearly everyone" misunderstands an aspect of the API then it is best to change the API or its documentation because the alternative (that is, to change "nearly everyone") is much more difficult.

When I hunted around to understand the progress bar I found NO tutorials or examples of any code that used threads. There was one, frankly rather dumb one, that used a timer.

I can certainly see that it isn't necessary for ALL calls to update the loop, but for the progress bar it is. If a programmer doesn't wish to waste time informing the user of progress then it is easy to omit the call. There is little point for a programmer to make the call to simply to increment some invisible internal counter -- that really does waste cycles.


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Tue Oct 15, 2013 6:01 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 734
Location: UK
If an exception is made for draws are to be done for GtkProgressBar this will affect the object hierarchy and inheritance. Also where will the developers stop with making exceptions? By doing that it would make things much more complex.

One reason threads are often not used in tutorials is that there are many pit-falls when using them and they can rapidly become hard to understand. Also what job you are doing will effect how you use GtkProgressBar.

In an application I work on I can have a variable number of progress bars. I have a couple of worker threads which send messages to the main GUI thread so that the progress bars and other information are updated.

What language are you using? My preferred languages are C and C++ (with gtkmm bindings). If you give how you would like to see the implementation I could come up with an example for you.

_________________
E.


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Tue Oct 15, 2013 7:57 am 
Offline
Familiar Face

Joined: Wed Jul 03, 2013 4:52 am
Posts: 9
I find the gtk documentation to be of a much higher standard than a lot of other libraries I've used.
The only thing I can say about devhelp is if you don't have gnome installed it's dependency hell to get devhelp working. I got tired of it and gave up.


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Fri Oct 18, 2013 1:30 am 
Offline
Familiar Face

Joined: Tue Oct 08, 2013 6:04 pm
Posts: 13
errol wrote:
If an exception is made for draws are to be done for GtkProgressBar this will affect the object hierarchy and inheritance. Also where will the developers stop with making exceptions? By doing that it would make things much more complex.

One reason threads are often not used in tutorials is that there are many pit-falls when using them and they can rapidly become hard to understand. Also what job you are doing will effect how you use GtkProgressBar.

In an application I work on I can have a variable number of progress bars. I have a couple of worker threads which send messages to the main GUI thread so that the progress bars and other information are updated.

What language are you using? My preferred languages are C and C++ (with gtkmm bindings). If you give how you would like to see the implementation I could come up with an example for you.

My code is all C. I have been wrapping a GUI around an application that I have been using for a couple of years to make it easier for a friend to use. I have the UI in about 500 lines of GTK+ code in a small add-on module that is the only code that needs to know about GTK+. It is, at heart, a batch image processor crunching sometimes dozens of images. It takes 15 numeric parameters and may work on the images for twenty minutes, so it is not an interactive tool at all. I have written various pieces of threaded code (some of the image processing within the application is multi-threaded with pthreads) but overall there isn't much use to making this application's UI particularly responsive once it is launched. The only useful thing would be to have a cancel button to end the run but leave the application operational. It's just as easy for the user to terminate the application and start over.

What was needed was a simple means to activate the progress bar. I have a single exported function that the core application can call from deep within an iterative loop to keep the user aware that things are working. So figuring how to force an iteration of the gtk_main_loop was key to using the progress bar.


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Wed Oct 23, 2013 2:33 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 734
Location: UK
OK this is a bit big but here is an example code I threw together. It will not win any awards for design, but it will show a way to separate the GUI from the worker thread. The updating of the progress-bar is done using a time-out, but there are many other ways of getting a request to update the display from the worker thread. Hope this helps

Code:
// gcc `pkg-config --cflags --libs gtk+-3.0`

#include <gtk/gtk.h>

/*
* Structure containing some of the widgets and
* Thread information needed for communicating
* between threads
*/

typedef struct {
    GtkWidget *win;
    GtkWidget *start;
    GtkWidget *cancel;
    GtkWidget *progress_bar;

    GThread *thread;
    GMutex mutex;
    gint frac;
    gboolean canceled;
} MyWin;

/*
* The worker thread
*/
static gpointer worker_thread (gpointer user_data)
{
    MyWin *w = (MyWin *) user_data;
    gint i;
    gboolean c;

    for (i = 0; i <= 1000; i++) {
        g_usleep (20000);            /* Simulate some work */

/* This does the interthread communication
* Checks the canceled flag and updates the progress variabel
* These are protected by a mutex.
* The canceled flag should be checked every 200ms as the user
* would expect a response with-in 250ms
*/
        g_mutex_lock (&w->mutex);
        c = w->canceled;
        if (c == TRUE)
            w->frac = -1;
        else
            w->frac = i;
        g_mutex_unlock (&w->mutex);

        if (c == TRUE)
            break;
    }

    return NULL;
}

/*
* A call-back called every 200ms to update the progress bar
* Also checks how the thread ended so that the buttons can
* be updated
*/
static gboolean update_progress (gpointer user_data)
{
    MyWin *w = (MyWin *) user_data;
    gint f;

    g_mutex_lock (&w->mutex);
    f = w->frac;
    g_mutex_unlock (&w->mutex);

    if (f < 0) {
        gtk_progress_bar_set_text (GTK_PROGRESS_BAR (w->progress_bar), "Canceled");
        gtk_widget_set_sensitive (w->start, TRUE);
        gtk_widget_set_sensitive (w->cancel, FALSE);
        g_thread_join (w->thread);
        return FALSE;
    } else if (f >= 1000) {
        gtk_progress_bar_set_text (GTK_PROGRESS_BAR (w->progress_bar), "Completed");
        gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (w->progress_bar), 1.0);
        gtk_widget_set_sensitive (w->start, TRUE);
        gtk_widget_set_sensitive (w->cancel, FALSE);
        g_thread_join (w->thread);
        return FALSE;
    } else {
        gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (w->progress_bar), (gdouble)f / 1000.0);
    }

    return TRUE;
}

/*
* Start button clicked. Starts a new thread, starts a time-out thats can
* update the progress bar and set the buttons
*/

static void start_clicked (GtkButton *button, gpointer user_data)
{
    MyWin *w = (MyWin *) user_data;

    g_mutex_lock (&w->mutex);
    w->frac = 0;
    w->canceled = FALSE;
    g_mutex_unlock (&w->mutex);

    if (!(w->thread = g_thread_try_new ("worker", worker_thread, w, NULL))) {
        return;
    }

    gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (w->progress_bar), 0.0);
    gtk_progress_bar_set_text (GTK_PROGRESS_BAR (w->progress_bar), NULL);
    gtk_widget_set_sensitive (w->start, FALSE);
    gtk_widget_set_sensitive (w->cancel, TRUE);

    g_timeout_add (200, update_progress, w);
}

/*
* Cancel button clicked. Only sets a flag for the thread
*/
static void cancel_clicked (GtkButton *button, gpointer user_data)
{
    MyWin *w = (MyWin *) user_data;

    g_mutex_lock (&w->mutex);
    w->canceled = TRUE;
    g_mutex_unlock (&w->mutex);
}

/*
* Create the window with buttons and a progress bar and prepares the
* mutex for the thread
*/
static MyWin * create_main_win (void)
{
    MyWin *w = g_slice_new (MyWin);
    GtkWidget *button_box;
    GtkWidget *grid;

    w->win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    w->start = gtk_button_new_with_label ("Start");
    w->cancel = gtk_button_new_with_label ("Cancel");
    w->progress_bar = gtk_progress_bar_new ();
    gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR (w->progress_bar), TRUE);

    button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
    gtk_box_pack_end (GTK_BOX (button_box), w->start, FALSE, FALSE, 0);
    gtk_box_pack_end (GTK_BOX (button_box), w->cancel, FALSE, FALSE, 0);

    grid = gtk_grid_new ();
    gtk_container_add (GTK_CONTAINER (w->win), grid);
    gtk_grid_attach (GTK_GRID (grid), w->progress_bar, 0, 0, 1, 1);
    gtk_grid_attach (GTK_GRID (grid), button_box, 0, 1, 1, 1);

    gtk_widget_set_sensitive (w->start, TRUE);
    gtk_widget_set_sensitive (w->cancel, FALSE);

    g_signal_connect (w->start, "clicked", G_CALLBACK (start_clicked), w);
    g_signal_connect (w->cancel, "clicked", G_CALLBACK (cancel_clicked), w);
    g_signal_connect (w->win, "destroy", G_CALLBACK (gtk_main_quit), NULL);

    g_mutex_init (&w->mutex);

    gtk_widget_show_all (w->win);

    return w;
}

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

    create_main_win ();
    gtk_main ();

    return 0;
}

_________________
E.


Top
 Profile  
 
 Post subject: Re: a documentation whine
PostPosted: Tue Oct 29, 2013 3:31 pm 
Offline
Familiar Face

Joined: Tue Oct 08, 2013 6:04 pm
Posts: 13
That's really great! Thank you. Wouldn't it be great if this were part of the documentation for the progress bar? I'm sure my needs are not unique.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group