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.
398 lines
12 KiB
C
398 lines
12 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
|
*
|
|
* Copyright 2016 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/>.
|
|
*
|
|
* Author: Felipe Borges <feborges@redhat.com>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include <glib.h>
|
|
#include <glib/gi18n.h>
|
|
#include <glib/gstdio.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <cups/cups.h>
|
|
#include <cups/ppd.h>
|
|
|
|
#include "pp-details-dialog.h"
|
|
#include "pp-ppd-selection-dialog.h"
|
|
#include "pp-printer.h"
|
|
#include "pp-utils.h"
|
|
|
|
struct _PpDetailsDialog {
|
|
GtkDialog parent_instance;
|
|
|
|
GtkLabel *dialog_title;
|
|
GtkButtonBox *driver_buttons;
|
|
GtkBox *loading_box;
|
|
GtkLabel *printer_address_label;
|
|
GtkEntry *printer_location_entry;
|
|
GtkLabel *printer_model_label;
|
|
GtkStack *printer_model_stack;
|
|
GtkEntry *printer_name_entry;
|
|
GtkButton *search_for_drivers_button;
|
|
|
|
gchar *printer_name;
|
|
gchar *ppd_file_name;
|
|
PPDList *all_ppds_list;
|
|
GCancellable *cancellable;
|
|
|
|
/* Dialogs */
|
|
PpPPDSelectionDialog *pp_ppd_selection_dialog;
|
|
};
|
|
|
|
G_DEFINE_TYPE (PpDetailsDialog, pp_details_dialog, GTK_TYPE_DIALOG)
|
|
|
|
static void
|
|
printer_name_changed (PpDetailsDialog *self)
|
|
{
|
|
const gchar *name;
|
|
g_autofree gchar *title = NULL;
|
|
|
|
name = pp_details_dialog_get_printer_name (self);
|
|
|
|
/* Translators: This is the title of the dialog. %s is the printer name. */
|
|
title = g_strdup_printf (_("%s Details"), name);
|
|
gtk_label_set_label (self->dialog_title, title);
|
|
}
|
|
|
|
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 set_ppd_cb (const gchar *printer_name, gboolean success, gpointer user_data);
|
|
|
|
static void
|
|
get_ppd_names_cb (PPDName **names,
|
|
const gchar *printer_name,
|
|
gboolean cancelled,
|
|
gpointer user_data)
|
|
{
|
|
PpDetailsDialog *self = (PpDetailsDialog*) user_data;
|
|
|
|
if (!cancelled)
|
|
{
|
|
if (names != NULL)
|
|
{
|
|
gtk_label_set_text (self->printer_model_label, names[0]->ppd_display_name);
|
|
printer_set_ppd_async (printer_name,
|
|
names[0]->ppd_name,
|
|
self->cancellable,
|
|
set_ppd_cb,
|
|
self);
|
|
ppd_names_free (names);
|
|
}
|
|
else
|
|
{
|
|
gtk_label_set_text (self->printer_model_label, _("No suitable driver found"));
|
|
}
|
|
|
|
gtk_stack_set_visible_child (self->printer_model_stack, GTK_WIDGET (self->printer_model_label));
|
|
}
|
|
}
|
|
|
|
static void
|
|
search_for_drivers (PpDetailsDialog *self)
|
|
{
|
|
gtk_stack_set_visible_child (self->printer_model_stack, GTK_WIDGET (self->loading_box));
|
|
gtk_widget_set_sensitive (GTK_WIDGET (self->search_for_drivers_button), FALSE);
|
|
|
|
get_ppd_names_async (self->printer_name,
|
|
1,
|
|
self->cancellable,
|
|
get_ppd_names_cb,
|
|
self);
|
|
}
|
|
|
|
static void
|
|
set_ppd_cb (const gchar *printer_name,
|
|
gboolean success,
|
|
gpointer user_data)
|
|
{
|
|
PpDetailsDialog *self = (PpDetailsDialog*) user_data;
|
|
|
|
gtk_label_set_text (GTK_LABEL (self->printer_model_label), self->ppd_file_name);
|
|
}
|
|
|
|
static void
|
|
ppd_selection_dialog_response_cb (GtkDialog *dialog,
|
|
gint response_id,
|
|
gpointer user_data)
|
|
{
|
|
PpDetailsDialog *self = (PpDetailsDialog*) user_data;
|
|
|
|
if (response_id == GTK_RESPONSE_OK)
|
|
{
|
|
g_autofree gchar *ppd_name = NULL;
|
|
|
|
ppd_name = pp_ppd_selection_dialog_get_ppd_name (self->pp_ppd_selection_dialog);
|
|
|
|
if (self->printer_name && ppd_name)
|
|
{
|
|
printer_set_ppd_async (self->printer_name,
|
|
ppd_name,
|
|
self->cancellable,
|
|
set_ppd_cb,
|
|
self);
|
|
|
|
g_clear_pointer (&self->ppd_file_name, g_free);
|
|
self->ppd_file_name = g_strdup (ppd_name);
|
|
}
|
|
}
|
|
|
|
gtk_widget_destroy (GTK_WIDGET (self->pp_ppd_selection_dialog));
|
|
self->pp_ppd_selection_dialog = NULL;
|
|
}
|
|
|
|
static void
|
|
get_all_ppds_async_cb (PPDList *ppds,
|
|
gpointer user_data)
|
|
{
|
|
PpDetailsDialog *self = user_data;
|
|
|
|
self->all_ppds_list = ppds;
|
|
|
|
if (self->pp_ppd_selection_dialog)
|
|
pp_ppd_selection_dialog_set_ppd_list (self->pp_ppd_selection_dialog,
|
|
self->all_ppds_list);
|
|
}
|
|
|
|
static void
|
|
select_ppd_in_dialog (PpDetailsDialog *self)
|
|
{
|
|
g_autofree gchar *device_id = NULL;
|
|
g_autofree gchar *manufacturer = NULL;
|
|
|
|
g_clear_pointer (&self->ppd_file_name, g_free);
|
|
self->ppd_file_name = g_strdup (cupsGetPPD (self->printer_name));
|
|
|
|
if (!self->pp_ppd_selection_dialog)
|
|
{
|
|
device_id =
|
|
get_ppd_attribute (self->ppd_file_name,
|
|
"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 (self->ppd_file_name,
|
|
"Manufacturer");
|
|
}
|
|
|
|
if (manufacturer == NULL)
|
|
{
|
|
manufacturer = g_strdup ("Raw");
|
|
}
|
|
|
|
if (self->all_ppds_list == NULL)
|
|
{
|
|
get_all_ppds_async (self->cancellable, get_all_ppds_async_cb, self);
|
|
}
|
|
|
|
self->pp_ppd_selection_dialog = pp_ppd_selection_dialog_new (
|
|
self->all_ppds_list,
|
|
manufacturer,
|
|
ppd_selection_dialog_response_cb,
|
|
self);
|
|
|
|
gtk_window_set_transient_for (GTK_WINDOW (self->pp_ppd_selection_dialog),
|
|
GTK_WINDOW (self));
|
|
|
|
gtk_dialog_run (GTK_DIALOG (self->pp_ppd_selection_dialog));
|
|
}
|
|
}
|
|
|
|
static void
|
|
select_ppd_manually (PpDetailsDialog *self)
|
|
{
|
|
GtkFileFilter *filter;
|
|
GtkWidget *dialog;
|
|
|
|
dialog = gtk_file_chooser_dialog_new (_("Select PPD File"),
|
|
GTK_WINDOW (self),
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
|
_("_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)
|
|
{
|
|
g_autofree gchar *ppd_filename = NULL;
|
|
|
|
ppd_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
|
|
|
if (self->printer_name && ppd_filename)
|
|
{
|
|
printer_set_ppd_file_async (self->printer_name,
|
|
ppd_filename,
|
|
self->cancellable,
|
|
set_ppd_cb,
|
|
self);
|
|
}
|
|
}
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
static void
|
|
update_sensitivity (PpDetailsDialog *self,
|
|
gboolean sensitive)
|
|
{
|
|
gtk_widget_set_sensitive (GTK_WIDGET (self->printer_name_entry), sensitive);
|
|
gtk_widget_set_sensitive (GTK_WIDGET (self->printer_location_entry), sensitive);
|
|
gtk_widget_set_sensitive (GTK_WIDGET (self->driver_buttons), sensitive);
|
|
}
|
|
|
|
static void
|
|
pp_details_dialog_init (PpDetailsDialog *self)
|
|
{
|
|
gtk_widget_init_template (GTK_WIDGET (self));
|
|
|
|
self->cancellable = g_cancellable_new ();
|
|
}
|
|
|
|
static void
|
|
pp_details_dialog_dispose (GObject *object)
|
|
{
|
|
PpDetailsDialog *self = PP_DETAILS_DIALOG (object);
|
|
|
|
g_clear_pointer (&self->printer_name, g_free);
|
|
g_clear_pointer (&self->ppd_file_name, g_free);
|
|
|
|
if (self->all_ppds_list != NULL)
|
|
{
|
|
ppd_list_free (self->all_ppds_list);
|
|
self->all_ppds_list = NULL;
|
|
}
|
|
|
|
g_cancellable_cancel (self->cancellable);
|
|
g_clear_object (&self->cancellable);
|
|
|
|
G_OBJECT_CLASS (pp_details_dialog_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
pp_details_dialog_class_init (PpDetailsDialogClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
object_class->dispose = pp_details_dialog_dispose;
|
|
|
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/printers/pp-details-dialog.ui");
|
|
|
|
gtk_widget_class_bind_template_child (widget_class, PpDetailsDialog, dialog_title);
|
|
gtk_widget_class_bind_template_child (widget_class, PpDetailsDialog, driver_buttons);
|
|
gtk_widget_class_bind_template_child (widget_class, PpDetailsDialog, loading_box);
|
|
gtk_widget_class_bind_template_child (widget_class, PpDetailsDialog, printer_address_label);
|
|
gtk_widget_class_bind_template_child (widget_class, PpDetailsDialog, printer_location_entry);
|
|
gtk_widget_class_bind_template_child (widget_class, PpDetailsDialog, printer_model_label);
|
|
gtk_widget_class_bind_template_child (widget_class, PpDetailsDialog, printer_model_stack);
|
|
gtk_widget_class_bind_template_child (widget_class, PpDetailsDialog, printer_name_entry);
|
|
gtk_widget_class_bind_template_child (widget_class, PpDetailsDialog, search_for_drivers_button);
|
|
|
|
gtk_widget_class_bind_template_callback (widget_class, printer_name_changed);
|
|
gtk_widget_class_bind_template_callback (widget_class, search_for_drivers);
|
|
gtk_widget_class_bind_template_callback (widget_class, select_ppd_in_dialog);
|
|
gtk_widget_class_bind_template_callback (widget_class, select_ppd_manually);
|
|
}
|
|
|
|
PpDetailsDialog *
|
|
pp_details_dialog_new (gchar *printer_name,
|
|
gchar *printer_location,
|
|
gchar *printer_address,
|
|
gchar *printer_make_and_model,
|
|
gboolean sensitive)
|
|
{
|
|
PpDetailsDialog *self;
|
|
g_autofree gchar *title = NULL;
|
|
g_autofree gchar *printer_url = NULL;
|
|
|
|
self = g_object_new (PP_DETAILS_DIALOG_TYPE,
|
|
"use-header-bar", TRUE,
|
|
NULL);
|
|
|
|
self->printer_name = g_strdup (printer_name);
|
|
self->ppd_file_name = NULL;
|
|
|
|
/* Translators: This is the title of the dialog. %s is the printer name. */
|
|
title = g_strdup_printf (_("%s Details"), printer_name);
|
|
gtk_label_set_label (self->dialog_title, title);
|
|
|
|
printer_url = g_strdup_printf ("<a href=\"http://%s:%d\">%s</a>", printer_address, ippPort (), printer_address);
|
|
gtk_label_set_markup (GTK_LABEL (self->printer_address_label), printer_url);
|
|
|
|
gtk_entry_set_text (GTK_ENTRY (self->printer_name_entry), printer_name);
|
|
gtk_entry_set_text (GTK_ENTRY (self->printer_location_entry), printer_location);
|
|
gtk_label_set_text (GTK_LABEL (self->printer_model_label), printer_make_and_model);
|
|
|
|
update_sensitivity (self, sensitive);
|
|
|
|
return self;
|
|
}
|
|
|
|
const gchar *
|
|
pp_details_dialog_get_printer_name (PpDetailsDialog *self)
|
|
{
|
|
g_return_val_if_fail (PP_IS_DETAILS_DIALOG (self), NULL);
|
|
return gtk_entry_get_text (GTK_ENTRY (self->printer_name_entry));
|
|
}
|
|
|
|
const gchar *
|
|
pp_details_dialog_get_printer_location (PpDetailsDialog *self)
|
|
{
|
|
g_return_val_if_fail (PP_IS_DETAILS_DIALOG (self), NULL);
|
|
return gtk_entry_get_text (GTK_ENTRY (self->printer_location_entry));
|
|
}
|