1 /* 2 * Copyright 2001-2005, Haiku. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 I.R. Adema 7 Stefano Ceccherini (burton666@libero.it) 8 */ 9 10 #include <Alert.h> 11 #include <Application.h> 12 #include <Debug.h> 13 #include <Entry.h> 14 #include <File.h> 15 #include <FindDirectory.h> 16 #include <Messenger.h> 17 #include <Path.h> 18 #include <PrintJob.h> 19 #include <Roster.h> 20 #include <View.h> 21 22 #include <pr_server.h> 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 29 static BMessenger *sPrintServer = NULL; 30 31 32 static void 33 EnsureValidMessenger() 34 { 35 if (sPrintServer == NULL) 36 sPrintServer = new BMessenger; 37 38 if (!sPrintServer->IsValid()) 39 *sPrintServer = BMessenger(PSRV_SIGNATURE_TYPE); 40 } 41 42 43 BPrintJob::BPrintJob(const char *job_name) 44 : 45 print_job_name(NULL), 46 page_number(0), 47 spoolFile(NULL), 48 pr_error(B_OK), 49 setup_msg(NULL), 50 default_setup_msg(NULL), 51 m_curPageHeader(NULL) 52 { 53 memset(¤t_header, 0, sizeof(current_header)); 54 if (job_name != NULL) 55 print_job_name = strdup(job_name); 56 } 57 58 59 BPrintJob::~BPrintJob() 60 { 61 free(print_job_name); 62 } 63 64 65 void 66 BPrintJob::BeginJob() 67 { 68 // TODO: this should be improved: 69 // - Take system printers into account 70 // - handle the case where the path doesn't exist 71 // - more 72 BPath path; 73 status_t status = find_directory(B_USER_PRINTERS_DIRECTORY, &path); 74 if (status < B_OK) 75 return; 76 77 char *printer = GetCurrentPrinterName(); 78 if (printer == NULL) 79 return; 80 81 path.Append(printer); 82 free(printer); 83 84 char mangledName[B_FILE_NAME_LENGTH]; 85 MangleName(mangledName); 86 87 path.Append(mangledName); 88 89 if (path.InitCheck() < B_OK) 90 return; 91 92 stop_the_show = 0; 93 page_number = 0; 94 95 strncpy(spool_file_name, path.Path(), sizeof(spool_file_name)); 96 spoolFile = new BFile(spool_file_name, B_READ_WRITE|B_CREATE_FILE); 97 98 AddSetupSpec(); 99 } 100 101 102 void 103 BPrintJob::CommitJob() 104 { 105 if (page_number <= 0) { 106 BAlert *alert = new BAlert("Alert", "No Pages to print!", "Okay"); 107 alert->Go(); 108 CancelJob(); 109 return; 110 } 111 112 EnsureValidMessenger(); 113 BMessage *message = new BMessage(PSRV_GET_ACTIVE_PRINTER); 114 BMessage *reply = new BMessage; 115 116 const char *printerName = NULL; 117 if (sPrintServer->SendMessage(message, reply) < B_OK || 118 reply->FindString("printer_name", &printerName) < B_OK) { 119 // TODO: Show an alert 120 delete message; 121 delete reply; 122 return; 123 } 124 125 delete message; 126 delete reply; 127 128 app_info appInfo; 129 be_app->GetAppInfo(&appInfo); 130 131 spoolFile->WriteAttr("_spool/Page Count", B_INT32_TYPE, 0, &page_number, sizeof(int32)); 132 spoolFile->WriteAttr("_spool/Description", B_STRING_TYPE, 0, print_job_name, strlen(print_job_name) + 1); 133 spoolFile->WriteAttr("_spool/Printer", B_STRING_TYPE, 0, printerName, strlen(printerName) + 1); 134 spoolFile->WriteAttr("_spool/Status", B_STRING_TYPE, 0, "waiting", strlen("waiting") + 1); 135 spoolFile->WriteAttr("_spool/MimeType", B_STRING_TYPE, 0, appInfo.signature, strlen(appInfo.signature) + 1); 136 137 message = new BMessage(PSRV_PRINT_SPOOLED_JOB); 138 reply = new BMessage; 139 140 message->AddString("JobName", print_job_name); 141 message->AddString("Spool File", spool_file_name); 142 sPrintServer->SendMessage(message, reply); 143 144 delete message; 145 delete reply; 146 } 147 148 149 status_t 150 BPrintJob::ConfigJob() 151 { 152 // TODO: Implement 153 return B_OK; 154 } 155 156 157 void 158 BPrintJob::CancelJob() 159 { 160 stop_the_show = 1; 161 BEntry(spool_file_name).Remove(); 162 delete spoolFile; 163 } 164 165 166 status_t 167 BPrintJob::ConfigPage() 168 { 169 return B_OK; 170 } 171 172 173 void 174 BPrintJob::SpoolPage() 175 { 176 NewPage(); 177 } 178 179 180 bool 181 BPrintJob::CanContinue() 182 { 183 // Check if our local error storage is still B_OK 184 return pr_error == B_OK && !stop_the_show; 185 } 186 187 188 void 189 BPrintJob::DrawView(BView *view, BRect rect, BPoint where) 190 { 191 if (view == NULL) 192 return; 193 194 // TODO: Finish me 195 if (view->LockLooper()) { 196 BPicture *picture = new BPicture; 197 RecurseView(view, where, picture, rect); 198 AddPicture(picture, &rect, where); 199 200 view->UnlockLooper(); 201 delete picture; 202 } 203 } 204 205 206 BMessage * 207 BPrintJob::Settings() 208 { 209 BMessage *message = NULL; 210 211 if (setup_msg != NULL) 212 message = new BMessage(*setup_msg); 213 214 return message; 215 } 216 217 218 void 219 BPrintJob::SetSettings(BMessage *message) 220 { 221 if (message != NULL) { 222 HandlePageSetup(message); 223 HandlePrintSetup(message); 224 delete setup_msg; 225 setup_msg = message; 226 } 227 } 228 229 230 bool 231 BPrintJob::IsSettingsMessageValid(BMessage *message) const 232 { 233 const char *messageName = NULL; 234 char *printerName = GetCurrentPrinterName(); 235 236 bool result = false; 237 238 // The passed message is valid if it contains the right printer name. 239 if (message != NULL 240 && message->FindString("printer_name", &messageName) == B_OK 241 && strcmp(printerName, messageName) == 0) 242 result = true; 243 244 free(printerName); 245 246 return result; 247 } 248 249 250 BRect 251 BPrintJob::PaperRect() 252 { 253 if (default_setup_msg == NULL) 254 LoadDefaultSettings(); 255 256 return paper_size; 257 } 258 259 260 BRect 261 BPrintJob::PrintableRect() 262 { 263 if (default_setup_msg == NULL) 264 LoadDefaultSettings(); 265 266 return usable_size; 267 } 268 269 270 void 271 BPrintJob::GetResolution(int32 *xdpi, int32 *ydpi) 272 { 273 int32 xres = -1, yres = -1; 274 275 const BMessage *message = NULL; 276 277 if (setup_msg != NULL) 278 message = setup_msg; 279 else { 280 if (default_setup_msg == NULL) 281 LoadDefaultSettings(); 282 message = default_setup_msg; 283 } 284 285 if (message != NULL) { 286 if (message->HasInt32(PSRV_FIELD_XRES)) 287 message->FindInt32(PSRV_FIELD_XRES, &xres); 288 if (message->HasInt32(PSRV_FIELD_YRES)) 289 message->FindInt32(PSRV_FIELD_YRES, &yres); 290 } 291 292 if (xdpi != NULL) 293 *xdpi = xres; 294 if (ydpi != NULL) 295 *ydpi = yres; 296 } 297 298 299 int32 300 BPrintJob::FirstPage() 301 { 302 return first_page; 303 } 304 305 306 int32 307 BPrintJob::LastPage() 308 { 309 return last_page; 310 } 311 312 313 int32 314 BPrintJob::PrinterType(void *) const 315 { 316 EnsureValidMessenger(); 317 318 BMessage message(PSRV_GET_ACTIVE_PRINTER); 319 BMessage reply; 320 321 sPrintServer->SendMessage(&message, &reply); 322 323 int32 type = B_COLOR_PRINTER; 324 reply.FindInt32("color", &type); 325 326 return type; 327 } 328 329 330 #if 0 331 #pragma mark ----- PRIVATE ----- 332 #endif 333 334 335 void 336 BPrintJob::RecurseView(BView *view, BPoint origin, 337 BPicture *picture, BRect rect) 338 { 339 ASSERT(picture != NULL); 340 341 view->AppendToPicture(picture); 342 view->f_is_printing = true; 343 view->Draw(rect); 344 view->f_is_printing = false; 345 view->EndPicture(); 346 347 // TODO: call recursively on every view's children. 348 } 349 350 351 void 352 BPrintJob::MangleName(char *filename) 353 { 354 char sysTime[10]; 355 snprintf(sysTime, sizeof(sysTime), "@%lld", system_time() / 1000); 356 strncpy(filename, print_job_name, B_FILE_NAME_LENGTH - sizeof(sysTime)); 357 strcat(filename, sysTime); 358 } 359 360 361 void 362 BPrintJob::HandlePageSetup(BMessage *setup) 363 { 364 } 365 366 367 bool 368 BPrintJob::HandlePrintSetup(BMessage *message) 369 { 370 if (message->HasRect(PSRV_FIELD_PRINTABLE_RECT)) 371 message->FindRect(PSRV_FIELD_PRINTABLE_RECT, &usable_size); 372 if (message->HasRect(PSRV_FIELD_PAPER_RECT)) 373 message->FindRect(PSRV_FIELD_PAPER_RECT, &paper_size); 374 if (message->HasInt32(PSRV_FIELD_FIRST_PAGE)) 375 message->FindInt32(PSRV_FIELD_FIRST_PAGE, &first_page); 376 if (message->HasInt32(PSRV_FIELD_LAST_PAGE)) 377 message->FindInt32(PSRV_FIELD_LAST_PAGE, &last_page); 378 379 return true; 380 } 381 382 383 void 384 BPrintJob::NewPage() 385 { 386 // TODO: this function could be removed, and its functionality moved 387 // to SpoolPage() 388 // TODO: Implement for real 389 page_number++; 390 } 391 392 393 void 394 BPrintJob::EndLastPage() 395 { 396 } 397 398 399 void 400 BPrintJob::AddSetupSpec() 401 { 402 if (setup_msg != NULL && spoolFile != NULL) 403 setup_msg->Flatten(spoolFile); 404 } 405 406 407 void 408 BPrintJob::AddPicture(BPicture *picture, BRect *rect, BPoint where) 409 { 410 ASSERT(picture != NULL); 411 ASSERT(spoolFile != NULL); 412 ASSERT(rect != NULL); 413 414 spoolFile->Write(&where, sizeof(where)); 415 spoolFile->Write(rect, sizeof(*rect)); 416 picture->Flatten(spoolFile); 417 } 418 419 420 char * 421 BPrintJob::GetCurrentPrinterName() const 422 { 423 EnsureValidMessenger(); 424 425 BMessage message(PSRV_GET_ACTIVE_PRINTER); 426 BMessage reply; 427 428 const char *printerName = NULL; 429 430 if (sPrintServer->SendMessage(&message, &reply) == B_OK) 431 reply.FindString("printer_name", &printerName); 432 433 return printerName != NULL ? strdup(printerName) : NULL; 434 } 435 436 437 void 438 BPrintJob::LoadDefaultSettings() 439 { 440 EnsureValidMessenger(); 441 442 BMessage message(PSRV_GET_DEFAULT_SETTINGS); 443 BMessage *reply = new BMessage; 444 445 sPrintServer->SendMessage(&message, reply); 446 447 if (reply->HasRect(PSRV_FIELD_PAPER_RECT)) 448 reply->FindRect(PSRV_FIELD_PAPER_RECT, &paper_size); 449 if (reply->HasRect(PSRV_FIELD_PRINTABLE_RECT)) 450 reply->FindRect(PSRV_FIELD_PRINTABLE_RECT, &usable_size); 451 452 delete default_setup_msg; 453 default_setup_msg = reply; 454 } 455 456 457 void BPrintJob::_ReservedPrintJob1() {} 458 void BPrintJob::_ReservedPrintJob2() {} 459 void BPrintJob::_ReservedPrintJob3() {} 460 void BPrintJob::_ReservedPrintJob4() {} 461