gnome-control-center/panels/printers/cc-printers-panel.c
Marek Kasik 45ba8e89e8 printers: Redesign of new printer dialog
This commit implements design changes from
https://live.gnome.org/Design/SystemSettings/Printers.

The new printer dialog gets informations about connected devices
from CUPS server asynchronously and separately for each backend now.

Entering an address into the entry and pressing the icon inside
the entry or enter starts to detect printers on the entered host.

Entering a text which is a substring of a name of a device or its location
filters the list to contain just devicess with the string in it (e.g. Canon
will keep devices with "Canon" in their name).

The PpNewPrinterDialog is regular object now. It emits signal "pre-response"
when dialog is closed and a printer is being added and signal "response" when
the new printer was added, addition of the new printer failed or the dialog was
cancelled.
This commit removes FirewallD support from new printer dialog. (#683229)
2012-09-04 14:09:06 +02:00

3012 lines
100 KiB
C

/*
* Copyright (C) 2010 Red Hat, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include <config.h>
#include "cc-printers-panel.h"
#include <string.h>
#include <glib/gi18n-lib.h>
#include <glib/gstdio.h>
#include <polkit/polkit.h>
#include <gdesktop-enums.h>
#include <cups/cups.h>
#include <math.h>
#include "cc-editable-entry.h"
#include "pp-new-printer-dialog.h"
#include "pp-ppd-selection-dialog.h"
#include "pp-options-dialog.h"
#include "pp-jobs-dialog.h"
#include "pp-utils.h"
#include "pp-maintenance-command.h"
CC_PANEL_REGISTER (CcPrintersPanel, cc_printers_panel)
#define PRINTERS_PANEL_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_PRINTERS_PANEL, CcPrintersPanelPrivate))
#define SUPPLY_BAR_HEIGHT 20
#define EMPTY_TEXT "\xe2\x80\x94"
#define RENEW_INTERVAL 500
#define SUBSCRIPTION_DURATION 600
#define CUPS_DBUS_NAME "org.cups.cupsd.Notifier"
#define CUPS_DBUS_PATH "/org/cups/cupsd/Notifier"
#define CUPS_DBUS_INTERFACE "org.cups.cupsd.Notifier"
#define CUPS_STATUS_CHECK_INTERVAL 5
#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
#define HAVE_CUPS_1_6 1
#endif
#ifndef HAVE_CUPS_1_6
#define ippGetState(ipp) ipp->state
#define ippGetStatusCode(ipp) ipp->request.status.status_code
#define ippGetString(attr, element, language) attr->values[element].string.text
#endif
struct _CcPrintersPanelPrivate
{
GtkBuilder *builder;
cups_dest_t *dests;
gchar **dest_model_names;
gchar **ppd_file_names;
int num_dests;
int current_dest;
int num_jobs;
GdkRGBA background_color;
GPermission *permission;
GSettings *lockdown_settings;
PpNewPrinterDialog *pp_new_printer_dialog;
PpPPDSelectionDialog *pp_ppd_selection_dialog;
PpOptionsDialog *pp_options_dialog;
PpJobsDialog *pp_jobs_dialog;
GDBusProxy *cups_proxy;
GDBusConnection *cups_bus_connection;
gint subscription_id;
guint subscription_renewal_id;
guint cups_status_check_id;
guint dbus_subscription_id;
GtkWidget *popup_menu;
GList *driver_change_list;
GCancellable *get_ppd_name_cancellable;
gboolean getting_ppd_names;
PPDList *all_ppds_list;
GHashTable *preferred_drivers;
GCancellable *get_all_ppds_cancellable;
gchar *new_printer_name;
gchar *new_printer_location;
gchar *new_printer_make_and_model;
gboolean new_printer_on_network;
gboolean select_new_printer;
gpointer dummy;
};
typedef struct
{
gchar *printer_name;
GCancellable *cancellable;
} SetPPDItem;
static void update_jobs_count (CcPrintersPanel *self);
static void actualize_printers_list (CcPrintersPanel *self);
static void update_sensitivity (gpointer user_data);
static void printer_disable_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data);
static void printer_set_default_cb (GtkToggleButton *button, gpointer user_data);
static void detach_from_cups_notifier (gpointer data);
static void free_dests (CcPrintersPanel *self);
static void
cc_printers_panel_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
cc_printers_panel_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
cc_printers_panel_dispose (GObject *object)
{
CcPrintersPanelPrivate *priv = CC_PRINTERS_PANEL (object)->priv;
if (priv->pp_new_printer_dialog)
g_clear_object (&priv->pp_new_printer_dialog);
free_dests (CC_PRINTERS_PANEL (object));
g_clear_pointer (&priv->new_printer_name, g_free);
g_clear_pointer (&priv->new_printer_location, g_free);
g_clear_pointer (&priv->new_printer_make_and_model, g_free);
if (priv->builder)
{
g_object_unref (priv->builder);
priv->builder = NULL;
}
if (priv->lockdown_settings)
{
g_object_unref (priv->lockdown_settings);
priv->lockdown_settings = NULL;
}
if (priv->permission)
{
g_object_unref (priv->permission);
priv->permission = NULL;
}
detach_from_cups_notifier (CC_PRINTERS_PANEL (object));
if (priv->cups_status_check_id > 0)
{
g_source_remove (priv->cups_status_check_id);
priv->cups_status_check_id = 0;
}
if (priv->all_ppds_list)
{
ppd_list_free (priv->all_ppds_list);
priv->all_ppds_list = NULL;
}
if (priv->preferred_drivers)
{
g_hash_table_unref (priv->preferred_drivers);
priv->preferred_drivers = NULL;
}
if (priv->get_all_ppds_cancellable)
{
g_cancellable_cancel (priv->get_all_ppds_cancellable);
g_object_unref (priv->get_all_ppds_cancellable);
priv->get_all_ppds_cancellable = NULL;
}
if (priv->driver_change_list)
{
GList *iter;
for (iter = priv->driver_change_list; iter; iter = iter->next)
{
SetPPDItem *item = (SetPPDItem *) iter->data;
g_cancellable_cancel (item->cancellable);
g_object_unref (item->cancellable);
g_free (item->printer_name);
g_free (item);
}
g_list_free (priv->driver_change_list);
priv->driver_change_list = NULL;
}
G_OBJECT_CLASS (cc_printers_panel_parent_class)->dispose (object);
}
static void
cc_printers_panel_finalize (GObject *object)
{
G_OBJECT_CLASS (cc_printers_panel_parent_class)->finalize (object);
}
static GPermission *
cc_printers_panel_get_permission (CcPanel *panel)
{
CcPrintersPanelPrivate *priv = CC_PRINTERS_PANEL (panel)->priv;
return priv->permission;
}
static const char *
cc_printers_panel_get_help_uri (CcPanel *panel)
{
return "help:gnome-help/printing";
}
static void
cc_printers_panel_class_init (CcPrintersPanelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
g_type_class_add_private (klass, sizeof (CcPrintersPanelPrivate));
object_class->get_property = cc_printers_panel_get_property;
object_class->set_property = cc_printers_panel_set_property;
object_class->dispose = cc_printers_panel_dispose;
object_class->finalize = cc_printers_panel_finalize;
panel_class->get_permission = cc_printers_panel_get_permission;
panel_class->get_help_uri = cc_printers_panel_get_help_uri;
}
static void
on_cups_notification (GDBusConnection *connection,
const char *sender_name,
const char *object_path,
const char *interface_name,
const char *signal_name,
GVariant *parameters,
gpointer user_data)
{
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
CcPrintersPanelPrivate *priv;
gboolean printer_is_accepting_jobs;
gchar *printer_name = NULL;
gchar *text = NULL;
gchar *printer_uri = NULL;
gchar *printer_state_reasons = NULL;
gchar *job_state_reasons = NULL;
gchar *job_name = NULL;
guint job_id;
gint printer_state;
gint job_state;
gint job_impressions_completed;
static const char * const requested_attrs[] = {
"job-printer-uri",
"job-originating-user-name"};
priv = PRINTERS_PANEL_PRIVATE (self);
if (g_strcmp0 (signal_name, "PrinterAdded") != 0 &&
g_strcmp0 (signal_name, "PrinterDeleted") != 0 &&
g_strcmp0 (signal_name, "PrinterStateChanged") != 0 &&
g_strcmp0 (signal_name, "PrinterStopped") != 0 &&
g_strcmp0 (signal_name, "JobCreated") != 0 &&
g_strcmp0 (signal_name, "JobCompleted") != 0)
return;
if (g_variant_n_children (parameters) == 1)
g_variant_get (parameters, "(&s)", &text);
else if (g_variant_n_children (parameters) == 6)
{
g_variant_get (parameters, "(&s&s&su&sb)",
&text,
&printer_uri,
&printer_name,
&printer_state,
&printer_state_reasons,
&printer_is_accepting_jobs);
}
else if (g_variant_n_children (parameters) == 11)
{
g_variant_get (parameters, "(&s&s&su&sbuu&s&su)",
&text,
&printer_uri,
&printer_name,
&printer_state,
&printer_state_reasons,
&printer_is_accepting_jobs,
&job_id,
&job_state,
&job_state_reasons,
&job_name,
&job_impressions_completed);
}
if (g_strcmp0 (signal_name, "PrinterAdded") == 0 ||
g_strcmp0 (signal_name, "PrinterDeleted") == 0 ||
g_strcmp0 (signal_name, "PrinterStateChanged") == 0 ||
g_strcmp0 (signal_name, "PrinterStopped") == 0)
actualize_printers_list (self);
else if (g_strcmp0 (signal_name, "JobCreated") == 0 ||
g_strcmp0 (signal_name, "JobCompleted") == 0)
{
http_t *http;
gchar *job_uri;
ipp_t *request, *response;
job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", job_id);
if ((http = httpConnectEncrypt (cupsServer (), ippPort (),
cupsEncryption ())) != NULL)
{
request = ippNewRequest (IPP_GET_JOB_ATTRIBUTES);
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
"job-uri", NULL, job_uri);
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
"requesting-user-name", NULL, cupsUser ());
ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
"requested-attributes", G_N_ELEMENTS (requested_attrs), NULL, requested_attrs);
response = cupsDoRequest (http, request, "/");
if (response)
{
if (ippGetStatusCode (response) <= IPP_OK_CONFLICT)
{
ipp_attribute_t *attr_username = NULL;
ipp_attribute_t *attr_printer_uri = NULL;
attr_username = ippFindAttribute(response, "job-originating-user-name", IPP_TAG_NAME);
attr_printer_uri = ippFindAttribute(response, "job-printer-uri", IPP_TAG_URI);
if (attr_username && attr_printer_uri &&
g_strcmp0 (ippGetString (attr_username, 0, NULL), cupsUser ()) == 0 &&
g_strrstr (ippGetString (attr_printer_uri, 0, NULL), "/") != 0 &&
priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL &&
g_strcmp0 (g_strrstr (ippGetString (attr_printer_uri, 0, NULL), "/") + 1,
priv->dests[priv->current_dest].name) == 0)
update_jobs_count (self);
}
ippDelete(response);
}
httpClose (http);
}
g_free (job_uri);
}
}
static gboolean
renew_subscription (gpointer data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) data;
static const char * const events[] = {
"printer-added",
"printer-deleted",
"printer-stopped",
"printer-state-changed",
"job-created",
"job-completed"};
priv = PRINTERS_PANEL_PRIVATE (self);
priv->subscription_id = renew_cups_subscription (priv->subscription_id,
events,
G_N_ELEMENTS (events),
SUBSCRIPTION_DURATION);
if (priv->subscription_id > 0)
return TRUE;
else
return FALSE;
}
static void
attach_to_cups_notifier (gpointer data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) data;
GError *error = NULL;
priv = PRINTERS_PANEL_PRIVATE (self);
if (renew_subscription (self))
{
priv->subscription_renewal_id =
g_timeout_add_seconds (RENEW_INTERVAL, renew_subscription, self);
priv->cups_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
0,
NULL,
CUPS_DBUS_NAME,
CUPS_DBUS_PATH,
CUPS_DBUS_INTERFACE,
NULL,
&error);
if (!priv->cups_proxy)
{
g_warning ("%s", error->message);
g_error_free (error);
return;
}
priv->cups_bus_connection = g_dbus_proxy_get_connection (priv->cups_proxy);
priv->dbus_subscription_id =
g_dbus_connection_signal_subscribe (priv->cups_bus_connection,
NULL,
CUPS_DBUS_INTERFACE,
NULL,
CUPS_DBUS_PATH,
NULL,
0,
on_cups_notification,
self,
NULL);
}
}
static void
detach_from_cups_notifier (gpointer data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) data;
priv = PRINTERS_PANEL_PRIVATE (self);
if (priv->dbus_subscription_id != 0) {
g_dbus_connection_signal_unsubscribe (priv->cups_bus_connection,
priv->dbus_subscription_id);
priv->dbus_subscription_id = 0;
}
cancel_cups_subscription (priv->subscription_id);
priv->subscription_id = 0;
if (priv->subscription_renewal_id != 0) {
g_source_remove (priv->subscription_renewal_id);
priv->subscription_renewal_id = 0;
}
if (priv->cups_proxy != NULL) {
g_object_unref (priv->cups_proxy);
priv->cups_proxy = NULL;
}
}
static void
free_dests (CcPrintersPanel *self)
{
CcPrintersPanelPrivate *priv;
gint i;
priv = PRINTERS_PANEL_PRIVATE (self);
if (priv->num_dests > 0)
{
for (i = 0; i < priv->num_dests; i++)
{
g_free (priv->dest_model_names[i]);
if (priv->ppd_file_names[i]) {
g_unlink (priv->ppd_file_names[i]);
g_free (priv->ppd_file_names[i]);
}
}
g_free (priv->dest_model_names);
g_free (priv->ppd_file_names);
cupsFreeDests (priv->num_dests, priv->dests);
}
priv->dests = NULL;
priv->num_dests = 0;
priv->current_dest = -1;
priv->dest_model_names = NULL;
priv->ppd_file_names = NULL;
}
enum
{
NOTEBOOK_INFO_PAGE = 0,
NOTEBOOK_NO_PRINTERS_PAGE,
NOTEBOOK_NO_CUPS_PAGE,
NOTEBOOK_N_PAGES
};
enum
{
PRINTER_ID_COLUMN,
PRINTER_NAME_COLUMN,
PRINTER_PAUSED_COLUMN,
PRINTER_DEFAULT_ICON_COLUMN,
PRINTER_ICON_COLUMN,
PRINTER_N_COLUMNS
};
static void
printer_selection_changed_cb (GtkTreeSelection *selection,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GtkTreeModel *model;
cups_ptype_t type = 0;
GtkTreeIter iter;
GtkWidget *widget;
GtkWidget *model_button;
GtkWidget *model_label;
GValue value = G_VALUE_INIT;
gchar *printer_make_and_model = NULL;
gchar *printer_model = NULL;
gchar *reason = NULL;
gchar **printer_reasons = NULL;
gchar *marker_types = NULL;
gchar *printer_name = NULL;
gchar *printer_icon = NULL;
gchar *printer_type = NULL;
gchar *supply_type = NULL;
gchar *printer_uri = NULL;
gchar *location = NULL;
gchar *status = NULL;
gchar *device_uri = NULL;
gchar *printer_hostname = NULL;
int printer_state = 3;
int id = -1;
int i, j;
static const char * const reasons[] =
{
"toner-low",
"toner-empty",
"developer-low",
"developer-empty",
"marker-supply-low",
"marker-supply-empty",
"cover-open",
"door-open",
"media-low",
"media-empty",
"offline",
"paused",
"marker-waste-almost-full",
"marker-waste-full",
"opc-near-eol",
"opc-life-over"
};
static const char * statuses[] =
{
/* Translators: The printer is low on toner */
N_("Low on toner"),
/* Translators: The printer has no toner left */
N_("Out of toner"),
/* Translators: "Developer" is a chemical for photo development,
* http://en.wikipedia.org/wiki/Photographic_developer */
N_("Low on developer"),
/* Translators: "Developer" is a chemical for photo development,
* http://en.wikipedia.org/wiki/Photographic_developer */
N_("Out of developer"),
/* Translators: "marker" is one color bin of the printer */
N_("Low on a marker supply"),
/* Translators: "marker" is one color bin of the printer */
N_("Out of a marker supply"),
/* Translators: One or more covers on the printer are open */
N_("Open cover"),
/* Translators: One or more doors on the printer are open */
N_("Open door"),
/* Translators: At least one input tray is low on media */
N_("Low on paper"),
/* Translators: At least one input tray is empty */
N_("Out of paper"),
/* Translators: The printer is offline */
NC_("printer state", "Offline"),
/* Translators: Someone has paused the Printer */
NC_("printer state", "Paused"),
/* Translators: The printer marker supply waste receptacle is almost full */
N_("Waste receptacle almost full"),
/* Translators: The printer marker supply waste receptacle is full */
N_("Waste receptacle full"),
/* Translators: Optical photo conductors are used in laser printers */
N_("The optical photo conductor is near end of life"),
/* Translators: Optical photo conductors are used in laser printers */
N_("The optical photo conductor is no longer functioning")
};
priv = PRINTERS_PANEL_PRIVATE (self);
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
gtk_tree_model_get (model, &iter,
PRINTER_ID_COLUMN, &id,
PRINTER_NAME_COLUMN, &printer_name,
PRINTER_ICON_COLUMN, &printer_icon,
-1);
}
else
id = -1;
priv->current_dest = id;
update_jobs_count (self);
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
{
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "notebook");
if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) >= NOTEBOOK_NO_PRINTERS_PAGE)
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), NOTEBOOK_INFO_PAGE);
for (i = 0; i < priv->dests[id].num_options; i++)
{
if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-location") == 0)
location = g_strdup (priv->dests[priv->current_dest].options[i].value);
else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-state") == 0)
printer_state = atoi (priv->dests[priv->current_dest].options[i].value);
else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-state-reasons") == 0)
reason = priv->dests[priv->current_dest].options[i].value;
else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "marker-types") == 0)
marker_types = priv->dests[priv->current_dest].options[i].value;
else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-make-and-model") == 0)
printer_make_and_model = priv->dests[priv->current_dest].options[i].value;
else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-uri-supported") == 0)
printer_uri = priv->dests[priv->current_dest].options[i].value;
else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-type") == 0)
printer_type = priv->dests[priv->current_dest].options[i].value;
else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "device-uri") == 0)
device_uri = priv->dests[priv->current_dest].options[i].value;
}
if (priv->ppd_file_names[priv->current_dest] == NULL)
priv->ppd_file_names[priv->current_dest] =
g_strdup (cupsGetPPD (priv->dests[priv->current_dest].name));
if (priv->dest_model_names[priv->current_dest] == NULL)
priv->dest_model_names[priv->current_dest] =
get_ppd_attribute (priv->ppd_file_names[priv->current_dest],
"ModelName");
printer_model = g_strdup (priv->dest_model_names[priv->current_dest]);
if (printer_model == NULL && printer_make_and_model)
{
gchar *breakpoint = NULL, *tmp = NULL, *tmp2 = NULL;
gchar backup;
size_t length = 0;
gchar *forbiden[] = {
"foomatic",
",",
"hpijs",
"hpcups",
"(recommended)",
"postscript (recommended)",
NULL };
tmp = g_ascii_strdown (printer_make_and_model, -1);
for (i = 0; i < g_strv_length (forbiden); i++)
{
tmp2 = g_strrstr (tmp, forbiden[i]);
if (breakpoint == NULL ||
(tmp2 != NULL && tmp2 < breakpoint))
breakpoint = tmp2;
}
if (breakpoint)
{
backup = *breakpoint;
*breakpoint = '\0';
length = strlen (tmp);
*breakpoint = backup;
g_free (tmp);
if (length > 0)
printer_model = g_strndup (printer_make_and_model, length);
}
else
printer_model = g_strdup (printer_make_and_model);
}
if (priv->new_printer_name &&
g_strcmp0 (priv->new_printer_name, printer_name) == 0)
{
/* Translators: Printer's state (printer is being configured right now) */
status = g_strdup ( C_("printer state", "Configuring"));
}
/* Find the first of the most severe reasons
* and show it in the status field
*/
if (!status &&
reason &&
!g_str_equal (reason, "none"))
{
int errors = 0, warnings = 0, reports = 0;
int error_index = -1, warning_index = -1, report_index = -1;
printer_reasons = g_strsplit (reason, ",", -1);
for (i = 0; i < g_strv_length (printer_reasons); i++)
{
for (j = 0; j < G_N_ELEMENTS (reasons); j++)
if (strncmp (printer_reasons[i],
reasons[j],
strlen (reasons[j])) == 0)
{
if (g_str_has_suffix (printer_reasons[i], "-report"))
{
if (reports == 0)
report_index = j;
reports++;
}
else if (g_str_has_suffix (printer_reasons[i], "-warning"))
{
if (warnings == 0)
warning_index = j;
warnings++;
}
else
{
if (errors == 0)
error_index = j;
errors++;
}
}
}
g_strfreev (printer_reasons);
if (error_index >= 0)
status = g_strdup (_(statuses[error_index]));
else if (warning_index >= 0)
status = g_strdup (_(statuses[warning_index]));
else if (report_index >= 0)
status = g_strdup (_(statuses[report_index]));
}
if (status == NULL)
{
switch (printer_state)
{
case 3:
/* Translators: Printer's state (can start new job without waiting) */
status = g_strdup ( C_("printer state", "Ready"));
break;
case 4:
/* Translators: Printer's state (jobs are processing) */
status = g_strdup ( C_("printer state", "Processing"));
break;
case 5:
/* Translators: Printer's state (no jobs can be processed) */
status = g_strdup ( C_("printer state", "Stopped"));
break;
}
}
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-icon");
g_value_init (&value, G_TYPE_INT);
g_object_get_property ((GObject *) widget, "icon-size", &value);
if (printer_icon)
{
gtk_image_set_from_icon_name ((GtkImage *) widget, printer_icon, g_value_get_int (&value));
g_free (printer_icon);
}
else
gtk_image_set_from_icon_name ((GtkImage *) widget, "printer", g_value_get_int (&value));
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-name-label");
if (printer_name)
{
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), printer_name);
g_free (printer_name);
}
else
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-status-label");
if (status)
{
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), status);
g_free (status);
}
else
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-location-label");
if (location)
{
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), location);
g_free (location);
}
else
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
model_button = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-model-button");
model_label = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-model-label");
if (printer_model)
{
gtk_button_set_label (GTK_BUTTON (model_button), printer_model);
gtk_label_set_text (GTK_LABEL (model_label), printer_model);
g_free (printer_model);
}
else
{
gtk_button_set_label (GTK_BUTTON (model_button), EMPTY_TEXT);
gtk_label_set_text (GTK_LABEL (model_label), EMPTY_TEXT);
}
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-ip-address-label");
if (printer_type)
type = atoi (printer_type);
printer_hostname = printer_get_hostname (type, device_uri, printer_uri);
if (printer_hostname)
{
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), printer_hostname);
g_free (printer_hostname);
}
else
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-disable-switch");
g_signal_handlers_block_by_func (G_OBJECT (widget), printer_disable_cb, self);
gtk_switch_set_active (GTK_SWITCH (widget), printer_state != 5);
g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_disable_cb, self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-default-check-button");
g_signal_handlers_block_by_func (G_OBJECT (widget), printer_set_default_cb, self);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->dests[id].is_default);
g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_set_default_cb, self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "supply-drawing-area");
gtk_widget_set_size_request (widget, -1, SUPPLY_BAR_HEIGHT);
gtk_widget_queue_draw (widget);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "supply-label");
if (marker_types && g_strrstr (marker_types, "toner") != NULL)
/* Translators: Toner supply */
supply_type = g_strdup ( _("Toner Level"));
else if (marker_types && g_strrstr (marker_types, "ink") != NULL)
/* Translators: Ink supply */
supply_type = g_strdup ( _("Ink Level"));
else
/* Translators: By supply we mean ink, toner, staples, water, ... */
supply_type = g_strdup ( _("Supply Level"));
if (supply_type)
{
gtk_label_set_text (GTK_LABEL (widget), supply_type);
g_free (supply_type);
}
else
gtk_label_set_text (GTK_LABEL (widget), EMPTY_TEXT);
}
else
{
if (id == -1)
{
if (priv->new_printer_name &&
g_strcmp0 (priv->new_printer_name, printer_name) == 0)
{
/* Translators: Printer's state (printer is being installed right now) */
status = g_strdup ( C_("printer state", "Installing"));
location = g_strdup (priv->new_printer_location);
printer_model = g_strdup (priv->new_printer_make_and_model);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "notebook");
if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) >= NOTEBOOK_NO_PRINTERS_PAGE)
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), NOTEBOOK_INFO_PAGE);
}
}
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-icon");
g_value_init (&value, G_TYPE_INT);
g_object_get_property ((GObject *) widget, "icon-size", &value);
if (printer_icon)
{
gtk_image_set_from_icon_name ((GtkImage *) widget, printer_icon, g_value_get_int (&value));
g_free (printer_icon);
}
else
gtk_image_set_from_icon_name ((GtkImage *) widget, "printer", g_value_get_int (&value));
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-name-label");
if (printer_name)
{
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), printer_name);
g_free (printer_name);
}
else
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-status-label");
if (status)
{
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), status);
g_free (status);
}
else
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-location-label");
if (location)
{
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), location);
g_free (location);
}
else
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
model_button = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-model-button");
model_label = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-model-label");
if (printer_model)
{
gtk_button_set_label (GTK_BUTTON (model_button), printer_model);
gtk_label_set_text (GTK_LABEL (model_label), printer_model);
g_free (printer_model);
}
else
{
gtk_button_set_label (GTK_BUTTON (model_button), EMPTY_TEXT);
gtk_label_set_text (GTK_LABEL (model_label), EMPTY_TEXT);
}
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-ip-address-label");
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-jobs-label");
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-disable-switch");
g_signal_handlers_block_by_func (G_OBJECT (widget), printer_disable_cb, self);
gtk_switch_set_active (GTK_SWITCH (widget), FALSE);
g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_disable_cb, self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-default-check-button");
g_signal_handlers_block_by_func (G_OBJECT (widget), printer_set_default_cb, self);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_set_default_cb, self);
}
update_sensitivity (self);
}
static void
actualize_printers_list (CcPrintersPanel *self)
{
CcPrintersPanelPrivate *priv;
GtkTreeSelection *selection;
GtkListStore *store;
cups_ptype_t printer_type = 0;
GtkTreeModel *model;
GtkTreeIter selected_iter;
GtkTreeView *treeview;
GtkTreeIter iter;
cups_job_t *jobs = NULL;
GtkWidget *widget;
gboolean paused = FALSE;
gboolean selected_iter_set = FALSE;
gboolean valid = FALSE;
http_t *http;
gchar *current_printer_name = NULL;
gchar *printer_icon_name = NULL;
gchar *default_icon_name = NULL;
gchar *device_uri = NULL;
gint new_printer_position = 0;
int current_dest = -1;
int i, j;
int num_jobs = 0;
priv = PRINTERS_PANEL_PRIVATE (self);
treeview = (GtkTreeView*)
gtk_builder_get_object (priv->builder, "printers-treeview");
if ((selection = gtk_tree_view_get_selection (treeview)) != NULL &&
gtk_tree_selection_get_selected (selection, &model, &iter))
{
gtk_tree_model_get (model, &iter,
PRINTER_NAME_COLUMN, &current_printer_name,
-1);
}
if (priv->new_printer_name &&
priv->select_new_printer)
{
g_free (current_printer_name);
current_printer_name = g_strdup (priv->new_printer_name);
priv->select_new_printer = FALSE;
}
free_dests (self);
priv->num_dests = cupsGetDests (&priv->dests);
priv->dest_model_names = g_new0 (gchar *, priv->num_dests);
priv->ppd_file_names = g_new0 (gchar *, priv->num_dests);
store = gtk_list_store_new (PRINTER_N_COLUMNS,
G_TYPE_INT,
G_TYPE_STRING,
G_TYPE_BOOLEAN,
G_TYPE_STRING,
G_TYPE_STRING);
if (priv->num_dests == 0 && !priv->new_printer_name)
{
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "notebook");
http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ());
if (http)
{
httpClose (http);
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), NOTEBOOK_NO_PRINTERS_PAGE);
}
else
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), NOTEBOOK_NO_CUPS_PAGE);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
PRINTER_ID_COLUMN, 0,
/* Translators: There are no printers available (none is configured or CUPS is not running) */
PRINTER_NAME_COLUMN, _("No printers available"),
PRINTER_PAUSED_COLUMN, TRUE,
PRINTER_DEFAULT_ICON_COLUMN, NULL,
PRINTER_ICON_COLUMN, NULL,
-1);
gtk_widget_set_sensitive (GTK_WIDGET (treeview), FALSE);
}
else
gtk_widget_set_sensitive (GTK_WIDGET (treeview), TRUE);
for (i = 0; i < priv->num_dests; i++)
{
gchar *instance;
if (priv->new_printer_name && new_printer_position >= 0)
{
gint comparison_result = g_ascii_strcasecmp (priv->dests[i].name, priv->new_printer_name);
if (comparison_result < 0)
new_printer_position = i + 1;
else if (comparison_result == 0)
new_printer_position = -1;
}
gtk_list_store_append (store, &iter);
if (priv->dests[i].instance)
{
instance = g_strdup_printf ("%s / %s", priv->dests[i].name, priv->dests[i].instance);
}
else
{
instance = g_strdup (priv->dests[i].name);
}
for (j = 0; j < priv->dests[i].num_options; j++)
{
if (g_strcmp0 (priv->dests[i].options[j].name, "printer-state") == 0)
paused = (g_strcmp0 (priv->dests[i].options[j].value, "5") == 0);
else if (g_strcmp0 (priv->dests[i].options[j].name, "device-uri") == 0)
device_uri = priv->dests[i].options[j].value;
else if (g_strcmp0 (priv->dests[i].options[j].name, "printer-type") == 0)
printer_type = atoi (priv->dests[i].options[j].value);
}
if (priv->dests[i].is_default)
default_icon_name = g_strdup ("emblem-default-symbolic");
else
default_icon_name = NULL;
if (printer_is_local (printer_type, device_uri))
printer_icon_name = g_strdup ("printer");
else
printer_icon_name = g_strdup ("printer-network");
gtk_list_store_set (store, &iter,
PRINTER_ID_COLUMN, i,
PRINTER_NAME_COLUMN, instance,
PRINTER_PAUSED_COLUMN, paused,
PRINTER_DEFAULT_ICON_COLUMN, default_icon_name,
PRINTER_ICON_COLUMN, printer_icon_name,
-1);
if (g_strcmp0 (current_printer_name, instance) == 0)
{
current_dest = i;
selected_iter = iter;
selected_iter_set = TRUE;
}
g_free (instance);
g_free (printer_icon_name);
g_free (default_icon_name);
}
if (priv->new_printer_name && new_printer_position >= 0)
{
gtk_list_store_insert (store, &iter, new_printer_position);
gtk_list_store_set (store, &iter,
PRINTER_ID_COLUMN, -1,
PRINTER_NAME_COLUMN, priv->new_printer_name,
PRINTER_PAUSED_COLUMN, TRUE,
PRINTER_DEFAULT_ICON_COLUMN, NULL,
PRINTER_ICON_COLUMN, priv->new_printer_on_network ?
"printer-network" : "printer",
-1);
if (g_strcmp0 (current_printer_name, priv->new_printer_name) == 0)
{
selected_iter = iter;
selected_iter_set = TRUE;
}
}
g_signal_handlers_block_by_func (
G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview))),
printer_selection_changed_cb,
self);
gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store));
g_signal_handlers_unblock_by_func (
G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview))),
printer_selection_changed_cb,
self);
if (selected_iter_set)
{
priv->current_dest = current_dest;
gtk_tree_selection_select_iter (
gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
&selected_iter);
}
else
{
num_jobs = cupsGetJobs (&jobs, NULL, 1, CUPS_WHICHJOBS_ALL);
/* Select last used printer */
if (num_jobs > 0)
{
for (i = 0; i < priv->num_dests; i++)
if (g_strcmp0 (priv->dests[i].name, jobs[num_jobs - 1].dest) == 0)
{
priv->current_dest = i;
break;
}
cupsFreeJobs (num_jobs, jobs);
}
/* Select default printer */
if (priv->current_dest < 0)
{
for (i = 0; i < priv->num_dests; i++)
if (priv->dests[i].is_default)
{
priv->current_dest = i;
break;
}
}
if (priv->current_dest >= 0)
{
gint id;
valid = gtk_tree_model_get_iter_first ((GtkTreeModel *) store,
&selected_iter);
while (valid)
{
gtk_tree_model_get ((GtkTreeModel *) store, &selected_iter,
PRINTER_ID_COLUMN, &id,
-1);
if (id == priv->current_dest)
break;
valid = gtk_tree_model_iter_next ((GtkTreeModel *) store,
&selected_iter);
}
gtk_tree_selection_select_iter (
gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
&selected_iter);
}
else if (priv->num_dests > 0)
{
/* Select first printer */
gtk_tree_model_get_iter_first ((GtkTreeModel *) store,
&selected_iter);
gtk_tree_selection_select_iter (
gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
&selected_iter);
}
}
g_free (current_printer_name);
g_object_unref (store);
update_sensitivity (self);
}
static void
set_cell_sensitivity_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer func_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) func_data;
gboolean paused = FALSE;
priv = PRINTERS_PANEL_PRIVATE (self);
gtk_tree_model_get (tree_model, iter, PRINTER_PAUSED_COLUMN, &paused, -1);
if (priv->num_dests == 0)
g_object_set (G_OBJECT (cell),
"ellipsize", PANGO_ELLIPSIZE_NONE,
"width-chars", -1,
NULL);
else
g_object_set (G_OBJECT (cell),
"ellipsize", PANGO_ELLIPSIZE_END,
"width-chars", 18,
NULL);
g_object_set (cell, "sensitive", !paused, NULL);
}
static void
set_pixbuf_cell_sensitivity_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer func_data)
{
gboolean paused = FALSE;
gtk_tree_model_get (tree_model, iter, PRINTER_PAUSED_COLUMN, &paused, -1);
g_object_set (cell, "sensitive", !paused, NULL);
}
static void
populate_printers_list (CcPrintersPanel *self)
{
CcPrintersPanelPrivate *priv;
GtkTreeViewColumn *column;
GtkCellRenderer *icon_renderer;
GtkCellRenderer *icon_renderer2;
GtkCellRenderer *renderer;
GtkWidget *treeview;
priv = PRINTERS_PANEL_PRIVATE (self);
treeview = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printers-treeview");
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
"changed", G_CALLBACK (printer_selection_changed_cb), self);
actualize_printers_list (self);
icon_renderer = gtk_cell_renderer_pixbuf_new ();
g_object_set (icon_renderer, "stock-size", gtk_icon_size_from_name ("cc-sidebar-list"), NULL);
gtk_cell_renderer_set_padding (icon_renderer, 4, 4);
column = gtk_tree_view_column_new_with_attributes ("Icon", icon_renderer,
"icon-name", PRINTER_ICON_COLUMN, NULL);
gtk_tree_view_column_set_cell_data_func (column, icon_renderer, set_pixbuf_cell_sensitivity_func,
self, NULL);
gtk_tree_view_column_set_expand (column, FALSE);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
renderer = gtk_cell_renderer_text_new ();
g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, "width-chars", 18, NULL);
column = gtk_tree_view_column_new_with_attributes ("Printer", renderer,
"text", PRINTER_NAME_COLUMN, NULL);
gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func,
self, NULL);
gtk_tree_view_column_set_expand (column, FALSE);
gtk_tree_view_column_set_min_width (column, 120);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
icon_renderer2 = gtk_cell_renderer_pixbuf_new ();
column = gtk_tree_view_column_new_with_attributes ("Default", icon_renderer2,
"icon-name", PRINTER_DEFAULT_ICON_COLUMN, NULL);
gtk_tree_view_column_set_expand (column, FALSE);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
}
enum
{
JOB_ID_COLUMN,
JOB_TITLE_COLUMN,
JOB_STATE_COLUMN,
JOB_CREATION_TIME_COLUMN,
JOB_N_COLUMNS
};
static void
update_jobs_count (CcPrintersPanel *self)
{
CcPrintersPanelPrivate *priv;
cups_job_t *jobs;
GtkWidget *widget;
gchar *active_jobs = NULL;
gint num_jobs;
priv = PRINTERS_PANEL_PRIVATE (self);
priv->num_jobs = -1;
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
{
priv->num_jobs = cupsGetJobs (&jobs, priv->dests[priv->current_dest].name, 1, CUPS_WHICHJOBS_ACTIVE);
if (priv->num_jobs > 0)
cupsFreeJobs (priv->num_jobs, jobs);
num_jobs = priv->num_jobs < 0 ? 0 : (guint) priv->num_jobs;
/* Translators: there is n active print jobs on this printer */
active_jobs = g_strdup_printf (ngettext ("%u active", "%u active", num_jobs), num_jobs);
}
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-jobs-label");
if (active_jobs)
{
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), active_jobs);
g_free (active_jobs);
}
else
cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
if (priv->pp_jobs_dialog)
{
pp_jobs_dialog_update (priv->pp_jobs_dialog);
}
}
static void
printer_disable_cb (GObject *gobject,
GParamSpec *pspec,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
gboolean paused = FALSE;
char *name = NULL;
int i;
priv = PRINTERS_PANEL_PRIVATE (self);
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
{
name = priv->dests[priv->current_dest].name;
for (i = 0; i < priv->dests[priv->current_dest].num_options; i++)
{
if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-state") == 0)
paused = (g_strcmp0 (priv->dests[priv->current_dest].options[i].value, "5") == 0);
}
}
if (name && printer_set_enabled (name, paused))
actualize_printers_list (self);
}
typedef struct {
gchar *color;
gchar *type;
gchar *name;
gint level;
} MarkerItem;
static gint
markers_cmp (gconstpointer a,
gconstpointer b)
{
MarkerItem *x = (MarkerItem*) a;
MarkerItem *y = (MarkerItem*) b;
if (x->level < y->level)
return 1;
else if (x->level == y->level)
return 0;
else
return -1;
}
static void
rounded_rectangle (cairo_t *cr, double x, double y, double w, double h, double r)
{
cairo_new_sub_path (cr);
cairo_arc (cr, x + r, y + r, r, M_PI, 3 * M_PI / 2);
cairo_arc (cr, x + w - r, y + r, r, 3 *M_PI / 2, 2 * M_PI);
cairo_arc (cr, x + w - r, y + h - r, r, 0, M_PI / 2);
cairo_arc (cr, x + r, y + h - r, r, M_PI / 2, M_PI);
cairo_close_path (cr);
}
static gboolean
supply_levels_draw_cb (GtkWidget *widget,
cairo_t *cr,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GtkStyleContext *context;
gchar *marker_levels = NULL;
gchar *marker_colors = NULL;
gchar *marker_names = NULL;
gchar *marker_types = NULL;
gchar *tooltip_text = NULL;
gint width;
gint height;
int i;
priv = PRINTERS_PANEL_PRIVATE (self);
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
cairo_rectangle (cr, 0.0, 0.0, width, height);
gdk_cairo_set_source_rgba (cr, &priv->background_color);
cairo_fill (cr);
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
{
for (i = 0; i < priv->dests[priv->current_dest].num_options; i++)
{
if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "marker-names") == 0)
marker_names = g_strcompress (priv->dests[priv->current_dest].options[i].value);
else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "marker-levels") == 0)
marker_levels = priv->dests[priv->current_dest].options[i].value;
else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "marker-colors") == 0)
marker_colors = priv->dests[priv->current_dest].options[i].value;
else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "marker-types") == 0)
marker_types = priv->dests[priv->current_dest].options[i].value;
}
if (marker_levels && marker_colors && marker_names && marker_types)
{
GdkRGBA border_color = {0.0, 0.0, 0.0, 1.0};
GSList *markers = NULL;
GSList *tmp_list = NULL;
GValue int_val = G_VALUE_INIT;
gchar **marker_levelsv = NULL;
gchar **marker_colorsv = NULL;
gchar **marker_namesv = NULL;
gchar **marker_typesv = NULL;
gchar *tmp = NULL;
gint border_radius = 0;
context = gtk_widget_get_style_context ((GtkWidget *)
gtk_builder_get_object (priv->builder, "printer-options-button"));
gtk_style_context_get_border_color (context, 0, &border_color);
gtk_style_context_get_property (
context, GTK_STYLE_PROPERTY_BORDER_RADIUS, 0, &int_val);
if (G_VALUE_HOLDS_INT (&int_val))
border_radius = g_value_get_int (&int_val);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "supply-drawing-area");
marker_levelsv = g_strsplit (marker_levels, ",", -1);
marker_colorsv = g_strsplit (marker_colors, ",", -1);
marker_namesv = g_strsplit (marker_names, ",", -1);
marker_typesv = g_strsplit (marker_types, ",", -1);
if (g_strv_length (marker_levelsv) == g_strv_length (marker_colorsv) &&
g_strv_length (marker_colorsv) == g_strv_length (marker_namesv) &&
g_strv_length (marker_namesv) == g_strv_length (marker_typesv))
{
for (i = 0; i < g_strv_length (marker_levelsv); i++)
{
MarkerItem *marker;
if (g_strcmp0 (marker_typesv[i], "ink") == 0 ||
g_strcmp0 (marker_typesv[i], "toner") == 0)
{
marker = g_new0 (MarkerItem, 1);
marker->type = g_strdup (marker_typesv[i]);
marker->name = g_strdup (marker_namesv[i]);
marker->color = g_strdup (marker_colorsv[i]);
marker->level = atoi (marker_levelsv[i]);
markers = g_slist_prepend (markers, marker);
}
}
markers = g_slist_sort (markers, markers_cmp);
for (tmp_list = markers; tmp_list; tmp_list = tmp_list->next)
{
GdkRGBA color = {0.0, 0.0, 0.0, 1.0};
double display_value;
int value;
value = ((MarkerItem*) tmp_list->data)->level;
gdk_rgba_parse (&color, ((MarkerItem*) tmp_list->data)->color);
if (value > 0)
{
display_value = value / 100.0 * (width - 3.0);
gdk_cairo_set_source_rgba (cr, &color);
rounded_rectangle (cr, 1.5, 1.5, display_value, SUPPLY_BAR_HEIGHT - 3.0, border_radius);
cairo_fill (cr);
}
if (tooltip_text)
{
tmp = g_strdup_printf ("%s\n%s",
tooltip_text,
((MarkerItem*) tmp_list->data)->name);
g_free (tooltip_text);
tooltip_text = tmp;
tmp = NULL;
}
else
tooltip_text = g_strdup_printf ("%s",
((MarkerItem*) tmp_list->data)->name);
}
cairo_set_line_width (cr, 1.0);
gdk_cairo_set_source_rgba (cr, &border_color);
rounded_rectangle (cr, 1.5, 1.5, width - 3.0, SUPPLY_BAR_HEIGHT - 3.0, border_radius);
cairo_stroke (cr);
for (tmp_list = markers; tmp_list; tmp_list = tmp_list->next)
{
g_free (((MarkerItem*) tmp_list->data)->name);
g_free (((MarkerItem*) tmp_list->data)->type);
g_free (((MarkerItem*) tmp_list->data)->color);
}
g_slist_free_full (markers, g_free);
}
g_strfreev (marker_levelsv);
g_strfreev (marker_colorsv);
g_strfreev (marker_namesv);
g_strfreev (marker_typesv);
}
g_free (marker_names);
if (tooltip_text)
{
gtk_widget_set_tooltip_text (widget, tooltip_text);
g_free (tooltip_text);
}
else
{
gtk_widget_set_tooltip_text (widget, NULL);
gtk_widget_set_has_tooltip (widget, FALSE);
}
}
return TRUE;
}
static void
printer_set_default_cb (GtkToggleButton *button,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
char *name = NULL;
priv = PRINTERS_PANEL_PRIVATE (self);
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
name = priv->dests[priv->current_dest].name;
if (name)
{
printer_set_default (name);
actualize_printers_list (self);
g_signal_handlers_block_by_func (G_OBJECT (button), printer_set_default_cb, self);
gtk_toggle_button_set_active (button, priv->dests[priv->current_dest].is_default);
g_signal_handlers_unblock_by_func (G_OBJECT (button), printer_set_default_cb, self);
}
}
static void
new_printer_dialog_pre_response_cb (PpNewPrinterDialog *dialog,
const gchar *device_name,
const gchar *device_location,
const gchar *device_make_and_model,
gboolean is_network_device,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
priv = PRINTERS_PANEL_PRIVATE (self);
priv->new_printer_name = g_strdup (device_name);
priv->new_printer_location = g_strdup (device_location);
priv->new_printer_make_and_model = g_strdup (device_make_and_model);
priv->new_printer_on_network = is_network_device;
priv->select_new_printer = TRUE;
actualize_printers_list (self);
}
static void
new_printer_dialog_response_cb (PpNewPrinterDialog *dialog,
gint response_id,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
priv = PRINTERS_PANEL_PRIVATE (self);
if (priv->pp_new_printer_dialog)
g_clear_object (&priv->pp_new_printer_dialog);
g_clear_pointer (&priv->new_printer_name, g_free);
g_clear_pointer (&priv->new_printer_location, g_free);
g_clear_pointer (&priv->new_printer_make_and_model, g_free);
if (response_id == GTK_RESPONSE_REJECT)
{
GtkWidget *message_dialog;
message_dialog = gtk_message_dialog_new (NULL,
0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
/* Translators: Addition of the new printer failed. */
_("Failed to add new printer."));
g_signal_connect (message_dialog,
"response",
G_CALLBACK (gtk_widget_destroy),
NULL);
gtk_widget_show (message_dialog);
}
actualize_printers_list (self);
}
static void
printer_add_cb (GtkToolButton *toolbutton,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GtkWidget *toplevel;
priv = PRINTERS_PANEL_PRIVATE (self);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
priv->pp_new_printer_dialog = PP_NEW_PRINTER_DIALOG (pp_new_printer_dialog_new (GTK_WINDOW (toplevel)));
g_signal_connect (priv->pp_new_printer_dialog,
"pre-response",
G_CALLBACK (new_printer_dialog_pre_response_cb),
self);
g_signal_connect (priv->pp_new_printer_dialog,
"response",
G_CALLBACK (new_printer_dialog_response_cb),
self);
}
static void
printer_remove_cb (GtkToolButton *toolbutton,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
char *printer_name = NULL;
priv = PRINTERS_PANEL_PRIVATE (self);
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
printer_name = priv->dests[priv->current_dest].name;
if (printer_name && printer_delete (printer_name))
actualize_printers_list (self);
}
static void
printer_name_edit_cb (GtkWidget *entry,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
const gchar *new_name;
gchar *old_name = NULL;
gint i;
priv = PRINTERS_PANEL_PRIVATE (self);
new_name = cc_editable_entry_get_text (CC_EDITABLE_ENTRY (entry));
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
old_name = priv->dests[priv->current_dest].name;
if (printer_rename (old_name, new_name))
{
free_dests (self);
priv->num_dests = cupsGetDests (&priv->dests);
priv->dest_model_names = g_new0 (gchar *, priv->num_dests);
priv->ppd_file_names = g_new0 (gchar *, priv->num_dests);
for (i = 0; i < priv->num_dests; i++)
if (g_strcmp0 (priv->dests[i].name, new_name) == 0)
{
priv->current_dest = i;
break;
}
}
actualize_printers_list (self);
}
static void
printer_location_edit_cb (GtkWidget *entry,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
const gchar *location;
gchar *printer_name = NULL;
priv = PRINTERS_PANEL_PRIVATE (self);
location = cc_editable_entry_get_text (CC_EDITABLE_ENTRY (entry));
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
printer_name = priv->dests[priv->current_dest].name;
if (printer_name && location &&
printer_set_location (printer_name, location))
actualize_printers_list (self);
}
static void
set_ppd_cb (gchar *printer_name,
gboolean success,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GList *iter;
priv = PRINTERS_PANEL_PRIVATE (self);
for (iter = priv->driver_change_list; iter; iter = iter->next)
{
SetPPDItem *item = (SetPPDItem *) iter->data;
if (g_strcmp0 (item->printer_name, printer_name) == 0)
{
priv->driver_change_list = g_list_remove_link (priv->driver_change_list, iter);
g_object_unref (item->cancellable);
g_free (item->printer_name);
g_free (item);
g_list_free (iter);
break;
}
}
update_sensitivity (self);
if (success)
{
actualize_printers_list (self);
}
g_free (printer_name);
}
static void
select_ppd_manually (GtkMenuItem *menuitem,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GtkFileFilter *filter;
GtkWidget *dialog;
gchar *printer_name = NULL;
priv = PRINTERS_PANEL_PRIVATE (self);
gtk_menu_shell_cancel (GTK_MENU_SHELL (priv->popup_menu));
dialog = gtk_file_chooser_dialog_new (_("Select PPD File"),
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter,
_("PostScript Printer Description files (*.ppd, *.PPD, *.ppd.gz, *.PPD.gz, *.PPD.GZ)"));
gtk_file_filter_add_pattern (filter, "*.ppd");
gtk_file_filter_add_pattern (filter, "*.PPD");
gtk_file_filter_add_pattern (filter, "*.ppd.gz");
gtk_file_filter_add_pattern (filter, "*.PPD.gz");
gtk_file_filter_add_pattern (filter, "*.PPD.GZ");
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
{
gchar *ppd_filename;
ppd_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
printer_name = priv->dests[priv->current_dest].name;
if (printer_name && ppd_filename)
{
SetPPDItem *item;
item = g_new0 (SetPPDItem, 1);
item->printer_name = g_strdup (printer_name);
item->cancellable = g_cancellable_new ();
priv->driver_change_list =
g_list_prepend (priv->driver_change_list, item);
update_sensitivity (self);
printer_set_ppd_file_async (printer_name,
ppd_filename,
item->cancellable,
set_ppd_cb,
user_data);
}
g_free (ppd_filename);
}
gtk_widget_destroy (dialog);
}
static void
ppd_selection_dialog_response_cb (GtkDialog *dialog,
gint response_id,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
gchar *printer_name = NULL;
priv = PRINTERS_PANEL_PRIVATE (self);
if (response_id == GTK_RESPONSE_OK)
{
gchar *ppd_name;
ppd_name = pp_ppd_selection_dialog_get_ppd_name (priv->pp_ppd_selection_dialog);
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
printer_name = priv->dests[priv->current_dest].name;
if (printer_name && ppd_name)
{
SetPPDItem *item;
item = g_new0 (SetPPDItem, 1);
item->printer_name = g_strdup (printer_name);
item->cancellable = g_cancellable_new ();
priv->driver_change_list = g_list_prepend (priv->driver_change_list,
item);
update_sensitivity (self);
printer_set_ppd_async (printer_name,
ppd_name,
item->cancellable,
set_ppd_cb,
user_data);
}
g_free (ppd_name);
}
pp_ppd_selection_dialog_free (priv->pp_ppd_selection_dialog);
priv->pp_ppd_selection_dialog = NULL;
}
static void
select_ppd_in_dialog (GtkMenuItem *menuitem,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GtkWidget *widget;
gchar *device_id = NULL;
gchar *manufacturer = NULL;
priv = PRINTERS_PANEL_PRIVATE (self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "main-vbox");
if (!priv->pp_ppd_selection_dialog)
{
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests)
{
device_id =
get_ppd_attribute (priv->ppd_file_names[priv->current_dest],
"1284DeviceID");
if (device_id)
{
manufacturer = get_tag_value (device_id, "mfg");
if (!manufacturer)
manufacturer = get_tag_value (device_id, "manufacturer");
}
if (manufacturer == NULL)
{
manufacturer =
get_ppd_attribute (priv->ppd_file_names[priv->current_dest],
"Manufacturer");
}
if (manufacturer == NULL)
{
manufacturer = g_strdup ("Raw");
}
}
priv->pp_ppd_selection_dialog = pp_ppd_selection_dialog_new (
GTK_WINDOW (gtk_widget_get_toplevel (widget)),
priv->all_ppds_list,
manufacturer,
ppd_selection_dialog_response_cb,
self);
g_free (manufacturer);
g_free (device_id);
}
}
static void
set_ppd_from_list (GtkMenuItem *menuitem,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
gchar *printer_name = NULL;
gchar *ppd_name;
priv = PRINTERS_PANEL_PRIVATE (self);
ppd_name = (gchar *) g_object_get_data (G_OBJECT (menuitem), "ppd-name");
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
printer_name = priv->dests[priv->current_dest].name;
if (printer_name && ppd_name)
{
SetPPDItem *item;
item = g_new0 (SetPPDItem, 1);
item->printer_name = g_strdup (printer_name);
item->cancellable = g_cancellable_new ();
priv->driver_change_list = g_list_prepend (priv->driver_change_list,
item);
update_sensitivity (self);
printer_set_ppd_async (printer_name,
ppd_name,
item->cancellable,
set_ppd_cb,
user_data);
}
}
static void
ppd_names_free (gpointer user_data)
{
PPDName **names = (PPDName **) user_data;
gint i;
if (names)
{
for (i = 0; names[i]; i++)
{
g_free (names[i]->ppd_name);
g_free (names[i]->ppd_display_name);
g_free (names[i]);
}
g_free (names);
}
}
static void
get_ppd_names_cb (PPDName **names,
const gchar *printer_name,
gboolean cancelled,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GtkWidget *informal = NULL;
GtkWidget *placeholders[3];
GtkWidget *spinner;
gpointer value = NULL;
gboolean found = FALSE;
PPDName **hash_names = NULL;
GList *children, *iter;
gint i;
priv = PRINTERS_PANEL_PRIVATE (self);
priv->getting_ppd_names = FALSE;
for (i = 0; i < 3; i++)
placeholders[i] = NULL;
children = gtk_container_get_children (GTK_CONTAINER (priv->popup_menu));
if (children)
{
for (iter = children; iter; iter = iter->next)
{
if (g_strcmp0 ((gchar *) g_object_get_data (G_OBJECT (iter->data), "purpose"),
"informal") == 0)
informal = GTK_WIDGET (iter->data);
else if (g_strcmp0 ((gchar *) g_object_get_data (G_OBJECT (iter->data), "purpose"),
"placeholder1") == 0)
placeholders[0] = GTK_WIDGET (iter->data);
else if (g_strcmp0 ((gchar *) g_object_get_data (G_OBJECT (iter->data), "purpose"),
"placeholder2") == 0)
placeholders[1] = GTK_WIDGET (iter->data);
else if (g_strcmp0 ((gchar *) g_object_get_data (G_OBJECT (iter->data), "purpose"),
"placeholder3") == 0)
placeholders[2] = GTK_WIDGET (iter->data);
}
g_list_free (children);
}
if (!priv->preferred_drivers)
{
priv->preferred_drivers = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, ppd_names_free);
}
if (!cancelled &&
!g_hash_table_lookup_extended (priv->preferred_drivers,
printer_name, NULL, NULL))
g_hash_table_insert (priv->preferred_drivers, g_strdup (printer_name), names);
if (priv->preferred_drivers &&
g_hash_table_lookup_extended (priv->preferred_drivers,
printer_name, NULL, &value))
{
hash_names = (PPDName **) value;
if (hash_names)
{
for (i = 0; hash_names[i]; i++)
{
if (placeholders[i])
{
gtk_menu_item_set_label (GTK_MENU_ITEM (placeholders[i]),
hash_names[i]->ppd_display_name);
g_object_set_data_full (G_OBJECT (placeholders[i]),
"ppd-name",
g_strdup (hash_names[i]->ppd_name),
g_free);
g_signal_connect (placeholders[i],
"activate",
G_CALLBACK (set_ppd_from_list),
self);
gtk_widget_set_sensitive (GTK_WIDGET (placeholders[i]), TRUE);
gtk_widget_show (placeholders[i]);
}
}
found = TRUE;
}
else
{
found = FALSE;
}
}
if (informal)
{
gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (informal), FALSE);
spinner = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (informal));
if (spinner)
gtk_spinner_stop (GTK_SPINNER (spinner));
if (found)
gtk_widget_hide (informal);
else
gtk_menu_item_set_label (GTK_MENU_ITEM (informal), _("No suitable driver found"));
}
gtk_widget_show_all (priv->popup_menu);
update_sensitivity (self);
}
static void
popup_menu_done (GtkMenuShell *menushell,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
priv = PRINTERS_PANEL_PRIVATE (self);
if (priv->get_ppd_name_cancellable)
{
g_cancellable_cancel (priv->get_ppd_name_cancellable);
g_object_unref (priv->get_ppd_name_cancellable);
priv->get_ppd_name_cancellable = NULL;
}
}
static void
popup_model_menu_cb (GtkButton *button,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GtkWidget *spinner;
GtkWidget *item;
priv = PRINTERS_PANEL_PRIVATE (self);
priv->popup_menu = gtk_menu_new ();
g_signal_connect (priv->popup_menu,
"selection-done",
G_CALLBACK (popup_menu_done),
user_data);
/*
* These placeholders are a workaround for a situation
* when we want to actually append new menu item in a callback.
* But unfortunately it is not possible to connect to "activate"
* signal of such menu item (appended after gtk_menu_popup()).
*/
item = gtk_image_menu_item_new_with_label ("");
g_object_set_data_full (G_OBJECT (item), "purpose",
g_strdup ("placeholder1"), g_free);
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
gtk_widget_set_no_show_all (item, TRUE);
gtk_widget_hide (item);
item = gtk_image_menu_item_new_with_label ("");
g_object_set_data_full (G_OBJECT (item), "purpose",
g_strdup ("placeholder2"), g_free);
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
gtk_widget_set_no_show_all (item, TRUE);
gtk_widget_hide (item);
item = gtk_image_menu_item_new_with_label ("");
g_object_set_data_full (G_OBJECT (item), "purpose",
g_strdup ("placeholder3"), g_free);
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
gtk_widget_set_no_show_all (item, TRUE);
gtk_widget_hide (item);
item = gtk_image_menu_item_new_with_label (_("Searching for preferred drivers..."));
spinner = gtk_spinner_new ();
gtk_spinner_start (GTK_SPINNER (spinner));
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), spinner);
gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (item), TRUE);
g_object_set_data_full (G_OBJECT (item), "purpose",
g_strdup ("informal"), g_free);
gtk_widget_set_sensitive (item, FALSE);
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
gtk_widget_set_no_show_all (item, TRUE);
gtk_widget_show (item);
item = gtk_separator_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
item = gtk_menu_item_new_with_label (_("Select from database..."));
g_object_set_data_full (G_OBJECT (item), "purpose",
g_strdup ("ppd-select"), g_free);
g_signal_connect (item, "activate", G_CALLBACK (select_ppd_in_dialog), self);
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
item = gtk_separator_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
item = gtk_menu_item_new_with_label (_("Provide PPD File..."));
g_object_set_data_full (G_OBJECT (item), "purpose",
g_strdup ("ppdfile-select"), g_free);
g_signal_connect (item, "activate", G_CALLBACK (select_ppd_manually), self);
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
gtk_widget_show_all (priv->popup_menu);
gtk_menu_popup (GTK_MENU (priv->popup_menu),
NULL, NULL, NULL, NULL, 0,
gtk_get_current_event_time());
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
{
if (priv->preferred_drivers &&
g_hash_table_lookup_extended (priv->preferred_drivers,
priv->dests[priv->current_dest].name,
NULL, NULL))
{
get_ppd_names_cb (NULL,
priv->dests[priv->current_dest].name,
FALSE,
user_data);
}
else
{
priv->get_ppd_name_cancellable = g_cancellable_new ();
priv->getting_ppd_names = TRUE;
get_ppd_names_async (priv->dests[priv->current_dest].name,
3,
priv->get_ppd_name_cancellable,
get_ppd_names_cb,
user_data);
update_sensitivity (self);
}
}
}
static void
pp_maintenance_command_execute_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpMaintenanceCommand *command = (PpMaintenanceCommand *) source_object;
GError *error = NULL;
pp_maintenance_command_execute_finish (command, res, &error);
g_object_unref (command);
}
static void
test_page_cb (GtkButton *button,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
cups_ptype_t type = 0;
const gchar *printer_type = NULL;
gchar *printer_name = NULL;
gint i;
priv = PRINTERS_PANEL_PRIVATE (self);
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
{
printer_name = priv->dests[priv->current_dest].name;
printer_type = cupsGetOption ("printer-type",
priv->dests[priv->current_dest].num_options,
priv->dests[priv->current_dest].options);
if (printer_type)
type = atoi (printer_type);
}
if (printer_name)
{
const gchar *const dirs[] = { "/usr/share/cups",
"/usr/local/share/cups",
NULL };
const gchar *testprint[] = { "%s/data/testprint",
"%s/data/testprint.ps",
NULL };
const gchar **pattern;
const gchar *datadir = NULL;
http_t *http = NULL;
gchar *printer_uri = NULL;
gchar *filename = NULL;
gchar *resource = NULL;
ipp_t *response = NULL;
ipp_t *request;
if ((datadir = getenv ("CUPS_DATADIR")) != NULL)
{
for (pattern = testprint; *pattern != NULL; pattern++)
{
filename = g_strdup_printf (*pattern, datadir);
if (g_access (filename, R_OK) == 0)
break;
else
{
g_free (filename);
filename = NULL;
}
}
}
else
{
for (i = 0; (datadir = dirs[i]) != NULL && filename == NULL; i++)
{
for (pattern = testprint; *pattern != NULL; pattern++)
{
filename = g_strdup_printf (*pattern, datadir);
if (g_access (filename, R_OK) == 0)
break;
else
{
g_free (filename);
filename = NULL;
}
}
}
}
if (filename)
{
if (type & CUPS_PRINTER_CLASS)
{
printer_uri = g_strdup_printf ("ipp://localhost/classes/%s", printer_name);
resource = g_strdup_printf ("/classes/%s", printer_name);
}
else
{
printer_uri = g_strdup_printf ("ipp://localhost/printers/%s", printer_name);
resource = g_strdup_printf ("/printers/%s", printer_name);
}
http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ());
if (http)
{
request = ippNewRequest (IPP_PRINT_JOB);
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, printer_uri);
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
"requesting-user-name", NULL, cupsUser ());
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
/* Translators: Name of job which makes printer to print test page */
"job-name", NULL, _("Test page"));
response = cupsDoFileRequest (http, request, resource, filename);
httpClose (http);
}
if (response)
{
if (ippGetState (response) == IPP_ERROR)
g_warning ("An error has occured during printing of test page.");
ippDelete (response);
}
g_free (filename);
g_free (printer_uri);
g_free (resource);
}
else
{
PpMaintenanceCommand *command;
command = pp_maintenance_command_new (printer_name,
"PrintSelfTestPage",
/* Translators: Name of job which makes printer to print test page */
_("Test page"));
pp_maintenance_command_execute_async (command, NULL, pp_maintenance_command_execute_cb, self);
}
}
}
static void
update_sensitivity (gpointer user_data)
{
CcPrintersPanelPrivate *priv;
GtkTreeSelection *selection;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
cups_ptype_t type = 0;
GtkTreeModel *model;
GtkTreeView *treeview;
GtkTreeIter tree_iter;
const char *cups_server = NULL;
GtkWidget *widget;
gboolean is_authorized;
gboolean is_discovered = FALSE;
gboolean is_class = FALSE;
gboolean is_changing_driver = FALSE;
gboolean printer_selected;
gboolean local_server = TRUE;
gboolean no_cups = FALSE;
gboolean is_new = FALSE;
gboolean already_present_local;
GList *iter;
gchar *current_printer_name = NULL;
gint i;
priv = PRINTERS_PANEL_PRIVATE (self);
is_authorized =
priv->permission &&
g_permission_get_allowed (G_PERMISSION (priv->permission)) &&
priv->lockdown_settings &&
!g_settings_get_boolean (priv->lockdown_settings, "disable-print-setup");
printer_selected = priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL;
if (printer_selected)
{
for (i = 0; i < priv->dests[priv->current_dest].num_options; i++)
{
if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-type") == 0)
{
type = atoi (priv->dests[priv->current_dest].options[i].value);
is_discovered = type & CUPS_PRINTER_DISCOVERED;
is_class = type & CUPS_PRINTER_CLASS;
break;
}
}
for (iter = priv->driver_change_list; iter; iter = iter->next)
{
SetPPDItem *item = (SetPPDItem *) iter->data;
if (g_strcmp0 (item->printer_name, priv->dests[priv->current_dest].name) == 0)
{
is_changing_driver = TRUE;
}
}
}
treeview = (GtkTreeView*)
gtk_builder_get_object (priv->builder, "printers-treeview");
selection = gtk_tree_view_get_selection (treeview);
if (selection &&
gtk_tree_selection_get_selected (selection, &model, &tree_iter))
{
gtk_tree_model_get (model, &tree_iter,
PRINTER_NAME_COLUMN, &current_printer_name,
-1);
}
if (priv->new_printer_name &&
g_strcmp0 (priv->new_printer_name, current_printer_name) == 0)
{
printer_selected = TRUE;
is_discovered = FALSE;
is_class = FALSE;
is_new = TRUE;
}
g_free (current_printer_name);
cups_server = cupsServer ();
if (cups_server &&
g_ascii_strncasecmp (cups_server, "localhost", 9) != 0 &&
g_ascii_strncasecmp (cups_server, "127.0.0.1", 9) != 0 &&
g_ascii_strncasecmp (cups_server, "::1", 3) != 0 &&
cups_server[0] != '/')
local_server = FALSE;
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "notebook");
if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) == NOTEBOOK_NO_CUPS_PAGE)
no_cups = TRUE;
already_present_local = local_server && !is_discovered && is_authorized && !is_new;
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-add-button");
gtk_widget_set_sensitive (widget, local_server && is_authorized && !no_cups && !priv->new_printer_name);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-add-button2");
gtk_widget_set_sensitive (widget, local_server && is_authorized && !no_cups && !priv->new_printer_name);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-remove-button");
gtk_widget_set_sensitive (widget, already_present_local && printer_selected && !no_cups);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-disable-switch");
gtk_widget_set_sensitive (widget, already_present_local);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-default-check-button");
gtk_widget_set_sensitive (widget, is_authorized && !is_new);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "print-test-page-button");
gtk_widget_set_sensitive (widget, printer_selected && !is_new);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-options-button");
gtk_widget_set_sensitive (widget, printer_selected && local_server && !is_discovered &&
!priv->pp_options_dialog && !is_new);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-jobs-button");
gtk_widget_set_sensitive (widget, printer_selected && !is_new);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-icon");
gtk_widget_set_sensitive (widget, printer_selected);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-name-label");
cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), already_present_local);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-location-label");
cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), already_present_local);
widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-model-notebook");
if (is_changing_driver)
{
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 2);
}
else
{
if (already_present_local && !is_class && !priv->getting_ppd_names)
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 0);
else
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 1);
}
}
static void
on_permission_changed (GPermission *permission,
GParamSpec *pspec,
gpointer data)
{
update_sensitivity (data);
}
static void
on_lockdown_settings_changed (GSettings *settings,
const char *key,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
if (g_str_equal (key, "disable-print-setup") == FALSE)
return;
priv = PRINTERS_PANEL_PRIVATE (self);
#if 0
/* FIXME */
gtk_widget_set_sensitive (priv->lock_button,
!g_settings_get_boolean (priv->lockdown_settings, "disable-print-setup"));
#endif
on_permission_changed (priv->permission, NULL, user_data);
}
static void
printer_options_response_cb (GtkDialog *dialog,
gint response_id,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
priv = PRINTERS_PANEL_PRIVATE (self);
pp_options_dialog_free (priv->pp_options_dialog);
priv->pp_options_dialog = NULL;
update_sensitivity (self);
if (response_id == GTK_RESPONSE_OK)
actualize_printers_list (self);
}
static void
printer_options_cb (GtkToolButton *toolbutton,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GtkWidget *widget;
gboolean is_authorized;
priv = PRINTERS_PANEL_PRIVATE (self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "main-vbox");
is_authorized =
priv->permission &&
g_permission_get_allowed (G_PERMISSION (priv->permission)) &&
priv->lockdown_settings &&
!g_settings_get_boolean (priv->lockdown_settings, "disable-print-setup");
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
{
priv->pp_options_dialog = pp_options_dialog_new (
GTK_WINDOW (gtk_widget_get_toplevel (widget)),
printer_options_response_cb,
self,
priv->dests[priv->current_dest].name,
is_authorized);
update_sensitivity (self);
}
}
static gboolean
cups_status_check (gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
gboolean result = TRUE;
http_t *http;
priv = self->priv = PRINTERS_PANEL_PRIVATE (self);
http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ());
if (http)
{
httpClose (http);
actualize_printers_list (self);
attach_to_cups_notifier (self);
priv->cups_status_check_id = 0;
result = FALSE;
}
return result;
}
static void
get_all_ppds_async_cb (PPDList *ppds,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
priv = self->priv = PRINTERS_PANEL_PRIVATE (self);
priv->all_ppds_list = ppds;
if (priv->pp_ppd_selection_dialog)
pp_ppd_selection_dialog_set_ppd_list (priv->pp_ppd_selection_dialog,
priv->all_ppds_list);
g_object_unref (priv->get_all_ppds_cancellable);
priv->get_all_ppds_cancellable = NULL;
}
static void
update_label_padding (GtkWidget *widget,
GtkAllocation *allocation,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GtkAllocation allocation1, allocation2;
GtkWidget *label;
GtkWidget *sublabel;
gint offset;
gint pad;
priv = PRINTERS_PANEL_PRIVATE (self);
sublabel = gtk_bin_get_child (GTK_BIN (widget));
if (sublabel)
{
gtk_widget_get_allocation (widget, &allocation1);
gtk_widget_get_allocation (sublabel, &allocation2);
offset = allocation2.x - allocation1.x;
label = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-model-label");
gtk_misc_get_padding (GTK_MISC (label), &pad, NULL);
if (offset != pad)
gtk_misc_set_padding (GTK_MISC (label), offset, 0);
}
}
static void
jobs_dialog_response_cb (GtkDialog *dialog,
gint response_id,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
priv = PRINTERS_PANEL_PRIVATE (self);
pp_jobs_dialog_free (priv->pp_jobs_dialog);
priv->pp_jobs_dialog = NULL;
}
static void
printer_jobs_cb (GtkToolButton *toolbutton,
gpointer user_data)
{
CcPrintersPanelPrivate *priv;
CcPrintersPanel *self = (CcPrintersPanel*) user_data;
GtkWidget *widget;
priv = PRINTERS_PANEL_PRIVATE (self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "main-vbox");
if (priv->current_dest >= 0 &&
priv->current_dest < priv->num_dests &&
priv->dests != NULL)
priv->pp_jobs_dialog = pp_jobs_dialog_new (
GTK_WINDOW (gtk_widget_get_toplevel (widget)),
jobs_dialog_response_cb,
self,
priv->dests[priv->current_dest].name);
}
static void
cc_printers_panel_init (CcPrintersPanel *self)
{
CcPrintersPanelPrivate *priv;
GtkWidget *top_widget;
GtkWidget *widget;
GError *error = NULL;
http_t *http;
gchar *objects[] = { "main-vbox", NULL };
GtkStyleContext *context;
guint builder_result;
priv = self->priv = PRINTERS_PANEL_PRIVATE (self);
/* initialize main data structure */
priv->builder = gtk_builder_new ();
priv->dests = NULL;
priv->dest_model_names = NULL;
priv->ppd_file_names = NULL;
priv->num_dests = 0;
priv->current_dest = -1;
priv->num_jobs = 0;
priv->pp_new_printer_dialog = NULL;
priv->pp_options_dialog = NULL;
priv->subscription_id = 0;
priv->cups_status_check_id = 0;
priv->subscription_renewal_id = 0;
priv->cups_proxy = NULL;
priv->cups_bus_connection = NULL;
priv->dbus_subscription_id = 0;
priv->new_printer_name = NULL;
priv->new_printer_location = NULL;
priv->new_printer_make_and_model = NULL;
priv->new_printer_on_network = FALSE;
priv->select_new_printer = FALSE;
priv->permission = NULL;
priv->lockdown_settings = NULL;
priv->getting_ppd_names = FALSE;
priv->all_ppds_list = NULL;
priv->get_all_ppds_cancellable = NULL;
priv->preferred_drivers = NULL;
builder_result = gtk_builder_add_objects_from_file (priv->builder,
DATADIR"/printers.ui",
objects, &error);
if (builder_result == 0)
{
/* Translators: The XML file containing user interface can not be loaded */
g_warning (_("Could not load ui: %s"), error->message);
g_error_free (error);
return;
}
/* add the top level widget */
top_widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "main-vbox");
/* connect signals */
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-add-button");
g_signal_connect (widget, "clicked", G_CALLBACK (printer_add_cb), self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-add-button2");
g_signal_connect (widget, "clicked", G_CALLBACK (printer_add_cb), self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-remove-button");
g_signal_connect (widget, "clicked", G_CALLBACK (printer_remove_cb), self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-disable-switch");
g_signal_connect (widget, "notify::active", G_CALLBACK (printer_disable_cb), self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "supply-drawing-area");
g_signal_connect (widget, "draw", G_CALLBACK (supply_levels_draw_cb), self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-default-check-button");
g_signal_connect (widget, "toggled", G_CALLBACK (printer_set_default_cb), self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "print-test-page-button");
g_signal_connect (widget, "clicked", G_CALLBACK (test_page_cb), self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-jobs-button");
g_signal_connect (widget, "clicked", G_CALLBACK (printer_jobs_cb), self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-options-button");
g_signal_connect (widget, "clicked", G_CALLBACK (printer_options_cb), self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-name-label");
g_signal_connect (widget, "editing-done", G_CALLBACK (printer_name_edit_cb), self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-location-label");
g_signal_connect (widget, "editing-done", G_CALLBACK (printer_location_edit_cb), self);
priv->lockdown_settings = g_settings_new ("org.gnome.desktop.lockdown");
if (priv->lockdown_settings)
g_signal_connect (priv->lockdown_settings,
"changed",
G_CALLBACK (on_lockdown_settings_changed),
self);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-model-button");
g_signal_connect (widget, "clicked", G_CALLBACK (popup_model_menu_cb), self);
g_signal_connect (widget, "size-allocate", G_CALLBACK (update_label_padding), self);
/* Set junctions */
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printers-scrolledwindow");
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printers-toolbar");
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
/* Make model label and ip-address label selectable */
widget = (GtkWidget*)
gtk_builder_get_object (priv->builder, "printer-ip-address-label");
cc_editable_entry_set_selectable (CC_EDITABLE_ENTRY (widget), TRUE);
/* Add unlock button */
priv->permission = (GPermission *)polkit_permission_new_sync (
"org.opensuse.cupspkhelper.mechanism.all-edit", NULL, NULL, NULL);
if (priv->permission != NULL)
{
g_signal_connect (priv->permission, "notify",
G_CALLBACK (on_permission_changed), self);
on_permission_changed (priv->permission, NULL, self);
}
else
g_warning ("Your system does not have the cups-pk-helper's policy \
\"org.opensuse.cupspkhelper.mechanism.all-edit\" installed. \
Please check your installation");
gtk_style_context_get_background_color (gtk_widget_get_style_context (top_widget),
GTK_STATE_FLAG_NORMAL,
&priv->background_color);
populate_printers_list (self);
attach_to_cups_notifier (self);
priv->get_all_ppds_cancellable = g_cancellable_new ();
get_all_ppds_async (priv->get_all_ppds_cancellable,
get_all_ppds_async_cb,
self);
http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ());
if (!http)
{
priv->cups_status_check_id =
g_timeout_add_seconds (CUPS_STATUS_CHECK_INTERVAL, cups_status_check, self);
}
else
httpClose (http);
gtk_container_add (GTK_CONTAINER (self), top_widget);
gtk_widget_show_all (GTK_WIDGET (self));
}
void
cc_printers_panel_register (GIOModule *module)
{
cc_printers_panel_register_type (G_TYPE_MODULE (module));
g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
CC_TYPE_PRINTERS_PANEL,
"printers", 0);
}