1 /* 2 * PrinterDriver.cpp 3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved. 4 * Copyright 2004 Michael Pfeiffer. 5 */ 6 7 #include "PrinterDriver.h" 8 9 #include <fs_attr.h> // for attr_info 10 #include <DataIO.h> 11 #include <File.h> 12 #include <FindDirectory.h> 13 #include <Message.h> 14 #include <Node.h> 15 #include <Path.h> 16 #include <StackOrHeapArray.h> 17 #include <String.h> 18 19 #include "AboutBox.h" 20 #include "AddPrinterDlg.h" 21 #include "DbgMsg.h" 22 #include "Exports.h" 23 #include "GraphicsDriver.h" 24 #include "PrinterCap.h" 25 #include "PrinterData.h" 26 #include "UIDriver.h" 27 #include "Preview.h" 28 #include "PrintUtils.h" 29 30 31 // Implementation of PrinterDriver 32 33 PrinterDriver::PrinterDriver(BNode* spoolFolder) 34 : 35 fSpoolFolder(spoolFolder), 36 fPrinterData(NULL), 37 fPrinterCap(NULL), 38 fGraphicsDriver(NULL) 39 { 40 } 41 42 PrinterDriver::~PrinterDriver() 43 { 44 delete fGraphicsDriver; 45 fGraphicsDriver = NULL; 46 47 delete fPrinterCap; 48 fPrinterCap = NULL; 49 50 delete fPrinterData; 51 fPrinterData = NULL; 52 } 53 54 55 PrinterData* 56 PrinterDriver::InstantiatePrinterData(BNode* node) 57 { 58 return new PrinterData(node); 59 } 60 61 void 62 PrinterDriver::InitPrinterDataAndCap() { 63 fPrinterData = InstantiatePrinterData(fSpoolFolder); 64 fPrinterData->Load(); 65 // NOTE: moved the load above from the constructor of PrinterData as 66 // we're inheriting from PrinterData and want our overridden versions 67 // of load to be called 68 fPrinterCap = InstantiatePrinterCap(fPrinterData); 69 } 70 71 void 72 PrinterDriver::About() 73 { 74 BString copyright; 75 copyright = "libprint Copyright © 1999-2000 Y.Takagi\n"; 76 copyright << GetCopyright(); 77 copyright << "All Rights Reserved."; 78 79 AboutBox app(GetSignature(), GetDriverName(), GetVersion(), copyright.String()); 80 app.Run(); 81 } 82 83 char* 84 PrinterDriver::AddPrinter(char* printerName) 85 { 86 // print_server has created a spool folder with name printerName in 87 // folder B_USER_PRINTERS_DIRECTORY. It can be used to store 88 // settings in the folder attributes. 89 DBGMSG((">%s: add_printer\n", GetDriverName())); 90 DBGMSG(("\tprinter_name: %s\n", printerName)); 91 DBGMSG(("<%s: add_printer\n", GetDriverName())); 92 93 if (fPrinterCap->Supports(PrinterCap::kProtocolClass)) { 94 if (fPrinterCap->CountCap(PrinterCap::kProtocolClass) > 1) { 95 AddPrinterDlg *dialog; 96 dialog = new AddPrinterDlg(fPrinterData, fPrinterCap); 97 if (dialog->Go() != B_OK) { 98 // dialog canceled 99 return NULL; 100 } 101 } else { 102 const ProtocolClassCap* pcCap; 103 pcCap = (const ProtocolClassCap*)fPrinterCap->GetDefaultCap( 104 PrinterCap::kProtocolClass); 105 if (pcCap != NULL) { 106 fPrinterData->SetProtocolClass(pcCap->fProtocolClass); 107 fPrinterData->Save(); 108 } 109 } 110 } 111 return printerName; 112 } 113 114 BMessage* 115 PrinterDriver::ConfigPage(BMessage* settings) 116 { 117 DBGMSG((">%s: config_page\n", GetDriverName())); 118 DUMP_BMESSAGE(settings); 119 DUMP_BNODE(fSpoolFolder); 120 121 BMessage pageSettings(*settings); 122 _MergeWithPreviousSettings(kAttrPageSettings, &pageSettings); 123 UIDriver uiDriver(&pageSettings, fPrinterData, fPrinterCap); 124 BMessage *result = uiDriver.ConfigPage(); 125 _WriteSettings(kAttrPageSettings, result); 126 127 DUMP_BMESSAGE(result); 128 DBGMSG(("<%s: config_page\n", GetDriverName())); 129 return result; 130 } 131 132 BMessage* 133 PrinterDriver::ConfigJob(BMessage* settings) 134 { 135 DBGMSG((">%s: config_job\n", GetDriverName())); 136 DUMP_BMESSAGE(settings); 137 DUMP_BNODE(fSpoolFolder); 138 139 BMessage jobSettings(*settings); 140 _MergeWithPreviousSettings(kAttrJobSettings, &jobSettings); 141 UIDriver uiDriver(&jobSettings, fPrinterData, fPrinterCap); 142 BMessage *result = uiDriver.ConfigJob(); 143 _WriteSettings(kAttrJobSettings, result); 144 145 DUMP_BMESSAGE(result); 146 DBGMSG(("<%s: config_job\n", GetDriverName())); 147 return result; 148 } 149 150 BMessage* 151 PrinterDriver::TakeJob(BFile* printJob, BMessage* settings) 152 { 153 DBGMSG((">%s: take_job\n", GetDriverName())); 154 DUMP_BMESSAGE(settings); 155 DUMP_BNODE(fSpoolFolder); 156 157 fGraphicsDriver = InstantiateGraphicsDriver(settings, fPrinterData, fPrinterCap); 158 const JobData* jobData = fGraphicsDriver->GetJobData(printJob); 159 if (jobData != NULL && jobData->GetShowPreview()) { 160 off_t offset = printJob->Position(); 161 PreviewWindow *preview = new PreviewWindow(printJob, true); 162 if (preview->Go() != B_OK) { 163 return new BMessage('okok'); 164 } 165 printJob->Seek(offset, SEEK_SET); 166 } 167 BMessage *result = fGraphicsDriver->TakeJob(printJob); 168 169 DUMP_BMESSAGE(result); 170 DBGMSG(("<%s: take_job\n", GetDriverName())); 171 return result; 172 } 173 174 // read settings from spool folder attribute 175 bool 176 PrinterDriver::_ReadSettings(const char* attrName, BMessage* settings) 177 { 178 attr_info info; 179 ssize_t size; 180 181 settings->MakeEmpty(); 182 183 if (fSpoolFolder->GetAttrInfo(attrName, &info) == B_OK && info.size > 0) { 184 BStackOrHeapArray<char, 0> data(info.size); 185 if (!data.IsValid()) 186 return false; 187 size = fSpoolFolder->ReadAttr(attrName, B_MESSAGE_TYPE, 0, data, info.size); 188 if (size == info.size && settings->Unflatten(data) == B_OK) { 189 return true; 190 } 191 } 192 return false; 193 } 194 195 // write settings to spool folder attribute 196 void 197 PrinterDriver::_WriteSettings(const char* attrName, BMessage* settings) 198 { 199 if (settings == NULL || settings->what != 'okok') return; 200 201 status_t status; 202 BMallocIO data; 203 status = settings->Flatten(&data); 204 205 if (status == B_OK) { 206 fSpoolFolder->WriteAttr(attrName, B_MESSAGE_TYPE, 0, data.Buffer(), 207 data.BufferLength()); 208 } 209 } 210 211 // read settings from spool folder attribute and merge them to current settings 212 void 213 PrinterDriver::_MergeWithPreviousSettings(const char* attrName, BMessage* settings) 214 { 215 if (settings == NULL) return; 216 217 BMessage stored; 218 if (_ReadSettings(attrName, &stored)) { 219 AddFields(&stored, settings); 220 *settings = stored; 221 } 222 } 223 224 // Implementation of PrinterDriverInstance 225 226 class PrinterDriverInstance 227 { 228 public: 229 PrinterDriverInstance(BNode* spoolFolder = NULL); 230 ~PrinterDriverInstance(); 231 PrinterDriver* GetPrinterDriver() { return fInstance; } 232 233 private: 234 PrinterDriver* fInstance; 235 }; 236 237 PrinterDriverInstance::PrinterDriverInstance(BNode* spoolFolder) 238 { 239 fInstance = instantiate_printer_driver(spoolFolder); 240 if (fInstance != NULL) { 241 fInstance->InitPrinterDataAndCap(); 242 } 243 } 244 245 PrinterDriverInstance::~PrinterDriverInstance() 246 { 247 delete fInstance; 248 fInstance = NULL; 249 } 250 251 252 // printer driver add-on functions 253 254 char *add_printer(char *printerName) 255 { 256 BPath path; 257 BNode folder; 258 BNode* spoolFolder = NULL; 259 // get spool folder 260 if (find_directory(B_USER_PRINTERS_DIRECTORY, &path) == B_OK && 261 path.Append(printerName) == B_OK && 262 folder.SetTo(path.Path()) == B_OK) { 263 spoolFolder = &folder; 264 } 265 266 PrinterDriverInstance instance(spoolFolder); 267 return instance.GetPrinterDriver()->AddPrinter(printerName); 268 } 269 270 BMessage *config_page(BNode *spoolFolder, BMessage *settings) 271 { 272 PrinterDriverInstance instance(spoolFolder); 273 return instance.GetPrinterDriver()->ConfigPage(settings); 274 } 275 276 BMessage *config_job(BNode *spoolFolder, BMessage *settings) 277 { 278 PrinterDriverInstance instance(spoolFolder); 279 return instance.GetPrinterDriver()->ConfigJob(settings); 280 } 281 282 BMessage *take_job(BFile *printJob, BNode *spoolFolder, BMessage *settings) 283 { 284 PrinterDriverInstance instance(spoolFolder); 285 return instance.GetPrinterDriver()->TakeJob(printJob, settings); 286 } 287 288 // main entry if printer driver is launched directly 289 290 int main(int argc, char* argv[]) 291 { 292 PrinterDriverInstance instance; 293 instance.GetPrinterDriver()->About(); 294 return 0; 295 } 296