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 | |
55 | typedef struct _GtkPageSetupUnixDialogClass GtkPageSetupUnixDialogClass; |
56 | |
57 | struct _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 | |
89 | struct _GtkPageSetupUnixDialogClass |
90 | { |
91 | GtkDialogClass parent_class; |
92 | }; |
93 | |
94 | |
95 | /* Keep these in line with GtkListStores defined in gtkpagesetupunixprintdialog.ui */ |
96 | enum { |
97 | PRINTER_LIST_COL_NAME, |
98 | PRINTER_LIST_COL_PRINTER, |
99 | PRINTER_LIST_N_COLS |
100 | }; |
101 | |
102 | enum { |
103 | PAGE_SETUP_LIST_COL_PAGE_SETUP, |
104 | PAGE_SETUP_LIST_COL_IS_SEPARATOR, |
105 | PAGE_SETUP_LIST_N_COLS |
106 | }; |
107 | |
108 | G_DEFINE_TYPE (GtkPageSetupUnixDialog, gtk_page_setup_unix_dialog, GTK_TYPE_DIALOG) |
109 | |
110 | static void gtk_page_setup_unix_dialog_finalize (GObject *object); |
111 | static void fill_paper_sizes_from_printer (GtkPageSetupUnixDialog *dialog, |
112 | GtkPrinter *printer); |
113 | static void printer_changed_callback (GtkDropDown *combo_box, |
114 | GParamSpec *pspec, |
115 | GtkPageSetupUnixDialog *dialog); |
116 | static void paper_size_changed (GtkDropDown *combo_box, |
117 | GParamSpec *pspec, |
118 | GtkPageSetupUnixDialog *dialog); |
119 | static void load_print_backends (GtkPageSetupUnixDialog *dialog); |
120 | |
121 | |
122 | static 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 | |
138 | static void |
139 | gtk_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 | |
166 | static void |
167 | setup_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 | |
177 | static void |
178 | bind_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 | |
212 | static void |
213 | bind_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 | |
225 | static gboolean |
226 | match_func (gpointer item, gpointer user_data) |
227 | { |
228 | return !gtk_printer_is_virtual (GTK_PRINTER (item)); |
229 | } |
230 | |
231 | static void |
232 | setup_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 | |
243 | static void |
244 | bind_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 | |
264 | static void |
265 | gtk_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 | |
345 | static void |
346 | gtk_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 | |
379 | static void |
380 | load_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 | |
399 | static GtkPageSetup * |
400 | get_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 | |
413 | static gboolean |
414 | page_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 | |
426 | static gboolean |
427 | page_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 | |
434 | static gboolean |
435 | set_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 | |
476 | static void |
477 | fill_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 | |
530 | static void |
531 | printer_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 | |
546 | static void |
547 | printer_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... */ |
604 | static char * |
605 | double_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 | |
638 | static void |
639 | custom_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 | |
661 | static void |
662 | paper_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 | */ |
777 | GtkWidget * |
778 | gtk_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 | |
796 | static GtkPageOrientation |
797 | get_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 | |
808 | static void |
809 | set_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 | */ |
839 | void |
840 | gtk_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 | */ |
858 | GtkPageSetup * |
859 | gtk_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 | |
870 | static gboolean |
871 | set_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 | */ |
906 | void |
907 | gtk_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 | **/ |
940 | GtkPrintSettings * |
941 | gtk_page_setup_unix_dialog_get_print_settings (GtkPageSetupUnixDialog *dialog) |
942 | { |
943 | return dialog->print_settings; |
944 | } |
945 | |