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 | |
46 | typedef struct |
47 | { |
48 | GtkUnit display_unit; |
49 | GtkWidget *spin_button; |
50 | } UnitWidget; |
51 | |
52 | struct _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 | |
79 | typedef struct _GtkCustomPaperUnixDialogClass GtkCustomPaperUnixDialogClass; |
80 | |
81 | struct _GtkCustomPaperUnixDialogClass |
82 | { |
83 | GtkDialogClass parent_class; |
84 | }; |
85 | |
86 | |
87 | enum { |
88 | PRINTER_LIST_COL_NAME, |
89 | PRINTER_LIST_COL_PRINTER, |
90 | PRINTER_LIST_N_COLS |
91 | }; |
92 | |
93 | |
94 | G_DEFINE_TYPE (GtkCustomPaperUnixDialog, gtk_custom_paper_unix_dialog, GTK_TYPE_DIALOG) |
95 | |
96 | |
97 | static void gtk_custom_paper_unix_dialog_constructed (GObject *object); |
98 | static void gtk_custom_paper_unix_dialog_finalize (GObject *object); |
99 | static void populate_dialog (GtkCustomPaperUnixDialog *dialog); |
100 | |
101 | |
102 | |
103 | GtkUnit |
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 | |
131 | static char * |
132 | custom_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 | |
142 | static char * |
143 | custom_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 | |
154 | GList * |
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 | |
200 | void |
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 | |
223 | void |
224 | gtk_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 | |
242 | static void |
243 | gtk_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 | |
277 | static void |
278 | gtk_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 | |
284 | static void |
285 | custom_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 | |
294 | static gboolean |
295 | match_func (gpointer item, gpointer user_data) |
296 | { |
297 | return !gtk_printer_is_virtual (GTK_PRINTER (item)); |
298 | } |
299 | |
300 | static void |
301 | gtk_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 | |
337 | static void |
338 | gtk_custom_paper_unix_dialog_constructed (GObject *object) |
339 | { |
340 | gboolean ; |
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 | |
354 | static void |
355 | gtk_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 | */ |
395 | GtkWidget * |
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 | |
415 | static void |
416 | load_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 | |
435 | static void unit_widget_changed (GtkCustomPaperUnixDialog *dialog); |
436 | |
437 | static GtkWidget * |
438 | new_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 | |
480 | static double |
481 | unit_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 | |
488 | static void |
489 | unit_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 | |
499 | static void |
500 | update_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 | |
510 | static void |
511 | update_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 | |
547 | static void |
548 | selected_custom_paper_changed (GObject *list, |
549 | GParamSpec *pspec, |
550 | GtkCustomPaperUnixDialog *dialog) |
551 | { |
552 | update_custom_widgets_from_list (dialog); |
553 | } |
554 | |
555 | static void |
556 | unit_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 | |
589 | static gboolean |
590 | custom_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 | |
612 | static void |
613 | add_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 | |
645 | static void |
646 | remove_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 | |
657 | static void |
658 | set_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 | |
678 | static void |
679 | get_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 | |
695 | static void |
696 | margins_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 | |
739 | static GtkWidget * |
740 | wrap_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 | |
769 | static void |
770 | setup_item (GtkSignalListItemFactory *factory, |
771 | GtkListItem *item) |
772 | { |
773 | gtk_list_item_set_child (self: item, child: gtk_editable_label_new (str: "" )); |
774 | } |
775 | |
776 | static void |
777 | label_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 | |
796 | static void |
797 | state_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 | |
807 | static void |
808 | bind_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 | |
827 | static void |
828 | unbind_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 | |
838 | static void |
839 | setup_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 | |
849 | static void |
850 | bind_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 | |
862 | static void |
863 | populate_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 | |