#include "wxinc.h" #include "wx/print.h" #include "wx/printdlg.h" #include "xvt.h" #ifdef WIN32 #include "oswin32.h" #else #include "oslinux.h" #include "incstr.h" #endif #include "xvintern.h" #pragma pack(4) struct TPRINT_RCD : public PRINT_RCD { unsigned char m_data[16*1024]; unsigned int m_size; // Dimensione della struct DEVMODE void SetData(void* data, unsigned int nSize); TPRINT_RCD(); ~TPRINT_RCD(); }; #pragma pack() void TPRINT_RCD::SetData(void* data, unsigned int nSize) { if (nSize <= sizeof(m_data)) { memcpy(m_data, data, nSize); m_size = nSize; } else xvt_dm_post_error("Printer info exceeds 16K"); } TPRINT_RCD::TPRINT_RCD() : m_size(0) { pr = NULL; memset(m_data, 0, sizeof(m_data)); } TPRINT_RCD::~TPRINT_RCD() { memset(m_data, 0, sizeof(m_data)); m_size = 0; } /////////////////////////////////////////////////////////// // TwxPrintOut /////////////////////////////////////////////////////////// class TwxPrintOut : public wxPrintout { protected: TPRINT_RCD* m_prcd; bool m_bBadDriver; virtual bool HasPage(int pageNum); virtual bool OnPrintPage(int pageNum); void ResetDC(); public: void SetBadDriver(bool bd) { m_bBadDriver = bd; } bool HasBadDriver() const { return m_bBadDriver; } void InitDC(TPRINT_RCD* prcd); TwxPrintOut(TPRINT_RCD* prcd = NULL); virtual ~TwxPrintOut(); }; static TwxPrintOut* m_po = NULL; bool TwxPrintOut::HasPage(int pageNum) { return true; } bool TwxPrintOut::OnPrintPage(int pageNum) { return false; } void TwxPrintOut::ResetDC() { wxDC* dc = GetDC(); if (dc != NULL) delete dc; } void TwxPrintOut::InitDC(TPRINT_RCD* prcd) { ResetDC(); wxDC* dc = NULL; m_prcd = prcd; if (m_prcd == NULL) { wxPrinter printer; #ifdef WIN32 dc = new wxPrinterDC(printer.GetPrintDialogData().GetPrintData()); #else dc = new wxPostScriptDC(printer.GetPrintDialogData().GetPrintData()); #endif } else { wxPrintData data; #ifdef WIN32 data.SetNativeData(OsWin32_ConvertToNativePrinterInfo(prcd->m_data, prcd->m_size)); data.ConvertFromNative(); dc = new wxPrinterDC(data); #else dc = new wxPostScriptDC(prcd->m_data); #endif } wxSize s = dc->GetPPI(); SetPPIPrinter(s.x, s.y); s = dc->GetSize(); SetPageSizePixels(s.x, s.y); SetDC(dc); } TwxPrintOut::TwxPrintOut(TPRINT_RCD* prcd) : wxPrintout(_GetAppTitle()), m_bBadDriver(false) { InitDC(prcd); } TwxPrintOut::~TwxPrintOut() { ResetDC(); } /////////////////////////////////////////////////////////// // TwxPrintOutCache /////////////////////////////////////////////////////////// class TwxPrintOutCache { unsigned long m_signature; TwxPrintOut* m_po; protected: unsigned long Signature(TPRINT_RCD* prcd) const; public: TwxPrintOut* Get(TPRINT_RCD* prcd); void Reset(); TwxPrintOutCache() : m_signature(0), m_po(NULL) { } ~TwxPrintOutCache() { Reset(); } } m_PrintoutCache; unsigned long TwxPrintOutCache::Signature(TPRINT_RCD* prcd) const { const unsigned char* data = (const unsigned char*)prcd; unsigned long h = 0; for (size_t c = 0; c < prcd->m_size; c++) { h = (h << 2) + data[c]; const unsigned long i = h & 0xC0000000; if (i) h = (h ^ (i >> 12)) & 0x3FFFFFFF; } return h; } void TwxPrintOutCache::Reset() { if (m_po != NULL) { delete m_po; m_po = NULL; } } TwxPrintOut* TwxPrintOutCache::Get(TPRINT_RCD* prcd) { unsigned long signature = Signature(prcd); if (m_po != NULL && m_signature == signature) return m_po; Reset(); m_po = new TwxPrintOut(prcd); m_signature = signature; return m_po; } /////////////////////////////////////////////////////////// // TPrintDC /////////////////////////////////////////////////////////// wxDC& TPrintDC::GetDC(bool) { _dc = m_po->GetDC(); // Forza display context corrente if (_dirty) _dirty = -1; return TDC::GetDC(false); } void TPrintDC::KillDC() { _dc = NULL; // _dc is owned by wxPrintout } TPrintDC::TPrintDC(wxWindow* owner) : TDC(owner) { } TPrintDC::~TPrintDC() { _dc = NULL; // Evita distruzione! } /////////////////////////////////////////////////////////// // Printing management :-((((( /////////////////////////////////////////////////////////// BOOLEAN xvt_app_escape(int esc_code, PRINT_RCD* rcd, long* ph, long* pw, long* pvr, long* phr) { *ph = *pw = *pvr = *phr = 0; switch (esc_code) { case XVT_ESC_GET_PRINTER_INFO: if (rcd == NULL || xvt_print_is_valid(rcd)) { int w, h; if (m_po == NULL) { TwxPrintOut* po = m_PrintoutCache.Get((TPRINT_RCD*)rcd); po->GetPPIPrinter(&w, &h); *phr = w; *pvr = h; po->GetPageSizePixels(&w, &h); *pw = w; *ph = h; } else { m_po->GetPPIPrinter(&w, &h); *phr = w; *pvr = h; m_po->GetPageSizePixels(&w, &h); *pw = w; *ph = h; } return TRUE; } break; default: break; } return FALSE; } BOOLEAN xvt_dm_post_page_setup(PRINT_RCD* precp) { wxPageSetupDialog dlg((wxWindow*)TASK_WIN); TPRINT_RCD* rcd = (TPRINT_RCD*)precp; wxPageSetupData& pdd = dlg.GetPageSetupData(); wxPrintData& data = pdd.GetPrintData(); #ifdef WIN32 void* pHandle = OsWin32_ConvertToNativePrinterInfo(rcd->m_data, rcd->m_size); data.SetNativeData(pHandle); data.ConvertFromNative(); #endif pdd.EnableMargins(false); const BOOLEAN ok = dlg.ShowModal() == wxID_OK; if (ok) { #ifdef WIN32 pHandle = data.GetNativeData(); unsigned int nSize = 0; void* ptr = OsWin32_ConvertFromNativePrinterInfo(pHandle, nSize); rcd->SetData(ptr, nSize); delete ptr; #else rcd->SetData((void *) &data, (unsigned int) sizeof(data)); #endif m_PrintoutCache.Reset(); } return ok; } long xvt_fmap_get_family_sizes(PRINT_RCD *precp, char *family, long *size_array, BOOLEAN *scalable, long max_sizes) { long size = 0; *scalable = FALSE; if (precp != NULL) { #ifdef WIN32 TwxPrintOut* po = m_PrintoutCache.Get((TPRINT_RCD*)precp); if (!po->HasBadDriver()) size = OsWin32_EnumerateSizes(po->GetDC()->GetHDC(), family, size_array, scalable, max_sizes); #else size = OsLinux_EnumerateSizes(family, size_array, scalable, max_sizes); #endif } return size; } long xvt_fmap_get_families(PRINT_RCD *precp, char **family_array, long max_families) { long size = 0; family_array[0] = NULL; if (precp != NULL) { #ifdef WIN32 TwxPrintOut* po = m_PrintoutCache.Get((TPRINT_RCD*)precp); size = OsWin32_EnumerateFamilies(po->GetDC()->GetHDC(), family_array, max_families); if (size == 0) po->SetBadDriver(true); #else size = OsLinux_EnumerateFamilies(family_array, max_families); #endif } return size; } void xvt_print_close(void) { // Nothing to do ? } BOOLEAN xvt_print_close_page(PRINT_RCD* /*precp*/) { BOOLEAN ok = m_po != NULL; if (ok) m_po->GetDC()->EndPage(); return ok; } PRINT_RCD* xvt_print_create(int *sizep) { TPRINT_RCD* pr = NULL; *sizep = 0; #ifdef WIN32 void* data = OsWin32_GetPrinterInfo(*sizep, NULL); if (data != NULL) { pr = new TPRINT_RCD; pr->SetData(data, *sizep); *sizep += 4; // Spazio per puntatore iniziale delete data; } #else wxPrinter printer; wxPrintData &data = printer.GetPrintDialogData().GetPrintData(); data.SetPrinterName(""); //verificare pr = new TPRINT_RCD; pr->SetData((void *) &data, (unsigned int) sizeof(data)); #endif return pr; } // Nuova funzione inventata da Aga PRINT_RCD* xvt_print_create_by_name(int* sizep, const char* name) { TPRINT_RCD* pr = NULL; *sizep = 0; #ifdef WIN32 void* data = OsWin32_GetPrinterInfo(*sizep, name); if (data != NULL) { pr = new TPRINT_RCD; pr->SetData(data, *sizep); *sizep += 4; // Spazio per puntatore iniziale delete data; } #else wxPrinter printer; wxPrintData &data = printer.GetPrintDialogData().GetPrintData(); wxString PrinterName(name); data.SetPrinterName(PrinterName); //verificare pr = new TPRINT_RCD; pr->SetData((void *) &data, (unsigned int) sizeof(data)); #endif return pr; } WINDOW xvt_print_create_win(PRINT_RCD* precp, char* /* title */) { WINDOW win = NULL_WIN; if (m_po != NULL) { m_po->InitDC((TPRINT_RCD*)precp); m_po->OnBeginPrinting(); m_po->OnBeginDocument(1, 32000); win = _print_win; } return win; } void xvt_print_destroy(PRINT_RCD* precp) { delete precp; } RCT* xvt_print_get_next_band(void) { static bool yes = false; static RCT rct; yes = !yes; if (m_po == NULL || !yes) return NULL; int w, h; m_po->GetPageSizePixels(&w, &h); rct.left = rct.top = 0; rct.right = w; rct.bottom = h; return &rct; } BOOLEAN xvt_print_is_valid(PRINT_RCD* precp) { BOOLEAN ok = precp != NULL && precp->pr == NULL; if (ok) { #ifdef WIN32 TPRINT_RCD* rcd = (TPRINT_RCD*)precp; ok = OsWin32_CheckPrinterInfo(rcd->m_data, rcd->m_size); #else // verificare (c'e' da fare qualcosa ?) #endif } return ok; } int xvt_print_get_name(PRINT_RCD* precp, char* name, int sz_s) { #ifdef WIN32 wxString n = ((const char*)precp) + 4; if (n.Length() >= 30) { SLIST plist = xvt_print_list_devices(); for (SLIST_ELT pitem = xvt_slist_get_first(plist); pitem != NULL; pitem = xvt_slist_get_next(plist, pitem)) { const wxString pname = xvt_slist_get(plist, pitem, NULL); if (pname.StartsWith(n)) { n = pname; break; } } xvt_slist_destroy(plist); } if (name != NULL && sz_s > 0) { strncpy(name, n, sz_s); name[sz_s-1] = '\0'; } return n.Length(); #else return 0; // TBI #endif } BOOLEAN xvt_print_open(void) { return m_po == NULL; } /////////////////////////////////////////////////////////// void CreateAbortWindow() { wxFrame* parent = (wxFrame*)TASK_WIN; wxPrintAbortDialog* win = new wxPrintAbortDialog(parent, "Stampa" , wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE); wxBoxSizer *button_sizer = new wxBoxSizer( wxVERTICAL ); button_sizer->Add( new wxStaticText( win, -1, "Stampa in corso..."), 0, wxALL, 10 ); button_sizer->Add( new wxButton( win, wxID_CANCEL, wxT("Annulla") ), 0, wxALL | wxALIGN_CENTER, 10 ); win->SetAutoLayout( TRUE ); win->SetSizer( button_sizer ); button_sizer->Fit(win); button_sizer->SetSizeHints (win) ; win->Show(); win->Update(); wxPrinterBase::sm_abortWindow = win; } void DestroyAbortWindow() { if (wxPrinterBase::sm_abortWindow != NULL) { wxPrinterBase::sm_abortWindow->Hide(); delete wxPrinterBase::sm_abortWindow; wxPrinterBase::sm_abortWindow = NULL; } } /////////////////////////////////////////////////////////// BOOLEAN xvt_print_start_thread(BOOLEAN(*print_fcn)(long), long data) { wxBeginBusyCursor(); m_po = new TwxPrintOut; wxEndBusyCursor(); CreateAbortWindow(); const BOOLEAN aborted = print_fcn(data); DestroyAbortWindow(); #ifdef WIN32 // Stampa un line feed aggiuntivo nella stampa su generica solo testo in Win 98 int w, h; m_po->GetPPIPrinter(&w, &h); if (h == 6) // Solo Win 98 torna 6 pixel per pollice = 1 pixel per riga { wxDC* dc = m_po->GetDC(); dc->StartPage(); OsWin32_SpoolRow("\n\n", 1, dc->GetHDC()); // Probabilmente basta "\n" (visto che poi specifichiamo 1) ma non ci fidiamo dc->EndPage(); } #endif m_po->OnEndDocument(); m_po->OnEndPrinting(); delete m_po; m_po = NULL; return aborted; } BOOLEAN xvt_print_open_page(PRINT_RCD* precp) { BOOLEAN ok = m_po != NULL; if (ok) { if (wxPrinterBase::sm_abortIt) ok = FALSE; else m_po->GetDC()->StartPage(); } return ok; } /////////////////////////////////////////////////////////// // Added by XVAGA /////////////////////////////////////////////////////////// #ifdef LINUX static bool is_cups() { static int printer_system = -1; if (printer_system < 0) printer_system = xvt_fsys_file_exists("/etc/cups/printer.conf") ? 1 : 2; return (printer_system == 1); } #endif SLIST xvt_print_list_devices() { SLIST list = xvt_slist_create(); #ifdef WIN32 char buf[4096]; memset(buf, 0, sizeof(buf)); GetProfileString("devices", NULL, "", buf, sizeof(buf)); int start = 0; for (int i = 0; i < sizeof(buf); i++) if (buf[i] == '\0') { const char* pname = buf+start; if (*pname == '\0') break; xvt_slist_add_at_elt(list, NULL, pname, NULL); start = i+1; } #else if (is_cups()) { ifstream p("/etc/cups/printer.conf"); // vedere char line[4096]; while (p.getline(line, sizeof(line))) { if (line[0] == '<') { char * s = strstr(line, "Printer") ; if (s != NULL) { s += 7; while (isspace(*s)) s++; if (*s) { char * l = s + strlen(s) - 1; while (isspace(*l)) l--; *(l + 1) = '\0'; xvt_slist_add_at_elt(list, NULL, s, 0L); } } } } } else { ifstream p("/etc/printcap"); // vedere char line[4096]; while (p.getline(line, sizeof(line))) { if (line[0] != '#') { const int len = strlen(line); int i; for (i = 0; i < len; i++) { const char c = line[i]; if (!(isalpha(c) || isdigit(c) || isblank(c))) break; } line[i] = '\0'; xvt_slist_add_at_elt(list, NULL, line, 0L); } } } #endif return list; } BOOLEAN xvt_print_set_default_device(const char* name) { BOOLEAN ok = name && *name > ' '; #ifdef WIN32 if (ok) { wxString pdev(name); if (pdev.Find(',') < 0) { char szDevice[256]; ::GetProfileString ("devices", pdev, "", szDevice, sizeof(szDevice)); pdev << ',' << szDevice; } ok = ::WriteProfileString("windows", "device", pdev) != 0; } #else SORRY_BOX(); //verificare #endif return ok; } BOOLEAN xvt_print_get_default_device(char* name, int namesize) { bool ok = FALSE; #ifdef WIN32 ok = ::GetProfileString ("windows", "device", ",,,", name, namesize) != 0; #else *name = '\0'; if (is_cups()) { ifstream p("/etc/cups/printer.conf"); // vedere char line[4096]; while (p.getline(line, sizeof(line))) { if (line[0] == '<') { char * s = strstr(line, "ltPrinter") ; if (s != NULL) { s += 9; while (isspace(*s)) s++; if (*s) { char * l = s + strlen(s) - 1; while (isspace(*l)) l--; *(l + 1) = '\0'; strcpy(name, s); } ok = TRUE; } } } } #endif return ok; } /////////////////////////////////////////////////////////// // Gestione files di configurazione /////////////////////////////////////////////////////////// int xvt_fsys_get_campo_stp_value(const char* name, char* value, int valsize) { BOOLEAN bFound = FALSE; #ifdef WIN32 const char* stpfile = "c:/campo.stp"; int p; DIRECTORY dir; char exedir[_MAX_PATH], path[_MAX_PATH]; xvt_fsys_get_default_dir(&dir); xvt_fsys_convert_dir_to_str(&dir, exedir, sizeof(exedir)); for (p = 1; ; p++) { int len = 0; char para[4]; sprintf(para, "%d", p); len = xvt_sys_get_profile_string(stpfile, para, "Program", "", path, sizeof(path)); if (len <= 0) break; if (path[len-1] == '\\' || path[len-1] == '/') { len--; path[len] = '\0'; } if (xvt_str_compare_ignoring_case(path, exedir) == 0) { xvt_sys_get_profile_string(stpfile, para, name, "", value, valsize); bFound = *value > ' '; break; } } #endif return bFound; } /* @($) CGetCampoIni FILES @(ID) Restituisce il nome del file che contiene il prefisso corrente. @(FD) @(ISV) s,s1 = stringhe di lavoro. Versione WIN32 e LINUX. @(FSV) */ const char* xvt_fsys_get_campo_ini() { static char* prawin = NULL; if (prawin == NULL) { BOOLEAN bFound = FALSE; char exedir[_MAX_PATH], path[_MAX_PATH]; // Nelle installazioni sfigate con programmi in rete cerca di stabilire il percorso locale di Campo.ini DIRECTORY dir; xvt_fsys_get_default_dir(&dir); xvt_fsys_convert_dir_to_str(&dir, exedir, sizeof(exedir)); #ifdef WIN32 if (xvt_fsys_is_network_drive(exedir)) bFound = xvt_fsys_get_campo_stp_value("CampoIni", path, sizeof(path)); if (!bFound) { /* const char* pp = getenv("PREFPATH"); if (pp != NULL) { char dri[_MAX_DRIVE], dir[_MAX_PATH]; xvt_fsys_parse_pathname(pp, dri, dir, NULL, NULL, NULL); xvt_fsys_build_pathname(path, dri, dir, "campo", "ini", NULL); bFound = TRUE; }*/ if (xvt_sys_get_os_version() == XVT_WS_WIN_SERVER) { xvt_fsys_build_pathname(path, NULL, wxGetHomeDir(), "campo", "ini", NULL); bFound = xvt_fsys_file_exists(path); if (!bFound) { char pathstd[_MAX_PATH]; xvt_fsys_build_pathname(pathstd, NULL, exedir, "campo", "ini", NULL); if (xvt_fsys_file_exists(pathstd)) wxCopyFile(pathstd, path); } } } if (!bFound) xvt_fsys_build_pathname(path, NULL, exedir, "campo", "ini", NULL); #else if (!bFound) { char username[32]; char ininame[_MAX_FNAME]; xvt_sys_get_user_name(username, sizeof(username)); if (xvt_str_compare_ignoring_case(username, "root") == 0) *username = '\0'; sprintf(ininame, "campo%s", username); xvt_fsys_build_pathname(path, NULL, exedir, ininame, "ini", NULL); if (!xvt_fsys_file_exists(path) && *username > ' ') { char pathstd[_MAX_PATH]; xvt_fsys_build_pathname(pathstd, NULL, exedir, "campo", "ini", NULL); if (xvt_fsys_file_exists(pathstd)) wxCopyFile(pathstd, path); } } #endif if (!xvt_fsys_file_exists(path)) { char msg[256]; sprintf(msg, "Impossibile aprire '%s'", (const char *)path); xvt_dm_post_fatal_exit(msg); } prawin = xvt_str_duplicate(path); } return prawin; }