From c992f6252cea5487126721ec1ddf3d207b883524 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Mon, 9 Aug 2004 06:28:57 +0000 Subject: [project @ 2004-08-09 06:28:56 by jmb] Printing support. Some issues remain - see the todo list at the top of print.c for more details svn path=/import/netsurf/; revision=1199 --- !NetSurf/Resources/en/Messages | 4 +- !NetSurf/Resources/en/Templates,fec | Bin 7689 -> 8838 bytes !NetSurf/Resources/fr/Messages | 4 +- !NetSurf/Resources/fr/Templates,fec | Bin 7823 -> 8972 bytes riscos/dialog.c | 15 +- riscos/gui.c | 46 ++- riscos/gui.h | 23 +- riscos/menus.c | 7 +- riscos/print.c | 708 ++++++++++++++++++++++++++++++++++++ riscos/print.h | 23 ++ riscos/window.c | 4 + 11 files changed, 826 insertions(+), 8 deletions(-) create mode 100644 riscos/print.c create mode 100644 riscos/print.h diff --git a/!NetSurf/Resources/en/Messages b/!NetSurf/Resources/en/Messages index fc34db854..1ff7f6c05 100644 --- a/!NetSurf/Resources/en/Messages +++ b/!NetSurf/Resources/en/Messages @@ -16,7 +16,7 @@ ExportAs:Export as Draw:Draw ‹^F3 Text:Text ^F3 SaveURL:Save location -Print:Print... +Print:Print PRINT NewWindow:New window ^N ViewSrc:View source... F8 Object:Object @@ -157,6 +157,8 @@ NoNameError:Please enter a name NoURLError:Please enter a URL URIError:NetSurf was unable to parse this URI file due to a syntax error. EmptyError:file is empty. +PrintError:An error occurred when printing: +PrintErrorRO2:It appears that the printer is busy. # Some general purpose words and phrases Bytes: B diff --git a/!NetSurf/Resources/en/Templates,fec b/!NetSurf/Resources/en/Templates,fec index 9245be2f5..43d9f783d 100644 Binary files a/!NetSurf/Resources/en/Templates,fec and b/!NetSurf/Resources/en/Templates,fec differ diff --git a/!NetSurf/Resources/fr/Messages b/!NetSurf/Resources/fr/Messages index c911298e4..88f95df3e 100644 --- a/!NetSurf/Resources/fr/Messages +++ b/!NetSurf/Resources/fr/Messages @@ -16,7 +16,7 @@ ExportAs:Exporter sous Draw:Draw ‹^F3 Text:Texte ^F3 SaveURL:Sauver le lieu -Print:Imprimer... +Print:Imprimer PRINT NewWindow:Nouvelle fenętre ^N ViewSrc:Voir le source... F8 Object:Objet @@ -157,6 +157,8 @@ NoNameError:Entrez un nom SVP NoURLError:Entrez une URL SVP URIError:NetSurf est incapable de traiter ce fichier URI ŕ cause d'une erreur de syntaxe. EmptyError:Le fichier est vide. +PrintError:An error occurred when printing: +PrintErrorRO2:It appears that the printer is busy. # Some general purpose words and phrases Bytes: O diff --git a/!NetSurf/Resources/fr/Templates,fec b/!NetSurf/Resources/fr/Templates,fec index 56972975d..1b016891a 100644 Binary files a/!NetSurf/Resources/fr/Templates,fec and b/!NetSurf/Resources/fr/Templates,fec differ diff --git a/riscos/dialog.c b/riscos/dialog.c index 126d1bcc8..ff79d55ab 100644 --- a/riscos/dialog.c +++ b/riscos/dialog.c @@ -39,7 +39,7 @@ wimp_w dialog_info, dialog_saveas, dialog_config, dialog_config_br, #endif dialog_zoom, dialog_pageinfo, dialog_objinfo, dialog_tooltip, dialog_warning, dialog_config_th_pane, dialog_debug, - dialog_folder, dialog_entry, dialog_search; + dialog_folder, dialog_entry, dialog_search, dialog_print; static int ro_gui_choices_font_size; static int ro_gui_choices_font_min_size; @@ -105,6 +105,7 @@ void ro_gui_dialog_init(void) dialog_folder = ro_gui_dialog_create("new_folder"); dialog_entry = ro_gui_dialog_create("new_entry"); dialog_search = ro_gui_dialog_create("search"); + dialog_print = ro_gui_dialog_create("print"); } @@ -352,6 +353,10 @@ bool ro_gui_dialog_keypress(wimp_key *key) #ifdef WITH_SEARCH if (key->w == dialog_search) return ro_gui_search_keypress(key); +#endif +#ifdef WITH_PRINT + if (key->w == dialog_print) + return ro_gui_print_keypress(key); #endif if (key->c == wimp_KEY_ESCAPE) { ro_gui_dialog_close(key->w); @@ -405,8 +410,14 @@ void ro_gui_dialog_click(wimp_pointer *pointer) ro_gui_dialog_click_warning(pointer); else if ((pointer->w == dialog_folder) || (pointer->w == dialog_entry)) ro_gui_hotlist_dialog_click(pointer); +#ifdef WITH_SEARCH else if (pointer->w == dialog_search) ro_gui_search_click(pointer); +#endif +#ifdef WITH_PRINT + else if (pointer->w == dialog_print) + ro_gui_print_click(pointer); +#endif } @@ -857,7 +868,7 @@ void ro_gui_dialog_click_config_th_pane(wimp_pointer *pointer) struct theme_entry *ro_gui_theme_entry(int index) { struct theme_entry *entry = theme_list; - for (int i = 0; i < index; i++) entry = entry->next; + for (int i = 0; i < index; i++) entry = entry->next; return entry; } diff --git a/riscos/gui.c b/riscos/gui.c index ebc450e3d..9b4ef478f 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -27,6 +27,7 @@ #include "oslib/osfile.h" #include "oslib/osfscontrol.h" #include "oslib/osspriteop.h" +#include "oslib/pdriver.h" #include "oslib/plugin.h" #include "oslib/wimp.h" #include "oslib/wimpspriteop.h" @@ -43,6 +44,9 @@ #ifdef WITH_PLUGIN #include "netsurf/riscos/plugin.h" #endif +#ifdef WITH_PRINT +#include "netsurf/riscos/print.h" +#endif #include "netsurf/riscos/save_complete.h" #include "netsurf/riscos/theme.h" #include "netsurf/riscos/toolbar.h" @@ -82,11 +86,12 @@ static clock_t gui_last_poll; /**< Time of last wimp_poll. */ osspriteop_area *gui_sprites; /**< Sprite area containing pointer and hotlist sprites */ /** Accepted wimp user messages. */ -static wimp_MESSAGE_LIST(29) task_messages = { { +static wimp_MESSAGE_LIST(33) task_messages = { { message_HELP_REQUEST, message_DATA_SAVE, message_DATA_SAVE_ACK, message_DATA_LOAD, + message_DATA_LOAD_ACK, message_DATA_OPEN, message_MENU_WARNING, message_MENUS_DELETED, @@ -117,6 +122,11 @@ static wimp_MESSAGE_LIST(29) task_messages = { { message_PLUG_IN_ABORT, message_PLUG_IN_ACTION, /* message_PLUG_IN_INFORMED, (not provided by oslib) */ +#endif +#ifdef WITH_PRINT + message_PRINT_SAVE, + message_PRINT_ERROR, + message_PRINT_TYPE_ODD, #endif 0 } }; @@ -939,7 +949,20 @@ void ro_gui_user_message(wimp_event_no event, wimp_message *message) break; case message_DATA_LOAD: - ro_msg_dataload(message); + if (event == wimp_USER_MESSAGE_ACKNOWLEDGE) { +#ifdef WITH_PRINT + if (print_current_window) + print_dataload_bounce(message); +#endif + } + else + ro_msg_dataload(message); + break; + + case message_DATA_LOAD_ACK: +#ifdef WITH_PRINT + print_cleanup(); +#endif break; case message_DATA_OPEN: @@ -998,6 +1021,18 @@ void ro_gui_user_message(wimp_event_no event, wimp_message *message) event == wimp_USER_MESSAGE_ACKNOWLEDGE); break; #endif +#ifdef WITH_PRINT + case message_PRINT_SAVE: + if (event == wimp_USER_MESSAGE_ACKNOWLEDGE) + print_save_bounce(message); + break; + case message_PRINT_ERROR: + print_error(message); + break; + case message_PRINT_TYPE_ODD: + print_type_odd(message); + break; +#endif case message_QUIT: netsurf_quit = true; @@ -1218,6 +1253,13 @@ char *ro_gui_url_file_parse(const char *file_name) void ro_msg_datasave_ack(wimp_message *message) { +#ifdef WITH_PRINT + if (print_current_window) { + print_ack(message); + return; + } +#endif + switch (gui_current_drag_type) { case GUI_DRAG_DOWNLOAD_SAVE: ro_gui_download_datasave_ack(message); diff --git a/riscos/gui.h b/riscos/gui.h index 514dc9509..c45c5b82c 100644 --- a/riscos/gui.h +++ b/riscos/gui.h @@ -26,7 +26,7 @@ struct toolbar; extern wimp_w dialog_info, dialog_saveas, dialog_config, dialog_config_br, dialog_config_prox, dialog_config_th, dialog_zoom, dialog_pageinfo, dialog_objinfo, dialog_tooltip, dialog_warning, dialog_config_th_pane, - dialog_debug, dialog_folder, dialog_entry, dialog_search; + dialog_debug, dialog_folder, dialog_entry, dialog_search, dialog_print; extern wimp_w history_window; extern wimp_w hotlist_window; extern wimp_menu *iconbar_menu, *browser_menu, *combo_menu, *hotlist_menu, @@ -244,6 +244,11 @@ void ro_gui_search_open(struct gui_window *g, int x, int y, bool sub_menu, bool void ro_gui_search_click(wimp_pointer *pointer); bool ro_gui_search_keypress(wimp_key *key); +/* in print.c */ +void ro_gui_print_open(struct gui_window *g, int x, int y, bool sub_menu, bool keypress); +void ro_gui_print_click(wimp_pointer *pointer); +bool ro_gui_print_keypress(wimp_key *key); + /* toolbar types */ #define TOOLBAR_BROWSER 0 #define TOOLBAR_HOTLIST 1 @@ -359,5 +364,21 @@ bool ro_gui_search_keypress(wimp_key *key); #define ICON_SEARCH_CANCEL 5 #define ICON_SEARCH_FIND 6 +#define ICON_PRINT_TO_BOTTOM 1 +#define ICON_PRINT_SHEETS 2 +#define ICON_PRINT_SHEETS_VALUE 3 +#define ICON_PRINT_SHEETS_DOWN 4 +#define ICON_PRINT_SHEETS_UP 5 +#define ICON_PRINT_SHEETS_TEXT 6 +#define ICON_PRINT_FG_IMAGES 7 +#define ICON_PRINT_BG_IMAGES 8 +#define ICON_PRINT_IN_BACKGROUND 9 +#define ICON_PRINT_UPRIGHT 10 +#define ICON_PRINT_SIDEWAYS 11 +#define ICON_PRINT_COPIES 12 +#define ICON_PRINT_COPIES_DOWN 13 +#define ICON_PRINT_COPIES_UP 14 +#define ICON_PRINT_CANCEL 15 +#define ICON_PRINT_PRINT 16 #endif diff --git a/riscos/menus.c b/riscos/menus.c index 8a5002b3d..4633cfeae 100644 --- a/riscos/menus.c +++ b/riscos/menus.c @@ -120,7 +120,7 @@ static wimp_MENU(8) page_menu = { { wimp_MENU_GIVE_WARNING, (wimp_menu *)1, DEFAULT_FLAGS, { "SaveComp" } }, { 0, (wimp_menu *)&export_menu, DEFAULT_FLAGS, { "Export" } }, { 0, (wimp_menu *)&link_menu, DEFAULT_FLAGS, { "SaveURL" } }, - { wimp_MENU_SEPARATE, wimp_NO_SUB_MENU, DEFAULT_FLAGS | wimp_ICON_SHADED, { "Print" } }, + { wimp_MENU_GIVE_WARNING | wimp_MENU_SEPARATE, (wimp_menu *)1, DEFAULT_FLAGS, { "Print" } }, { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "NewWindow" } }, { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ViewSrc" } } } @@ -1071,6 +1071,11 @@ void ro_gui_menu_browser_warning(wimp_message_menu_warning *warning) break; } break; + + case 5: /* Print -> */ + ro_gui_print_open(current_gui, warning->pos.x, + warning->pos.y, true, false); + break; } break; diff --git a/riscos/print.c b/riscos/print.c new file mode 100644 index 000000000..a15d9b35d --- /dev/null +++ b/riscos/print.c @@ -0,0 +1,708 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 John M Bell + */ + +#include +#include + +#include "oslib/font.h" +#include "oslib/hourglass.h" +#include "oslib/osfile.h" +#include "oslib/osfind.h" +#include "oslib/pdriver.h" +#include "oslib/wimp.h" + +#include "netsurf/utils/config.h" +#include "netsurf/content/content.h" +#include "netsurf/render/font.h" +#include "netsurf/render/html.h" +#include "netsurf/render/layout.h" +#include "netsurf/riscos/gui.h" +#include "netsurf/riscos/print.h" +#include "netsurf/riscos/wimp.h" +#include "netsurf/utils/log.h" +#include "netsurf/utils/utils.h" + +/** \todo position images correctly (seem to be offset + * to the right and upwards by half the print margin width) + * \todo fix images when printing with the PostScript driver + * (redraws appear not to be intercepted) + * \todo landscape format pages + * \todo be somewhat more intelligent and try not to crop pages + * half way up a line of text + * \todo make use of print stylesheets + */ + +#ifdef WITH_PRINT + +/* 1 millipoint == 1/400 OS unit = 1/800 browser units */ + +struct gui_window *print_current_window = 0; +static bool print_in_background = false; +static int print_num_copies = 1; +static bool print_bg_images = true; +static int print_max_sheets = -1; + +/* array of fonts in document - max 255 */ +struct print_font { + font_f handle; + void *fontName; +}; + +static void print_update_sheets_shaded_state(bool on); +static void print_send_printsave(struct content *c); +static bool print_send_printtypeknown(wimp_message *m); +static void print_document(struct gui_window *g, const char *filename); +static bool print_find_fonts(struct box *box, struct print_font **print_fonts, int *numFonts); + +/** + * Open the print dialog + * + * \param g parent window + * \param x leftmost edge of dialog (only if sub_menu == true) + * \param y topmost edge of dialog (as above) + * \param sub_menu open window as a submenu or as a persistent dialog + * \param keypress whether we were opened by a keypress + */ +void ro_gui_print_open(struct gui_window *g, int x, int y, bool sub_menu, bool keypress) +{ + char *pdName; + bool printers_exists = true; + os_error *e; + + assert(g != NULL); + + print_current_window = g; + + /* Read Printer Driver name */ + e = xpdriver_info(0, 0, 0, 0, &pdName, 0, 0, 0); + if (e) { + LOG(("%s", e->errmess)); + printers_exists = false; + } + + print_bg_images = g->option.background_images; + + ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_TO_BOTTOM, true); + + ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_SHEETS, false); + ro_gui_set_icon_integer(dialog_print, ICON_PRINT_SHEETS_VALUE, 1); + ro_gui_set_icon_string(dialog_print, ICON_PRINT_SHEETS_TEXT, "sheet is filled"); + print_update_sheets_shaded_state(true); + + ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_FG_IMAGES, true); + ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_FG_IMAGES, true); + + ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_BG_IMAGES, print_bg_images); + + ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_IN_BACKGROUND, false); + + ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_UPRIGHT, true); + ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_SIDEWAYS, false); + + ro_gui_set_icon_integer(dialog_print, ICON_PRINT_COPIES, 1); + + if (!printers_exists) { + ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_PRINT, true); + } + else { + ro_gui_set_window_title(dialog_print, pdName); + } + + if (sub_menu) { + e = xwimp_create_sub_menu((wimp_menu *) dialog_print, x, y); + if (e) { + LOG(("xwimp_create_sub_menu: 0x%x: %s", + e->errnum, e->errmess)); + warn_user("MenuError", e->errmess); + } + } + else { + ro_gui_dialog_open_persistant(g->window, dialog_print, !keypress); + } +} + +/** + * Handle mouse clicks in print dialog + * + * \param pointer wimp_pointer block + */ +void ro_gui_print_click(wimp_pointer *pointer) +{ + int copies = atoi(ro_gui_get_icon_string(dialog_print, + ICON_PRINT_COPIES)); + int sheets = atoi(ro_gui_get_icon_string(dialog_print, + ICON_PRINT_SHEETS_VALUE)); + + if (pointer->buttons == wimp_CLICK_MENU) + return; + + switch (pointer->i) { + case ICON_PRINT_SHEETS: + /* retain selection state */ + ro_gui_set_icon_selected_state(dialog_print, + pointer->i, true); + print_update_sheets_shaded_state(false); + break; + case ICON_PRINT_TO_BOTTOM: + print_update_sheets_shaded_state(true); + case ICON_PRINT_UPRIGHT: + case ICON_PRINT_SIDEWAYS: + /* retain selection state */ + ro_gui_set_icon_selected_state(dialog_print, + pointer->i, true); + break; + case ICON_PRINT_COPIES_UP: copies += 1; break; + case ICON_PRINT_COPIES_DOWN: copies -= 1; break; + case ICON_PRINT_SHEETS_UP: sheets += 1; break; + case ICON_PRINT_SHEETS_DOWN: sheets -= 1; break; + case ICON_PRINT_CANCEL: + print_cleanup(); + break; + case ICON_PRINT_PRINT: + print_in_background = ro_gui_get_icon_selected_state(dialog_print, ICON_PRINT_IN_BACKGROUND); + print_num_copies = copies; + if (ro_gui_get_icon_selected_state(dialog_print, ICON_PRINT_SHEETS)) + print_max_sheets = sheets; + else + print_max_sheets = -1; + print_current_window->option.background_images = ro_gui_get_icon_selected_state(dialog_print, ICON_PRINT_BG_IMAGES); + print_send_printsave(print_current_window->bw->current_content); + break; + } + + if (copies < 1) + copies = 1; + else if (copies > 99) + copies = 99; + ro_gui_set_icon_integer(dialog_print, ICON_PRINT_COPIES, copies); + + if (sheets < 1) + sheets = 1; + else if (sheets > 99) + sheets = 99; + ro_gui_set_icon_integer(dialog_print, ICON_PRINT_SHEETS_VALUE, sheets); + if (sheets > 1) + ro_gui_set_icon_string(dialog_print, ICON_PRINT_SHEETS_TEXT, "sheets are filled"); + else + ro_gui_set_icon_string(dialog_print, ICON_PRINT_SHEETS_TEXT, "sheet is filled"); +} + +/** + * Handle keypresses in print dialog + * + * \param key wimp_key block + * \return true if keypress dealt with, false otherwise. + */ +bool ro_gui_print_keypress(wimp_key *key) +{ + switch (key->c) { + case wimp_KEY_ESCAPE: + print_cleanup(); + return true; + case wimp_KEY_RETURN: + print_in_background = ro_gui_get_icon_selected_state(dialog_print, ICON_PRINT_IN_BACKGROUND); + print_num_copies = atoi(ro_gui_get_icon_string(dialog_print, ICON_PRINT_COPIES)); + if (ro_gui_get_icon_selected_state(dialog_print, ICON_PRINT_SHEETS)) + print_max_sheets = atoi(ro_gui_get_icon_string(dialog_print, ICON_PRINT_SHEETS_VALUE)); + else + print_max_sheets = -1; + print_current_window->option.background_images = ro_gui_get_icon_selected_state(dialog_print, ICON_PRINT_BG_IMAGES); + print_send_printsave(print_current_window->bw->current_content); + return true; + } + + return false; +} + +/** + * Set shaded state of sheets + * + * \param on whether to turn shading on or off + */ +void print_update_sheets_shaded_state(bool on) +{ + ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_VALUE, on); + ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_DOWN, on); + ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_UP, on); + ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_TEXT, on); + ro_gui_set_caret_first(dialog_print); +} + +/** + * Send a message_PRINT_SAVE + * + * \param c content to print + */ +void print_send_printsave(struct content *c) +{ + wimp_full_message_data_xfer m; + os_error *e; + int len; + + len = strlen(c->title) + 1; + if (212 < len) + len = 212; + + m.size = ((44+len+3) & ~3); + m.your_ref = 0; + m.action = message_PRINT_SAVE; + m.w = (wimp_w)0; + m.i = m.pos.x = m.pos.y = 0; + m.est_size = 1024; /* arbitrary value - it really doesn't matter */ + m.file_type = ro_content_filetype(c); + strncpy(m.file_name, c->title, 211); + m.file_name[211] = 0; + e = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, + (wimp_message *)&m, 0); + if (e) { + LOG(("xwimp_send_message: 0x%x: %s", + e->errnum, e->errmess)); + warn_user("WimpError", e->errmess); + print_cleanup(); + } +} + +/** + * Send a message_PRINT_TYPE_KNOWN + * + * \param m message to reply to + * \return true on success, false otherwise + */ +bool print_send_printtypeknown(wimp_message *m) +{ + os_error *e; + + m->size = 20; + m->your_ref = m->my_ref; + m->action = message_PRINT_TYPE_KNOWN; + e = xwimp_send_message(wimp_USER_MESSAGE, m, m->sender); + if (e) { + LOG(("xwimp_send_message: 0x%x: %s", + e->errnum, e->errmess)); + warn_user("WimpError", e->errmess); + return false; + } + + return true; +} + +/** + * Handle a bounced message_PRINT_SAVE + * + * \param m the bounced message + */ +void print_save_bounce(wimp_message *m) +{ + /* try to print anyway (we're graphics printing) */ + if (print_current_window) { + print_document(print_current_window, "printer:"); + } + print_cleanup(); +} + +/** + * Handle message_PRINT_ERROR + * + * \param m the message containing the error + */ +void print_error(wimp_message *m) +{ + pdriver_message_print_error *p = (pdriver_message_print_error*)&m->data; + if (m->size == 20) + warn_user("PrintErrorRO2", 0); + else + warn_user("PrintError", p->errmess); + + print_cleanup(); +} + +/** + * Handle message_PRINT_TYPE_ODD + * + * \param m the message to handle + */ +void print_type_odd(wimp_message *m) +{ + if (m->your_ref != 0 && !print_in_background) { + /* reply to a previous message (ie printsave) */ + if (print_current_window && print_send_printtypeknown(m)) { + print_document(print_current_window, "printer:"); + } + print_cleanup(); + } + else { + /* broadcast message */ + /* no need to do anything */ + } + +} + +/** + * Handle message_DATASAVE_ACK for the printing protocol + * + * \param m the message to handle + */ +void print_ack(wimp_message *m) +{ + int type; + os_error *e; + + /* Read Printer Driver Type */ + e = xpdriver_info(&type, 0, 0, 0, 0, 0, 0, 0); + if (e) { + LOG(("%s", e->errmess)); + print_cleanup(); + return; + } + + type &= 0xFFFF0000; /* we don't care about the version no */ + + if (print_current_window) { + print_document(print_current_window, + (const char*)m->data.data_xfer.file_name); + + /* send dataload */ + m->your_ref = m->my_ref; + m->action = message_DATA_LOAD; + + /* We cheat here and, instead of giving Printers what + * it asked for (a copy of the file so it can poke us + * later via a broadcast of PrintTypeOdd), we give + * it a file that it can print itself without having + * to bother us further. For PostScript printers + * (type 0) we give it a PostScript file. Otherwise, + * we give it a PrintOut file. + * + * This method has a couple of advantages: + * - we can reuse this code for background printing + * (we simply ignore the PrintTypeOdd reply) + * - there's no need to ensure all components of a + * page queued to be printed still exist when it + * reaches the top of the queue. (which reduces + * complexity a fair bit) + */ + if (type == 0) + /* postscript */ + m->data.data_xfer.file_type = 0xff5; + else + /* printout */ + m->data.data_xfer.file_type = 0xff4; + + e = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, m, + m->sender); + if (e) { + LOG(("xwimp_send_message: 0x%x: %s", + e->errnum, e->errmess)); + warn_user("WimpError", e->errmess); + /* and delete temporary file */ + xosfile_delete(m->data.data_xfer.file_name, + 0, 0, 0, 0, 0); + print_cleanup(); + } + } +} + +/** + * Handle a bounced dataload message + * + * \param m the message to handle + */ +void print_dataload_bounce(wimp_message *m) +{ + xosfile_delete(m->data.data_xfer.file_name, 0, 0, 0, 0, 0); + print_cleanup(); +} + +/** + * Cleanup after printing + */ +void print_cleanup(void) +{ + print_current_window->option.background_images = print_bg_images; + print_current_window = 0; + print_max_sheets = -1; + xwimp_create_menu((wimp_menu *)-1, 0, 0); + ro_gui_dialog_close(dialog_print); +} + +/** + * Print a document + * + * \param g gui_window containing the document to print + * \param filename name of file to print to + */ +void print_document(struct gui_window *g, const char *filename) +{ + struct content *c = g->bw->current_content; + struct box *box = NULL; + int temp; + os_error *e; + pdriver_features features; + int left, right, top, bottom, width, height; + os_fw fhandle, old_job = 0; + int yscroll = 0, sheets = print_max_sheets; + + /* no point printing a blank page */ + if (!c) + return; + + LOG(("Printing page (%d)", print_max_sheets)); + + if (c->type == CONTENT_HTML) + box = c->data.html.layout->children; + + /* Read Printer Driver Features */ + e = xpdriver_info(0, 0, 0, &features, 0, 0, 0, 0); + if (e) { + LOG(("%s", e->errmess)); + return; + } + + LOG(("read features")); + + /* Acquire page size */ + e = xpdriver_page_size(&width, &height, &left, &bottom, &right, &top); + if (e) { + LOG(("%s", e->errmess)); + return; + } + + LOG(("page size: %d x %d", width/800, height/800)); + + width = (right - left) / 800; + height = (top - bottom) / 800; + + LOG(("printable area: [(%d, %d), (%d, %d)] = %d x %d", + left, bottom, right, top, width, height)); + + + temp = c->width; + + /* layout the document to the correct width */ + if (c->type == CONTENT_HTML) + layout_document(box, width, c->data.html.box_pool); + + /* open printer */ + e = xosfind_openoutw(0xf, filename, 0, &fhandle); + if (e) { + LOG(("%s", e->errmess)); + return; + } + + LOG(("opened %s", filename)); + + /* select print job */ + e = xpdriver_select_jobw(fhandle, "NetSurf", &old_job); + if (e) { + LOG(("%s", e->errmess)); + xosfind_closew(fhandle); + return; + } + + LOG(("selected job - polling the wimp now does bad things(TM)")); + + /* declare fonts, if necessary */ + if (features & pdriver_FEATURE_DECLARE_FONT && + c->type == CONTENT_HTML) { + struct print_font *print_fonts = + calloc(255, sizeof(*print_fonts)); + int numFonts = 0; + int i; + + if (!print_fonts) { + LOG(("malloc failed")); + goto error; + } + + if(!print_find_fonts(box, &print_fonts, &numFonts)) { + LOG(("print_find_fonts_failed")); + for (i = 0; i != numFonts; ++i) { + free((print_fonts[i]).fontName); + } + free(print_fonts); + goto error; + } + LOG(("%d", numFonts)); + + for (i = 0; i != numFonts; ++i) { + LOG(("0x%x: %s", (print_fonts[i]).handle, (char*)(print_fonts[i]).fontName)); + e = xpdriver_declare_font((font_f)(print_fonts[i]).handle, (print_fonts[i]).fontName, 0); + if (e) { + for (i = 0; i != numFonts; ++i) { + free((print_fonts[i]).fontName); + } + free(print_fonts); + LOG(("%s", e->errmess)); + goto error; + } + } + + for (i = 0; i != numFonts; ++i) { + free((print_fonts[i]).fontName); + } + free(print_fonts); + + e = xpdriver_declare_font(0, 0, 0); + if (e) { + LOG(("%s", e->errmess)); + goto error; + } + + LOG(("declared fonts")); + } + + do { + os_box b = {left/400 - 2, bottom/400 - 2, + right/400 + 2, top/400 + 2}; + os_hom_trfm t = { { { 65536, 0}, {0, 65536} } }; + os_coord p = {left, bottom}; + + e = xhourglass_percentage((int)(yscroll*100/c->height)); + if (e) { + LOG(("%s", e->errmess)); + /* the hourglass failing to be updated + * shouldn't stop the printjob + */ + } + + /* Give page rectangle */ + e = xpdriver_give_rectangle(0, &b, &t, &p, os_COLOUR_WHITE); + if (e) { + LOG(("%s", e->errmess)); + goto error; + } + + LOG(("given rectangle: [(%d, %d), (%d, %d)]", b.x0, b.y0, b.x1, b.y1)); + + /* and redraw the document */ + osbool more; + e = xpdriver_draw_page(print_num_copies, &b, 0, 0, &more, 0); + if (e) { + LOG(("%s", e->errmess)); + goto error; + } + + LOG(("done draw_page")); + + ro_gui_current_redraw_gui = g; + + while (more) { + LOG(("redrawing area: [(%d, %d), (%d, %d)]", b.x0, b.y0, b.x1, b.y1)); + if (c) { + content_redraw(c, b.x0, b.y1+(yscroll*2), + c->width * 2, c->height * 2, + b.x0, b.y0, + b.x1-1, b.y1-1, + 1.0 /* scale == 100% */); + } + e = xpdriver_get_rectangle(&b, &more, 0); + if (e) { + LOG(("%s", e->errmess)); + ro_gui_current_redraw_gui = NULL; + goto error; + } + } + + yscroll += height; + } while (yscroll <= c->height && --sheets != 0); + + ro_gui_current_redraw_gui = NULL; + LOG(("finished redraw")); + + /* clean up */ + e = xpdriver_end_jobw(fhandle); + if (e) { + LOG(("%s", e->errmess)); + goto error; + } + xosfind_close(fhandle); + if (old_job) xpdriver_select_jobw(old_job, 0, 0); + + LOG(("done job")); + + /* restore document layout */ + if (c->type == CONTENT_HTML) + layout_document(box, temp, c->data.html.box_pool); + + return; + +error: + xpdriver_abort_job(fhandle); + xosfind_close(fhandle); + if (old_job) xpdriver_select_jobw(old_job, 0, 0); + + /* restore document layout */ + if (c->type == CONTENT_HTML) + layout_document(box, temp, c->data.html.box_pool); +} + +/** + * Find all fonts in a document + * + * \param box Root of box tree + * \param print_fonts pointer to array of fonts in document + * \paran numFonts number of fonts declared + * \return true on success, false otherwise + */ +bool print_find_fonts(struct box *box, struct print_font **print_fonts, int *numFonts) +{ + struct box *a; + const char *txt; + int txt_len; + unsigned int width, rolength, consumed; + const char *rofontname, *rotext; + int i; + + assert(box); + + if (box->text && box->font && box->length > 0) { + txt = box->text; + txt_len = box->length; + + if (box->font->ftype == FONTTYPE_UFONT) { + /** \todo handle ufont */ + LOG(("ufont")); + return false; + } + + nsfont_txtenum(box->font, txt, txt_len, + &width, &rofontname, + &rotext, &rolength, + &consumed); + + if (rotext == NULL) { + LOG(("rotext = null (%d)", txt_len)); + return false; + } + + for (i = 0; i != *numFonts; ++i) { + if (!strcmp(((*print_fonts)[i]).fontName, rofontname)) + break; + } + + if (i == *numFonts) { + /* max 255 fonts (as per draw) */ + if (*numFonts == 255) + return false; + if ((((*print_fonts)[*numFonts]).fontName = strdup(rofontname)) == NULL) { + LOG(("failed to strdup (%s)", rofontname)); + return false; + } + ((*print_fonts)[(*numFonts)++]).handle = (font_f)box->font->handle; + } + + free((void*)rotext); + } + + for (a = box->children; a; a = a->next) { + if (!print_find_fonts(a, print_fonts, numFonts)) + return false; + } + + return true; +} +#endif diff --git a/riscos/print.h b/riscos/print.h new file mode 100644 index 000000000..c499167f7 --- /dev/null +++ b/riscos/print.h @@ -0,0 +1,23 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 John M Bell + */ + +#ifndef _NETSURF_RISCOS_PRINT_H_ +#define _NETSURF_RISCOS_PRINT_H_ + +struct gui_window; + +extern struct gui_window *print_current_window; + +void print_save_bounce(wimp_message *m); +void print_error(wimp_message *m); +void print_type_odd(wimp_message *m); +void print_ack(wimp_message *m); +void print_dataload_bounce(wimp_message *m); +void print_cleanup(void); + +#endif + diff --git a/riscos/window.c b/riscos/window.c index 7f97220fb..ab945cb0d 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -1402,6 +1402,10 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar) } return true; + case wimp_KEY_PRINT: + ro_gui_print_open(g, 0, 0, false, true); + return true; + case wimp_KEY_UP: case wimp_KEY_DOWN: case wimp_KEY_PAGE_UP: -- cgit v1.2.3