gnome-control-center/panels/printers/pp-new-printer-dialog.c
Brandon Nielsen c239521e9d Change PpPPDSelectionDialog to GtkDialog
The dialog is now displayed by calling gtk_dialog_run and
gtk_window_set_transient_for in the window displaying the dialog.
Cleanup is handled using gtk_widget_destroy.

Destructors in the windows using the dialog no longer cleanup the dialog
as it is assumed it will be either cleaned up after the response
callback, or handled by the destroy_with_parent property set on the
dialog itself.
2021-01-08 02:49:32 +00:00

2071 lines
69 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright 2009-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, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <unistd.h>
#include <stdlib.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <cups/cups.h>
#include "pp-new-printer-dialog.h"
#include "pp-ppd-selection-dialog.h"
#include "pp-utils.h"
#include "pp-host.h"
#include "pp-cups.h"
#include "pp-samba.h"
#include "pp-new-printer.h"
#include <gdk/gdkx.h>
#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
#endif
/*
* Additional delay to the default 150ms delay in GtkSearchEntry
* resulting in total delay of 500ms.
*/
#define HOST_SEARCH_DELAY (500 - 150)
#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->builder, s))
#define AUTHENTICATION_PAGE "authentication-page"
#define ADDPRINTER_PAGE "addprinter-page"
static void set_device (PpNewPrinterDialog *self,
PpPrintDevice *device,
GtkTreeIter *iter);
static void replace_device (PpNewPrinterDialog *self,
PpPrintDevice *old_device,
PpPrintDevice *new_device);
static void populate_devices_list (PpNewPrinterDialog *self);
static void search_entry_activated_cb (PpNewPrinterDialog *self);
static void search_entry_changed_cb (PpNewPrinterDialog *self);
static void new_printer_dialog_response_cb (PpNewPrinterDialog *self,
gint response_id);
static void update_dialog_state (PpNewPrinterDialog *self);
static void add_devices_to_list (PpNewPrinterDialog *self,
GPtrArray *devices);
static void remove_device_from_list (PpNewPrinterDialog *self,
const gchar *device_name);
enum
{
DEVICE_GICON_COLUMN = 0,
DEVICE_NAME_COLUMN,
DEVICE_DISPLAY_NAME_COLUMN,
DEVICE_DESCRIPTION_COLUMN,
SERVER_NEEDS_AUTHENTICATION_COLUMN,
DEVICE_VISIBLE_COLUMN,
DEVICE_COLUMN,
DEVICE_N_COLUMNS
};
struct _PpNewPrinterDialog
{
GObject parent_instance;
GtkBuilder *builder;
GPtrArray *local_cups_devices;
GtkListStore *store;
GtkTreeModelFilter *filter;
GtkTreeView *treeview;
cups_dest_t *dests;
gint num_of_dests;
GCancellable *cancellable;
GCancellable *remote_host_cancellable;
gboolean cups_searching;
gboolean samba_authenticated_searching;
gboolean samba_searching;
PpPPDSelectionDialog *ppd_selection_dialog;
PpPrintDevice *new_device;
PPDList *list;
GtkWidget *dialog;
GtkWindow *parent;
GIcon *local_printer_icon;
GIcon *remote_printer_icon;
GIcon *authenticated_server_icon;
PpHost *snmp_host;
PpHost *socket_host;
PpHost *lpd_host;
PpHost *remote_cups_host;
PpSamba *samba_host;
guint host_search_timeout_id;
};
G_DEFINE_TYPE (PpNewPrinterDialog, pp_new_printer_dialog, G_TYPE_OBJECT)
static void pp_new_printer_dialog_finalize (GObject *object);
enum {
PRE_RESPONSE,
RESPONSE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
static void
pp_new_printer_dialog_class_init (PpNewPrinterDialogClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pp_new_printer_dialog_finalize;
/**
* PpNewPrinterDialog::pre-response:
* @device: the device that is being added
*
* The signal which gets emitted when the new printer dialog is closed.
*/
signals[PRE_RESPONSE] =
g_signal_new ("pre-response",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_generic,
G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
/**
* PpNewPrinterDialog::response:
* @response-id: response id of dialog
*
* The signal which gets emitted after the printer is added and configured.
*/
signals[RESPONSE] =
g_signal_new ("response",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_generic,
G_TYPE_NONE, 1, G_TYPE_INT);
}
PpNewPrinterDialog *
pp_new_printer_dialog_new (GtkWindow *parent,
PPDList *ppd_list)
{
PpNewPrinterDialog *self;
self = g_object_new (PP_TYPE_NEW_PRINTER_DIALOG, NULL);
self->list = ppd_list_copy (ppd_list);
self->parent = parent;
gtk_window_set_transient_for (GTK_WINDOW (self->dialog), GTK_WINDOW (parent));
gtk_widget_show (self->dialog);
return PP_NEW_PRINTER_DIALOG (self);
}
void
pp_new_printer_dialog_set_ppd_list (PpNewPrinterDialog *self,
PPDList *list)
{
self->list = ppd_list_copy (list);
if (self->ppd_selection_dialog)
pp_ppd_selection_dialog_set_ppd_list (self->ppd_selection_dialog, self->list);
}
static void
emit_pre_response (PpNewPrinterDialog *self,
const gchar *device_name,
const gchar *device_location,
const gchar *device_make_and_model,
gboolean network_device)
{
g_signal_emit (self,
signals[PRE_RESPONSE],
0,
device_name,
device_location,
device_make_and_model,
network_device);
}
static void
emit_response (PpNewPrinterDialog *self,
gint response_id)
{
g_signal_emit (self, signals[RESPONSE], 0, response_id);
}
typedef struct
{
gchar *server_name;
gpointer dialog;
} AuthSMBData;
static void
get_authenticated_samba_devices_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
AuthSMBData *data = user_data;
PpNewPrinterDialog *self = PP_NEW_PRINTER_DIALOG (data->dialog);
g_autoptr(GPtrArray) devices = NULL;
gboolean cancelled = FALSE;
g_autoptr(GError) error = NULL;
devices = pp_samba_get_devices_finish (PP_SAMBA (source_object), res, &error);
if (devices != NULL)
{
self->samba_authenticated_searching = FALSE;
for (guint i = 0; i < devices->len; i++)
{
PpPrintDevice *device = g_ptr_array_index (devices, i);
if (pp_print_device_is_authenticated_server (device))
{
cancelled = TRUE;
break;
}
}
if (!cancelled)
{
if (devices != NULL)
{
add_devices_to_list (self, devices);
if (devices->len > 0)
{
gtk_entry_set_text (GTK_ENTRY (WID ("search-entry")), pp_print_device_get_device_location (g_ptr_array_index (devices, 0)));
search_entry_activated_cb (self);
}
}
}
update_dialog_state (self);
}
else
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("%s", error->message);
self->samba_authenticated_searching = FALSE;
update_dialog_state (self);
}
}
g_free (data->server_name);
g_free (data);
}
static void
go_to_page (PpNewPrinterDialog *self,
const gchar *page)
{
GtkStack *stack;
stack = GTK_STACK (WID ("dialog-stack"));
gtk_stack_set_visible_child_name (stack, page);
stack = GTK_STACK (WID ("headerbar-topright-buttons"));
gtk_stack_set_visible_child_name (stack, page);
stack = GTK_STACK (WID ("headerbar-topleft-buttons"));
gtk_stack_set_visible_child_name (stack, page);
}
static gchar *
get_entry_text (const gchar *object_name,
PpNewPrinterDialog *self)
{
return g_strdup (gtk_entry_get_text (GTK_ENTRY (WID (object_name))));
}
static void
on_authenticate (PpNewPrinterDialog *self)
{
gchar *hostname = NULL;
gchar *username = NULL;
gchar *password = NULL;
username = get_entry_text ("username-entry", self);
password = get_entry_text ("password-entry", self);
if ((username == NULL) || (username[0] == '\0') ||
(password == NULL) || (password[0] == '\0'))
{
g_clear_pointer (&username, g_free);
g_clear_pointer (&password, g_free);
return;
}
pp_samba_set_auth_info (PP_SAMBA (self->samba_host), username, password);
gtk_header_bar_set_title (GTK_HEADER_BAR (WID ("headerbar")), _("Add Printer"));
go_to_page (self, ADDPRINTER_PAGE);
g_object_get (PP_HOST (self->samba_host), "hostname", &hostname, NULL);
remove_device_from_list (self, hostname);
}
static void
on_authentication_required (PpNewPrinterDialog *self)
{
g_autofree gchar *hostname = NULL;
g_autofree gchar *title = NULL;
g_autofree gchar *text = NULL;
gtk_header_bar_set_subtitle (GTK_HEADER_BAR (WID ("headerbar")), NULL);
gtk_header_bar_set_title (GTK_HEADER_BAR (WID ("headerbar")), _("Unlock Print Server"));
g_object_get (self->samba_host, "hostname", &hostname, NULL);
/* Translators: Samba server needs authentication of the user to show list of its printers. */
title = g_strdup_printf (_("Unlock %s."), hostname);
gtk_label_set_text (GTK_LABEL (WID ("authentication-title")), title);
/* Translators: Samba server needs authentication of the user to show list of its printers. */
text = g_strdup_printf (_("Enter username and password to view printers on %s."), hostname);
gtk_label_set_text (GTK_LABEL (WID ("authentication-text")), text);
go_to_page (self, AUTHENTICATION_PAGE);
g_signal_connect_object (WID ("authenticate-button"), "clicked", G_CALLBACK (on_authenticate), self, G_CONNECT_SWAPPED);
}
static void
auth_entries_changed (PpNewPrinterDialog *self)
{
gboolean can_authenticate = FALSE;
gchar *username = NULL;
gchar *password = NULL;
username = get_entry_text ("username-entry", self);
password = get_entry_text ("password-entry", self);
can_authenticate = (username != NULL && username[0] != '\0' &&
password != NULL && password[0] != '\0');
gtk_widget_set_sensitive (WID ("authenticate-button"), can_authenticate);
g_clear_pointer (&username, g_free);
g_clear_pointer (&password, g_free);
}
static void
on_go_back_button_clicked (PpNewPrinterDialog *self)
{
pp_samba_set_auth_info (self->samba_host, NULL, NULL);
g_clear_object (&self->samba_host);
go_to_page (self, ADDPRINTER_PAGE);
gtk_header_bar_set_title (GTK_HEADER_BAR (WID ("headerbar")), _("Add Printer"));
gtk_widget_set_sensitive (WID ("new-printer-add-button"), FALSE);
gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (self->treeview));
}
static void
authenticate_samba_server (PpNewPrinterDialog *self)
{
GtkTreeModel *model;
GtkTreeIter iter;
AuthSMBData *data;
gchar *server_name = NULL;
gtk_widget_set_sensitive (WID ("unlock-button"), FALSE);
gtk_widget_set_sensitive (WID ("authenticate-button"), FALSE);
gtk_widget_grab_focus (WID ("username-entry"));
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->treeview), &model, &iter))
{
gtk_tree_model_get (model, &iter,
DEVICE_NAME_COLUMN, &server_name,
-1);
if (server_name != NULL)
{
g_clear_object (&self->samba_host);
self->samba_host = pp_samba_new (server_name);
g_signal_connect_object (self->samba_host,
"authentication-required",
G_CALLBACK (on_authentication_required),
self, G_CONNECT_SWAPPED);
self->samba_authenticated_searching = TRUE;
update_dialog_state (self);
data = g_new (AuthSMBData, 1);
data->server_name = server_name;
data->dialog = self;
pp_samba_get_devices_async (self->samba_host,
TRUE,
self->cancellable,
get_authenticated_samba_devices_cb,
data);
}
}
}
static gboolean
stack_key_press_cb (PpNewPrinterDialog *self,
GdkEvent *event)
{
gtk_widget_grab_focus (WID ("search-entry"));
gtk_main_do_event (event);
return TRUE;
}
static void
pp_new_printer_dialog_init (PpNewPrinterDialog *self)
{
GtkStyleContext *context;
GtkWidget *widget;
g_autoptr(GError) error = NULL;
gchar *objects[] = { "dialog",
"devices-liststore",
"devices-model-filter",
NULL };
guint builder_result;
self->builder = gtk_builder_new ();
builder_result = gtk_builder_add_objects_from_resource (self->builder,
"/org/gnome/control-center/printers/new-printer-dialog.ui",
objects, &error);
if (builder_result == 0)
{
g_warning ("Could not load ui: %s", error->message);
}
self->local_cups_devices = g_ptr_array_new_with_free_func (g_object_unref);
/* GCancellable for cancelling of async operations */
self->cancellable = g_cancellable_new ();
/* Construct dialog */
self->dialog = WID ("dialog");
self->treeview = GTK_TREE_VIEW (WID ("devices-treeview"));
self->store = GTK_LIST_STORE (gtk_builder_get_object (self->builder, "devices-liststore"));
self->filter = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (self->builder, "devices-model-filter"));
/* Connect signals */
g_signal_connect_object (self->dialog, "response", G_CALLBACK (new_printer_dialog_response_cb), self, G_CONNECT_SWAPPED);
widget = WID ("search-entry");
g_signal_connect_object (widget, "activate", G_CALLBACK (search_entry_activated_cb), self, G_CONNECT_SWAPPED);
g_signal_connect_object (widget, "search-changed", G_CALLBACK (search_entry_changed_cb), self, G_CONNECT_SWAPPED);
g_signal_connect_object (WID ("unlock-button"), "clicked", G_CALLBACK (authenticate_samba_server), self, G_CONNECT_SWAPPED);
g_signal_connect_object (WID ("stack"), "key-press-event", G_CALLBACK (stack_key_press_cb), self, G_CONNECT_SWAPPED);
/* Authentication form widgets */
g_signal_connect_object (WID ("username-entry"), "changed", G_CALLBACK (auth_entries_changed), self, G_CONNECT_SWAPPED);
g_signal_connect_object (WID ("password-entry"), "changed", G_CALLBACK (auth_entries_changed), self, G_CONNECT_SWAPPED);
g_signal_connect_object (WID ("go-back-button"), "clicked", G_CALLBACK (on_go_back_button_clicked), self, G_CONNECT_SWAPPED);
/* Set junctions */
widget = WID ("scrolledwindow1");
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
widget = WID ("toolbar1");
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
/* Fill with data */
populate_devices_list (self);
}
static void
pp_new_printer_dialog_finalize (GObject *object)
{
PpNewPrinterDialog *self = PP_NEW_PRINTER_DIALOG (object);
g_cancellable_cancel (self->remote_host_cancellable);
g_cancellable_cancel (self->cancellable);
g_clear_handle_id (&self->host_search_timeout_id, g_source_remove);
g_clear_object (&self->remote_host_cancellable);
g_clear_object (&self->cancellable);
g_clear_pointer (&self->dialog, gtk_widget_destroy);
g_clear_pointer (&self->list, ppd_list_free);
g_clear_object (&self->builder);
g_clear_pointer (&self->local_cups_devices, g_ptr_array_unref);
g_clear_object (&self->new_device);
g_clear_object (&self->local_printer_icon);
g_clear_object (&self->remote_printer_icon);
g_clear_object (&self->authenticated_server_icon);
g_clear_object (&self->snmp_host);
g_clear_object (&self->socket_host);
g_clear_object (&self->lpd_host);
g_clear_object (&self->remote_cups_host);
g_clear_object (&self->samba_host);
if (self->num_of_dests > 0)
{
cupsFreeDests (self->num_of_dests, self->dests);
self->num_of_dests = 0;
self->dests = NULL;
}
G_OBJECT_CLASS (pp_new_printer_dialog_parent_class)->finalize (object);
}
static void
device_selection_changed_cb (PpNewPrinterDialog *self)
{
GtkTreeModel *model;
GtkTreeIter iter;
GtkWidget *widget;
GtkWidget *stack;
gboolean authentication_needed;
gboolean selected;
selected = gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->treeview),
&model,
&iter);
if (selected)
{
gtk_tree_model_get (model, &iter,
SERVER_NEEDS_AUTHENTICATION_COLUMN, &authentication_needed,
-1);
widget = WID ("new-printer-add-button");
gtk_widget_set_sensitive (widget, selected);
widget = WID ("unlock-button");
gtk_widget_set_sensitive (widget, authentication_needed);
stack = WID ("headerbar-topright-buttons");
if (authentication_needed)
gtk_stack_set_visible_child_name (GTK_STACK (stack), "unlock-button");
else
gtk_stack_set_visible_child_name (GTK_STACK (stack), ADDPRINTER_PAGE);
}
}
static void
remove_device_from_list (PpNewPrinterDialog *self,
const gchar *device_name)
{
GtkTreeIter iter;
gboolean cont;
cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter);
while (cont)
{
g_autoptr(PpPrintDevice) device = NULL;
gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
DEVICE_COLUMN, &device,
-1);
if (g_strcmp0 (pp_print_device_get_device_name (device), device_name) == 0)
{
gtk_list_store_remove (self->store, &iter);
break;
}
cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->store), &iter);
}
update_dialog_state (self);
}
static gboolean
prepend_original_name (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer data)
{
g_autoptr(PpPrintDevice) device = NULL;
GList **list = data;
gtk_tree_model_get (model, iter,
DEVICE_COLUMN, &device,
-1);
*list = g_list_prepend (*list, g_strdup (pp_print_device_get_device_original_name (device)));
return FALSE;
}
static void
add_device_to_list (PpNewPrinterDialog *self,
PpPrintDevice *device)
{
GList *original_names_list = NULL;
gint acquisition_method;
if (device)
{
if (pp_print_device_get_host_name (device) == NULL)
{
g_autofree gchar *host_name = guess_device_hostname (device);
g_object_set (device, "host-name", host_name, NULL);
}
acquisition_method = pp_print_device_get_acquisition_method (device);
if (pp_print_device_get_device_id (device) ||
pp_print_device_get_device_ppd (device) ||
(pp_print_device_get_host_name (device) &&
acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER) ||
acquisition_method == ACQUISITION_METHOD_SAMBA_HOST ||
acquisition_method == ACQUISITION_METHOD_SAMBA ||
(pp_print_device_get_device_uri (device) &&
(acquisition_method == ACQUISITION_METHOD_JETDIRECT ||
acquisition_method == ACQUISITION_METHOD_LPD)))
{
g_autofree gchar *canonicalized_name = NULL;
g_object_set (device,
"device-original-name", pp_print_device_get_device_name (device),
NULL);
gtk_tree_model_foreach (GTK_TREE_MODEL (self->store),
prepend_original_name,
&original_names_list);
original_names_list = g_list_reverse (original_names_list);
canonicalized_name = canonicalize_device_name (original_names_list,
self->local_cups_devices,
self->dests,
self->num_of_dests,
device);
g_list_free_full (original_names_list, g_free);
g_object_set (device,
"display-name", canonicalized_name,
"device-name", canonicalized_name,
NULL);
if (pp_print_device_get_acquisition_method (device) == ACQUISITION_METHOD_DEFAULT_CUPS_SERVER)
g_ptr_array_add (self->local_cups_devices, g_object_ref (device));
else
set_device (self, device, NULL);
}
else if (pp_print_device_is_authenticated_server (device) &&
pp_print_device_get_host_name (device) != NULL)
{
g_autoptr(PpPrintDevice) store_device = NULL;
store_device = g_object_new (PP_TYPE_PRINT_DEVICE,
"device-name", pp_print_device_get_host_name (device),
"host-name", pp_print_device_get_host_name (device),
"is-authenticated-server", pp_print_device_is_authenticated_server (device),
NULL);
set_device (self, store_device, NULL);
}
}
}
static void
add_devices_to_list (PpNewPrinterDialog *self,
GPtrArray *devices)
{
for (guint i = 0; i < devices->len; i++)
add_device_to_list (self, g_ptr_array_index (devices, i));
}
static PpPrintDevice *
device_in_list (gchar *device_uri,
GPtrArray *device_list)
{
for (guint i = 0; i < device_list->len; i++)
{
PpPrintDevice *device = g_ptr_array_index (device_list, i);
/* GroupPhysicalDevices returns uris without port numbers */
if (pp_print_device_get_device_uri (device) != NULL &&
g_str_has_prefix (pp_print_device_get_device_uri (device), device_uri))
return g_object_ref (device);
}
return NULL;
}
static PpPrintDevice *
device_in_liststore (gchar *device_uri,
GtkListStore *device_liststore)
{
GtkTreeIter iter;
gboolean cont;
cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (device_liststore), &iter);
while (cont)
{
g_autoptr(PpPrintDevice) device = NULL;
gtk_tree_model_get (GTK_TREE_MODEL (device_liststore), &iter,
DEVICE_COLUMN, &device,
-1);
/* GroupPhysicalDevices returns uris without port numbers */
if (pp_print_device_get_device_uri (device) != NULL &&
g_str_has_prefix (pp_print_device_get_device_uri (device), device_uri))
{
return g_steal_pointer(&device);
}
cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (device_liststore), &iter);
}
return NULL;
}
static void
update_dialog_state (PpNewPrinterDialog *self)
{
GtkTreeIter iter;
GtkWidget *header;
GtkWidget *stack;
gboolean searching;
searching = self->cups_searching ||
self->remote_cups_host != NULL ||
self->snmp_host != NULL ||
self->socket_host != NULL ||
self->lpd_host != NULL ||
self->samba_host != NULL ||
self->samba_authenticated_searching ||
self->samba_searching;
header = WID ("headerbar");
stack = WID ("stack");
if (searching)
{
gtk_header_bar_set_subtitle (GTK_HEADER_BAR (header), _("Searching for Printers"));
}
else
{
gtk_header_bar_set_subtitle (GTK_HEADER_BAR (header), NULL);
}
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter))
gtk_stack_set_visible_child_name (GTK_STACK (stack), "standard-page");
else
gtk_stack_set_visible_child_name (GTK_STACK (stack), searching ? "loading-page" : "no-printers-page");
}
static void
group_physical_devices_cb (gchar ***device_uris,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
gint i, j;
if (device_uris != NULL)
{
for (i = 0; device_uris[i] != NULL; i++)
{
/* Is there any device in this sublist? */
if (device_uris[i][0] != NULL)
{
g_autoptr(PpPrintDevice) device = NULL;
for (j = 0; device_uris[i][j] != NULL; j++)
{
device = device_in_liststore (device_uris[i][j], self->store);
if (device != NULL)
break;
}
/* Is this sublist represented in the current list of devices? */
if (device != NULL)
{
/* Is there better device in the sublist? */
if (j != 0)
{
g_autoptr(PpPrintDevice) better_device = NULL;
better_device = device_in_list (device_uris[i][0], self->local_cups_devices);
replace_device (self, device, better_device);
}
}
else
{
device = device_in_list (device_uris[i][0], self->local_cups_devices);
if (device != NULL)
set_device (self, device, NULL);
}
}
}
for (i = 0; device_uris[i] != NULL; i++)
g_strfreev (device_uris[i]);
g_free (device_uris);
}
else
{
for (i = 0; i < self->local_cups_devices->len; i++)
set_device (self, g_ptr_array_index (self->local_cups_devices, i), NULL);
g_ptr_array_set_size (self->local_cups_devices, 0);
}
update_dialog_state (self);
}
static void
group_physical_devices_dbus_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr(GVariant) output = NULL;
g_autoptr(GError) error = NULL;
gchar ***result = NULL;
gint i;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
&error);
if (output)
{
g_autoptr(GVariant) array = NULL;
g_variant_get (output, "(@aas)", &array);
if (array)
{
g_autoptr(GVariantIter) iter = NULL;
GStrv device_uris;
result = g_new0 (gchar **, g_variant_n_children (array) + 1);
g_variant_get (array, "aas", &iter);
i = 0;
while (g_variant_iter_next (iter, "^as", &device_uris))
{
result[i] = device_uris;
i++;
}
}
}
else if (error &&
error->domain == G_DBUS_ERROR &&
(error->code == G_DBUS_ERROR_SERVICE_UNKNOWN ||
error->code == G_DBUS_ERROR_UNKNOWN_METHOD))
{
g_warning ("Install system-config-printer which provides \
DBus method \"GroupPhysicalDevices\" to group duplicates in device list.");
}
else
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("%s", error->message);
}
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
group_physical_devices_cb (result, user_data);
}
static void
get_cups_devices_cb (GPtrArray *devices,
gboolean finished,
gboolean cancelled,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
g_autoptr(GDBusConnection) bus = NULL;
GVariantBuilder device_list;
GVariantBuilder device_hash;
PpPrintDevice **all_devices;
const gchar *device_class;
GtkTreeIter iter;
gboolean cont;
g_autoptr(GError) error = NULL;
gint length, i;
if (!cancelled)
{
if (finished)
{
self->cups_searching = FALSE;
}
if (devices != NULL)
{
add_devices_to_list (self, devices);
length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (self->store), NULL) + self->local_cups_devices->len;
if (length > 0)
{
all_devices = g_new0 (PpPrintDevice *, length);
i = 0;
cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter);
while (cont)
{
g_autoptr(PpPrintDevice) device = NULL;
gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
DEVICE_COLUMN, &device,
-1);
all_devices[i] = g_object_new (PP_TYPE_PRINT_DEVICE,
"device-id", pp_print_device_get_device_id (device),
"device-make-and-model", pp_print_device_get_device_make_and_model (device),
"is-network-device", pp_print_device_is_network_device (device),
"device-uri", pp_print_device_get_device_uri (device),
NULL);
i++;
cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->store), &iter);
}
for (guint j = 0; j < self->local_cups_devices->len; j++)
{
PpPrintDevice *pp_device = g_ptr_array_index (self->local_cups_devices, j);
all_devices[i] = g_object_new (PP_TYPE_PRINT_DEVICE,
"device-id", pp_print_device_get_device_id (pp_device),
"device-make-and-model", pp_print_device_get_device_make_and_model (pp_device),
"is-network-device", pp_print_device_is_network_device (pp_device),
"device-uri", pp_print_device_get_device_uri (pp_device),
NULL);
i++;
}
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (bus)
{
g_variant_builder_init (&device_list, G_VARIANT_TYPE ("a{sv}"));
for (i = 0; i < length; i++)
{
if (pp_print_device_get_device_uri (all_devices[i]))
{
g_variant_builder_init (&device_hash, G_VARIANT_TYPE ("a{ss}"));
if (pp_print_device_get_device_id (all_devices[i]))
g_variant_builder_add (&device_hash,
"{ss}",
"device-id",
pp_print_device_get_device_id (all_devices[i]));
if (pp_print_device_get_device_make_and_model (all_devices[i]))
g_variant_builder_add (&device_hash,
"{ss}",
"device-make-and-model",
pp_print_device_get_device_make_and_model (all_devices[i]));
if (pp_print_device_is_network_device (all_devices[i]))
device_class = "network";
else
device_class = "direct";
g_variant_builder_add (&device_hash,
"{ss}",
"device-class",
device_class);
g_variant_builder_add (&device_list,
"{sv}",
pp_print_device_get_device_uri (all_devices[i]),
g_variant_builder_end (&device_hash));
}
}
g_dbus_connection_call (bus,
SCP_BUS,
SCP_PATH,
SCP_IFACE,
"GroupPhysicalDevices",
g_variant_new ("(v)", g_variant_builder_end (&device_list)),
G_VARIANT_TYPE ("(aas)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
self->cancellable,
group_physical_devices_dbus_cb,
self);
}
else
{
g_warning ("Failed to get system bus: %s", error->message);
group_physical_devices_cb (NULL, user_data);
}
for (i = 0; i < length; i++)
g_object_unref (all_devices[i]);
g_free (all_devices);
}
else
{
update_dialog_state (self);
}
}
else
{
update_dialog_state (self);
}
}
}
static void
get_snmp_devices_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) devices = NULL;
devices = pp_host_get_snmp_devices_finish (PP_HOST (source_object), res, &error);
if (devices != NULL)
{
g_clear_object(&self->snmp_host);
add_devices_to_list (self, devices);
update_dialog_state (self);
}
else
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("%s", error->message);
g_clear_object(&self->snmp_host);
update_dialog_state (self);
}
}
}
static void
get_remote_cups_devices_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) devices = NULL;
devices = pp_host_get_remote_cups_devices_finish (PP_HOST (source_object), res, &error);
if (devices != NULL)
{
g_clear_object(&self->remote_cups_host);
add_devices_to_list (self, devices);
update_dialog_state (self);
}
else
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("%s", error->message);
g_clear_object(&self->remote_cups_host);
update_dialog_state (self);
}
}
}
static void
get_samba_host_devices_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GError) error = NULL;
devices = pp_samba_get_devices_finish (PP_SAMBA (source_object), res, &error);
if (devices != NULL)
{
g_clear_object(&self->samba_host);
add_devices_to_list (self, devices);
update_dialog_state (self);
}
else
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("%s", error->message);
g_clear_object(&self->samba_host);
update_dialog_state (self);
}
}
}
static void
get_samba_devices_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GError) error = NULL;
devices = pp_samba_get_devices_finish (PP_SAMBA (source_object), res, &error);
if (devices != NULL)
{
self->samba_searching = FALSE;
add_devices_to_list (self, devices);
update_dialog_state (self);
}
else
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("%s", error->message);
self->samba_searching = FALSE;
update_dialog_state (self);
}
}
}
static void
get_jetdirect_devices_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) devices = NULL;
devices = pp_host_get_jetdirect_devices_finish (PP_HOST (source_object), res, &error);
if (devices != NULL)
{
g_clear_object(&self->socket_host);
add_devices_to_list (self, devices);
update_dialog_state (self);
}
else
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("%s", error->message);
g_clear_object(&self->socket_host);
update_dialog_state (self);
}
}
}
static void
get_lpd_devices_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) devices = NULL;
devices = pp_host_get_lpd_devices_finish (PP_HOST (source_object), res, &error);
if (devices != NULL)
{
g_clear_object(&self->lpd_host);
add_devices_to_list (self, devices);
update_dialog_state (self);
}
else
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("%s", error->message);
g_clear_object(&self->lpd_host);
update_dialog_state (self);
}
}
}
static void
get_cups_devices (PpNewPrinterDialog *self)
{
self->cups_searching = TRUE;
update_dialog_state (self);
get_cups_devices_async (self->cancellable,
get_cups_devices_cb,
self);
}
static gboolean
parse_uri (const gchar *uri,
gchar **scheme,
gchar **host,
gint *port)
{
const gchar *tmp = NULL;
g_autofree gchar *resulting_host = NULL;
gchar *position;
*port = PP_HOST_UNSET_PORT;
position = g_strrstr (uri, "://");
if (position != NULL)
{
*scheme = g_strndup (uri, position - uri);
tmp = position + 3;
}
else
{
tmp = uri;
}
if (g_strrstr (tmp, "@"))
tmp = g_strrstr (tmp, "@") + 1;
if ((position = g_strrstr (tmp, "/")))
{
*position = '\0';
resulting_host = g_strdup (tmp);
*position = '/';
}
else
{
resulting_host = g_strdup (tmp);
}
if ((position = g_strrstr (resulting_host, ":")))
{
*position = '\0';
*port = atoi (position + 1);
}
*host = g_uri_unescape_string (resulting_host,
G_URI_RESERVED_CHARS_GENERIC_DELIMITERS
G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS);
return TRUE;
}
typedef struct
{
PpNewPrinterDialog *dialog;
gchar *host_scheme;
gchar *host_name;
gint host_port;
} THostSearchData;
static void
search_for_remote_printers_free (THostSearchData *data)
{
g_free (data->host_scheme);
g_free (data->host_name);
g_free (data);
}
static gboolean
search_for_remote_printers (THostSearchData *data)
{
PpNewPrinterDialog *self = data->dialog;
g_cancellable_cancel (self->remote_host_cancellable);
g_clear_object (&self->remote_host_cancellable);
self->remote_host_cancellable = g_cancellable_new ();
self->remote_cups_host = pp_host_new (data->host_name);
self->snmp_host = pp_host_new (data->host_name);
self->socket_host = pp_host_new (data->host_name);
self->lpd_host = pp_host_new (data->host_name);
if (data->host_port != PP_HOST_UNSET_PORT)
{
g_object_set (self->remote_cups_host, "port", data->host_port, NULL);
g_object_set (self->snmp_host, "port", data->host_port, NULL);
/* Accept port different from the default one only if user specifies
* scheme (for socket and lpd printers).
*/
if (data->host_scheme != NULL &&
g_ascii_strcasecmp (data->host_scheme, "socket") == 0)
g_object_set (self->socket_host, "port", data->host_port, NULL);
if (data->host_scheme != NULL &&
g_ascii_strcasecmp (data->host_scheme, "lpd") == 0)
g_object_set (self->lpd_host, "port", data->host_port, NULL);
}
self->samba_host = pp_samba_new (data->host_name);
update_dialog_state (data->dialog);
pp_host_get_remote_cups_devices_async (self->remote_cups_host,
self->remote_host_cancellable,
get_remote_cups_devices_cb,
data->dialog);
pp_host_get_snmp_devices_async (self->snmp_host,
self->remote_host_cancellable,
get_snmp_devices_cb,
data->dialog);
pp_host_get_jetdirect_devices_async (self->socket_host,
self->remote_host_cancellable,
get_jetdirect_devices_cb,
data->dialog);
pp_host_get_lpd_devices_async (self->lpd_host,
self->remote_host_cancellable,
get_lpd_devices_cb,
data->dialog);
pp_samba_get_devices_async (self->samba_host,
FALSE,
self->remote_host_cancellable,
get_samba_host_devices_cb,
data->dialog);
self->host_search_timeout_id = 0;
return G_SOURCE_REMOVE;
}
static void
search_address (const gchar *text,
PpNewPrinterDialog *self,
gboolean delay_search)
{
GtkTreeIter iter;
gboolean found = FALSE;
gboolean subfound;
gboolean next_set;
gboolean cont;
g_autofree gchar *lowercase_text = NULL;
gchar **words;
gint words_length = 0;
gint i;
gint acquisition_method;
lowercase_text = g_ascii_strdown (text, -1);
words = g_strsplit_set (lowercase_text, " ", -1);
if (words)
{
words_length = g_strv_length (words);
cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter);
while (cont)
{
g_autoptr(PpPrintDevice) device = NULL;
g_autofree gchar *lowercase_name = NULL;
g_autofree gchar *lowercase_location = NULL;
gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
DEVICE_COLUMN, &device,
-1);
lowercase_name = g_ascii_strdown (pp_print_device_get_device_name (device), -1);
if (pp_print_device_get_device_location (device))
lowercase_location = g_ascii_strdown (pp_print_device_get_device_location (device), -1);
else
lowercase_location = NULL;
subfound = TRUE;
for (i = 0; words[i]; i++)
{
if (!g_strrstr (lowercase_name, words[i]) &&
(!lowercase_location || !g_strrstr (lowercase_location, words[i])))
subfound = FALSE;
}
if (subfound)
found = TRUE;
gtk_list_store_set (GTK_LIST_STORE (self->store), &iter,
DEVICE_VISIBLE_COLUMN, subfound,
-1);
cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->store), &iter);
}
g_strfreev (words);
}
/*
* The given word is probably an address since it was not found among
* already present devices.
*/
if (!found && words_length == 1)
{
cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter);
while (cont)
{
g_autoptr(PpPrintDevice) device = NULL;
next_set = FALSE;
gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
DEVICE_COLUMN, &device,
-1);
gtk_list_store_set (GTK_LIST_STORE (self->store), &iter,
DEVICE_VISIBLE_COLUMN, TRUE,
-1);
acquisition_method = pp_print_device_get_acquisition_method (device);
if (acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER ||
acquisition_method == ACQUISITION_METHOD_SNMP ||
acquisition_method == ACQUISITION_METHOD_JETDIRECT ||
acquisition_method == ACQUISITION_METHOD_LPD ||
acquisition_method == ACQUISITION_METHOD_SAMBA_HOST)
{
if (!gtk_list_store_remove (self->store, &iter))
break;
else
next_set = TRUE;
}
if (!next_set)
cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->store), &iter);
}
if (text && text[0] != '\0')
{
g_autoptr(GSocketConnectable) conn = NULL;
g_autofree gchar *test_uri = NULL;
g_autofree gchar *test_port = NULL;
gchar *scheme = NULL;
gchar *host = NULL;
gint port;
parse_uri (text, &scheme, &host, &port);
if (host != NULL)
{
if (port >= 0)
test_port = g_strdup_printf (":%d", port);
else
test_port = g_strdup ("");
test_uri = g_strdup_printf ("%s://%s%s",
scheme != NULL && scheme[0] != '\0' ? scheme : "none",
host,
test_port);
conn = g_network_address_parse_uri (test_uri, 0, NULL);
if (conn != NULL)
{
THostSearchData *search_data;
search_data = g_new (THostSearchData, 1);
search_data->host_scheme = scheme;
search_data->host_name = host;
search_data->host_port = port;
search_data->dialog = self;
if (self->host_search_timeout_id != 0)
{
g_source_remove (self->host_search_timeout_id);
self->host_search_timeout_id = 0;
}
if (delay_search)
{
self->host_search_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
HOST_SEARCH_DELAY,
(GSourceFunc) search_for_remote_printers,
search_data,
(GDestroyNotify) search_for_remote_printers_free);
}
else
{
search_for_remote_printers (search_data);
search_for_remote_printers_free (search_data);
}
}
}
}
}
}
static void
search_entry_activated_cb (PpNewPrinterDialog *self)
{
search_address (gtk_entry_get_text (GTK_ENTRY (WID ("search-entry"))),
self,
FALSE);
}
static void
search_entry_changed_cb (PpNewPrinterDialog *self)
{
search_address (gtk_entry_get_text (GTK_ENTRY (WID ("search-entry"))),
self,
TRUE);
}
static gchar *
get_local_scheme_description_from_uri (gchar *device_uri)
{
gchar *description = NULL;
if (device_uri != NULL)
{
if (g_str_has_prefix (device_uri, "usb") ||
g_str_has_prefix (device_uri, "hp:/usb/") ||
g_str_has_prefix (device_uri, "hpfax:/usb/"))
{
/* Translators: The found device is a printer connected via USB */
description = g_strdup (_("USB"));
}
else if (g_str_has_prefix (device_uri, "serial"))
{
/* Translators: The found device is a printer connected via serial port */
description = g_strdup (_("Serial Port"));
}
else if (g_str_has_prefix (device_uri, "parallel") ||
g_str_has_prefix (device_uri, "hp:/par/") ||
g_str_has_prefix (device_uri, "hpfax:/par/"))
{
/* Translators: The found device is a printer connected via parallel port */
description = g_strdup (_("Parallel Port"));
}
else if (g_str_has_prefix (device_uri, "bluetooth"))
{
/* Translators: The found device is a printer connected via Bluetooth */
description = g_strdup (_("Bluetooth"));
}
}
return description;
}
static void
set_device (PpNewPrinterDialog *self,
PpPrintDevice *device,
GtkTreeIter *iter)
{
GtkTreeIter titer;
gint acquisition_method;
if (device != NULL)
{
acquisition_method = pp_print_device_get_acquisition_method (device);
if (pp_print_device_get_display_name (device) &&
(pp_print_device_get_device_id (device) ||
pp_print_device_get_device_ppd (device) ||
(pp_print_device_get_host_name (device) &&
acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER) ||
(pp_print_device_get_device_uri (device) &&
(acquisition_method == ACQUISITION_METHOD_JETDIRECT ||
acquisition_method == ACQUISITION_METHOD_LPD)) ||
acquisition_method == ACQUISITION_METHOD_SAMBA_HOST ||
acquisition_method == ACQUISITION_METHOD_SAMBA))
{
g_autofree gchar *description = NULL;
description = get_local_scheme_description_from_uri (pp_print_device_get_device_uri (device));
if (description == NULL)
{
if (pp_print_device_get_device_location (device) != NULL && pp_print_device_get_device_location (device)[0] != '\0')
{
/* Translators: Location of found network printer (e.g. Kitchen, Reception) */
description = g_strdup_printf (_("Location: %s"), pp_print_device_get_device_location (device));
}
else if (pp_print_device_get_host_name (device) != NULL && pp_print_device_get_host_name (device)[0] != '\0')
{
/* Translators: Network address of found printer */
description = g_strdup_printf (_("Address: %s"), pp_print_device_get_host_name (device));
}
}
if (iter == NULL)
gtk_list_store_append (self->store, &titer);
gtk_list_store_set (self->store, iter == NULL ? &titer : iter,
DEVICE_GICON_COLUMN, pp_print_device_is_network_device (device) ? self->remote_printer_icon : self->local_printer_icon,
DEVICE_NAME_COLUMN, pp_print_device_get_device_name (device),
DEVICE_DISPLAY_NAME_COLUMN, pp_print_device_get_display_name (device),
DEVICE_DESCRIPTION_COLUMN, description,
DEVICE_VISIBLE_COLUMN, TRUE,
DEVICE_COLUMN, device,
-1);
}
else if (pp_print_device_is_authenticated_server (device) &&
pp_print_device_get_host_name (device) != NULL)
{
if (iter == NULL)
gtk_list_store_append (self->store, &titer);
gtk_list_store_set (self->store, iter == NULL ? &titer : iter,
DEVICE_GICON_COLUMN, self->authenticated_server_icon,
DEVICE_NAME_COLUMN, pp_print_device_get_host_name (device),
DEVICE_DISPLAY_NAME_COLUMN, pp_print_device_get_host_name (device),
/* Translators: This item is a server which needs authentication to show its printers */
DEVICE_DESCRIPTION_COLUMN, _("Server requires authentication"),
SERVER_NEEDS_AUTHENTICATION_COLUMN, TRUE,
DEVICE_VISIBLE_COLUMN, TRUE,
DEVICE_COLUMN, device,
-1);
}
}
}
static void
replace_device (PpNewPrinterDialog *self,
PpPrintDevice *old_device,
PpPrintDevice *new_device)
{
GtkTreeIter iter;
gboolean cont;
if (old_device != NULL && new_device != NULL)
{
cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter);
while (cont)
{
g_autoptr(PpPrintDevice) device = NULL;
gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
DEVICE_COLUMN, &device,
-1);
if (old_device == device)
{
set_device (self, new_device, &iter);
break;
}
cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->store), &iter);
}
}
}
static void
cups_get_dests_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
PpCupsDests *dests;
g_autoptr(GError) error = NULL;
dests = pp_cups_get_dests_finish (PP_CUPS (source_object), res, &error);
if (dests)
{
self->dests = dests->dests;
self->num_of_dests = dests->num_of_dests;
get_cups_devices (self);
}
else
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("%s", error->message);
get_cups_devices (self);
}
}
}
static void
row_activated_cb (PpNewPrinterDialog *self)
{
GtkTreeModel *model;
GtkTreeIter iter;
gboolean authentication_needed;
gboolean selected;
selected = gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->treeview),
&model,
&iter);
if (selected)
{
gtk_tree_model_get (model, &iter, SERVER_NEEDS_AUTHENTICATION_COLUMN, &authentication_needed, -1);
if (authentication_needed)
{
authenticate_samba_server (self);
}
else
{
gtk_dialog_response (GTK_DIALOG (self->dialog), GTK_RESPONSE_OK);
}
}
}
static void
cell_data_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
gboolean selected = FALSE;
g_autofree gchar *name = NULL;
g_autofree gchar *description = NULL;
selected = gtk_tree_selection_iter_is_selected (gtk_tree_view_get_selection (self->treeview), iter);
gtk_tree_model_get (tree_model, iter,
DEVICE_DISPLAY_NAME_COLUMN, &name,
DEVICE_DESCRIPTION_COLUMN, &description,
-1);
if (name != NULL)
{
g_autofree gchar *text = NULL;
if (description != NULL)
{
if (selected)
text = g_markup_printf_escaped ("<b>%s</b>\n<small>%s</small>",
name,
description);
else
text = g_markup_printf_escaped ("<b>%s</b>\n<small><span foreground=\"#555555\">%s</span></small>",
name,
description);
}
else
{
text = g_markup_printf_escaped ("<b>%s</b>\n ",
name);
}
g_object_set (G_OBJECT (cell),
"markup", text,
NULL);
}
}
static void
populate_devices_list (PpNewPrinterDialog *self)
{
GtkTreeViewColumn *column;
g_autoptr(PpSamba) samba = NULL;
g_autoptr(GEmblem) emblem = NULL;
g_autoptr(PpCups) cups = NULL;
g_autoptr(GIcon) icon = NULL;
g_autoptr(GIcon) emblem_icon = NULL;
GtkCellRenderer *text_renderer;
GtkCellRenderer *icon_renderer;
g_signal_connect_object (gtk_tree_view_get_selection (self->treeview),
"changed", G_CALLBACK (device_selection_changed_cb), self, G_CONNECT_SWAPPED);
g_signal_connect_object (self->treeview,
"row-activated", G_CALLBACK (row_activated_cb), self, G_CONNECT_SWAPPED);
self->local_printer_icon = g_themed_icon_new ("printer");
self->remote_printer_icon = g_themed_icon_new ("printer-network");
icon = g_themed_icon_new ("network-server");
emblem_icon = g_themed_icon_new ("changes-prevent");
emblem = g_emblem_new (emblem_icon);
self->authenticated_server_icon = g_emblemed_icon_new (icon, emblem);
icon_renderer = gtk_cell_renderer_pixbuf_new ();
g_object_set (icon_renderer, "stock-size", GTK_ICON_SIZE_DIALOG, NULL);
gtk_cell_renderer_set_alignment (icon_renderer, 1.0, 0.5);
gtk_cell_renderer_set_padding (icon_renderer, 4, 4);
column = gtk_tree_view_column_new_with_attributes ("Icon", icon_renderer,
"gicon", DEVICE_GICON_COLUMN, NULL);
gtk_tree_view_column_set_max_width (column, -1);
gtk_tree_view_column_set_min_width (column, 80);
gtk_tree_view_append_column (self->treeview, column);
text_renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Devices", text_renderer,
NULL);
gtk_tree_view_column_set_cell_data_func (column, text_renderer, cell_data_func,
self, NULL);
gtk_tree_view_append_column (self->treeview, column);
gtk_tree_model_filter_set_visible_column (self->filter, DEVICE_VISIBLE_COLUMN);
cups = pp_cups_new ();
pp_cups_get_dests_async (cups, self->cancellable, cups_get_dests_cb, self);
self->samba_searching = TRUE;
update_dialog_state (self);
samba = pp_samba_new (NULL);
pp_samba_get_devices_async (samba, FALSE, self->cancellable, get_samba_devices_cb, self);
}
static void
printer_add_async_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
GtkResponseType response_id = GTK_RESPONSE_OK;
gboolean success;
g_autoptr(GError) error = NULL;
success = pp_new_printer_add_finish (PP_NEW_PRINTER (source_object), res, &error);
if (success)
{
emit_response (self, response_id);
}
else
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("%s", error->message);
response_id = GTK_RESPONSE_REJECT;
emit_response (self, response_id);
}
}
}
static void
ppd_selection_cb (GtkDialog *_dialog,
gint response_id,
gpointer user_data)
{
PpNewPrinterDialog *self = user_data;
g_autoptr(PpNewPrinter) new_printer = NULL;
GList *original_names_list = NULL;
g_autofree gchar *ppd_name = NULL;
g_autofree gchar *ppd_display_name = NULL;
guint window_id = 0;
gint acquisition_method;
if (response_id == GTK_RESPONSE_OK) {
ppd_name = pp_ppd_selection_dialog_get_ppd_name (self->ppd_selection_dialog);
ppd_display_name = pp_ppd_selection_dialog_get_ppd_display_name (self->ppd_selection_dialog);
}
else {
emit_response (self, GTK_RESPONSE_CANCEL);
}
if (ppd_name)
{
g_object_set (self->new_device, "device-ppd", ppd_name, NULL);
acquisition_method = pp_print_device_get_acquisition_method (self->new_device);
if ((acquisition_method == ACQUISITION_METHOD_JETDIRECT ||
acquisition_method == ACQUISITION_METHOD_LPD) &&
ppd_display_name != NULL)
{
g_autofree gchar *printer_name = NULL;
g_object_set (self->new_device,
"device-name", ppd_display_name,
"device-original-name", ppd_display_name,
NULL);
gtk_tree_model_foreach (GTK_TREE_MODEL (self->store),
prepend_original_name,
&original_names_list);
original_names_list = g_list_reverse (original_names_list);
printer_name = canonicalize_device_name (original_names_list,
self->local_cups_devices,
self->dests,
self->num_of_dests,
self->new_device);
g_list_free_full (original_names_list, g_free);
g_object_set (self->new_device,
"device-name", printer_name,
"device-original-name", printer_name,
NULL);
}
emit_pre_response (self,
pp_print_device_get_device_name (self->new_device),
pp_print_device_get_device_location (self->new_device),
pp_print_device_get_device_make_and_model (self->new_device),
pp_print_device_is_network_device (self->new_device));
window_id = (guint) GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (gtk_window_get_transient_for (GTK_WINDOW (self->dialog)))));
new_printer = pp_new_printer_new ();
g_object_set (new_printer,
"name", pp_print_device_get_device_name (self->new_device),
"original-name", pp_print_device_get_device_original_name (self->new_device),
"device-uri", pp_print_device_get_device_uri (self->new_device),
"device-id", pp_print_device_get_device_id (self->new_device),
"ppd-name", pp_print_device_get_device_ppd (self->new_device),
"ppd-file-name", pp_print_device_get_device_ppd (self->new_device),
"info", pp_print_device_get_device_info (self->new_device),
"location", pp_print_device_get_device_location (self->new_device),
"make-and-model", pp_print_device_get_device_make_and_model (self->new_device),
"host-name", pp_print_device_get_host_name (self->new_device),
"host-port", pp_print_device_get_host_port (self->new_device),
"is-network-device", pp_print_device_is_network_device (self->new_device),
"window-id", window_id,
NULL);
self->cancellable = g_cancellable_new ();
pp_new_printer_add_async (new_printer,
self->cancellable,
printer_add_async_cb,
self);
g_clear_object (&self->new_device);
}
gtk_widget_destroy (GTK_WIDGET (self->ppd_selection_dialog));
}
static void
new_printer_dialog_response_cb (PpNewPrinterDialog *self,
gint response_id)
{
g_autoptr(PpPrintDevice) device = NULL;
GtkTreeModel *model;
GtkTreeIter iter;
gint acquisition_method;
gtk_widget_hide (GTK_WIDGET (self->dialog));
if (response_id == GTK_RESPONSE_OK)
{
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->treeview), &model, &iter))
{
gtk_tree_model_get (model, &iter,
DEVICE_COLUMN, &device,
-1);
}
if (device)
{
PpNewPrinter *new_printer;
guint window_id = 0;
acquisition_method = pp_print_device_get_acquisition_method (device);
if (acquisition_method == ACQUISITION_METHOD_SAMBA ||
acquisition_method == ACQUISITION_METHOD_SAMBA_HOST ||
acquisition_method == ACQUISITION_METHOD_JETDIRECT ||
acquisition_method == ACQUISITION_METHOD_LPD)
{
self->new_device = pp_print_device_copy (device);
self->ppd_selection_dialog =
pp_ppd_selection_dialog_new (self->list,
NULL,
ppd_selection_cb,
self);
gtk_window_set_transient_for (GTK_WINDOW (self->ppd_selection_dialog),
GTK_WINDOW (self->parent));
gtk_dialog_run (GTK_DIALOG (self->ppd_selection_dialog));
}
else
{
emit_pre_response (self,
pp_print_device_get_device_name (device),
pp_print_device_get_device_location (device),
pp_print_device_get_device_make_and_model (device),
pp_print_device_is_network_device (device));
window_id = (guint) GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (gtk_window_get_transient_for (GTK_WINDOW (self->dialog)))));
new_printer = pp_new_printer_new ();
g_object_set (new_printer,
"name", pp_print_device_get_device_name (device),
"original-name", pp_print_device_get_device_original_name (device),
"device-uri", pp_print_device_get_device_uri (device),
"device-id", pp_print_device_get_device_id (device),
"ppd-name", pp_print_device_get_device_ppd (device),
"ppd-file-name", pp_print_device_get_device_ppd (device),
"info", pp_print_device_get_device_info (device),
"location", pp_print_device_get_device_location (device),
"make-and-model", pp_print_device_get_device_make_and_model (device),
"host-name", pp_print_device_get_host_name (device),
"host-port", pp_print_device_get_host_port (device),
"is-network-device", pp_print_device_is_network_device (device),
"window-id", window_id,
NULL);
self->cancellable = g_cancellable_new ();
pp_new_printer_add_async (new_printer,
self->cancellable,
printer_add_async_cb,
self);
}
}
}
else
{
emit_response (self, GTK_RESPONSE_CANCEL);
}
}