1/* GtkPageSetupUnixDialog
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#include "gtkintl.h"
25#include "gtkprivate.h"
26
27#include "gtkbutton.h"
28#include "gtkscrolledwindow.h"
29#include "gtkcheckbutton.h"
30#include "gtklabel.h"
31#include "gtkgrid.h"
32#include "gtkcelllayout.h"
33#include "gtkcellrenderertext.h"
34
35#include "gtkpagesetupunixdialog.h"
36#include "gtkcustompaperunixdialog.h"
37#include "gtkprintbackendprivate.h"
38#include "gtkpapersize.h"
39#include "gtkprintutils.h"
40#include "gtkdialogprivate.h"
41
42/**
43 * GtkPageSetupUnixDialog:
44 *
45 * `GtkPageSetupUnixDialog` implements a page setup dialog for platforms
46 * which don’t provide a native page setup dialog, like Unix.
47 *
48 * ![An example GtkPageSetupUnixDialog](pagesetupdialog.png)
49 *
50 * It can be used very much like any other GTK dialog, at the
51 * cost of the portability offered by the high-level printing
52 * API in [class@Gtk.PrintOperation].
53 */
54
55typedef struct _GtkPageSetupUnixDialogClass GtkPageSetupUnixDialogClass;
56
57struct _GtkPageSetupUnixDialog
58{
59 GtkDialog parent_instance;
60
61 GListModel *printer_list;
62 GListStore *page_setup_list;
63 GListStore *custom_paper_list;
64 GListStore *manage_papers_list;
65 GListStore *paper_size_list;
66
67 GList *print_backends;
68
69 GtkWidget *printer_combo;
70 GtkWidget *paper_size_combo;
71 GtkWidget *paper_size_label;
72
73 GtkWidget *portrait_radio;
74 GtkWidget *reverse_portrait_radio;
75 GtkWidget *landscape_radio;
76 GtkWidget *reverse_landscape_radio;
77
78 gulong request_details_tag;
79 GtkPrinter *request_details_printer;
80
81 GtkPrintSettings *print_settings;
82
83 gboolean internal_change;
84
85 /* Save last setup so we can re-set it after selecting manage custom sizes */
86 GtkPageSetup *last_setup;
87};
88
89struct _GtkPageSetupUnixDialogClass
90{
91 GtkDialogClass parent_class;
92};
93
94
95/* Keep these in line with GtkListStores defined in gtkpagesetupunixprintdialog.ui */
96enum {
97 PRINTER_LIST_COL_NAME,
98 PRINTER_LIST_COL_PRINTER,
99 PRINTER_LIST_N_COLS
100};
101
102enum {
103 PAGE_SETUP_LIST_COL_PAGE_SETUP,
104 PAGE_SETUP_LIST_COL_IS_SEPARATOR,
105 PAGE_SETUP_LIST_N_COLS
106};
107
108G_DEFINE_TYPE (GtkPageSetupUnixDialog, gtk_page_setup_unix_dialog, GTK_TYPE_DIALOG)
109
110static void gtk_page_setup_unix_dialog_finalize (GObject *object);
111static void fill_paper_sizes_from_printer (GtkPageSetupUnixDialog *dialog,
112 GtkPrinter *printer);
113static void printer_changed_callback (GtkDropDown *combo_box,
114 GParamSpec *pspec,
115 GtkPageSetupUnixDialog *dialog);
116static void paper_size_changed (GtkDropDown *combo_box,
117 GParamSpec *pspec,
118 GtkPageSetupUnixDialog *dialog);
119static void load_print_backends (GtkPageSetupUnixDialog *dialog);
120
121
122static const char common_paper_sizes[][16] = {
123 "na_letter",
124 "na_legal",
125 "iso_a4",
126 "iso_a5",
127 "roc_16k",
128 "iso_b5",
129 "jis_b5",
130 "na_number-10",
131 "iso_dl",
132 "jpn_chou3",
133 "na_ledger",
134 "iso_a3"
135};
136
137
138static void
139gtk_page_setup_unix_dialog_class_init (GtkPageSetupUnixDialogClass *class)
140{
141 GObjectClass *object_class;
142 GtkWidgetClass *widget_class;
143
144 object_class = G_OBJECT_CLASS (class);
145 widget_class = GTK_WIDGET_CLASS (class);
146
147 object_class->finalize = gtk_page_setup_unix_dialog_finalize;
148
149 /* Bind class to template
150 */
151 gtk_widget_class_set_template_from_resource (widget_class,
152 resource_name: "/org/gtk/libgtk/ui/gtkpagesetupunixdialog.ui");
153
154 gtk_widget_class_bind_template_child (widget_class, GtkPageSetupUnixDialog, printer_combo);
155 gtk_widget_class_bind_template_child (widget_class, GtkPageSetupUnixDialog, paper_size_combo);
156 gtk_widget_class_bind_template_child (widget_class, GtkPageSetupUnixDialog, paper_size_label);
157 gtk_widget_class_bind_template_child (widget_class, GtkPageSetupUnixDialog, portrait_radio);
158 gtk_widget_class_bind_template_child (widget_class, GtkPageSetupUnixDialog, reverse_portrait_radio);
159 gtk_widget_class_bind_template_child (widget_class, GtkPageSetupUnixDialog, landscape_radio);
160 gtk_widget_class_bind_template_child (widget_class, GtkPageSetupUnixDialog, reverse_landscape_radio);
161
162 gtk_widget_class_bind_template_callback (widget_class, printer_changed_callback);
163 gtk_widget_class_bind_template_callback (widget_class, paper_size_changed);
164}
165
166static void
167setup_paper_size_item (GtkSignalListItemFactory *factory,
168 GtkListItem *item)
169{
170 GtkWidget *label;
171
172 label = gtk_label_new (str: "");
173 gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START);
174 gtk_list_item_set_child (self: item, child: label);
175}
176
177static void
178bind_paper_size_list_item (GtkSignalListItemFactory *factory,
179 GtkListItem *item,
180 GtkPageSetupUnixDialog *self)
181{
182 GtkPageSetup *page_setup;
183 GtkWidget *label;
184 guint pos;
185 GListModel *papers;
186 GListModel *model;
187 gpointer first;
188
189 page_setup = gtk_list_item_get_item (self: item);
190 label = gtk_list_item_get_child (self: item);
191
192 pos = gtk_list_item_get_position (self: item);
193 papers = gtk_drop_down_get_model (self: GTK_DROP_DOWN (ptr: self->paper_size_combo));
194 model = gtk_flatten_list_model_get_model_for_item (self: GTK_FLATTEN_LIST_MODEL (ptr: papers), position: pos);
195 if (model != G_LIST_MODEL (ptr: self->manage_papers_list))
196 {
197 GtkPaperSize *paper_size = gtk_page_setup_get_paper_size (setup: page_setup);
198 gtk_label_set_text (GTK_LABEL (label), str: gtk_paper_size_get_display_name (size: paper_size));
199 }
200 else
201 gtk_label_set_text (GTK_LABEL (label), _("Manage Custom Sizes…"));
202
203 first = g_list_model_get_item (list: model, position: 0);
204 g_object_unref (object: first);
205 if (pos != 0 &&
206 page_setup == GTK_PAGE_SETUP (first))
207 gtk_widget_add_css_class (widget: gtk_widget_get_parent (widget: label), css_class: "separator");
208 else
209 gtk_widget_remove_css_class (widget: gtk_widget_get_parent (widget: label), css_class: "separator");
210}
211
212static void
213bind_paper_size_item (GtkSignalListItemFactory *factory,
214 GtkListItem *item,
215 GtkPageSetupUnixDialog *self)
216{
217 GtkWidget *label;
218
219 bind_paper_size_list_item (factory, item, self);
220
221 label = gtk_list_item_get_child (self: item);
222 gtk_widget_remove_css_class (widget: label, css_class: "separator-before");
223}
224
225static gboolean
226match_func (gpointer item, gpointer user_data)
227{
228 return !gtk_printer_is_virtual (GTK_PRINTER (item));
229}
230
231static void
232setup_printer_item (GtkSignalListItemFactory *factory,
233 GtkListItem *item)
234{
235 GtkWidget *label;
236
237 label = gtk_label_new (str: "");
238 gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START);
239 gtk_label_set_xalign (GTK_LABEL (label), xalign: 0.0);
240 gtk_list_item_set_child (self: item, child: label);
241}
242
243static void
244bind_printer_item (GtkSignalListItemFactory *factory,
245 GtkListItem *item,
246 GtkPageSetupUnixDialog *self)
247{
248 GtkPrinter *printer;
249 GtkWidget *label;
250 const char *location;
251 const char *name;
252 char *str;
253
254 printer = gtk_list_item_get_item (self: item);
255 label = gtk_list_item_get_child (self: item);
256
257 name = gtk_printer_get_name (printer);
258 location = gtk_printer_get_location (printer);
259 str = g_strdup_printf (format: "<b>%s</b>\n%s", name, location ? location : "");
260 gtk_label_set_markup (GTK_LABEL (label), str);
261 g_free (mem: str);
262}
263
264static void
265gtk_page_setup_unix_dialog_init (GtkPageSetupUnixDialog *dialog)
266{
267 GtkListItemFactory *factory;
268 GListStore *store;
269 GListModel *paper_size_list;
270 GtkPrinter *printer;
271 GListStore *printer_list;
272 GListStore *printer_list_list;
273 GListModel *full_list;
274 GtkFilter *filter;
275 GtkPageSetup *page_setup;
276
277 dialog->internal_change = TRUE;
278 dialog->print_backends = NULL;
279
280 gtk_widget_init_template (GTK_WIDGET (dialog));
281 gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (dialog));
282 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
283 _("_Cancel"), GTK_RESPONSE_CANCEL,
284 _("_Apply"), GTK_RESPONSE_OK,
285 NULL);
286 gtk_dialog_set_default_response (GTK_DIALOG (dialog), response_id: GTK_RESPONSE_OK);
287
288 dialog->page_setup_list = g_list_store_new (GTK_TYPE_PAGE_SETUP);
289 dialog->custom_paper_list = g_list_store_new (GTK_TYPE_PAGE_SETUP);
290 dialog->manage_papers_list = g_list_store_new (GTK_TYPE_PAGE_SETUP);
291 page_setup = gtk_page_setup_new ();
292 g_list_store_append (store: dialog->manage_papers_list, item: page_setup);
293 g_object_unref (object: page_setup);
294
295 factory = gtk_signal_list_item_factory_new ();
296 g_signal_connect (factory, "setup", G_CALLBACK (setup_paper_size_item), dialog);
297 g_signal_connect (factory, "bind", G_CALLBACK (bind_paper_size_item), dialog);
298 gtk_drop_down_set_factory (self: GTK_DROP_DOWN (ptr: dialog->paper_size_combo), factory);
299 g_object_unref (object: factory);
300
301 factory = gtk_signal_list_item_factory_new ();
302 g_signal_connect (factory, "setup", G_CALLBACK (setup_paper_size_item), dialog);
303 g_signal_connect (factory, "bind", G_CALLBACK (bind_paper_size_list_item), dialog);
304 gtk_drop_down_set_list_factory (self: GTK_DROP_DOWN (ptr: dialog->paper_size_combo), factory);
305 g_object_unref (object: factory);
306
307 store = g_list_store_new (G_TYPE_LIST_MODEL);
308 g_list_store_append (store, item: dialog->page_setup_list);
309 g_list_store_append (store, item: dialog->custom_paper_list);
310 g_list_store_append (store, item: dialog->manage_papers_list);
311 paper_size_list = G_LIST_MODEL (ptr: gtk_flatten_list_model_new (model: G_LIST_MODEL (ptr: store)));
312 gtk_drop_down_set_model (self: GTK_DROP_DOWN (ptr: dialog->paper_size_combo), model: paper_size_list);
313 g_object_unref (object: paper_size_list);
314
315 /* Do this in code, we want the translatable strings without the markup */
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 (_("Any Printer"), NULL, FALSE);
319 gtk_printer_set_location (printer, _("For portable documents"));
320 g_list_store_append (store: printer_list, item: printer);
321 g_object_unref (object: printer);
322 g_list_store_append (store: printer_list_list, item: printer_list);
323 g_object_unref (object: printer_list);
324
325 full_list = G_LIST_MODEL (ptr: gtk_flatten_list_model_new (model: G_LIST_MODEL (ptr: printer_list_list)));
326
327 filter = GTK_FILTER (ptr: gtk_custom_filter_new (match_func, NULL, NULL));
328 dialog->printer_list = G_LIST_MODEL (ptr: gtk_filter_list_model_new (model: full_list, filter));
329
330 factory = gtk_signal_list_item_factory_new ();
331 g_signal_connect (factory, "setup", G_CALLBACK (setup_printer_item), dialog);
332 g_signal_connect (factory, "bind", G_CALLBACK (bind_printer_item), dialog);
333 gtk_drop_down_set_factory (self: GTK_DROP_DOWN (ptr: dialog->printer_combo), factory);
334 g_object_unref (object: factory);
335
336 gtk_drop_down_set_model (self: GTK_DROP_DOWN (ptr: dialog->printer_combo), model: dialog->printer_list);
337 printer_changed_callback (combo_box: GTK_DROP_DOWN (ptr: dialog->printer_combo), NULL, dialog);
338
339 /* Load data */
340 gtk_print_load_custom_papers (store: dialog->custom_paper_list);
341 load_print_backends (dialog);
342 dialog->internal_change = FALSE;
343}
344
345static void
346gtk_page_setup_unix_dialog_finalize (GObject *object)
347{
348 GtkPageSetupUnixDialog *dialog = GTK_PAGE_SETUP_UNIX_DIALOG (object);
349 GList *node;
350
351 if (dialog->request_details_tag)
352 {
353 g_signal_handler_disconnect (instance: dialog->request_details_printer,
354 handler_id: dialog->request_details_tag);
355 g_object_unref (object: dialog->request_details_printer);
356 dialog->request_details_printer = NULL;
357 dialog->request_details_tag = 0;
358 }
359
360 g_clear_object (&dialog->printer_list);
361 g_clear_object (&dialog->page_setup_list);
362 g_clear_object (&dialog->custom_paper_list);
363 g_clear_object (&dialog->manage_papers_list);
364
365 if (dialog->print_settings)
366 {
367 g_object_unref (object: dialog->print_settings);
368 dialog->print_settings = NULL;
369 }
370
371 for (node = dialog->print_backends; node != NULL; node = node->next)
372 gtk_print_backend_destroy (GTK_PRINT_BACKEND (node->data));
373 g_list_free_full (list: dialog->print_backends, free_func: g_object_unref);
374 dialog->print_backends = NULL;
375
376 G_OBJECT_CLASS (gtk_page_setup_unix_dialog_parent_class)->finalize (object);
377}
378
379static void
380load_print_backends (GtkPageSetupUnixDialog *dialog)
381{
382 GListModel *full_list;
383 GListStore *printer_list_list;
384 GList *node;
385
386 full_list = gtk_filter_list_model_get_model (self: GTK_FILTER_LIST_MODEL (ptr: dialog->printer_list));
387 printer_list_list = G_LIST_STORE (ptr: gtk_flatten_list_model_get_model (self: GTK_FLATTEN_LIST_MODEL (ptr: full_list)));
388
389 if (g_module_supported ())
390 dialog->print_backends = gtk_print_backend_load_modules ();
391
392 for (node = dialog->print_backends; node != NULL; node = node->next)
393 {
394 GtkPrintBackend *backend = node->data;
395 g_list_store_append (store: printer_list_list, item: gtk_print_backend_get_printers (print_backend: backend));
396 }
397}
398
399static GtkPageSetup *
400get_current_page_setup (GtkPageSetupUnixDialog *dialog)
401{
402 guint selected;
403 GListModel *model;
404
405 selected = gtk_drop_down_get_selected (self: GTK_DROP_DOWN (ptr: dialog->paper_size_combo));
406 model = gtk_drop_down_get_model (self: GTK_DROP_DOWN (ptr: dialog->paper_size_combo));
407 if (selected != GTK_INVALID_LIST_POSITION)
408 return g_list_model_get_item (list: model, position: selected);
409
410 return gtk_page_setup_new ();
411}
412
413static gboolean
414page_setup_is_equal (GtkPageSetup *a,
415 GtkPageSetup *b)
416{
417 return
418 gtk_paper_size_is_equal (size1: gtk_page_setup_get_paper_size (setup: a),
419 size2: gtk_page_setup_get_paper_size (setup: b)) &&
420 gtk_page_setup_get_top_margin (setup: a, unit: GTK_UNIT_MM) == gtk_page_setup_get_top_margin (setup: b, unit: GTK_UNIT_MM) &&
421 gtk_page_setup_get_bottom_margin (setup: a, unit: GTK_UNIT_MM) == gtk_page_setup_get_bottom_margin (setup: b, unit: GTK_UNIT_MM) &&
422 gtk_page_setup_get_left_margin (setup: a, unit: GTK_UNIT_MM) == gtk_page_setup_get_left_margin (setup: b, unit: GTK_UNIT_MM) &&
423 gtk_page_setup_get_right_margin (setup: a, unit: GTK_UNIT_MM) == gtk_page_setup_get_right_margin (setup: b, unit: GTK_UNIT_MM);
424}
425
426static gboolean
427page_setup_is_same_size (GtkPageSetup *a,
428 GtkPageSetup *b)
429{
430 return gtk_paper_size_is_equal (size1: gtk_page_setup_get_paper_size (setup: a),
431 size2: gtk_page_setup_get_paper_size (setup: b));
432}
433
434static gboolean
435set_paper_size (GtkPageSetupUnixDialog *dialog,
436 GtkPageSetup *page_setup,
437 gboolean size_only,
438 gboolean add_item)
439{
440 GListModel *model;
441 GtkPageSetup *list_page_setup;
442 guint i;
443
444 if (page_setup == NULL)
445 return FALSE;
446
447 model = gtk_drop_down_get_model (self: GTK_DROP_DOWN (ptr: dialog->paper_size_combo));
448 for (i = 0; i < g_list_model_get_n_items (list: model); i++)
449 {
450 list_page_setup = g_list_model_get_item (list: model, position: i);
451 if (list_page_setup == NULL)
452 continue;
453
454 if ((size_only && page_setup_is_same_size (a: page_setup, b: list_page_setup)) ||
455 (!size_only && page_setup_is_equal (a: page_setup, b: list_page_setup)))
456 {
457 gtk_drop_down_set_selected (self: GTK_DROP_DOWN (ptr: dialog->paper_size_combo), position: i);
458 g_object_unref (object: list_page_setup);
459 return TRUE;
460 }
461
462 g_object_unref (object: list_page_setup);
463 }
464
465 if (add_item)
466 {
467 i = g_list_model_get_n_items (list: model);
468 g_list_store_append (store: dialog->page_setup_list, item: page_setup);
469 gtk_drop_down_set_selected (self: GTK_DROP_DOWN (ptr: dialog->paper_size_combo), position: i);
470 return TRUE;
471 }
472
473 return FALSE;
474}
475
476static void
477fill_paper_sizes_from_printer (GtkPageSetupUnixDialog *dialog,
478 GtkPrinter *printer)
479{
480 GList *list, *l;
481 GtkPageSetup *current_page_setup, *page_setup;
482 GtkPaperSize *paper_size;
483 int i;
484
485 g_list_store_remove_all (store: dialog->page_setup_list);
486
487 if (printer == NULL)
488 {
489 for (i = 0; i < G_N_ELEMENTS (common_paper_sizes); i++)
490 {
491 page_setup = gtk_page_setup_new ();
492 paper_size = gtk_paper_size_new (name: common_paper_sizes[i]);
493 gtk_page_setup_set_paper_size_and_default_margins (setup: page_setup, size: paper_size);
494 gtk_paper_size_free (size: paper_size);
495
496 g_list_store_append (store: dialog->page_setup_list, item: page_setup);
497 g_object_unref (object: page_setup);
498 }
499 }
500 else
501 {
502 list = gtk_printer_list_papers (printer);
503 /* TODO: We should really sort this list so interesting size
504 are at the top */
505 for (l = list; l != NULL; l = l->next)
506 {
507 page_setup = l->data;
508 g_list_store_append (store: dialog->page_setup_list, item: page_setup);
509 g_object_unref (object: page_setup);
510 }
511 g_list_free (list);
512 }
513
514 current_page_setup = NULL;
515
516 /* When selecting a different printer, select its default paper size */
517 if (printer != NULL)
518 current_page_setup = gtk_printer_get_default_page_size (printer);
519
520 if (current_page_setup == NULL)
521 current_page_setup = get_current_page_setup (dialog);
522
523 if (!set_paper_size (dialog, page_setup: current_page_setup, FALSE, FALSE))
524 set_paper_size (dialog, page_setup: current_page_setup, TRUE, TRUE);
525
526 if (current_page_setup)
527 g_object_unref (object: current_page_setup);
528}
529
530static void
531printer_changed_finished_callback (GtkPrinter *printer,
532 gboolean success,
533 GtkPageSetupUnixDialog *dialog)
534{
535 g_signal_handler_disconnect (instance: dialog->request_details_printer,
536 handler_id: dialog->request_details_tag);
537 g_object_unref (object: dialog->request_details_printer);
538 dialog->request_details_tag = 0;
539 dialog->request_details_printer = NULL;
540
541 if (success)
542 fill_paper_sizes_from_printer (dialog, printer);
543
544}
545
546static void
547printer_changed_callback (GtkDropDown *combo_box,
548 GParamSpec *pspec,
549 GtkPageSetupUnixDialog *dialog)
550{
551 GtkPrinter *printer;
552 guint selected;
553
554 if (dialog->request_details_tag)
555 {
556 g_signal_handler_disconnect (instance: dialog->request_details_printer,
557 handler_id: dialog->request_details_tag);
558 g_object_unref (object: dialog->request_details_printer);
559 dialog->request_details_printer = NULL;
560 dialog->request_details_tag = 0;
561 }
562
563 selected = gtk_drop_down_get_selected (self: GTK_DROP_DOWN (ptr: dialog->printer_combo));
564 if (selected != GTK_INVALID_LIST_POSITION)
565 {
566 GListModel *model;
567
568 model = gtk_drop_down_get_model (self: GTK_DROP_DOWN (ptr: dialog->printer_combo));
569 printer = g_list_model_get_item (list: model, position: selected);
570 if (strcmp (s1: gtk_printer_get_name (printer), _("Any Printer")) == 0)
571 g_clear_object (&printer);
572
573 if (printer == NULL ||
574 gtk_printer_has_details (printer))
575 fill_paper_sizes_from_printer (dialog, printer);
576 else
577 {
578 dialog->request_details_printer = g_object_ref (printer);
579 dialog->request_details_tag =
580 g_signal_connect (printer, "details-acquired",
581 G_CALLBACK (printer_changed_finished_callback), dialog);
582 gtk_printer_request_details (printer);
583 }
584
585 if (printer)
586 g_object_unref (object: printer);
587
588 if (dialog->print_settings)
589 {
590 const char *name = NULL;
591
592 if (printer)
593 name = gtk_printer_get_name (printer);
594
595 gtk_print_settings_set (settings: dialog->print_settings,
596 key: "format-for-printer", value: name);
597 }
598 }
599}
600
601/* We do this munging because we don't want to show zero digits
602 after the decimal point, and not to many such digits if they
603 are nonzero. I wish printf let you specify max precision for %f... */
604static char *
605double_to_string (double d,
606 GtkUnit unit)
607{
608 char *val, *p;
609 struct lconv *locale_data;
610 const char *decimal_point;
611 int decimal_point_len;
612
613 locale_data = localeconv ();
614 decimal_point = locale_data->decimal_point;
615 decimal_point_len = strlen (s: decimal_point);
616
617 /* Max two decimal digits for inch, max one for mm */
618 if (unit == GTK_UNIT_INCH)
619 val = g_strdup_printf (format: "%.2f", d);
620 else
621 val = g_strdup_printf (format: "%.1f", d);
622
623 if (strstr (haystack: val, needle: decimal_point))
624 {
625 p = val + strlen (s: val) - 1;
626 while (*p == '0')
627 p--;
628 if (p - val + 1 >= decimal_point_len &&
629 strncmp (s1: p - (decimal_point_len - 1), s2: decimal_point, n: decimal_point_len) == 0)
630 p -= decimal_point_len;
631 p[1] = '\0';
632 }
633
634 return val;
635}
636
637
638static void
639custom_paper_dialog_response_cb (GtkDialog *custom_paper_dialog,
640 int response_id,
641 gpointer user_data)
642{
643 GtkPageSetupUnixDialog *dialog = GTK_PAGE_SETUP_UNIX_DIALOG (user_data);
644 GtkPageSetup *last_page_setup;
645
646 dialog->internal_change = TRUE;
647 gtk_print_load_custom_papers (store: dialog->custom_paper_list);
648 printer_changed_callback (combo_box: GTK_DROP_DOWN (ptr: dialog->printer_combo), NULL, dialog);
649 dialog->internal_change = FALSE;
650
651 if (dialog->last_setup)
652 last_page_setup = g_object_ref (dialog->last_setup);
653 else
654 last_page_setup = gtk_page_setup_new (); /* "good" default */
655 set_paper_size (dialog, page_setup: last_page_setup, FALSE, TRUE);
656 g_object_unref (object: last_page_setup);
657
658 gtk_window_destroy (GTK_WINDOW (custom_paper_dialog));
659}
660
661static void
662paper_size_changed (GtkDropDown *combo_box,
663 GParamSpec *pspec,
664 GtkPageSetupUnixDialog *dialog)
665{
666 GtkPageSetup *page_setup, *last_page_setup;
667 guint selected;
668 GtkUnit unit;
669 char *str, *w, *h;
670 char *top, *bottom, *left, *right;
671 GtkLabel *label;
672 const char *unit_str;
673
674 if (dialog->internal_change)
675 return;
676
677 label = GTK_LABEL (dialog->paper_size_label);
678
679 selected = gtk_drop_down_get_selected (self: GTK_DROP_DOWN (ptr: combo_box));
680 if (selected != GTK_INVALID_LIST_POSITION)
681 {
682 GListModel *papers, *model;
683
684 papers = gtk_drop_down_get_model (self: GTK_DROP_DOWN (ptr: dialog->paper_size_combo));
685 page_setup = g_list_model_get_item (list: papers, position: selected);
686 model = gtk_flatten_list_model_get_model_for_item (self: GTK_FLATTEN_LIST_MODEL (ptr: papers), position: selected);
687
688 if (model == G_LIST_MODEL (ptr: dialog->manage_papers_list))
689 {
690 GtkWidget *custom_paper_dialog;
691
692 /* Change from "manage" menu item to last value */
693 if (dialog->last_setup)
694 last_page_setup = g_object_ref (dialog->last_setup);
695 else
696 last_page_setup = gtk_page_setup_new (); /* "good" default */
697 set_paper_size (dialog, page_setup: last_page_setup, FALSE, TRUE);
698 g_object_unref (object: last_page_setup);
699
700 /* And show the custom paper dialog */
701 custom_paper_dialog = _gtk_custom_paper_unix_dialog_new (GTK_WINDOW (dialog), NULL);
702 g_signal_connect (custom_paper_dialog, "response", G_CALLBACK (custom_paper_dialog_response_cb), dialog);
703 gtk_window_present (GTK_WINDOW (custom_paper_dialog));
704
705 g_object_unref (object: page_setup);
706
707 return;
708 }
709
710 if (dialog->last_setup)
711 g_object_unref (object: dialog->last_setup);
712
713 dialog->last_setup = g_object_ref (page_setup);
714
715 unit = _gtk_print_get_default_user_units ();
716
717 if (unit == GTK_UNIT_MM)
718 unit_str = _("mm");
719 else
720 unit_str = _("inch");
721
722 w = double_to_string (d: gtk_page_setup_get_paper_width (setup: page_setup, unit),
723 unit);
724 h = double_to_string (d: gtk_page_setup_get_paper_height (setup: page_setup, unit),
725 unit);
726 str = g_strdup_printf (format: "%s × %s %s", w, h, unit_str);
727 g_free (mem: w);
728 g_free (mem: h);
729
730 gtk_label_set_text (self: label, str);
731 g_free (mem: str);
732
733 top = double_to_string (d: gtk_page_setup_get_top_margin (setup: page_setup, unit), unit);
734 bottom = double_to_string (d: gtk_page_setup_get_bottom_margin (setup: page_setup, unit), unit);
735 left = double_to_string (d: gtk_page_setup_get_left_margin (setup: page_setup, unit), unit);
736 right = double_to_string (d: gtk_page_setup_get_right_margin (setup: page_setup, unit), unit);
737
738 str = g_strdup_printf (_("Margins:\n"
739 " Left: %s %s\n"
740 " Right: %s %s\n"
741 " Top: %s %s\n"
742 " Bottom: %s %s"
743 ),
744 left, unit_str,
745 right, unit_str,
746 top, unit_str,
747 bottom, unit_str);
748 g_free (mem: top);
749 g_free (mem: bottom);
750 g_free (mem: left);
751 g_free (mem: right);
752
753 gtk_widget_set_tooltip_text (widget: dialog->paper_size_label, text: str);
754 g_free (mem: str);
755
756 g_object_unref (object: page_setup);
757 }
758 else
759 {
760 gtk_label_set_text (self: label, str: "");
761 gtk_widget_set_tooltip_text (widget: dialog->paper_size_label, NULL);
762 if (dialog->last_setup)
763 g_object_unref (object: dialog->last_setup);
764 dialog->last_setup = NULL;
765 }
766}
767
768/**
769 * gtk_page_setup_unix_dialog_new:
770 * @title: (nullable): the title of the dialog
771 * @parent: (nullable): transient parent of the dialog
772 *
773 * Creates a new page setup dialog.
774 *
775 * Returns: the new `GtkPageSetupUnixDialog`
776 */
777GtkWidget *
778gtk_page_setup_unix_dialog_new (const char *title,
779 GtkWindow *parent)
780{
781 GtkWidget *result;
782
783 if (title == NULL)
784 title = _("Page Setup");
785
786 result = g_object_new (GTK_TYPE_PAGE_SETUP_UNIX_DIALOG,
787 first_property_name: "title", title,
788 NULL);
789
790 if (parent)
791 gtk_window_set_transient_for (GTK_WINDOW (result), parent);
792
793 return result;
794}
795
796static GtkPageOrientation
797get_orientation (GtkPageSetupUnixDialog *dialog)
798{
799 if (gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->portrait_radio)))
800 return GTK_PAGE_ORIENTATION_PORTRAIT;
801 if (gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->landscape_radio)))
802 return GTK_PAGE_ORIENTATION_LANDSCAPE;
803 if (gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->reverse_landscape_radio)))
804 return GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE;
805 return GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT;
806}
807
808static void
809set_orientation (GtkPageSetupUnixDialog *dialog,
810 GtkPageOrientation orientation)
811{
812 switch (orientation)
813 {
814 case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
815 gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->reverse_portrait_radio), TRUE);
816 break;
817 case GTK_PAGE_ORIENTATION_PORTRAIT:
818 gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->portrait_radio), TRUE);
819 break;
820 case GTK_PAGE_ORIENTATION_LANDSCAPE:
821 gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->landscape_radio), TRUE);
822 break;
823 case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
824 gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->reverse_landscape_radio), TRUE);
825 break;
826 default:
827 break;
828 }
829}
830
831/**
832 * gtk_page_setup_unix_dialog_set_page_setup:
833 * @dialog: a `GtkPageSetupUnixDialog`
834 * @page_setup: a `GtkPageSetup`
835 *
836 * Sets the `GtkPageSetup` from which the page setup
837 * dialog takes its values.
838 */
839void
840gtk_page_setup_unix_dialog_set_page_setup (GtkPageSetupUnixDialog *dialog,
841 GtkPageSetup *page_setup)
842{
843 if (page_setup)
844 {
845 set_paper_size (dialog, page_setup, FALSE, TRUE);
846 set_orientation (dialog, orientation: gtk_page_setup_get_orientation (setup: page_setup));
847 }
848}
849
850/**
851 * gtk_page_setup_unix_dialog_get_page_setup:
852 * @dialog: a `GtkPageSetupUnixDialog`
853 *
854 * Gets the currently selected page setup from the dialog.
855 *
856 * Returns: (transfer none): the current page setup
857 */
858GtkPageSetup *
859gtk_page_setup_unix_dialog_get_page_setup (GtkPageSetupUnixDialog *dialog)
860{
861 GtkPageSetup *page_setup;
862
863 page_setup = get_current_page_setup (dialog);
864
865 gtk_page_setup_set_orientation (setup: page_setup, orientation: get_orientation (dialog));
866
867 return page_setup;
868}
869
870static gboolean
871set_active_printer (GtkPageSetupUnixDialog *dialog,
872 const char *printer_name)
873{
874 guint i, n;
875 GtkPrinter *printer;
876
877 if (!printer_name)
878 return FALSE;
879
880 for (i = 0, n = g_list_model_get_n_items (list: dialog->printer_list); i < n; i++)
881 {
882 printer = g_list_model_get_item (list: dialog->printer_list, position: i);
883
884 if (strcmp (s1: gtk_printer_get_name (printer), s2: printer_name) == 0)
885 {
886 gtk_drop_down_set_selected (self: GTK_DROP_DOWN (ptr: dialog->printer_combo), position: i);
887 g_object_unref (object: printer);
888
889 return TRUE;
890 }
891
892 g_object_unref (object: printer);
893 }
894
895 return FALSE;
896}
897
898/**
899 * gtk_page_setup_unix_dialog_set_print_settings:
900 * @dialog: a `GtkPageSetupUnixDialog`
901 * @print_settings: (nullable): a `GtkPrintSettings`
902 *
903 * Sets the `GtkPrintSettings` from which the page setup dialog
904 * takes its values.
905 */
906void
907gtk_page_setup_unix_dialog_set_print_settings (GtkPageSetupUnixDialog *dialog,
908 GtkPrintSettings *print_settings)
909{
910 const char *format_for_printer;
911
912 if (dialog->print_settings == print_settings) return;
913
914 if (dialog->print_settings)
915 g_object_unref (object: dialog->print_settings);
916
917 dialog->print_settings = print_settings;
918
919 if (print_settings)
920 {
921 g_object_ref (print_settings);
922
923 format_for_printer = gtk_print_settings_get (settings: print_settings, key: "format-for-printer");
924
925 /* Set printer if in list, otherwise set when
926 * that printer is added
927 */
928 set_active_printer (dialog, printer_name: format_for_printer);
929 }
930}
931
932/**
933 * gtk_page_setup_unix_dialog_get_print_settings:
934 * @dialog: a `GtkPageSetupUnixDialog`
935 *
936 * Gets the current print settings from the dialog.
937 *
938 * Returns: (transfer none) (nullable): the current print settings
939 **/
940GtkPrintSettings *
941gtk_page_setup_unix_dialog_get_print_settings (GtkPageSetupUnixDialog *dialog)
942{
943 return dialog->print_settings;
944}
945

source code of gtk/gtk/gtkpagesetupunixdialog.c