1 #include <pango/pangocairo.h>
3 #include <gtk/gtkprintoperation.h>
5 static GtkWidget *main_window;
6 static char *filename = NULL;
7 static GtkPageSetup *page_setup = NULL;
8 static GtkPrintSettings *settings = NULL;
9 static gboolean file_changed = FALSE;
10 static GtkTextBuffer *buffer;
11 static GtkWidget *statusbar;
12 static GList *active_prints = NULL;
21 basename = g_strdup ("Untitled");
23 basename = g_path_get_basename (filename);
25 title = g_strdup_printf ("Simple Editor with printing - %s", basename);
28 gtk_window_set_title (GTK_WINDOW (main_window), title);
33 update_statusbar (void)
38 const char *print_str;
40 gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 0);
42 gtk_text_buffer_get_iter_at_mark (buffer,
44 gtk_text_buffer_get_insert (buffer));
46 row = gtk_text_iter_get_line (&iter);
47 col = gtk_text_iter_get_line_offset (&iter);
52 GtkPrintOperation *op = active_prints->data;
53 print_str = gtk_print_operation_get_status_string (op);
56 msg = g_strdup_printf ("%d, %d%s %s",
58 file_changed?" - Modified":"",
61 gtk_statusbar_push (GTK_STATUSBAR (statusbar), 0, msg);
76 GtkTextIter start, end;
78 gtk_text_buffer_get_start_iter (buffer, &start);
79 gtk_text_buffer_get_end_iter (buffer, &end);
80 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
84 set_text (const char *text, gsize len)
86 gtk_text_buffer_set_text (buffer, text, len);
92 do_new (GtkAction *action)
100 load_file (const char *open_filename)
102 GtkWidget *error_dialog;
109 if (g_file_get_contents (open_filename, &contents, &len, &error))
111 if (g_utf8_validate (contents, len, NULL))
113 filename = g_strdup (open_filename);
114 set_text (contents, len);
119 error_dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
120 GTK_DIALOG_DESTROY_WITH_PARENT,
123 "Error loading file %s:\n%s",
130 error_dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
131 GTK_DIALOG_DESTROY_WITH_PARENT,
134 "Error loading file %s:\n%s",
138 g_error_free (error);
142 g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
143 gtk_widget_show (error_dialog);
148 do_open (GtkAction *action)
154 dialog = gtk_file_chooser_dialog_new ("Select file",
155 GTK_WINDOW (main_window),
156 GTK_FILE_CHOOSER_ACTION_OPEN,
157 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
158 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
160 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
161 response = gtk_dialog_run (GTK_DIALOG (dialog));
163 if (response == GTK_RESPONSE_OK)
165 open_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
166 load_file (open_filename);
167 g_free (open_filename);
170 gtk_widget_destroy (dialog);
174 save_file (const char *save_filename)
176 char *text = get_text ();
177 GtkWidget *error_dialog;
181 if (g_file_set_contents (save_filename,
184 if (save_filename != filename)
187 filename = g_strdup (save_filename);
189 file_changed = FALSE;
194 error_dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
195 GTK_DIALOG_DESTROY_WITH_PARENT,
198 "Error saving to file %s:\n%s",
202 g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
203 gtk_widget_show (error_dialog);
205 g_error_free (error);
210 do_save_as (GtkAction *action)
216 dialog = gtk_file_chooser_dialog_new ("Select file",
217 GTK_WINDOW (main_window),
218 GTK_FILE_CHOOSER_ACTION_SAVE,
219 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
220 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
222 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
223 response = gtk_dialog_run (GTK_DIALOG (dialog));
225 if (response == GTK_RESPONSE_OK)
227 save_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
228 save_file (save_filename);
229 g_free (save_filename);
232 gtk_widget_destroy (dialog);
236 do_save (GtkAction *action)
238 if (filename == NULL)
241 save_file (filename);
251 begin_print (GtkPrintOperation *operation,
252 GtkPrintContext *context,
253 PrintData *print_data)
255 PangoFontDescription *desc;
256 PangoLayoutLine *layout_line;
257 double width, height;
263 width = gtk_print_context_get_width (context);
264 height = gtk_print_context_get_height (context);
266 print_data->layout = gtk_print_context_create_layout (context);
268 desc = pango_font_description_from_string ("Sans 12");
269 pango_layout_set_font_description (print_data->layout, desc);
270 pango_font_description_free (desc);
272 pango_layout_set_width (print_data->layout, width * PANGO_SCALE);
274 pango_layout_set_text (print_data->layout, print_data->text, -1);
276 num_lines = pango_layout_get_line_count (print_data->layout);
281 for (line = 0; line < num_lines; line++)
283 PangoRectangle ink_rect, logical_rect;
286 layout_line = pango_layout_get_line (print_data->layout, line);
287 pango_layout_line_get_extents (layout_line, &ink_rect, &logical_rect);
289 line_height = logical_rect.height / 1024.0;
291 if (page_height + line_height > height)
293 page_breaks = g_list_prepend (page_breaks, GINT_TO_POINTER (line));
297 page_height += line_height;
300 page_breaks = g_list_reverse (page_breaks);
301 gtk_print_operation_set_n_pages (operation, g_list_length (page_breaks) + 1);
303 print_data->page_breaks = page_breaks;
308 draw_page (GtkPrintOperation *operation,
309 GtkPrintContext *context,
311 PrintData *print_data)
316 PangoLayoutIter *iter;
322 pagebreak = g_list_nth (print_data->page_breaks, page_nr - 1);
323 start = GPOINTER_TO_INT (pagebreak->data);
326 pagebreak = g_list_nth (print_data->page_breaks, page_nr);
327 if (pagebreak == NULL)
328 end = pango_layout_get_line_count (print_data->layout);
330 end = GPOINTER_TO_INT (pagebreak->data);
332 cr = gtk_print_context_get_cairo (context);
334 cairo_set_source_rgb (cr, 0, 0, 0);
338 iter = pango_layout_get_iter (print_data->layout);
341 PangoRectangle logical_rect;
342 PangoLayoutLine *line;
347 line = pango_layout_iter_get_line (iter);
349 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
350 baseline = pango_layout_iter_get_baseline (iter);
353 start_pos = logical_rect.y / 1024.0;
355 cairo_move_to (cr, logical_rect.x / 1024.0, baseline / 1024.0 - start_pos);
357 pango_cairo_show_layout_line (cr, line);
362 pango_layout_iter_next_line (iter));
366 do_page_setup (GtkAction *action)
368 GtkPageSetup *new_page_setup;
370 if (settings == NULL)
371 settings = gtk_print_settings_new ();
373 new_page_setup = gtk_print_run_page_setup_dialog (GTK_WINDOW (main_window),
374 page_setup, settings);
377 g_object_unref (page_setup);
379 page_setup = new_page_setup;
383 status_changed_cb (GtkPrintOperation *op,
386 if (gtk_print_operation_is_finished (op))
388 active_prints = g_list_remove (active_prints, op);
395 do_print (GtkAction *action)
397 GtkWidget *error_dialog;
398 GtkPrintOperation *print;
399 PrintData print_data;
400 GtkPrintOperationResult res;
403 print_data.text = get_text ();
405 print = gtk_print_operation_new ();
408 if (settings != NULL)
409 gtk_print_operation_set_print_settings (print, settings);
411 if (page_setup != NULL)
412 gtk_print_operation_set_default_page_setup (print, page_setup);
414 g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), &print_data);
415 g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), &print_data);
418 res = gtk_print_operation_run (print, GTK_WINDOW (main_window), &error);
420 if (res == GTK_PRINT_OPERATION_RESULT_ERROR)
422 error_dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
423 GTK_DIALOG_DESTROY_WITH_PARENT,
426 "Error printing file:\n%s",
428 g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
429 gtk_widget_show (error_dialog);
430 g_error_free (error);
432 else if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
434 if (settings != NULL)
435 g_object_unref (settings);
436 settings = g_object_ref (gtk_print_operation_get_print_settings (print));
439 if (!gtk_print_operation_is_finished (print))
441 g_object_ref (print);
442 active_prints = g_list_append (active_prints, print);
445 /* This ref is unref:ed when we get the final state change */
446 g_signal_connect (print, "status_changed",
447 G_CALLBACK (status_changed_cb), NULL);
450 g_object_unref (print);
454 do_about (GtkAction *action)
456 const gchar *authors[] = {
460 gtk_show_about_dialog (GTK_WINDOW (main_window),
461 "name", "print test editor",
463 "copyright", "(C) Red Hat, Inc",
464 "comments", "Program to demonstrate GTK+ printing.",
470 do_quit (GtkAction *action)
475 static GtkActionEntry entries[] = {
476 { "FileMenu", NULL, "_File" }, /* name, stock id, label */
477 { "HelpMenu", NULL, "_Help" }, /* name, stock id, label */
478 { "New", GTK_STOCK_NEW, /* name, stock id */
479 "_New", "<control>N", /* label, accelerator */
480 "Create a new file", /* tooltip */
481 G_CALLBACK (do_new) },
482 { "Open", GTK_STOCK_OPEN, /* name, stock id */
483 "_Open","<control>O", /* label, accelerator */
484 "Open a file", /* tooltip */
485 G_CALLBACK (do_open) },
486 { "Save", GTK_STOCK_SAVE, /* name, stock id */
487 "_Save","<control>S", /* label, accelerator */
488 "Save current file", /* tooltip */
489 G_CALLBACK (do_save) },
490 { "SaveAs", GTK_STOCK_SAVE, /* name, stock id */
491 "Save _As...", NULL, /* label, accelerator */
492 "Save to a file", /* tooltip */
493 G_CALLBACK (do_save_as) },
494 { "Quit", GTK_STOCK_QUIT, /* name, stock id */
495 "_Quit", "<control>Q", /* label, accelerator */
496 "Quit", /* tooltip */
497 G_CALLBACK (do_quit) },
498 { "About", NULL, /* name, stock id */
499 "_About", "<control>A", /* label, accelerator */
500 "About", /* tooltip */
501 G_CALLBACK (do_about) },
502 { "PageSetup", NULL, /* name, stock id */
503 "Page _Setup", NULL, /* label, accelerator */
504 "Set up the page", /* tooltip */
505 G_CALLBACK (do_page_setup) },
506 { "Print", GTK_STOCK_PRINT, /* name, stock id */
507 NULL, NULL, /* label, accelerator */
508 "Print the document", /* tooltip */
509 G_CALLBACK (do_print) },
511 static guint n_entries = G_N_ELEMENTS (entries);
513 static const gchar *ui_info =
515 " <menubar name='MenuBar'>"
516 " <menu action='FileMenu'>"
517 " <menuitem action='New'/>"
518 " <menuitem action='Open'/>"
519 " <menuitem action='Save'/>"
520 " <menuitem action='SaveAs'/>"
521 " <menuitem action='PageSetup'/>"
522 " <menuitem action='Print'/>"
524 " <menuitem action='Quit'/>"
526 " <menu action='HelpMenu'>"
527 " <menuitem action='About'/>"
533 buffer_changed_callback (GtkTextBuffer *buffer)
540 mark_set_callback (GtkTextBuffer *buffer,
541 const GtkTextIter *new_location,
549 update_resize_grip (GtkWidget *widget,
550 GdkEventWindowState *event,
551 GtkStatusbar *statusbar)
553 if (event->changed_mask & (GDK_WINDOW_STATE_MAXIMIZED |
554 GDK_WINDOW_STATE_FULLSCREEN))
558 maximized = event->new_window_state & (GDK_WINDOW_STATE_MAXIMIZED |
559 GDK_WINDOW_STATE_FULLSCREEN);
560 gtk_statusbar_set_has_resize_grip (statusbar, !maximized);
572 GtkActionGroup *actions;
575 main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
577 gtk_window_set_default_size (GTK_WINDOW (main_window),
580 g_signal_connect (main_window, "delete-event",
581 G_CALLBACK (gtk_main_quit), NULL);
583 actions = gtk_action_group_new ("Actions");
584 gtk_action_group_add_actions (actions, entries, n_entries, NULL);
586 ui = gtk_ui_manager_new ();
587 gtk_ui_manager_insert_action_group (ui, actions, 0);
588 gtk_window_add_accel_group (GTK_WINDOW (main_window),
589 gtk_ui_manager_get_accel_group (ui));
590 gtk_container_set_border_width (GTK_CONTAINER (main_window), 0);
593 if (!gtk_ui_manager_add_ui_from_string (ui, ui_info, -1, &error))
595 g_message ("building menus failed: %s", error->message);
596 g_error_free (error);
599 table = gtk_table_new (1, 3, FALSE);
600 gtk_container_add (GTK_CONTAINER (main_window), table);
602 bar = gtk_ui_manager_get_widget (ui, "/MenuBar");
603 gtk_widget_show (bar);
604 gtk_table_attach (GTK_TABLE (table),
606 /* X direction */ /* Y direction */
608 GTK_EXPAND | GTK_FILL, 0,
611 /* Create document */
612 sw = gtk_scrolled_window_new (NULL, NULL);
614 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
615 GTK_POLICY_AUTOMATIC,
616 GTK_POLICY_AUTOMATIC);
618 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
621 gtk_table_attach (GTK_TABLE (table),
623 /* X direction */ /* Y direction */
625 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
628 contents = gtk_text_view_new ();
629 gtk_widget_grab_focus (contents);
631 gtk_container_add (GTK_CONTAINER (sw),
634 /* Create statusbar */
636 statusbar = gtk_statusbar_new ();
637 gtk_table_attach (GTK_TABLE (table),
639 /* X direction */ /* Y direction */
641 GTK_EXPAND | GTK_FILL, 0,
644 /* Show text widget info in the statusbar */
645 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (contents));
647 g_signal_connect_object (buffer,
649 G_CALLBACK (buffer_changed_callback),
653 g_signal_connect_object (buffer,
654 "mark_set", /* cursor moved */
655 G_CALLBACK (mark_set_callback),
659 g_signal_connect_object (main_window,
660 "window_state_event",
661 G_CALLBACK (update_resize_grip),
667 gtk_widget_show_all (main_window);
671 main (int argc, char **argv)
673 gtk_init (&argc, &argv);