printoperation: fix another case where operation may complete twice
authorMichael Catanzaro <mcatanzaro@redhat.com>
Tue, 26 Sep 2023 23:52:37 +0000 (18:52 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 28 Sep 2023 00:42:45 +0000 (20:42 -0400)
This is a little tricky. At first, I thought we had a codepath where we
fail to schedule the idle that completes the print operation: if we take
the gtk_print_backend_printer_list_is_done path for each printer
backend, then printer_list_done_cb() is never executed and we never
schedule the idle. But in fact, in this case, then backends == NULL at
the bottom of find_printer(), and we'll schedule the idle there, so it's
OK. Except it's not really OK, because we'll schedule it even if a
printer was already found, resulting in the callback completing twice
and a double free.

Simplify this. Schedule the idle in find_printer() only if there are
*initially* no backends, not also if all backends are immediately ready
and already removed from consideration. Instead, always call
printer_list_done_cb() for every backend in find_printer_init(). After
the previous commit, printer_list_done_cb() will schedule the idle when
appropriate.

printer_list_done_cb() additionally disconnects signals that we did not
connect in this codepath, but it does so using
g_signal_handlers_disconnect_by_func, which is harmless. Otherwise, the
only extra work it's doing is scheduling the idle, and that's exactly
what find_printer_init() is missing.

gtk/print/gtkprintoperation-unix.c

index 7a6fb04254f2fa14f9ed52767591a57b541d4ed7..4d592eeb6cddeb07064dae1d72f3180a95772511 100644 (file)
@@ -1165,9 +1165,7 @@ find_printer_init (PrinterFinder   *finder,
 
   if (gtk_print_backend_printer_list_is_done (backend))
     {
-      finder->backends = g_list_remove (finder->backends, backend);
-      gtk_print_backend_destroy (backend);
-      g_object_unref (backend);
+      printer_list_done_cb (backend, finder);
     }
   else
     {
@@ -1229,14 +1227,17 @@ find_printer (const char *printer,
   if (g_module_supported ())
     finder->backends = gtk_print_backend_load_modules ();
 
+  if (finder->backends == NULL)
+    {
+      g_idle_add (find_printer_idle, finder);
+      return;
+    }
+
   for (node = finder->backends; !finder->found_printer && node != NULL; node = next)
     {
       next = node->next;
       find_printer_init (finder, GTK_PRINT_BACKEND (node->data));
     }
-
-  if (finder->backends == NULL)
-    g_idle_add (find_printer_idle, finder);
 }