GCC Code Coverage Report


Directory: ./
File: panels/printers/pp-options-dialog.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 299 0.0%
Functions: 0 26 0.0%
Branches: 0 127 0.0%

Line Branch Exec Source
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2012 Red Hat, Inc,
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Marek Kasik <mkasik@redhat.com>
19 */
20
21 #include "config.h"
22
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27
28 #include <glib.h>
29 #include <glib/gi18n.h>
30 #include <glib/gstdio.h>
31 #include <gtk/gtk.h>
32
33 #include <cups/cups.h>
34 #include <cups/ppd.h>
35
36 #include "pp-options-dialog.h"
37 #include "pp-maintenance-command.h"
38 #include "pp-ppd-option-widget.h"
39 #include "pp-ipp-option-widget.h"
40 #include "pp-utils.h"
41 #include "pp-printer.h"
42
43 struct _PpOptionsDialog {
44 AdwWindow parent_instance;
45
46 GtkTreeSelection *categories_selection;
47 GtkTreeView *categories_treeview;
48 GtkWidget *main_box;
49 GtkNotebook *notebook;
50 GtkSpinner *spinner;
51 GtkStack *stack;
52
53 gchar *printer_name;
54
55 gchar *ppd_filename;
56 gboolean ppd_filename_set;
57
58 cups_dest_t *destination;
59 gboolean destination_set;
60
61 GHashTable *ipp_attributes;
62 gboolean ipp_attributes_set;
63
64 gboolean sensitive;
65 };
66
67 G_DEFINE_TYPE (PpOptionsDialog, pp_options_dialog, ADW_TYPE_WINDOW)
68
69 enum
70 {
71 CATEGORY_IDS_COLUMN = 0,
72 CATEGORY_NAMES_COLUMN
73 };
74
75 /* These lists come from Gtk+ */
76 /* TODO: Only "Resolution" currently has a context to disambiguate it from
77 * the display settings. All of these should have contexts, but it
78 * was late in the release cycle and this partial solution was
79 * preferable. See:
80 * https://gitlab.gnome.org/GNOME/gnome-control-center/merge_requests/414#note_446778
81 */
82 static const struct {
83 const char *keyword;
84 const char *translation_context;
85 const char *translation;
86 } ppd_option_translations[] = {
87 { "Duplex", NULL, N_("Two Sided") },
88 { "MediaType", NULL, N_("Paper Type") },
89 { "InputSlot", NULL, N_("Paper Source") },
90 { "OutputBin", NULL, N_("Output Tray") },
91 { "Resolution", "printing option", NC_("printing option", "Resolution") },
92 { "PreFilter", NULL, N_("GhostScript pre-filtering") },
93 };
94
95 /* keep sorted when changing */
96 static const char *allowed_page_setup_options[] = {
97 "InputSlot",
98 "MediaType",
99 "OutputBin",
100 "PageSize",
101 };
102
103 /* keep sorted when changing */
104 static const char *allowed_color_options[] = {
105 "BRColorEnhancement",
106 "BRColorMatching",
107 "BRColorMatching",
108 "BRColorMode",
109 "BRGammaValue",
110 "BRImprovedGray",
111 "BlackSubstitution",
112 "ColorModel",
113 "HPCMYKInks",
114 "HPCSGraphics",
115 "HPCSImages",
116 "HPCSText",
117 "HPColorSmart",
118 "RPSBlackMode",
119 "RPSBlackOverPrint",
120 "Rcmyksimulation",
121 };
122
123 /* keep sorted when changing */
124 static const char *allowed_color_groups[] = {
125 "Color",
126 "Color1",
127 "Color2",
128 "ColorBalance",
129 "ColorPage",
130 "ColorSettings1",
131 "ColorSettings2",
132 "ColorSettings3",
133 "ColorSettings4",
134 "EPColorSettings",
135 "FPColorWise1",
136 "FPColorWise2",
137 "FPColorWise3",
138 "FPColorWise4",
139 "FPColorWise5",
140 "HPCMYKInksPanel",
141 "HPColorOptions",
142 "HPColorOptionsPanel",
143 "HPColorQualityOptionsPanel",
144 "ManualColor",
145 };
146
147 /* keep sorted when changing */
148 static const char *allowed_image_quality_options[] = {
149 "BRDocument",
150 "BRHalfTonePattern",
151 "BRNormalPrt",
152 "BRPrintQuality",
153 "BitsPerPixel",
154 "Darkness",
155 "Dithering",
156 "EconoMode",
157 "Economode",
158 "HPEconoMode",
159 "HPEdgeControl",
160 "HPGraphicsHalftone",
161 "HPHalftone",
162 "HPImagingOptions",
163 "HPLJDensity",
164 "HPPhotoHalftone",
165 "HPPrintQualityOptions",
166 "HPResolutionOptions",
167 "OutputMode",
168 "REt",
169 "RPSBitsPerPixel",
170 "RPSDitherType",
171 "Resolution",
172 "ScreenLock",
173 "Smoothing",
174 "TonerSaveMode",
175 "UCRGCRForImage",
176 };
177
178 /* keep sorted when changing */
179 static const char *allowed_image_quality_groups[] = {
180 "EPQualitySettings",
181 "FPImageQuality1",
182 "FPImageQuality2",
183 "FPImageQuality3",
184 "ImageQualityPage",
185 "Quality",
186 };
187
188 /* keep sorted when changing */
189 static const char * allowed_finishing_options[] = {
190 "BindColor",
191 "BindEdge",
192 "BindType",
193 "BindWhen",
194 "Booklet",
195 "FoldType",
196 "FoldWhen",
197 "HPStaplerOptions",
198 "Jog",
199 "Slipsheet",
200 "Sorter",
201 "StapleLocation",
202 "StapleOrientation",
203 "StapleWhen",
204 "StapleX",
205 "StapleY",
206 };
207
208 /* keep sorted when changing */
209 static const char *allowed_job_groups[] = {
210 "JobHandling",
211 "JobLog",
212 };
213
214 /* keep sorted when changing */
215 static const char *allowed_finishing_groups[] = {
216 "Booklet",
217 "BookletCover",
218 "BookletModeOptions",
219 "FPFinishing1",
220 "FPFinishing2",
221 "FPFinishing3",
222 "FPFinishing4",
223 "Finishing",
224 "FinishingOptions",
225 "FinishingPage",
226 "HPBookletPanel",
227 "HPFinishing",
228 "HPFinishingOptions",
229 "HPFinishingPanel",
230 };
231
232 /* keep sorted when changing */
233 static const char *allowed_installable_options_groups[] = {
234 "InstallableOptions",
235 };
236
237 /* keep sorted when changing */
238 static const char *allowed_page_setup_groups[] = {
239 "HPMarginAndLayout",
240 "OutputControl",
241 "PaperHandling",
242 "Paper",
243 "Source",
244 };
245
246 /* keep sorted when changing */
247 static const char *disallowed_ppd_options[] = {
248 "Collate",
249 "Copies",
250 "Duplex",
251 "HPManualDuplexOrientation",
252 "HPManualDuplexSwitch",
253 "OutputOrder",
254 "PageRegion"
255 };
256
257 static int
258 strptr_cmp (const void *a,
259 const void *b)
260 {
261 char **aa = (char **)a;
262 char **bb = (char **)b;
263 return strcmp (*aa, *bb);
264 }
265
266 static gboolean
267 string_in_table (gchar *str,
268 const gchar *table[],
269 gint table_len)
270 {
271 return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
272 }
273
274 #define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
275
276 static const gchar *
277 ppd_option_name_translate (ppd_option_t *option)
278 {
279 gint i;
280
281 for (i = 0; i < G_N_ELEMENTS (ppd_option_translations); i++)
282 {
283 if (g_strcmp0 (ppd_option_translations[i].keyword, option->keyword) == 0)
284 {
285 if (ppd_option_translations[i].translation_context)
286 return g_dpgettext2(NULL, ppd_option_translations[i].translation_context, ppd_option_translations[i].translation);
287 else
288 return _(ppd_option_translations[i].translation);
289 }
290 }
291
292 return option->text;
293 }
294
295 static gint
296 grid_get_height (GtkWidget *grid)
297 {
298 GtkWidget *child;
299 gint height = 0;
300 gint row = 0;
301 gint max = 0;
302
303 for (child = gtk_widget_get_first_child (grid);
304 child;
305 child = gtk_widget_get_next_sibling (child))
306 {
307 gtk_grid_query_child (GTK_GRID (grid),
308 child,
309 NULL, &row,
310 NULL, &height);
311
312 if (height + row > max)
313 max = height + row;
314 }
315
316 return max;
317 }
318
319 static gboolean
320 grid_is_empty (GtkWidget *grid)
321 {
322 return gtk_widget_get_first_child (grid) == NULL;
323 }
324
325 static GtkWidget *
326 ipp_option_add (IPPAttribute *attr_supported,
327 IPPAttribute *attr_default,
328 const gchar *option_name,
329 const gchar *option_display_name,
330 const gchar *printer_name,
331 GtkWidget *grid,
332 gboolean sensitive)
333 {
334 GtkWidget *widget;
335 GtkWidget *label;
336 gint position;
337
338 widget = (GtkWidget *) pp_ipp_option_widget_new (attr_supported,
339 attr_default,
340 option_name,
341 printer_name);
342 if (widget)
343 {
344 gtk_widget_set_visible (widget, TRUE);
345 gtk_widget_set_sensitive (widget, sensitive);
346 position = grid_get_height (grid);
347
348 label = gtk_label_new (option_display_name);
349 gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
350 gtk_widget_add_css_class (label, "dim-label");
351 gtk_widget_set_halign (label, GTK_ALIGN_END);
352 gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
353 gtk_widget_set_margin_start (label, 10);
354 gtk_grid_attach (GTK_GRID (grid), label, 0, position, 1, 1);
355
356 gtk_widget_set_margin_start (widget, 20);
357 gtk_grid_attach (GTK_GRID (grid), widget, 1, position, 1, 1);
358 }
359
360 return widget;
361 }
362
363 static GtkWidget *
364 ppd_option_add (ppd_option_t option,
365 const gchar *printer_name,
366 GtkWidget *grid,
367 gboolean sensitive)
368 {
369 GtkWidget *widget;
370 GtkWidget *label;
371 gint position;
372
373 widget = (GtkWidget *) pp_ppd_option_widget_new (&option, printer_name);
374 if (widget)
375 {
376 gtk_widget_set_visible (widget, TRUE);
377 gtk_widget_set_sensitive (widget, sensitive);
378 position = grid_get_height (grid);
379
380 label = gtk_label_new (ppd_option_name_translate (&option));
381 gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
382 gtk_widget_add_css_class (label, "dim-label");
383 gtk_widget_set_halign (label, GTK_ALIGN_END);
384 gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
385 gtk_widget_set_margin_start (label, 10);
386 gtk_grid_attach (GTK_GRID (grid), label, 0, position, 1, 1);
387
388 gtk_widget_set_margin_start (widget, 20);
389 gtk_grid_attach (GTK_GRID (grid), widget, 1, position, 1, 1);
390 }
391
392 return widget;
393 }
394
395 static GtkWidget *
396 tab_grid_new ()
397 {
398 GtkWidget *grid;
399
400 grid = gtk_grid_new ();
401 gtk_widget_set_margin_start (grid, 20);
402 gtk_widget_set_margin_end (grid, 20);
403 gtk_widget_set_margin_top (grid, 20);
404 gtk_widget_set_margin_bottom (grid, 20);
405 gtk_grid_set_row_spacing (GTK_GRID (grid), 15);
406
407 return grid;
408 }
409
410 static void
411 tab_add (PpOptionsDialog *self,
412 const gchar *tab_name,
413 GtkWidget *grid)
414 {
415 GtkListStore *store;
416 GtkTreeIter iter;
417 GtkWidget *scrolled_window;
418 gboolean unref_store = FALSE;
419 gint id;
420
421 if (!grid_is_empty (grid))
422 {
423 scrolled_window = gtk_scrolled_window_new ();
424 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
425 GTK_POLICY_NEVER,
426 GTK_POLICY_AUTOMATIC);
427 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled_window), grid);
428
429 id = gtk_notebook_append_page (self->notebook,
430 scrolled_window,
431 NULL);
432
433 if (id >= 0)
434 {
435 store = GTK_LIST_STORE (gtk_tree_view_get_model (self->categories_treeview));
436 if (!store)
437 {
438 store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
439 unref_store = TRUE;
440 }
441
442 gtk_list_store_append (store, &iter);
443 gtk_list_store_set (store, &iter,
444 CATEGORY_IDS_COLUMN, id,
445 CATEGORY_NAMES_COLUMN, tab_name,
446 -1);
447
448 if (unref_store)
449 {
450 gtk_tree_view_set_model (self->categories_treeview, GTK_TREE_MODEL (store));
451 g_object_unref (store);
452 }
453 }
454 }
455 else
456 {
457 g_object_ref_sink (grid);
458 g_object_unref (grid);
459 }
460 }
461
462 static void
463 category_selection_changed_cb (PpOptionsDialog *self)
464 {
465 GtkTreeModel *model;
466 GtkTreeIter iter;
467 gint id = -1;
468
469 if (gtk_tree_selection_get_selected (self->categories_selection, &model, &iter))
470 {
471 gtk_tree_model_get (model, &iter,
472 CATEGORY_IDS_COLUMN, &id,
473 -1);
474 }
475
476 if (id >= 0)
477 {
478 gtk_notebook_set_current_page (self->notebook, id);
479 }
480 }
481
482 static void
483 populate_options_real (PpOptionsDialog *self)
484 {
485 GtkTreeModel *model;
486 GtkTreeIter iter;
487 ppd_file_t *ppd_file;
488 GtkWidget *grid;
489 GtkWidget *general_tab_grid = tab_grid_new ();
490 GtkWidget *page_setup_tab_grid = tab_grid_new ();
491 GtkWidget *installable_options_tab_grid = tab_grid_new ();
492 GtkWidget *job_tab_grid = tab_grid_new ();
493 GtkWidget *image_quality_tab_grid = tab_grid_new ();
494 GtkWidget *color_tab_grid = tab_grid_new ();
495 GtkWidget *finishing_tab_grid = tab_grid_new ();
496 GtkWidget *advanced_tab_grid = tab_grid_new ();
497 gint i, j;
498
499 gtk_spinner_stop (self->spinner);
500
501 gtk_stack_set_visible_child (self->stack, self->main_box);
502
503 if (self->ipp_attributes)
504 {
505 /* Add number-up option to Page Setup tab */
506 ipp_option_add (g_hash_table_lookup (self->ipp_attributes,
507 "number-up-supported"),
508 g_hash_table_lookup (self->ipp_attributes,
509 "number-up-default"),
510 "number-up",
511 /* Translators: This option sets number of pages printed on one sheet */
512 _("Pages per side"),
513 self->printer_name,
514 page_setup_tab_grid,
515 self->sensitive);
516
517 /* Add sides option to Page Setup tab */
518 ipp_option_add (g_hash_table_lookup (self->ipp_attributes,
519 "sides-supported"),
520 g_hash_table_lookup (self->ipp_attributes,
521 "sides-default"),
522 "sides",
523 /* Translators: This option sets whether to print on both sides of paper */
524 _("Two-sided"),
525 self->printer_name,
526 page_setup_tab_grid,
527 self->sensitive);
528
529 /* Add orientation-requested option to Page Setup tab */
530 ipp_option_add (g_hash_table_lookup (self->ipp_attributes,
531 "orientation-requested-supported"),
532 g_hash_table_lookup (self->ipp_attributes,
533 "orientation-requested-default"),
534 "orientation-requested",
535 /* Translators: This option sets orientation of print (portrait, landscape...) */
536 _("Orientation"),
537 self->printer_name,
538 page_setup_tab_grid,
539 self->sensitive);
540 }
541
542 if (self->destination && self->ppd_filename)
543 {
544 ppd_file = ppdOpenFile (self->ppd_filename);
545 ppdLocalize (ppd_file);
546
547 if (ppd_file)
548 {
549 ppdMarkDefaults (ppd_file);
550 cupsMarkOptions (ppd_file,
551 self->destination->num_options,
552 self->destination->options);
553
554 for (i = 0; i < ppd_file->num_groups; i++)
555 {
556 for (j = 0; j < ppd_file->groups[i].num_options; j++)
557 {
558 grid = NULL;
559
560 if (STRING_IN_TABLE (ppd_file->groups[i].name,
561 allowed_color_groups))
562 grid = color_tab_grid;
563 else if (STRING_IN_TABLE (ppd_file->groups[i].name,
564 allowed_image_quality_groups))
565 grid = image_quality_tab_grid;
566 else if (STRING_IN_TABLE (ppd_file->groups[i].name,
567 allowed_job_groups))
568 grid = job_tab_grid;
569 else if (STRING_IN_TABLE (ppd_file->groups[i].name,
570 allowed_finishing_groups))
571 grid = finishing_tab_grid;
572 else if (STRING_IN_TABLE (ppd_file->groups[i].name,
573 allowed_installable_options_groups))
574 grid = installable_options_tab_grid;
575 else if (STRING_IN_TABLE (ppd_file->groups[i].name,
576 allowed_page_setup_groups))
577 grid = page_setup_tab_grid;
578
579 if (!STRING_IN_TABLE (ppd_file->groups[i].options[j].keyword,
580 disallowed_ppd_options))
581 {
582 if (!grid && STRING_IN_TABLE (ppd_file->groups[i].options[j].keyword,
583 allowed_color_options))
584 grid = color_tab_grid;
585 else if (!grid && STRING_IN_TABLE (ppd_file->groups[i].options[j].keyword,
586 allowed_image_quality_options))
587 grid = image_quality_tab_grid;
588 else if (!grid && STRING_IN_TABLE (ppd_file->groups[i].options[j].keyword,
589 allowed_finishing_options))
590 grid = finishing_tab_grid;
591 else if (!grid && STRING_IN_TABLE (ppd_file->groups[i].options[j].keyword,
592 allowed_page_setup_options))
593 grid = page_setup_tab_grid;
594
595 if (!grid)
596 grid = advanced_tab_grid;
597
598 ppd_option_add (ppd_file->groups[i].options[j],
599 self->printer_name,
600 grid,
601 self->sensitive);
602 }
603 }
604 }
605
606 ppdClose (ppd_file);
607 }
608 }
609
610 self->ppd_filename_set = FALSE;
611 if (self->ppd_filename)
612 {
613 g_unlink (self->ppd_filename);
614 g_free (self->ppd_filename);
615 self->ppd_filename = NULL;
616 }
617
618 self->destination_set = FALSE;
619 if (self->destination)
620 {
621 cupsFreeDests (1, self->destination);
622 self->destination = NULL;
623 }
624
625 self->ipp_attributes_set = FALSE;
626 if (self->ipp_attributes)
627 {
628 g_hash_table_unref (self->ipp_attributes);
629 self->ipp_attributes = NULL;
630 }
631
632 /* Translators: "General" tab contains general printer options */
633 tab_add (self, C_("Printer Option Group", "General"), general_tab_grid);
634
635 /* Translators: "Page Setup" tab contains settings related to pages (page size, paper source, etc.) */
636 tab_add (self, C_("Printer Option Group", "Page Setup"), page_setup_tab_grid);
637
638 /* Translators: "Installable Options" tab contains settings of presence of installed options (amount of RAM, duplex unit, etc.) */
639 tab_add (self, C_("Printer Option Group", "Installable Options"), installable_options_tab_grid);
640
641 /* Translators: "Job" tab contains settings for jobs */
642 tab_add (self, C_("Printer Option Group", "Job"), job_tab_grid);
643
644 /* Translators: "Image Quality" tab contains settings for quality of output print (e.g. resolution) */
645 tab_add (self, C_("Printer Option Group", "Image Quality"), image_quality_tab_grid);
646
647 /* Translators: "Color" tab contains color settings (e.g. color printing) */
648 tab_add (self, C_("Printer Option Group", "Color"), color_tab_grid);
649
650 /* Translators: "Finishing" tab contains finishing settings (e.g. booklet printing) */
651 tab_add (self, C_("Printer Option Group", "Finishing"), finishing_tab_grid);
652
653 /* Translators: "Advanced" tab contains all others settings */
654 tab_add (self, C_("Printer Option Group", "Advanced"), advanced_tab_grid);
655
656 /* Select the first option group */
657 if ((model = gtk_tree_view_get_model (self->categories_treeview)) != NULL &&
658 gtk_tree_model_get_iter_first (model, &iter))
659 gtk_tree_selection_select_iter (self->categories_selection, &iter);
660 }
661
662 static void
663 printer_get_ppd_cb (const gchar *ppd_filename,
664 gpointer user_data)
665 {
666 PpOptionsDialog *self = (PpOptionsDialog *) user_data;
667
668 if (self->ppd_filename)
669 {
670 g_unlink (self->ppd_filename);
671 g_free (self->ppd_filename);
672 }
673
674 self->ppd_filename = g_strdup (ppd_filename);
675 self->ppd_filename_set = TRUE;
676
677 if (self->destination_set &&
678 self->ipp_attributes_set)
679 {
680 populate_options_real (self);
681 }
682 }
683
684 static void
685 get_named_dest_cb (cups_dest_t *dest,
686 gpointer user_data)
687 {
688 PpOptionsDialog *self = (PpOptionsDialog *) user_data;
689
690 if (self->destination)
691 cupsFreeDests (1, self->destination);
692
693 self->destination = dest;
694 self->destination_set = TRUE;
695
696 if (self->ppd_filename_set &&
697 self->ipp_attributes_set)
698 {
699 populate_options_real (self);
700 }
701 }
702
703 static void
704 get_ipp_attributes_cb (GHashTable *table,
705 gpointer user_data)
706 {
707 PpOptionsDialog *self = (PpOptionsDialog *) user_data;
708
709 if (self->ipp_attributes)
710 g_hash_table_unref (self->ipp_attributes);
711
712 self->ipp_attributes = g_hash_table_ref (table);
713 self->ipp_attributes_set = TRUE;
714
715 if (self->ppd_filename_set &&
716 self->destination_set)
717 {
718 populate_options_real (self);
719 }
720 }
721
722 static void
723 populate_options (PpOptionsDialog *self)
724 {
725 GtkTreeViewColumn *column;
726 GtkCellRenderer *renderer;
727 /*
728 * Options which we need to obtain through an IPP request
729 * to be able to fill the options dialog.
730 * *-supported - possible values of the option
731 * *-default - actual value of the option
732 */
733 const gchar *attributes[] =
734 { "number-up-supported",
735 "number-up-default",
736 "sides-supported",
737 "sides-default",
738 "orientation-requested-supported",
739 "orientation-requested-default",
740 NULL};
741
742 gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->spinner));
743
744 renderer = gtk_cell_renderer_text_new ();
745
746 column = gtk_tree_view_column_new_with_attributes ("Categories", renderer,
747 "text", CATEGORY_NAMES_COLUMN, NULL);
748 gtk_tree_view_column_set_expand (column, TRUE);
749 gtk_tree_view_append_column (self->categories_treeview, column);
750
751 gtk_spinner_start (self->spinner);
752
753 printer_get_ppd_async (self->printer_name,
754 NULL,
755 0,
756 printer_get_ppd_cb,
757 self);
758
759 get_named_dest_async (self->printer_name,
760 get_named_dest_cb,
761 self);
762
763 get_ipp_attributes_async (self->printer_name,
764 (gchar **) attributes,
765 get_ipp_attributes_cb,
766 self);
767 }
768
769 static void
770 pp_maintenance_command_execute_cb (GObject *source_object,
771 GAsyncResult *res,
772 gpointer user_data)
773 {
774 pp_maintenance_command_execute_finish (PP_MAINTENANCE_COMMAND(source_object), res, NULL);
775 }
776
777 static gchar *
778 get_testprint_filename (const gchar *datadir)
779 {
780 const gchar *testprint[] = { "/data/testprint",
781 "/data/testprint.ps",
782 NULL };
783 gchar *filename = NULL;
784 gint i;
785
786 for (i = 0; testprint[i] != NULL; i++)
787 {
788 filename = g_strconcat (datadir, testprint[i], NULL);
789 if (g_access (filename, R_OK) == 0)
790 break;
791
792 g_clear_pointer (&filename, g_free);
793 }
794
795 return filename;
796 }
797
798 static void
799 print_test_page_cb (GObject *source_object,
800 GAsyncResult *result,
801 gpointer user_data)
802 {
803 pp_printer_print_file_finish (PP_PRINTER (source_object),
804 result, NULL);
805 }
806
807 static void
808 test_page_cb (PpOptionsDialog *self)
809 {
810 gint i;
811
812 if (self->printer_name)
813 {
814 const gchar *const dirs[] = { "/usr/share/cups",
815 "/usr/local/share/cups",
816 NULL };
817 const gchar *datadir = NULL;
818 g_autofree gchar *filename = NULL;
819
820 datadir = getenv ("CUPS_DATADIR");
821 if (datadir != NULL)
822 {
823 filename = get_testprint_filename (datadir);
824 }
825 else
826 {
827 for (i = 0; dirs[i] != NULL && filename == NULL; i++)
828 filename = get_testprint_filename (dirs[i]);
829 }
830
831 if (filename != NULL)
832 {
833 g_autoptr(PpPrinter) printer = NULL;
834
835 printer = pp_printer_new (self->printer_name);
836 pp_printer_print_file_async (printer,
837 filename,
838 /* Translators: Name of job which makes printer to print test page */
839 _("Test Page"),
840 NULL,
841 print_test_page_cb,
842 NULL);
843 }
844 else
845 {
846 g_autoptr(PpMaintenanceCommand) command = NULL;
847
848 command = pp_maintenance_command_new (self->printer_name,
849 "PrintSelfTestPage",
850 NULL,
851 /* Translators: Name of job which makes printer to print test page */
852 _("Test page"));
853
854 pp_maintenance_command_execute_async (command, NULL, pp_maintenance_command_execute_cb, NULL);
855 }
856 }
857 }
858
859 PpOptionsDialog *
860 pp_options_dialog_new (gchar *printer_name,
861 gboolean sensitive)
862 {
863 PpOptionsDialog *self;
864
865 self = g_object_new (pp_options_dialog_get_type (), NULL);
866
867 self->printer_name = g_strdup (printer_name);
868
869 self->sensitive = sensitive;
870
871 gtk_window_set_title (GTK_WINDOW (self), printer_name);
872
873 populate_options (self);
874
875 return self;
876 }
877
878 static void
879 pp_options_dialog_dispose (GObject *object)
880 {
881 PpOptionsDialog *self = PP_OPTIONS_DIALOG (object);
882
883 g_free (self->printer_name);
884 self->printer_name = NULL;
885
886 if (self->ppd_filename)
887 {
888 g_unlink (self->ppd_filename);
889 g_free (self->ppd_filename);
890 self->ppd_filename = NULL;
891 }
892
893 if (self->destination)
894 {
895 cupsFreeDests (1, self->destination);
896 self->destination = NULL;
897 }
898
899 if (self->ipp_attributes)
900 {
901 g_hash_table_unref (self->ipp_attributes);
902 self->ipp_attributes = NULL;
903 }
904
905 G_OBJECT_CLASS (pp_options_dialog_parent_class)->dispose (object);
906 }
907
908 void
909 pp_options_dialog_class_init (PpOptionsDialogClass *klass)
910 {
911 GObjectClass *object_class = G_OBJECT_CLASS (klass);
912 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
913
914 object_class->dispose = pp_options_dialog_dispose;
915
916 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/printers/pp-options-dialog.ui");
917
918 gtk_widget_class_bind_template_child (widget_class, PpOptionsDialog, categories_selection);
919 gtk_widget_class_bind_template_child (widget_class, PpOptionsDialog, categories_treeview);
920 gtk_widget_class_bind_template_child (widget_class, PpOptionsDialog, main_box);
921 gtk_widget_class_bind_template_child (widget_class, PpOptionsDialog, notebook);
922 gtk_widget_class_bind_template_child (widget_class, PpOptionsDialog, spinner);
923 gtk_widget_class_bind_template_child (widget_class, PpOptionsDialog, stack);
924
925 gtk_widget_class_bind_template_callback (widget_class, category_selection_changed_cb);
926 gtk_widget_class_bind_template_callback (widget_class, test_page_cb);
927
928 gtk_widget_class_add_binding_action (widget_class, GDK_KEY_Escape, 0, "window.close", NULL);
929 }
930
931 void
932 pp_options_dialog_init (PpOptionsDialog *self)
933 {
934 gtk_widget_init_template (GTK_WIDGET (self));
935 }
936