diff options
-rw-r--r-- | plugins/print-notifications/gsd-print-notifications-manager.c | 287 |
1 files changed, 234 insertions, 53 deletions
diff --git a/plugins/print-notifications/gsd-print-notifications-manager.c b/plugins/print-notifications/gsd-print-notifications-manager.c index 53aaccff..6735110f 100644 --- a/plugins/print-notifications/gsd-print-notifications-manager.c +++ b/plugins/print-notifications/gsd-print-notifications-manager.c @@ -44,6 +44,14 @@ #define CUPS_DBUS_PATH "/org/cups/cupsd/Notifier" #define CUPS_DBUS_INTERFACE "org.cups.cupsd.Notifier" +#define GSD_DBUS_NAME "org.gnome.SettingsDaemon" +#define GSD_DBUS_PATH "/org/gnome/SettingsDaemon" +#define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon" + +#define GSD_PRINT_NOTIFICATIONS_DBUS_NAME GSD_DBUS_NAME ".PrintNotifications" +#define GSD_PRINT_NOTIFICATIONS_DBUS_PATH GSD_DBUS_PATH "/PrintNotifications" +#define GSD_PRINT_NOTIFICATIONS_DBUS_INTERFACE GSD_DBUS_BASE_INTERFACE ".PrintNotifications" + #define RENEW_INTERVAL 3500 #define SUBSCRIPTION_DURATION 3600 #define CONNECTING_TIMEOUT 60 @@ -73,11 +81,26 @@ ippNextAttribute (ipp_t *ipp) } #endif +/* + * Ignored events for print jobs are stored as "1 << value" + * where the value is from ipp_jstate_t enum which ranges from 3 to 9. + */ +static const gchar introspection_xml[] = +"<node>" +" <interface name='org.gnome.SettingsDaemon.PrintNotifications'>" +" <method name='DoNotNotifyJob'>" +" <arg name='job-id' direction='in' type='i'/>" +" <arg name='ignored-events' direction='in' type='t'/>" +" </method>" +" </interface>" +"</node>"; + struct _GsdPrintNotificationsManager { GObject parent; GDBusConnection *cups_bus_connection; + GDBusConnection *session_bus_connection; gint subscription_id; cups_dest_t *dests; gint num_dests; @@ -93,6 +116,10 @@ struct _GsdPrintNotificationsManager gint last_notify_sequence_number; guint start_idle_id; GList *held_jobs; + + guint name_id; + GDBusNodeInfo *introspection_data; + GList *ignored_jobs; }; static void gsd_print_notifications_manager_class_init (GsdPrintNotificationsManagerClass *klass); @@ -557,6 +584,38 @@ check_job_for_authentication (gpointer userdata) return G_SOURCE_REMOVE; } +struct +{ + gint job_id; + guint64 ignored_events; +} typedef TIgnoredJob; + +static TIgnoredJob * +find_ignored_job (GsdPrintNotificationsManager *manager, + gint job_id) +{ + TIgnoredJob *ignored_job = NULL; + GList *iter; + + for (iter = manager->ignored_jobs; iter != NULL; iter = iter->next) { + if (((TIgnoredJob *) iter->data)->job_id == job_id) { + ignored_job = (TIgnoredJob *) iter->data; + } + } + + return ignored_job; +} + +static void +remove_ignored_job (GsdPrintNotificationsManager *manager, + TIgnoredJob *ignored_job) +{ + if (ignored_job != NULL) { + manager->ignored_jobs = g_list_remove (manager->ignored_jobs, ignored_job); + g_free (ignored_job); + } +} + static void process_cups_notification (GsdPrintNotificationsManager *manager, const char *notify_subscribed_event, @@ -573,6 +632,7 @@ process_cups_notification (GsdPrintNotificationsManager *manager, gint job_impressions_completed) { ipp_attribute_t *attr; + TIgnoredJob *ignored_job = NULL; gboolean my_job = FALSE; gboolean known_reason; HeldJob *held_job; @@ -657,6 +717,8 @@ process_cups_notification (GsdPrintNotificationsManager *manager, g_free (job_uri); httpClose (http); } + + ignored_job = find_ignored_job (manager, notify_job_id); } if (g_strcmp0 (notify_subscribed_event, "printer-added") == 0) { @@ -683,72 +745,102 @@ process_cups_notification (GsdPrintNotificationsManager *manager, case IPP_JOB_PROCESSING: break; case IPP_JOB_STOPPED: - /* Translators: A print job has been stopped */ - primary_text = g_strdup (C_("print job state", "Printing stopped")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_STOPPED))) { + /* Translators: A print job has been stopped */ + primary_text = g_strdup (C_("print job state", "Printing stopped")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } break; case IPP_JOB_CANCELED: - /* Translators: A print job has been canceled */ - primary_text = g_strdup (C_("print job state", "Printing canceled")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_CANCELED))) { + /* Translators: A print job has been canceled */ + primary_text = g_strdup (C_("print job state", "Printing canceled")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; case IPP_JOB_ABORTED: - /* Translators: A print job has been aborted */ - primary_text = g_strdup (C_("print job state", "Printing aborted")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_ABORTED))) { + /* Translators: A print job has been aborted */ + primary_text = g_strdup (C_("print job state", "Printing aborted")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; case IPP_JOB_COMPLETED: - /* Translators: A print job has been completed */ - primary_text = g_strdup (C_("print job state", "Printing completed")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_COMPLETED))) { + /* Translators: A print job has been completed */ + primary_text = g_strdup (C_("print job state", "Printing completed")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; } } else if (g_strcmp0 (notify_subscribed_event, "job-state-changed") == 0 && my_job) { switch (job_state) { case IPP_JOB_PROCESSING: - g_hash_table_insert (manager->printing_printers, - g_strdup (printer_name), NULL); - - /* Translators: A job is printing */ - primary_text = g_strdup (C_("print job state", "Printing")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_PROCESSING))) { + g_hash_table_insert (manager->printing_printers, + g_strdup (printer_name), NULL); + + /* Translators: A job is printing */ + primary_text = g_strdup (C_("print job state", "Printing")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } break; case IPP_JOB_STOPPED: - g_hash_table_remove (manager->printing_printers, - printer_name); - /* Translators: A print job has been stopped */ - primary_text = g_strdup (C_("print job state", "Printing stopped")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_STOPPED))) { + g_hash_table_remove (manager->printing_printers, + printer_name); + /* Translators: A print job has been stopped */ + primary_text = g_strdup (C_("print job state", "Printing stopped")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } break; case IPP_JOB_CANCELED: - g_hash_table_remove (manager->printing_printers, - printer_name); - /* Translators: A print job has been canceled */ - primary_text = g_strdup (C_("print job state", "Printing canceled")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_CANCELED))) { + g_hash_table_remove (manager->printing_printers, + printer_name); + /* Translators: A print job has been canceled */ + primary_text = g_strdup (C_("print job state", "Printing canceled")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; case IPP_JOB_ABORTED: - g_hash_table_remove (manager->printing_printers, - printer_name); - /* Translators: A print job has been aborted */ - primary_text = g_strdup (C_("print job state", "Printing aborted")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_ABORTED))) { + g_hash_table_remove (manager->printing_printers, + printer_name); + /* Translators: A print job has been aborted */ + primary_text = g_strdup (C_("print job state", "Printing aborted")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; case IPP_JOB_COMPLETED: - g_hash_table_remove (manager->printing_printers, - printer_name); - /* Translators: A print job has been completed */ - primary_text = g_strdup (C_("print job state", "Printing completed")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_COMPLETED))) { + g_hash_table_remove (manager->printing_printers, + printer_name); + /* Translators: A print job has been completed */ + primary_text = g_strdup (C_("print job state", "Printing completed")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } else { + remove_ignored_job (manager, ignored_job); + } break; case IPP_JOB_HELD: held_job = g_new (HeldJob, 1); @@ -766,13 +858,15 @@ process_cups_notification (GsdPrintNotificationsManager *manager, } } else if (g_strcmp0 (notify_subscribed_event, "job-created") == 0 && my_job) { if (job_state == IPP_JOB_PROCESSING) { - g_hash_table_insert (manager->printing_printers, - g_strdup (printer_name), NULL); + if (ignored_job == NULL || !(ignored_job->ignored_events & (1 << IPP_JOB_PROCESSING))) { + g_hash_table_insert (manager->printing_printers, + g_strdup (printer_name), NULL); - /* Translators: A job is printing */ - primary_text = g_strdup (C_("print job state", "Printing")); - /* Translators: "print-job xy" on a printer */ - secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + /* Translators: A job is printing */ + primary_text = g_strdup (C_("print job state", "Printing")); + /* Translators: "print-job xy" on a printer */ + secondary_text = g_strdup_printf (C_("print job", "“%s” on %s"), job_name, printer_name); + } } } else if (g_strcmp0 (notify_subscribed_event, "printer-state-changed") == 0) { cups_dest_t *dest = NULL; @@ -1514,6 +1608,73 @@ gsd_print_notifications_manager_got_dbus_connection (GObject *source_object } } +static void +handle_method_call (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + GsdPrintNotificationsManager *manager = GSD_PRINT_NOTIFICATIONS_MANAGER (user_data); + + if (g_strcmp0 (method_name, "DoNotNotifyJob") == 0) { + TIgnoredJob *ignored_job; + guint64 events = 0; + gint job_id = 0; + + g_variant_get (parameters, "(it)", &job_id, &events); + + if (job_id > 0 && events > 0) { + ignored_job = g_new (TIgnoredJob, 1); + ignored_job->job_id = job_id; + ignored_job->ignored_events = events; + manager->ignored_jobs = g_list_prepend (manager->ignored_jobs, ignored_job); + } + + g_dbus_method_invocation_return_value (invocation, NULL); + } else { + g_assert_not_reached (); + } +} + +static const GDBusInterfaceVTable interface_vtable = +{ + handle_method_call, + NULL, + NULL +}; + +static void +gsd_print_notifications_manager_got_session_dbus_connection (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GsdPrintNotificationsManager *manager = (GsdPrintNotificationsManager *) user_data; + GError *error = NULL; + + manager->session_bus_connection = g_bus_get_finish (res, &error); + if (manager->session_bus_connection != NULL) { + g_dbus_connection_register_object (manager->session_bus_connection, + GSD_PRINT_NOTIFICATIONS_DBUS_PATH, + manager->introspection_data->interfaces[0], + &interface_vtable, + manager, + NULL, + NULL); + + manager->name_id = g_bus_own_name_on_connection (manager->session_bus_connection, + GSD_PRINT_NOTIFICATIONS_DBUS_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + NULL, NULL, NULL, NULL); + } else { + g_warning ("Connection to message bus failed: %s", error->message); + g_error_free (error); + } +} + static gboolean gsd_print_notifications_manager_start_idle (gpointer data) { @@ -1523,6 +1684,11 @@ gsd_print_notifications_manager_start_idle (gpointer data) manager->printing_printers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_bus_get (G_BUS_TYPE_SESSION, + NULL, + gsd_print_notifications_manager_got_session_dbus_connection, + data); + /* * Set a password callback which cancels authentication * before we prepare a correct solution (see bug #725440). @@ -1569,6 +1735,10 @@ gsd_print_notifications_manager_start (GsdPrintNotificationsManager *manager, manager->cups_connection_timeout_id = 0; manager->last_notify_sequence_number = -1; manager->held_jobs = NULL; + manager->ignored_jobs = NULL; + manager->session_bus_connection = NULL; + manager->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); + g_assert (manager->introspection_data != NULL); manager->start_idle_id = g_idle_add (gsd_print_notifications_manager_start_idle, manager); g_source_set_name_by_id (manager->start_idle_id, "[gnome-settings-daemon] gsd_print_notifications_manager_start_idle"); @@ -1588,6 +1758,17 @@ gsd_print_notifications_manager_stop (GsdPrintNotificationsManager *manager) g_debug ("Stopping print-notifications manager"); + if (manager->name_id != 0) { + g_bus_unown_name (manager->name_id); + manager->name_id = 0; + } + + g_clear_object (&manager->session_bus_connection); + + g_clear_pointer (&manager->introspection_data, g_dbus_node_info_unref); + + g_list_free_full (manager->ignored_jobs, g_free); + cupsFreeDests (manager->num_dests, manager->dests); manager->num_dests = 0; manager->dests = NULL; |