1/* GtkCustomPaperUnixDialog
2 * Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
3 * Copyright © 2006, 2007, 2008 Christian Persch
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20#include "config.h"
21#include <string.h>
22#include <locale.h>
23
24#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
25#include <langinfo.h>
26#endif
27
28#include "gtkintl.h"
29#include "gtkprivate.h"
30
31#include "gtkliststore.h"
32
33#include "gtksignallistitemfactory.h"
34#include "gtklabel.h"
35#include "gtkspinbutton.h"
36
37#include "gtkcustompaperunixdialog.h"
38#include "gtkprintbackendprivate.h"
39#include "gtkprintutils.h"
40#include "gtkdialogprivate.h"
41
42#define LEGACY_CUSTOM_PAPER_FILENAME ".gtk-custom-papers"
43#define CUSTOM_PAPER_FILENAME "custom-papers"
44
45
46typedef struct
47{
48 GtkUnit display_unit;
49 GtkWidget *spin_button;
50} UnitWidget;
51
52struct _GtkCustomPaperUnixDialog
53{
54 GtkDialog parent_instance;
55
56 GtkWidget *listview;
57 GtkWidget *values_box;
58 GtkWidget *printer_combo;
59 GtkWidget *width_widget;
60 GtkWidget *height_widget;
61 GtkWidget *top_widget;
62 GtkWidget *bottom_widget;
63 GtkWidget *left_widget;
64 GtkWidget *right_widget;
65
66 gulong printer_inserted_tag;
67
68 guint request_details_tag;
69 GtkPrinter *request_details_printer;
70
71 guint non_user_change : 1;
72
73 GListStore *custom_paper_list;
74 GListModel *printer_list;
75
76 GList *print_backends;
77};
78
79typedef struct _GtkCustomPaperUnixDialogClass GtkCustomPaperUnixDialogClass;
80
81struct _GtkCustomPaperUnixDialogClass
82{
83 GtkDialogClass parent_class;
84};
85
86
87enum {
88 PRINTER_LIST_COL_NAME,
89 PRINTER_LIST_COL_PRINTER,
90 PRINTER_LIST_N_COLS
91};
92
93
94G_DEFINE_TYPE (GtkCustomPaperUnixDialog, gtk_custom_paper_unix_dialog, GTK_TYPE_DIALOG)
95
96
97static void gtk_custom_paper_unix_dialog_constructed (GObject *object);
98static void gtk_custom_paper_unix_dialog_finalize (GObject *object);
99static void populate_dialog (GtkCustomPaperUnixDialog *dialog);
100
101
102
103GtkUnit
104_gtk_print_get_default_user_units (void)
105{
106 /* Translate to the default units to use for presenting
107 * lengths to the user. Translate to default:inch if you
108 * want inches, otherwise translate to default:mm.
109 * Do *not* translate it to "predefinito:mm", if it
110 * it isn't default:mm or default:inch it will not work
111 */
112 char *e = _("default:mm");
113
114#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
115 char *imperial = NULL;
116
117 imperial = nl_langinfo (item: _NL_MEASUREMENT_MEASUREMENT);
118 if (imperial && imperial[0] == 2 )
119 return GTK_UNIT_INCH; /* imperial */
120 if (imperial && imperial[0] == 1 )
121 return GTK_UNIT_MM; /* metric */
122#endif
123
124 if (strcmp (s1: e, s2: "default:inch")==0)
125 return GTK_UNIT_INCH;
126 else if (strcmp (s1: e, s2: "default:mm"))
127 g_warning ("Whoever translated default:mm did so wrongly.");
128 return GTK_UNIT_MM;
129}
130
131static char *
132custom_paper_get_legacy_filename (void)
133{
134 char *filename;
135
136 filename = g_build_filename (first_element: g_get_home_dir (),
137 LEGACY_CUSTOM_PAPER_FILENAME, NULL);
138 g_assert (filename != NULL);
139 return filename;
140}
141
142static char *
143custom_paper_get_filename (void)
144{
145 char *filename;
146
147 filename = g_build_filename (first_element: g_get_user_config_dir (),
148 "gtk-4.0",
149 CUSTOM_PAPER_FILENAME, NULL);
150 g_assert (filename != NULL);
151 return filename;
152}
153
154GList *
155_gtk_load_custom_papers (void)
156{
157 GKeyFile *keyfile;
158 char *filename;
159 char **groups;
160 gsize n_groups, i;
161 gboolean load_ok;
162 GList *result = NULL;
163
164 filename = custom_paper_get_filename ();
165
166 keyfile = g_key_file_new ();
167 load_ok = g_key_file_load_from_file (key_file: keyfile, file: filename, flags: 0, NULL);
168 g_free (mem: filename);
169 if (!load_ok)
170 {
171 /* try legacy file */
172 filename = custom_paper_get_legacy_filename ();
173 load_ok = g_key_file_load_from_file (key_file: keyfile, file: filename, flags: 0, NULL);
174 g_free (mem: filename);
175 }
176 if (!load_ok)
177 {
178 g_key_file_free (key_file: keyfile);
179 return NULL;
180 }
181
182 groups = g_key_file_get_groups (key_file: keyfile, length: &n_groups);
183 for (i = 0; i < n_groups; ++i)
184 {
185 GtkPageSetup *page_setup;
186
187 page_setup = gtk_page_setup_new_from_key_file (key_file: keyfile, group_name: groups[i], NULL);
188 if (!page_setup)
189 continue;
190
191 result = g_list_prepend (list: result, data: page_setup);
192 }
193
194 g_strfreev (str_array: groups);
195 g_key_file_free (key_file: keyfile);
196
197 return g_list_reverse (list: result);
198}
199
200void
201_gtk_print_load_custom_papers (GtkListStore *store)
202{
203 GtkTreeIter iter;
204 GList *papers, *p;
205 GtkPageSetup *page_setup;
206
207 gtk_list_store_clear (list_store: store);
208
209 papers = _gtk_load_custom_papers ();
210 for (p = papers; p; p = p->next)
211 {
212 page_setup = p->data;
213 gtk_list_store_append (list_store: store, iter: &iter);
214 gtk_list_store_set (list_store: store, iter: &iter,
215 0, page_setup,
216 -1);
217 g_object_unref (object: page_setup);
218 }
219
220 g_list_free (list: papers);
221}
222
223void
224gtk_print_load_custom_papers (GListStore *store)
225{
226 GList *papers, *p;
227 GtkPageSetup *page_setup;
228
229 g_list_store_remove_all (store);
230
231 papers = _gtk_load_custom_papers ();
232 for (p = papers; p; p = p->next)
233 {
234 page_setup = p->data;
235 g_list_store_append (store, item: page_setup);
236 g_object_unref (object: page_setup);
237 }
238
239 g_list_free (list: papers);
240}
241
242static void
243gtk_print_save_custom_papers (GListStore *store)
244{
245 GKeyFile *keyfile;
246 char *filename, *data, *parentdir;
247 gsize len;
248 int i = 0;
249
250 keyfile = g_key_file_new ();
251
252 for (i = 0; i < g_list_model_get_n_items (list: G_LIST_MODEL (ptr: store)); i++)
253 {
254 GtkPageSetup *page_setup;
255 char group[32];
256
257 page_setup = g_list_model_get_item (list: G_LIST_MODEL (ptr: store), position: i);
258 g_snprintf (string: group, n: sizeof (group), format: "Paper%u", i);
259 gtk_page_setup_to_key_file (setup: page_setup, key_file: keyfile, group_name: group);
260 g_object_unref (object: page_setup);
261 }
262
263 filename = custom_paper_get_filename ();
264 parentdir = g_build_filename (first_element: g_get_user_config_dir (),
265 "gtk-4.0",
266 NULL);
267 if (g_mkdir_with_parents (pathname: parentdir, mode: 0700) == 0)
268 {
269 data = g_key_file_to_data (key_file: keyfile, length: &len, NULL);
270 g_file_set_contents (filename, contents: data, length: len, NULL);
271 g_free (mem: data);
272 }
273 g_free (mem: parentdir);
274 g_free (mem: filename);
275}
276
277static void
278gtk_custom_paper_unix_dialog_class_init (GtkCustomPaperUnixDialogClass *class)
279{
280 G_OBJECT_CLASS (class)->constructed = gtk_custom_paper_unix_dialog_constructed;
281 G_OBJECT_CLASS (class)->finalize = gtk_custom_paper_unix_dialog_finalize;
282}
283
284static void
285custom_paper_dialog_response_cb (GtkDialog *dialog,
286 int response,
287 gpointer user_data)
288{
289 GtkCustomPaperUnixDialog *self = GTK_CUSTOM_PAPER_UNIX_DIALOG (dialog);
290
291 gtk_print_save_custom_papers (store: self->custom_paper_list);
292}
293
294static gboolean
295match_func (gpointer item, gpointer user_data)
296{
297 return !gtk_printer_is_virtual (GTK_PRINTER (item));
298}
299
300static void
301gtk_custom_paper_unix_dialog_init (GtkCustomPaperUnixDialog *dialog)
302{
303 GtkPrinter *printer;
304 GListStore *printer_list;
305 GListStore *printer_list_list;
306 GListModel *full_list;
307 GtkFilter *filter;
308
309 gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (dialog));
310
311 dialog->print_backends = NULL;
312
313 dialog->request_details_printer = NULL;
314 dialog->request_details_tag = 0;
315
316 printer_list_list = g_list_store_new (G_TYPE_LIST_MODEL);
317 printer_list = g_list_store_new (GTK_TYPE_PRINTER);
318 printer = gtk_printer_new (_("Margins from Printer…"), NULL, FALSE);
319 g_list_store_append (store: printer_list, item: printer);
320 g_object_unref (object: printer);
321 g_list_store_append (store: printer_list_list, item: printer_list);
322 g_object_unref (object: printer_list);
323
324 full_list = G_LIST_MODEL (ptr: gtk_flatten_list_model_new (model: G_LIST_MODEL (ptr: printer_list_list)));
325
326 filter = GTK_FILTER (ptr: gtk_custom_filter_new (match_func, NULL, NULL));
327 dialog->printer_list = G_LIST_MODEL (ptr: gtk_filter_list_model_new (model: full_list, filter));
328
329 dialog->custom_paper_list = g_list_store_new (GTK_TYPE_PAGE_SETUP);
330 gtk_print_load_custom_papers (store: dialog->custom_paper_list);
331
332 populate_dialog (dialog);
333
334 g_signal_connect (dialog, "response", G_CALLBACK (custom_paper_dialog_response_cb), NULL);
335}
336
337static void
338gtk_custom_paper_unix_dialog_constructed (GObject *object)
339{
340 gboolean use_header;
341
342 G_OBJECT_CLASS (gtk_custom_paper_unix_dialog_parent_class)->constructed (object);
343
344 g_object_get (object, first_property_name: "use-header-bar", &use_header, NULL);
345 if (!use_header)
346 {
347 gtk_dialog_add_buttons (GTK_DIALOG (object),
348 _("_Close"), GTK_RESPONSE_CLOSE,
349 NULL);
350 gtk_dialog_set_default_response (GTK_DIALOG (object), response_id: GTK_RESPONSE_CLOSE);
351 }
352}
353
354static void
355gtk_custom_paper_unix_dialog_finalize (GObject *object)
356{
357 GtkCustomPaperUnixDialog *dialog = GTK_CUSTOM_PAPER_UNIX_DIALOG (object);
358 GList *node;
359
360 if (dialog->printer_list)
361 {
362 g_signal_handler_disconnect (instance: dialog->printer_list, handler_id: dialog->printer_inserted_tag);
363 g_object_unref (object: dialog->printer_list);
364 dialog->printer_list = NULL;
365 }
366
367 if (dialog->request_details_tag)
368 {
369 g_signal_handler_disconnect (instance: dialog->request_details_printer,
370 handler_id: dialog->request_details_tag);
371 g_object_unref (object: dialog->request_details_printer);
372 dialog->request_details_printer = NULL;
373 dialog->request_details_tag = 0;
374 }
375
376 g_clear_object (&dialog->custom_paper_list);
377
378 for (node = dialog->print_backends; node; node = node->next)
379 gtk_print_backend_destroy (GTK_PRINT_BACKEND (node->data));
380 g_list_free_full (list: dialog->print_backends, free_func: g_object_unref);
381 dialog->print_backends = NULL;
382
383 G_OBJECT_CLASS (gtk_custom_paper_unix_dialog_parent_class)->finalize (object);
384}
385
386/**
387 * gtk_custom_paper_unix_dialog_new:
388 * @title: (nullable): the title of the dialog
389 * @parent: (nullable): transient parent of the dialog
390 *
391 * Creates a new custom paper dialog.
392 *
393 * Returns: the new `GtkCustomPaperUnixDialog`
394 */
395GtkWidget *
396_gtk_custom_paper_unix_dialog_new (GtkWindow *parent,
397 const char *title)
398{
399 GtkWidget *result;
400
401 if (title == NULL)
402 title = _("Manage Custom Sizes");
403
404 result = g_object_new (GTK_TYPE_CUSTOM_PAPER_UNIX_DIALOG,
405 first_property_name: "title", title,
406 "transient-for", parent,
407 "modal", parent != NULL,
408 "destroy-with-parent", TRUE,
409 "resizable", FALSE,
410 NULL);
411
412 return result;
413}
414
415static void
416load_print_backends (GtkCustomPaperUnixDialog *dialog)
417{
418 GListModel *full_list;
419 GListStore *printer_list_list;
420 GList *node;
421
422 full_list = gtk_filter_list_model_get_model (self: GTK_FILTER_LIST_MODEL (ptr: dialog->printer_list));
423 printer_list_list = G_LIST_STORE (ptr: gtk_flatten_list_model_get_model (self: GTK_FLATTEN_LIST_MODEL (ptr: full_list)));
424
425 if (g_module_supported ())
426 dialog->print_backends = gtk_print_backend_load_modules ();
427
428 for (node = dialog->print_backends; node != NULL; node = node->next)
429 {
430 GtkPrintBackend *backend = GTK_PRINT_BACKEND (node->data);
431 g_list_store_append (store: printer_list_list, item: gtk_print_backend_get_printers (print_backend: backend));
432 }
433}
434
435static void unit_widget_changed (GtkCustomPaperUnixDialog *dialog);
436
437static GtkWidget *
438new_unit_widget (GtkCustomPaperUnixDialog *dialog,
439 GtkUnit unit,
440 GtkWidget *mnemonic_label)
441{
442 GtkWidget *hbox, *button, *label;
443 UnitWidget *data;
444
445 data = g_new0 (UnitWidget, 1);
446 data->display_unit = unit;
447
448 hbox = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 6);
449
450 button = gtk_spin_button_new_with_range (min: 0.0, max: 9999.0, step: 1);
451 gtk_widget_set_valign (widget: button, align: GTK_ALIGN_BASELINE);
452 if (unit == GTK_UNIT_INCH)
453 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (button), digits: 2);
454 else
455 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (button), digits: 1);
456
457 gtk_box_append (GTK_BOX (hbox), child: button);
458 gtk_widget_show (widget: button);
459
460 data->spin_button = button;
461
462 g_signal_connect_swapped (button, "value-changed",
463 G_CALLBACK (unit_widget_changed), dialog);
464
465 if (unit == GTK_UNIT_INCH)
466 label = gtk_label_new (_("inch"));
467 else
468 label = gtk_label_new (_("mm"));
469 gtk_widget_set_valign (widget: label, align: GTK_ALIGN_BASELINE);
470
471 gtk_box_append (GTK_BOX (hbox), child: label);
472 gtk_widget_show (widget: label);
473 gtk_label_set_mnemonic_widget (GTK_LABEL (mnemonic_label), widget: button);
474
475 g_object_set_data_full (G_OBJECT (hbox), key: "unit-data", data, destroy: g_free);
476
477 return hbox;
478}
479
480static double
481unit_widget_get (GtkWidget *unit_widget)
482{
483 UnitWidget *data = g_object_get_data (G_OBJECT (unit_widget), key: "unit-data");
484 return _gtk_print_convert_to_mm (len: gtk_spin_button_get_value (GTK_SPIN_BUTTON (data->spin_button)),
485 unit: data->display_unit);
486}
487
488static void
489unit_widget_set (GtkWidget *unit_widget,
490 double value)
491{
492 UnitWidget *data;
493
494 data = g_object_get_data (G_OBJECT (unit_widget), key: "unit-data");
495 gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->spin_button),
496 value: _gtk_print_convert_from_mm (len: value, unit: data->display_unit));
497}
498
499static void
500update_combo_sensitivity_from_printers (GtkCustomPaperUnixDialog *dialog)
501{
502 gboolean sensitive = FALSE;
503
504 if (g_list_model_get_n_items (list: dialog->printer_list) > 1)
505 sensitive = TRUE;
506
507 gtk_widget_set_sensitive (widget: dialog->printer_combo, sensitive);
508}
509
510static void
511update_custom_widgets_from_list (GtkCustomPaperUnixDialog *dialog)
512{
513 GListModel *model;
514 GtkPageSetup *page_setup;
515
516 model = G_LIST_MODEL (ptr: gtk_list_view_get_model (GTK_LIST_VIEW (dialog->listview)));
517 page_setup = gtk_single_selection_get_selected_item (self: GTK_SINGLE_SELECTION (ptr: model));
518
519 dialog->non_user_change = TRUE;
520 if (page_setup != NULL)
521 {
522 unit_widget_set (unit_widget: dialog->width_widget,
523 value: gtk_page_setup_get_paper_width (setup: page_setup, unit: GTK_UNIT_MM));
524 unit_widget_set (unit_widget: dialog->height_widget,
525 value: gtk_page_setup_get_paper_height (setup: page_setup, unit: GTK_UNIT_MM));
526 unit_widget_set (unit_widget: dialog->top_widget,
527 value: gtk_page_setup_get_top_margin (setup: page_setup, unit: GTK_UNIT_MM));
528 unit_widget_set (unit_widget: dialog->bottom_widget,
529 value: gtk_page_setup_get_bottom_margin (setup: page_setup, unit: GTK_UNIT_MM));
530 unit_widget_set (unit_widget: dialog->left_widget,
531 value: gtk_page_setup_get_left_margin (setup: page_setup, unit: GTK_UNIT_MM));
532 unit_widget_set (unit_widget: dialog->right_widget,
533 value: gtk_page_setup_get_right_margin (setup: page_setup, unit: GTK_UNIT_MM));
534
535 gtk_widget_set_sensitive (widget: dialog->values_box, TRUE);
536 }
537 else
538 {
539 gtk_widget_set_sensitive (widget: dialog->values_box, FALSE);
540 }
541
542 if (dialog->printer_list)
543 update_combo_sensitivity_from_printers (dialog);
544 dialog->non_user_change = FALSE;
545}
546
547static void
548selected_custom_paper_changed (GObject *list,
549 GParamSpec *pspec,
550 GtkCustomPaperUnixDialog *dialog)
551{
552 update_custom_widgets_from_list (dialog);
553}
554
555static void
556unit_widget_changed (GtkCustomPaperUnixDialog *dialog)
557{
558 double w, h, top, bottom, left, right;
559 GListModel *model;
560 GtkPageSetup *page_setup;
561 GtkPaperSize *paper_size;
562
563 if (dialog->non_user_change)
564 return;
565
566 model = G_LIST_MODEL (ptr: gtk_list_view_get_model (GTK_LIST_VIEW (dialog->listview)));
567 page_setup = gtk_single_selection_get_selected_item (self: GTK_SINGLE_SELECTION (ptr: model));
568
569 if (page_setup != NULL)
570 {
571 w = unit_widget_get (unit_widget: dialog->width_widget);
572 h = unit_widget_get (unit_widget: dialog->height_widget);
573
574 paper_size = gtk_page_setup_get_paper_size (setup: page_setup);
575 gtk_paper_size_set_size (size: paper_size, width: w, height: h, unit: GTK_UNIT_MM);
576
577 top = unit_widget_get (unit_widget: dialog->top_widget);
578 bottom = unit_widget_get (unit_widget: dialog->bottom_widget);
579 left = unit_widget_get (unit_widget: dialog->left_widget);
580 right = unit_widget_get (unit_widget: dialog->right_widget);
581
582 gtk_page_setup_set_top_margin (setup: page_setup, margin: top, unit: GTK_UNIT_MM);
583 gtk_page_setup_set_bottom_margin (setup: page_setup, margin: bottom, unit: GTK_UNIT_MM);
584 gtk_page_setup_set_left_margin (setup: page_setup, margin: left, unit: GTK_UNIT_MM);
585 gtk_page_setup_set_right_margin (setup: page_setup, margin: right, unit: GTK_UNIT_MM);
586 }
587}
588
589static gboolean
590custom_paper_name_used (GtkCustomPaperUnixDialog *dialog,
591 const char *name)
592{
593 GtkPageSetup *page_setup;
594 GtkPaperSize *paper_size;
595 guint i;
596
597 for (i = 0; i < g_list_model_get_n_items (list: G_LIST_MODEL (ptr: dialog->custom_paper_list)); i++)
598 {
599 page_setup = g_list_model_get_item (list: G_LIST_MODEL (ptr: dialog->custom_paper_list), position: i);
600 paper_size = gtk_page_setup_get_paper_size (setup: page_setup);
601 if (strcmp (s1: name, s2: gtk_paper_size_get_name (size: paper_size)) == 0)
602 {
603 g_object_unref (object: page_setup);
604 return TRUE;
605 }
606 g_object_unref (object: page_setup);
607 }
608
609 return FALSE;
610}
611
612static void
613add_custom_paper (GtkCustomPaperUnixDialog *dialog)
614{
615 GtkPageSetup *page_setup;
616 GtkPaperSize *paper_size;
617 char *name;
618 int i;
619
620 i = 1;
621 name = NULL;
622 do
623 {
624 g_free (mem: name);
625 name = g_strdup_printf (_("Custom Size %d"), i);
626 i++;
627 } while (custom_paper_name_used (dialog, name));
628
629 page_setup = gtk_page_setup_new ();
630 paper_size = gtk_paper_size_new_custom (name, display_name: name,
631 width: gtk_page_setup_get_paper_width (setup: page_setup, unit: GTK_UNIT_MM),
632 height: gtk_page_setup_get_paper_height (setup: page_setup, unit: GTK_UNIT_MM),
633 unit: GTK_UNIT_MM);
634 gtk_page_setup_set_paper_size (setup: page_setup, size: paper_size);
635 gtk_paper_size_free (size: paper_size);
636
637 g_list_store_append (store: dialog->custom_paper_list, item: page_setup);
638 g_object_unref (object: page_setup);
639
640 /* FIXME start editing */
641
642 g_free (mem: name);
643}
644
645static void
646remove_custom_paper (GtkCustomPaperUnixDialog *dialog)
647{
648 GListModel *model;
649 guint selected;
650
651 model = G_LIST_MODEL (ptr: gtk_list_view_get_model (GTK_LIST_VIEW (dialog->listview)));
652 selected = gtk_single_selection_get_selected (self: GTK_SINGLE_SELECTION (ptr: model));
653 if (selected != GTK_INVALID_LIST_POSITION)
654 g_list_store_remove (store: dialog->custom_paper_list, position: selected);
655}
656
657static void
658set_margins_from_printer (GtkCustomPaperUnixDialog *dialog,
659 GtkPrinter *printer)
660{
661 double top, bottom, left, right;
662
663 top = bottom = left = right = 0;
664 if (!gtk_printer_get_hard_margins (printer, top: &top, bottom: &bottom, left: &left, right: &right))
665 return;
666
667 dialog->non_user_change = TRUE;
668 unit_widget_set (unit_widget: dialog->top_widget, value: _gtk_print_convert_to_mm (len: top, unit: GTK_UNIT_POINTS));
669 unit_widget_set (unit_widget: dialog->bottom_widget, value: _gtk_print_convert_to_mm (len: bottom, unit: GTK_UNIT_POINTS));
670 unit_widget_set (unit_widget: dialog->left_widget, value: _gtk_print_convert_to_mm (len: left, unit: GTK_UNIT_POINTS));
671 unit_widget_set (unit_widget: dialog->right_widget, value: _gtk_print_convert_to_mm (len: right, unit: GTK_UNIT_POINTS));
672 dialog->non_user_change = FALSE;
673
674 /* Only send one change */
675 unit_widget_changed (dialog);
676}
677
678static void
679get_margins_finished_callback (GtkPrinter *printer,
680 gboolean success,
681 GtkCustomPaperUnixDialog *dialog)
682{
683 g_signal_handler_disconnect (instance: dialog->request_details_printer,
684 handler_id: dialog->request_details_tag);
685 g_object_unref (object: dialog->request_details_printer);
686 dialog->request_details_tag = 0;
687 dialog->request_details_printer = NULL;
688
689 if (success)
690 set_margins_from_printer (dialog, printer);
691
692 gtk_drop_down_set_selected (self: GTK_DROP_DOWN (ptr: dialog->printer_combo), position: 0);
693}
694
695static void
696margins_from_printer_changed (GtkCustomPaperUnixDialog *dialog)
697{
698 guint selected;
699 GtkPrinter *printer;
700
701 if (dialog->request_details_tag)
702 {
703 g_signal_handler_disconnect (instance: dialog->request_details_printer,
704 handler_id: dialog->request_details_tag);
705 g_object_unref (object: dialog->request_details_printer);
706 dialog->request_details_printer = NULL;
707 dialog->request_details_tag = 0;
708 }
709
710 selected = gtk_drop_down_get_selected (self: GTK_DROP_DOWN (ptr: dialog->printer_combo));
711 if (selected != 0)
712 {
713 GListModel *model;
714
715 model = gtk_drop_down_get_model (self: GTK_DROP_DOWN (ptr: dialog->printer_combo));
716 printer = g_list_model_get_item (list: model, position: selected);
717
718 if (printer)
719 {
720 if (gtk_printer_has_details (printer))
721 {
722 set_margins_from_printer (dialog, printer);
723 gtk_drop_down_set_selected (self: GTK_DROP_DOWN (ptr: dialog->printer_combo), position: 0);
724 }
725 else
726 {
727 dialog->request_details_printer = g_object_ref (printer);
728 dialog->request_details_tag =
729 g_signal_connect (printer, "details-acquired",
730 G_CALLBACK (get_margins_finished_callback), dialog);
731 gtk_printer_request_details (printer);
732 }
733
734 g_object_unref (object: printer);
735 }
736 }
737}
738
739static GtkWidget *
740wrap_in_frame (const char *label,
741 GtkWidget *child)
742{
743 GtkWidget *frame, *label_widget;
744 char *bold_text;
745
746 label_widget = gtk_label_new (NULL);
747 gtk_widget_set_halign (widget: label_widget, align: GTK_ALIGN_START);
748 gtk_widget_set_valign (widget: label_widget, align: GTK_ALIGN_CENTER);
749 gtk_widget_show (widget: label_widget);
750
751 bold_text = g_markup_printf_escaped (format: "<b>%s</b>", label);
752 gtk_label_set_markup (GTK_LABEL (label_widget), str: bold_text);
753 g_free (mem: bold_text);
754
755 frame = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 6);
756 gtk_box_append (GTK_BOX (frame), child: label_widget);
757
758 gtk_widget_set_margin_start (widget: child, margin: 12);
759 gtk_widget_set_halign (widget: child, align: GTK_ALIGN_FILL);
760 gtk_widget_set_valign (widget: child, align: GTK_ALIGN_FILL);
761
762 gtk_box_append (GTK_BOX (frame), child);
763
764 gtk_widget_show (widget: frame);
765
766 return frame;
767}
768
769static void
770setup_item (GtkSignalListItemFactory *factory,
771 GtkListItem *item)
772{
773 gtk_list_item_set_child (self: item, child: gtk_editable_label_new (str: ""));
774}
775
776static void
777label_changed (GObject *object,
778 GParamSpec *pspec,
779 GtkListItem *item)
780{
781 GtkPageSetup *page_setup;
782 GtkPaperSize *paper_size;
783 const char *new_text;
784
785 page_setup = gtk_list_item_get_item (self: item);
786
787 new_text = gtk_editable_get_text (GTK_EDITABLE (object));
788
789 paper_size = gtk_paper_size_new_custom (name: new_text, display_name: new_text,
790 width: gtk_page_setup_get_paper_width (setup: page_setup, unit: GTK_UNIT_MM),
791 height: gtk_page_setup_get_paper_height (setup: page_setup, unit: GTK_UNIT_MM), unit: GTK_UNIT_MM);
792 gtk_page_setup_set_paper_size (setup: page_setup, size: paper_size);
793 gtk_paper_size_free (size: paper_size);
794}
795
796static void
797state_changed (GtkWidget *item,
798 GtkStateFlags old_state,
799 GtkWidget *label)
800{
801 gboolean selected;
802
803 selected = (gtk_widget_get_state_flags (widget: item) & GTK_STATE_FLAG_SELECTED) != 0;
804 gtk_editable_set_editable (GTK_EDITABLE (label), is_editable: selected);
805}
806
807static void
808bind_item (GtkSignalListItemFactory *factory,
809 GtkListItem *item)
810{
811 GtkPageSetup *page_setup;
812 GtkPaperSize *paper_size;
813 GtkWidget *label;
814
815 page_setup = gtk_list_item_get_item (self: item);
816 label = gtk_list_item_get_child (self: item);
817
818 paper_size = gtk_page_setup_get_paper_size (setup: page_setup);
819 gtk_editable_set_text (GTK_EDITABLE (label),
820 text: gtk_paper_size_get_display_name (size: paper_size));
821 g_signal_connect (label, "notify::text",
822 G_CALLBACK (label_changed), item);
823 g_signal_connect (gtk_widget_get_parent (label), "state-flags-changed",
824 G_CALLBACK (state_changed), label);
825}
826
827static void
828unbind_item (GtkSignalListItemFactory *factory,
829 GtkListItem *item)
830{
831 GtkWidget *label;
832
833 label = gtk_list_item_get_child (self: item);
834 g_signal_handlers_disconnect_by_func (label, label_changed, item);
835 g_signal_handlers_disconnect_by_func (gtk_widget_get_parent (label), state_changed, label);
836}
837
838static void
839setup_printer_item (GtkSignalListItemFactory *factory,
840 GtkListItem *item)
841{
842 GtkWidget *label;
843
844 label = gtk_label_new (str: "");
845 gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START);
846 gtk_list_item_set_child (self: item, child: label);
847}
848
849static void
850bind_printer_item (GtkSignalListItemFactory *factory,
851 GtkListItem *item)
852{
853 GtkPrinter *printer;
854 GtkWidget *label;
855
856 printer = gtk_list_item_get_item (self: item);
857 label = gtk_list_item_get_child (self: item);
858
859 gtk_label_set_label (GTK_LABEL (label), str: gtk_printer_get_name (printer));
860}
861
862static void
863populate_dialog (GtkCustomPaperUnixDialog *dialog)
864{
865 GtkDialog *cpu_dialog = GTK_DIALOG (dialog);
866 GtkWidget *content_area;
867 GtkWidget *grid, *label, *widget, *frame, *combo;
868 GtkWidget *hbox, *vbox, *listview, *scrolled, *toolbar, *button;
869 GtkUnit user_units;
870 GtkSelectionModel *model;
871 GtkListItemFactory *factory;
872
873 content_area = gtk_dialog_get_content_area (dialog: cpu_dialog);
874 gtk_box_set_spacing (GTK_BOX (content_area), spacing: 2); /* 2 * 5 + 2 = 12 */
875
876 hbox = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 18);
877 gtk_widget_set_margin_start (widget: hbox, margin: 20);
878 gtk_widget_set_margin_end (widget: hbox, margin: 20);
879 gtk_widget_set_margin_top (widget: hbox, margin: 20);
880 gtk_widget_set_margin_bottom (widget: hbox, margin: 20);
881 gtk_box_append (GTK_BOX (content_area), child: hbox);
882 gtk_widget_show (widget: hbox);
883
884 vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 0);
885 gtk_box_append (GTK_BOX (hbox), child: vbox);
886 gtk_widget_show (widget: vbox);
887
888 scrolled = gtk_scrolled_window_new ();
889 gtk_widget_set_vexpand (widget: scrolled, TRUE);
890 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
891 hscrollbar_policy: GTK_POLICY_NEVER, vscrollbar_policy: GTK_POLICY_AUTOMATIC);
892 gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (scrolled), TRUE);
893 gtk_box_append (GTK_BOX (vbox), child: scrolled);
894 gtk_widget_show (widget: scrolled);
895
896 model = GTK_SELECTION_MODEL (ptr: gtk_single_selection_new (g_object_ref (G_LIST_MODEL (dialog->custom_paper_list))));
897 g_signal_connect (model, "notify::selected", G_CALLBACK (selected_custom_paper_changed), dialog);
898
899 factory = gtk_signal_list_item_factory_new ();
900 g_signal_connect (factory, "setup", G_CALLBACK (setup_item), NULL);
901 g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL);
902 g_signal_connect (factory, "unbind", G_CALLBACK (unbind_item), NULL);
903
904 listview = gtk_list_view_new (model, factory);
905 gtk_widget_set_size_request (widget: listview, width: 140, height: -1);
906
907 dialog->listview = listview;
908
909 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), child: listview);
910
911 toolbar = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0);
912
913 gtk_widget_add_css_class (widget: toolbar, css_class: "linked");
914
915 gtk_box_append (GTK_BOX (vbox), child: toolbar);
916
917 button = gtk_button_new_from_icon_name (icon_name: "list-add-symbolic");
918 g_signal_connect_swapped (button, "clicked", G_CALLBACK (add_custom_paper), dialog);
919
920 gtk_box_append (GTK_BOX (toolbar), child: button);
921
922 button = gtk_button_new_from_icon_name (icon_name: "list-remove-symbolic");
923 g_signal_connect_swapped (button, "clicked", G_CALLBACK (remove_custom_paper), dialog);
924
925 gtk_box_append (GTK_BOX (toolbar), child: button);
926
927 user_units = _gtk_print_get_default_user_units ();
928
929 vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 18);
930 dialog->values_box = vbox;
931 gtk_box_append (GTK_BOX (hbox), child: vbox);
932 gtk_widget_show (widget: vbox);
933
934 grid = gtk_grid_new ();
935
936 gtk_grid_set_row_spacing (GTK_GRID (grid), spacing: 6);
937 gtk_grid_set_column_spacing (GTK_GRID (grid), spacing: 12);
938
939 label = gtk_label_new_with_mnemonic (_("_Width:"));
940 gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START);
941 gtk_widget_set_valign (widget: label, align: GTK_ALIGN_BASELINE);
942 gtk_widget_show (widget: label);
943 gtk_grid_attach (GTK_GRID (grid), child: label, column: 0, row: 0, width: 1, height: 1);
944
945 widget = new_unit_widget (dialog, unit: user_units, mnemonic_label: label);
946 dialog->width_widget = widget;
947 gtk_grid_attach (GTK_GRID (grid), child: widget, column: 1, row: 0, width: 1, height: 1);
948 gtk_widget_show (widget);
949
950 label = gtk_label_new_with_mnemonic (_("_Height:"));
951 gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START);
952 gtk_widget_set_valign (widget: label, align: GTK_ALIGN_BASELINE);
953 gtk_widget_show (widget: label);
954 gtk_grid_attach (GTK_GRID (grid), child: label, column: 0, row: 1, width: 1, height: 1);
955
956 widget = new_unit_widget (dialog, unit: user_units, mnemonic_label: label);
957 dialog->height_widget = widget;
958 gtk_grid_attach (GTK_GRID (grid), child: widget, column: 1, row: 1, width: 1, height: 1);
959 gtk_widget_show (widget);
960
961 frame = wrap_in_frame (_("Paper Size"), child: grid);
962 gtk_widget_show (widget: grid);
963 gtk_box_append (GTK_BOX (vbox), child: frame);
964 gtk_widget_show (widget: frame);
965
966 grid = gtk_grid_new ();
967 gtk_grid_set_row_spacing (GTK_GRID (grid), spacing: 6);
968 gtk_grid_set_column_spacing (GTK_GRID (grid), spacing: 12);
969
970 label = gtk_label_new_with_mnemonic (_("_Top:"));
971 gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START);
972 gtk_widget_set_valign (widget: label, align: GTK_ALIGN_BASELINE);
973 gtk_grid_attach (GTK_GRID (grid), child: label, column: 0, row: 0, width: 1, height: 1);
974 gtk_widget_show (widget: label);
975
976 widget = new_unit_widget (dialog, unit: user_units, mnemonic_label: label);
977 dialog->top_widget = widget;
978 gtk_grid_attach (GTK_GRID (grid), child: widget, column: 1, row: 0, width: 1, height: 1);
979 gtk_widget_show (widget);
980
981 label = gtk_label_new_with_mnemonic (_("_Bottom:"));
982 gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START);
983 gtk_widget_set_valign (widget: label, align: GTK_ALIGN_BASELINE);
984 gtk_grid_attach (GTK_GRID (grid), child: label, column: 0, row: 1, width: 1, height: 1);
985 gtk_widget_show (widget: label);
986
987 widget = new_unit_widget (dialog, unit: user_units, mnemonic_label: label);
988 dialog->bottom_widget = widget;
989 gtk_grid_attach (GTK_GRID (grid), child: widget, column: 1, row: 1, width: 1, height: 1);
990 gtk_widget_show (widget);
991
992 label = gtk_label_new_with_mnemonic (_("_Left:"));
993 gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START);
994 gtk_widget_set_valign (widget: label, align: GTK_ALIGN_BASELINE);
995 gtk_grid_attach (GTK_GRID (grid), child: label, column: 0, row: 2, width: 1, height: 1);
996 gtk_widget_show (widget: label);
997
998 widget = new_unit_widget (dialog, unit: user_units, mnemonic_label: label);
999 dialog->left_widget = widget;
1000 gtk_grid_attach (GTK_GRID (grid), child: widget, column: 1, row: 2, width: 1, height: 1);
1001 gtk_widget_show (widget);
1002
1003 label = gtk_label_new_with_mnemonic (_("_Right:"));
1004 gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START);
1005 gtk_widget_set_valign (widget: label, align: GTK_ALIGN_BASELINE);
1006 gtk_grid_attach (GTK_GRID (grid), child: label, column: 0, row: 3, width: 1, height: 1);
1007 gtk_widget_show (widget: label);
1008
1009 widget = new_unit_widget (dialog, unit: user_units, mnemonic_label: label);
1010 dialog->right_widget = widget;
1011 gtk_grid_attach (GTK_GRID (grid), child: widget, column: 1, row: 3, width: 1, height: 1);
1012 gtk_widget_show (widget);
1013
1014 hbox = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0);
1015 gtk_grid_attach (GTK_GRID (grid), child: hbox, column: 0, row: 4, width: 2, height: 1);
1016 gtk_widget_show (widget: hbox);
1017
1018 combo = gtk_drop_down_new (g_object_ref (dialog->printer_list), NULL);
1019
1020 factory = gtk_signal_list_item_factory_new ();
1021 g_signal_connect (factory, "setup", G_CALLBACK (setup_printer_item), dialog);
1022 g_signal_connect (factory, "bind", G_CALLBACK (bind_printer_item), dialog);
1023 gtk_drop_down_set_factory (self: GTK_DROP_DOWN (ptr: combo), factory);
1024 g_object_unref (object: factory);
1025
1026 dialog->printer_combo = combo;
1027
1028 dialog->printer_inserted_tag =
1029 g_signal_connect_swapped (dialog->printer_list, "items-changed",
1030 G_CALLBACK (update_combo_sensitivity_from_printers), dialog);
1031 update_combo_sensitivity_from_printers (dialog);
1032
1033 gtk_drop_down_set_selected (self: GTK_DROP_DOWN (ptr: combo), position: 0);
1034 gtk_box_append (GTK_BOX (hbox), child: combo);
1035
1036 g_signal_connect_swapped (combo, "notify::selected",
1037 G_CALLBACK (margins_from_printer_changed), dialog);
1038
1039 frame = wrap_in_frame (_("Paper Margins"), child: grid);
1040 gtk_widget_show (widget: grid);
1041 gtk_box_append (GTK_BOX (vbox), child: frame);
1042 gtk_widget_show (widget: frame);
1043
1044 update_custom_widgets_from_list (dialog);
1045
1046 if (g_list_model_get_n_items (list: G_LIST_MODEL (ptr: dialog->custom_paper_list)) == 0)
1047 add_custom_paper (dialog);
1048
1049 load_print_backends (dialog);
1050}
1051

source code of gtk/gtk/gtkcustompaperunixdialog.c