After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 346903 - gtk_enumerate_printers needs events to complete
gtk_enumerate_printers needs events to complete
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Printing
2.10.x
Other Linux
: Normal normal
: ---
Assigned To: gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2006-07-07 14:55 UTC by Carolyn_MacLeod
Modified: 2011-02-04 16:10 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
a little patch to not freeze gtk_enumerate_printers (not final) (7.89 KB, patch)
2008-08-26 14:49 UTC, Marek Kašík
none Details | Review
a patch to not freeze gtk_enumerate_printers (19.77 KB, patch)
2008-08-29 10:50 UTC, Marek Kašík
reviewed Details | Review
newer patch to not freeze gtk_enumerate_printers (22.99 KB, patch)
2008-09-09 12:28 UTC, Marek Kašík
reviewed Details | Review
actualized patch (22.96 KB, patch)
2008-09-15 12:36 UTC, Marek Kašík
none Details | Review
actualized patch (23.63 KB, patch)
2008-09-16 12:53 UTC, Marek Kašík
none Details | Review
using a GtkPrintBackend::status property (25.66 KB, patch)
2008-09-17 21:52 UTC, Matthias Clasen
committed Details | Review

Description Carolyn_MacLeod 2006-07-07 14:55:37 UTC
This problem was originally noted in bug 344074 comment 14 in gtk+ 2.9.4. The problem is still present in 2.10.0 - in fact, it seems slightly worse.

The problem is that I need to "wiggle the mouse" (or click, or use keyboard... often several times...) in order to get the enumeration to proceed.

The GtkPrinterFunc is always called right away for the file backend, but the cups backend seems to need a "kick-start" to get the event loop rolling so that it can call the GtkPrinterFunc. Once the enumeration proceedes, it continues all the way to the end. I only have the file & cups backends, so I cannot comment on whether every backend switch needs events.

The problem becomes even more apparent - and critical - when there is no GUI to send events to. For example, the following code never returns.

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

/*
gcc -g -o p `pkg-config --cflags --libs gtk+-2.0 gtk+-unix-print-2.0` test.c
*/

int printer_cb (GtkPrinter  *printer,  void *data) {
	printf ("\tprinter cb %s default: %i\n", gtk_printer_get_name(printer), gtk_printer_is_default(printer));
	return gtk_printer_is_default(printer);
}

int main (int argc, char** argv) {
	gtk_init_check (&argc, &argv);
	
	gtk_enumerate_printers(printer_cb, 0, 0, 1);
	printf ("------------------------\n");
}
Comment 1 Matthias Clasen 2006-07-17 18:51:21 UTC
hmm. thats unfortunate, and probably not easy to fix.
Comment 2 Carolyn_MacLeod 2006-07-17 19:32:17 UTC
Yeah, I wondered. I'm sorry I just left the comment in the old bug to mark the problem, and didn't open a new bug for this before 2.10 - my fault there.

Do you really need to run an event loop to get the list of printers?
We were hoping to avoid that, which is why we requested the 'printer list' feature instead of just asking the backends ourselves.
Comment 3 Carolyn_MacLeod 2006-08-23 21:26:50 UTC
Please note that this is now blocking eclipse bug:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=153936
Comment 4 Matthias Clasen 2006-08-31 17:07:07 UTC
Hmm, I have tried to reproduce this, but your little test program
works nicely for me. It first logs the file printer, then it sits
for a bit, and then it dumps a whole list of printers it got from
cups.

Comment 5 Carolyn_MacLeod 2006-08-31 21:08:10 UTC
I am leaving for a week's vacation in about 2 minutes. I'll try it again with the latest gtk printing code when I get back. How long is "a bit"?
Comment 6 Matthias Clasen 2006-08-31 21:43:13 UTC
"a bit" is measured in seconds, not minutes. not that long, really
Comment 7 Carolyn_MacLeod 2006-09-13 21:09:12 UTC
Tried gtk 2.10.3 and both my C code and my Java code work now. You must have fixed something else in the same area, and got a free fix on the side <grin>.
You can close this bug now. Thanks! ("a bit" is about 3 seconds for me, FYI)
Comment 8 Matthias Clasen 2006-09-14 16:16:35 UTC
great, I'll close this bug then.
Comment 9 Matthias Clasen 2008-08-15 21:16:05 UTC
Ok, so this bug has reappeared, at least I have a new Fedora bug report for it.
And I think I understand what is happening now. This is just a case of cups not responding, so we should perhaps use Mareks nonblocking cups work to handle request_printer_list, too.

Comment 10 Marek Kašík 2008-08-22 14:03:29 UTC
Hi,
there is a problem with the cups_request_printer_list (). It is started every 3 seconds and looks for cups backend's got_default_printer flag. If it is FALSE then it tries it at next 3 seconds. If it is TRUE then it try to retrieve printer list from CUPS server (blocking connection).
The got_default_printer is set in cups_request_default_printer which is called at init of cups backend. But cups_request_default_printer perform non-blocking test  of CUPS server availability. It has no MAX_ATTEMPTS value, it performs such test until the server is available.

One possible way how to fix this is:
a) add MAX_ATTEMPTS variable for cups_request_default_printer connection tests (and make it changeable)
b) change cups_request_printer_list to non-blocking (with MAX_ATTEMPTS too)
c) cancel dependency of cups_request_printer_list on got_default_printer flag

But in GtkPrintUnixDialog we need to set max_attempts to infinity (or zero :-) ) to be able to dynamically populate dialog with printers from newly started server (which was stopped before, or unreachable).

  Regards

    Marek
Comment 11 Matthias Clasen 2008-08-26 03:08:43 UTC
Hey Marek, a couple of comments:

1) Looking at cups_request_default_printer, I think it does the connection test a bit too early, maybe. We could easily do the envvar checks before testing the cups availability...

2) I think we need to understand why request_printer_list is waiting for got_default_printer. I believe the idea is that we don't want to first populate the printer list, select the first, only to flicker when the selection jumps to the default printer later. One idea to avoid doing things this way would be to get the information about the default printer at the same time as we are getting the printer list. From reading the cups documentation at http://www.cups.org/documentation.php/spec-ipp.html it seems to me that we should be able to do that by requesting the printer-type attribute and looking for the 
bit:

0x00020000  	Is the a default printer on the network.

(of course, we still need to look for the envvars first)

3) Why do you think we need some MAX_ATTEMPTS limit ? Shouldn't we just keep trying to get the printer list (without blocking) until we succeed ?
Comment 12 Marek Kašík 2008-08-26 14:02:07 UTC
Hey Matthias,
1) Yes, the connection test should be done after those envvar checks.
2) It sounds like good idea (and it works). :) Only one problem I see is that the "printer-type" attribute exists from CUPS 1.1.7, so we need to preserve the old method of getting default printer's name.
3) The problem is that the gtk_enumerate_printer waits for list of printers (printer_list->loop). We need to tell that we won't wait longer.
There is one other way how to handle this. We can stop looking for the printers if the server is not available, but we will loose ability to populate GtkPrintDialog with printers if the server become online during run of GtkPrintDialog (or we can set some flag to indicate that we will wait if the server is not available - change of API).

  Marek
Comment 13 Marek Kašík 2008-08-26 14:49:58 UTC
Created attachment 117407 [details] [review]
a little patch to not freeze gtk_enumerate_printers (not final)

This patch changes a little gtk_cups_connection_test_is_server_available() function. It returns GtkCupsConnectionState. It tells whether the connection is available, not available or in progress. It is used in cups_request_printer_list() to quit from g_main_loop (PrinterList->loop) if the connection is not available. (the ability to populate GtkPrintDialog with printers after reconnecting unreachable server is lost - there is not the flag yet)

  Marek
Comment 14 Matthias Clasen 2008-08-27 19:57:48 UTC
Quick comments:

1) the gtkprinter.c change looks wrong

2) it appears to me that we should maybe only have a single connection test and use it for both the default-printer and the list-printers requests ? Is there any value to having to separate connection test instances ?
Comment 15 Marek Kašík 2008-08-29 10:50:59 UTC
Created attachment 117578 [details] [review]
a patch to not freeze gtk_enumerate_printers

Hi,
this patch:
1) change behaviour of gtk_enumerate_printer() (it is not waiting if the CUPS server is not available)

2) change cups_connection_test_is_server_available() to (more appropriate now) cups_connection_test_get_state()

3) cancels dependency of cups_request_printer_list() on got_default_printer flag (we acquire default printer flag during cups_request_printer_list(), but we preserve old method for compatibility with old CUPS)

  Regards

    Marek

P.S.:
"1) the gtkprinter.c change looks wrong" - It is not clear to me why is the GDK_THREADS_LEAVE before GDK_THREADS_ENTER (do we need this outside of a critical section?)
Comment 16 Matthias Clasen 2008-08-29 16:20:14 UTC
gtk_enumerate_printers is a public gtk function, so apps are supposed to hold the gdk lock when calling it. Therefore, we need to drop the lock before entering the recursive mainloop, and reacquire it afterwards. This is the same as in gtk_main()...
Comment 17 Matthias Clasen 2008-08-29 16:57:08 UTC
Patch looks good on a quick first look. One thing I notice is we may need to check the server version when deciding whether to get printer-type or do the separate get-default request, not just the version fo the client-side libraries.
Comment 18 Marek Kašík 2008-09-01 13:54:50 UTC
Hi Matthias,
the problem is that only one method to get CUPS version is requesting "cups-version" attribute. But this attribute is present from CUPS version 1.3b1 :) ("printer-type" attribute from 1.1.7). So, if we want to find out whether the "printer-type" attribute is present, we have to inspect returned set of attributes.
But this is a problem. The decision to start old-style cups_get_default_printer() is coming too late and the printer list is shown without having default printer selected.

  Regards

    Marek
Comment 19 Matthias Clasen 2008-09-06 03:33:41 UTC
Yeah, well. The worst that can happen is that there is a little bit of flashing when we select the default later, right ?
Comment 20 Marek Kašík 2008-09-09 12:28:11 UTC
Created attachment 118354 [details] [review]
newer patch to not freeze gtk_enumerate_printers

Hi,
if the "printer-type" attribute is not present then the default printer is requested from CUPS. Therefore, default printer is selected later in such a case. I lowered timeout of requesting default printer, so it doesn't take much time (something about 1 second). If user select another printer in the meantime then the default printer is not selected by the program.

  Regards

    Marek
Comment 21 Matthias Clasen 2008-09-11 03:23:33 UTC
+      if (got_printer_type)
+        {
+          if (default_printer && !cups_backend->got_default_printer)
+            {
+              cups_backend->got_default_printer = TRUE;
+              cups_backend->default_printer = g_strdup (printer_name);
+            }
+        }
+      else
+        {
+          if (!cups_backend->got_default_printer)
+            cups_get_default_printer (cups_backend);
+        }

Hmm, this is run for each printer that gets listed, right ? 
In the !got_printer_type case, won't it call cups_get_default_printer repeatedly ?


I'm not really happy with the printer_list_wait api. Looking at the uses of the function, it is called exactly once. It appears to me that the cups backend should be able to figure this out without the extra api. I mean, the flag is initially set to TRUE, and the only place where it is ever changed is if somebody calls enumerate_printers, when it is set to FALSE. If we really need a flag for that, I'd prefer to have it as

GList *gtk_print_backend_get_printer_list (GtkPrintBackend *backend, gboolean wait_for_server);



 
Comment 22 Marek Kašík 2008-09-11 08:14:23 UTC
Hi Matthias,
the function cups_get_default_printer() is called for each printer in the "!got_printer_type" case. But there is a test at beginning of this function which prevents the function to request the default printer. I didn't want to duplicate this test because of easier maintenance of the code.

The flag is necessary. We need to distinguish between 2 cases. The first is when we need to know whether the CUPS server is not available and we should stop looking for him and print informations we have (console applications). And the second is the case when we have GUI (for example GtkPrintDialog) and we want to be able to list printers from server which has been connected after the start of the dialog.
The second case is more often, so the initial setting of "wait" flag to TRUE.

I didn't want to change API of already present functions, so I created new functions gtk_print_backend_set_printer_list_wait and gtk_print_backend_get_printer_list_wait. But I can change it, it looks better.

  Regards

    Marek
Comment 23 Matthias Clasen 2008-09-11 12:11:02 UTC
Ok, it just doesn't look to me like the current code will actually work right with the flag in all cases. It is set to true initially, but never thereafter.
So, if I call gtk_enumerate_printers and later bring up the print dialog, it will have been set to FALSE and we will not wait anymore even though we want to populate the ui. I think putting the flag directly into the list_printers api will help with that, too, since it means we have to specify each time if we want to wait or not.

Another, slighlty hypthetical case: what happens if I call gtk_enumerate_printers while the print dialog is open and waiting for the server ?
Comment 24 Marek Kašík 2008-09-15 12:36:53 UTC
Created attachment 118741 [details] [review]
actualized patch

Hi Matthias,
the function gtk_enumerate_printers allocates its own backends. Therefore the two backends called by these two ways are independent (almost).
One problem is executing g_main_loop_run() inside of gtk_enumerate_printers if GtkPrintDialog is running and vice-versa case. In such a case the dialog stops react to events. It starts to react after finishing of the gtk_enumerate_printers (if it finish).
When the gtk_enumerate_printers is executed before GtkPrintDialog the dialog doesn't show until end of the gtk_enumerate_printer function.

Another inconvenience is in propagating of the parameter "wait_for_server", you have to insert it into definitions of these functions:
gtk_print_backend_get_printer_list
cups_get_printer_list
cups_request_printer_list
cups_request_printer_list_cb
cups_get_default_printer
cups_request_default_printer
cups_request_default_printer_cb

And there is another problem. You need to pass a pointer with user data in gdk_threads_add_timeout_*. Pointer to the backend is passed in all cases. But there is no place for another parameter such as gboolean. You have to pass it using the pointer, so you have to insert it into backend or to a derived structure.

We can say that calling of the gtk_enumerate_printers shouln't overlap executing of GtkPrintDialog.
I tested it.

  Regards

    Marek


P.S.: The attached patch is similar to the previous one but handles some unlike situations.
Comment 25 Matthias Clasen 2008-09-16 05:08:29 UTC
> Another inconvenience is in propagating of the parameter "wait_for_server", you
> have to insert it into definitions of these functions:
> gtk_print_backend_get_printer_list
> cups_get_printer_list
> cups_request_printer_list
> cups_request_printer_list_cb
> cups_get_default_printer
> cups_request_default_printer
> cups_request_default_printer_cb

Ah, hmm. I had envisioned just adding the parameter to get_printer_list, and then use a flag in the printbackend struct, like you do now. 
Comment 26 Marek Kašík 2008-09-16 12:53:19 UTC
Created attachment 118822 [details] [review]
actualized patch

Hi Matthias,
I reworked it. The gtk_print_backend_get_printer_list() function accepts second parameter now. The parameter is the "wait_for_server" flag, which it stores to the backend and use then.

  Marek
Comment 27 Matthias Clasen 2008-09-16 21:23:01 UTC
Looks good now, pretty much. I think we can easily get away without adding 
gtk_print_backend_get_wait_for_server to the backend api. The two uses inside the cups backend can just use the flag directly, imo.
Comment 28 Marek Kašík 2008-09-17 11:32:15 UTC
There is a little inconvenience that wait_for_server flag is defined in GtkPrintBackendPrivate, so I can not use the flag directly. Therefore I defined the new function.

  Marek
Comment 29 Matthias Clasen 2008-09-17 19:12:40 UTC
Hmm, looking at this patch in more depth, I'm not really happy with the way the wait_for_server flag is kept in the GtkPrintBackend class, instead of in the cups backend, where it is used. Other print backends don't even have a notion of 'server', so it feels like something that should be cups-backend-specific.

I think I'd much rather see this done slightly differently, with the cups backend keeping track of the connection status, and emitting a signal when the status changes. A handler of that signal could then be used to break the wait in gtk_enumerate_printers.

I'll try to rework the patch in that direction later tonight.
Comment 30 Matthias Clasen 2008-09-17 21:52:56 UTC
Created attachment 118909 [details] [review]
using a GtkPrintBackend::status property

This is the patch I'm going to commit.

We can probably also make use of the backend status information to display some helpful hint in the print dialog, if the cups server is unavailable.
Comment 31 Matthias Clasen 2008-09-17 22:07:30 UTC
2008-09-17  Matthias Clasen  <mclasen@redhat.com>

        Bug 346903 – gtk_enumerate_printers needs events to complete

        * gtk/gtkprintbackend.h:
        * gtk/gtkprintbackend.c: Add a GtkPrintBackend::status property.

        * modules/printbackends/cups/gtkcupsutils.h:
        * modules/printbackends/cups/gtkcupsutils.c: Turn the connection
        test into a tristate available/unavailable/in progress.

        * modules/printbackends/cups/gtkprintbackendcups.c: Use a single
        connection test instance for getting the default printer and for
        getting the printer list. Set the GtkPrintBackend::status property
        according to the result of the connection test. Use the printer-type
        attribute to find the default printer, if cups supports it.

        * gtk/gtkprinter.c: When enumerating printers, give up when
        the backend status is 'unavailable'.

        * gtk/gtkprintunixdialog.c (printer_status_cb): Select the printer
        when it is the default and nothing else has been selected yet.
Comment 32 Carolyn_MacLeod 2008-10-17 15:55:51 UTC
I suspect that this fix has broken eclipse. We are hanging (again) when calling gtk_enumerate_printers: https://bugs.eclipse.org/bugs/show_bug.cgi?id=153936

Can you confirm for me that this fix is in gtk+-2.14.3-r2 ?
Can you also please confirm that gtk+-2.14.3-r2 is built without the "-cups" flag?

Was this fix tested with gtk built without the "-cups" flag?
Comment 33 Carolyn_MacLeod 2008-10-17 16:04:35 UTC
> Was this fix tested with gtk built without the "-cups" flag?

That sentence sounds 'grumpy' <g>, but that was not the intent. I only mentioned it because our user who reported the problem mentioned that he rebuilt with "-cups" and the problem went away. Not sure if that's a clue or not.
Comment 34 Javier Jardón (IRC: jjardon) 2010-10-29 16:53:48 UTC
Thank you for taking the time to report this bug and helping to make GTK+ better.

We are sorry that we do not always have the capacity to look at all reported bugs in a timely manner. There have been many changes in GTK+ since that time you reported the bug and your problem may have been fixed with some of the updates.

It would help us a lot if you could test a current, supported, GTK+ version (2.22 or, even better, current master). If you can test it, and it is still an issue, we would appreciate if you could upload any log / test case that are relevant for this particular issue.
Comment 35 Tobias Mueller 2011-02-01 11:21:18 UTC
The fix will be in any recent GTK+. Please reopen if this is not the case. Thanks.