1 /* 2 * Copyright 2001-2009, Haiku. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * I.R. Adema 7 * Stefano Ceccherini (burton666@libero.it) 8 * Michael Pfeiffer 9 * julun <host.haiku@gmx.de> 10 */ 11 12 13 #include <PrintJob.h> 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 #include <Alert.h> 20 #include <Application.h> 21 #include <Button.h> 22 #include <Debug.h> 23 #include <Entry.h> 24 #include <File.h> 25 #include <FindDirectory.h> 26 #include <Messenger.h> 27 #include <NodeInfo.h> 28 #include <OS.h> 29 #include <Path.h> 30 #include <Region.h> 31 #include <Roster.h> 32 #include <SystemCatalog.h> 33 #include <View.h> 34 35 #include <AutoDeleter.h> 36 #include <pr_server.h> 37 #include <ViewPrivate.h> 38 39 using BPrivate::gSystemCatalog; 40 41 #undef B_TRANSLATION_CONTEXT 42 #define B_TRANSLATION_CONTEXT "PrintJob" 43 44 #undef B_TRANSLATE 45 #define B_TRANSLATE(str) \ 46 gSystemCatalog.GetString(B_TRANSLATE_MARK(str), "PrintJob") 47 48 49 /*! Summary of spool file: 50 51 |-----------------------------------| 52 | print_file_header | 53 |-----------------------------------| 54 | BMessage print_job_settings | 55 |-----------------------------------| 56 | | 57 | ********** (first page) ********* | 58 | * * | 59 | * _page_header_ * | 60 | * ----------------------------- * | 61 | * |---------------------------| * | 62 | * | BPoint where | * | 63 | * | BRect bounds | * | 64 | * | BPicture pic | * | 65 | * |---------------------------| * | 66 | * |---------------------------| * | 67 | * | BPoint where | * | 68 | * | BRect bounds | * | 69 | * | BPicture pic | * | 70 | * |---------------------------| * | 71 | ********************************* | 72 | | 73 | ********* (second page) ********* | 74 | * * | 75 | * _page_header_ * | 76 | * ----------------------------- * | 77 | * |---------------------------| * | 78 | * | BPoint where | * | 79 | * | BRect bounds | * | 80 | * | BPicture pic | * | 81 | * |---------------------------| * | 82 | ********************************* | 83 |-----------------------------------| 84 85 BeOS R5 print_file_header.version is 1 << 16 86 BeOS R5 print_file_header.first_page is -1 87 88 each page can consist of a collection of picture structures 89 remaining pages start at _page_header_.next_page of previous _page_header_ 90 91 See also: "How to Write a BeOS R5 Printer Driver" for description of spool 92 file format: http://haiku-os.org/documents/dev/how_to_write_a_printer_driver 93 */ 94 95 96 struct _page_header_ { 97 int32 number_of_pictures; 98 off_t next_page; 99 int32 reserved[10]; 100 } _PACKED; 101 102 103 static void 104 ShowError(const char* message) 105 { 106 BAlert* alert = new BAlert(B_TRANSLATE("Error"), message, B_TRANSLATE("OK")); 107 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 108 alert->Go(); 109 } 110 111 112 // #pragma mark -- PrintServerMessenger 113 114 115 namespace BPrivate { 116 117 118 class PrintServerMessenger { 119 public: 120 PrintServerMessenger(uint32 what, BMessage* input); 121 ~PrintServerMessenger(); 122 123 BMessage* Request(); 124 status_t SendRequest(); 125 126 void SetResult(BMessage* result); 127 BMessage* Result() const { return fResult; } 128 129 static status_t GetPrintServerMessenger(BMessenger& messenger); 130 131 private: 132 void RejectUserInput(); 133 void AllowUserInput(); 134 void DeleteSemaphore(); 135 static status_t MessengerThread(void* data); 136 137 uint32 fWhat; 138 BMessage* fInput; 139 BMessage* fRequest; 140 BMessage* fResult; 141 sem_id fThreadCompleted; 142 BAlert* fHiddenApplicationModalWindow; 143 }; 144 145 146 } // namespace BPrivate 147 148 149 using namespace BPrivate; 150 151 152 // #pragma mark -- BPrintJob 153 154 155 BPrintJob::BPrintJob(const char* jobName) 156 : 157 fPrintJobName(NULL), 158 fSpoolFile(NULL), 159 fError(B_NO_INIT), 160 fSetupMessage(NULL), 161 fDefaultSetupMessage(NULL), 162 fAbort(0), 163 fCurrentPageHeader(NULL) 164 { 165 memset(&fSpoolFileHeader, 0, sizeof(print_file_header)); 166 167 if (jobName != NULL && jobName[0]) 168 fPrintJobName = strdup(jobName); 169 170 fCurrentPageHeader = new _page_header_; 171 if (fCurrentPageHeader != NULL) 172 memset(fCurrentPageHeader, 0, sizeof(_page_header_)); 173 } 174 175 176 BPrintJob::~BPrintJob() 177 { 178 CancelJob(); 179 180 free(fPrintJobName); 181 delete fSetupMessage; 182 delete fDefaultSetupMessage; 183 delete fCurrentPageHeader; 184 } 185 186 187 status_t 188 BPrintJob::ConfigPage() 189 { 190 PrintServerMessenger messenger(PSRV_SHOW_PAGE_SETUP, fSetupMessage); 191 status_t status = messenger.SendRequest(); 192 if (status != B_OK) 193 return status; 194 195 delete fSetupMessage; 196 fSetupMessage = messenger.Result(); 197 _HandlePageSetup(fSetupMessage); 198 199 return B_OK; 200 } 201 202 203 status_t 204 BPrintJob::ConfigJob() 205 { 206 PrintServerMessenger messenger(PSRV_SHOW_PRINT_SETUP, fSetupMessage); 207 status_t status = messenger.SendRequest(); 208 if (status != B_OK) 209 return status; 210 211 delete fSetupMessage; 212 fSetupMessage = messenger.Result(); 213 if (!_HandlePrintSetup(fSetupMessage)) 214 return B_ERROR; 215 216 fError = B_OK; 217 return B_OK; 218 } 219 220 221 void 222 BPrintJob::BeginJob() 223 { 224 fError = B_ERROR; 225 226 // can not start a new job until it has been commited or cancelled 227 if (fSpoolFile != NULL || fCurrentPageHeader == NULL) 228 return; 229 230 // TODO show alert, setup message is required 231 if (fSetupMessage == NULL) 232 return; 233 234 // create spool file 235 BPath path; 236 status_t status = find_directory(B_USER_PRINTERS_DIRECTORY, &path); 237 if (status != B_OK) 238 return; 239 240 char *printer = _GetCurrentPrinterName(); 241 if (printer == NULL) 242 return; 243 MemoryDeleter _(printer); 244 245 path.Append(printer); 246 247 char mangledName[B_FILE_NAME_LENGTH]; 248 _GetMangledName(mangledName, B_FILE_NAME_LENGTH); 249 250 path.Append(mangledName); 251 if (path.InitCheck() != B_OK) 252 return; 253 254 // TODO: fSpoolFileName should store the name only (not path which can be 255 // 1024 bytes long) 256 strlcpy(fSpoolFileName, path.Path(), sizeof(fSpoolFileName)); 257 fSpoolFile = new BFile(fSpoolFileName, B_READ_WRITE | B_CREATE_FILE); 258 259 if (fSpoolFile->InitCheck() != B_OK) { 260 CancelJob(); 261 return; 262 } 263 264 // add print_file_header 265 // page_count is updated in CommitJob() 266 // on BeOS R5 the offset to the first page was always -1 267 fSpoolFileHeader.version = 1 << 16; 268 fSpoolFileHeader.page_count = 0; 269 fSpoolFileHeader.first_page = (off_t)-1; 270 271 if (fSpoolFile->Write(&fSpoolFileHeader, sizeof(print_file_header)) 272 != sizeof(print_file_header)) { 273 CancelJob(); 274 return; 275 } 276 277 // add printer settings message 278 if (!fSetupMessage->HasString(PSRV_FIELD_CURRENT_PRINTER)) 279 fSetupMessage->AddString(PSRV_FIELD_CURRENT_PRINTER, printer); 280 281 _AddSetupSpec(); 282 _NewPage(); 283 284 // state variables 285 fAbort = 0; 286 fError = B_OK; 287 } 288 289 290 void 291 BPrintJob::CommitJob() 292 { 293 if (fSpoolFile == NULL) 294 return; 295 296 if (fSpoolFileHeader.page_count == 0) { 297 ShowError(B_TRANSLATE("No pages to print!")); 298 CancelJob(); 299 return; 300 } 301 302 // update spool file 303 _EndLastPage(); 304 305 // write spool file header 306 fSpoolFile->Seek(0, SEEK_SET); 307 fSpoolFile->Write(&fSpoolFileHeader, sizeof(print_file_header)); 308 309 // set file attributes 310 app_info appInfo; 311 be_app->GetAppInfo(&appInfo); 312 const char* printerName = ""; 313 fSetupMessage->FindString(PSRV_FIELD_CURRENT_PRINTER, &printerName); 314 315 BNodeInfo info(fSpoolFile); 316 info.SetType(PSRV_SPOOL_FILETYPE); 317 318 fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_PAGECOUNT, B_INT32_TYPE, 0, 319 &fSpoolFileHeader.page_count, sizeof(int32)); 320 fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_DESCRIPTION, B_STRING_TYPE, 0, 321 fPrintJobName, strlen(fPrintJobName) + 1); 322 fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_PRINTER, B_STRING_TYPE, 0, 323 printerName, strlen(printerName) + 1); 324 fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_STATUS, B_STRING_TYPE, 0, 325 PSRV_JOB_STATUS_WAITING, strlen(PSRV_JOB_STATUS_WAITING) + 1); 326 fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_MIMETYPE, B_STRING_TYPE, 0, 327 appInfo.signature, strlen(appInfo.signature) + 1); 328 329 delete fSpoolFile; 330 fSpoolFile = NULL; 331 fError = B_ERROR; 332 333 // notify print server 334 BMessenger printServer; 335 if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK) 336 return; 337 338 BMessage request(PSRV_PRINT_SPOOLED_JOB); 339 request.AddString("JobName", fPrintJobName); 340 request.AddString("Spool File", fSpoolFileName); 341 342 BMessage reply; 343 printServer.SendMessage(&request, &reply); 344 } 345 346 347 void 348 BPrintJob::CancelJob() 349 { 350 if (fSpoolFile == NULL) 351 return; 352 353 fAbort = 1; 354 BEntry(fSpoolFileName).Remove(); 355 delete fSpoolFile; 356 fSpoolFile = NULL; 357 } 358 359 360 void 361 BPrintJob::SpoolPage() 362 { 363 if (fSpoolFile == NULL) 364 return; 365 366 if (fCurrentPageHeader->number_of_pictures == 0) 367 return; 368 369 fSpoolFileHeader.page_count++; 370 fSpoolFile->Seek(0, SEEK_END); 371 if (fCurrentPageHeaderOffset) { 372 // update last written page_header 373 fCurrentPageHeader->next_page = fSpoolFile->Position(); 374 fSpoolFile->Seek(fCurrentPageHeaderOffset, SEEK_SET); 375 fSpoolFile->Write(fCurrentPageHeader, sizeof(_page_header_)); 376 fSpoolFile->Seek(fCurrentPageHeader->next_page, SEEK_SET); 377 } 378 379 _NewPage(); 380 } 381 382 383 bool 384 BPrintJob::CanContinue() 385 { 386 // Check if our local error storage is still B_OK 387 return fError == B_OK && !fAbort; 388 } 389 390 391 void 392 BPrintJob::DrawView(BView* view, BRect rect, BPoint where) 393 { 394 if (fSpoolFile == NULL) 395 return; 396 397 if (view == NULL) 398 return; 399 400 if (view->LockLooper()) { 401 BPicture picture; 402 _RecurseView(view, B_ORIGIN - rect.LeftTop(), &picture, rect); 403 _AddPicture(picture, rect, where); 404 view->UnlockLooper(); 405 } 406 } 407 408 409 BMessage* 410 BPrintJob::Settings() 411 { 412 if (fSetupMessage == NULL) 413 return NULL; 414 415 return new BMessage(*fSetupMessage); 416 } 417 418 419 void 420 BPrintJob::SetSettings(BMessage* message) 421 { 422 if (message != NULL) 423 _HandlePrintSetup(message); 424 425 delete fSetupMessage; 426 fSetupMessage = message; 427 } 428 429 430 bool 431 BPrintJob::IsSettingsMessageValid(BMessage* message) const 432 { 433 char* printerName = _GetCurrentPrinterName(); 434 if (printerName == NULL) 435 return false; 436 437 const char* name = NULL; 438 // The passed message is valid if it contains the right printer name. 439 bool valid = message != NULL 440 && message->FindString("printer_name", &name) == B_OK 441 && strcmp(printerName, name) == 0; 442 443 free(printerName); 444 return valid; 445 } 446 447 448 // Either SetSettings() or ConfigPage() has to be called prior 449 // to any of the getters otherwise they return undefined values. 450 BRect 451 BPrintJob::PaperRect() 452 { 453 if (fDefaultSetupMessage == NULL) 454 _LoadDefaultSettings(); 455 456 return fPaperSize; 457 } 458 459 460 BRect 461 BPrintJob::PrintableRect() 462 { 463 if (fDefaultSetupMessage == NULL) 464 _LoadDefaultSettings(); 465 466 return fUsableSize; 467 } 468 469 470 void 471 BPrintJob::GetResolution(int32* xdpi, int32* ydpi) 472 { 473 if (fDefaultSetupMessage == NULL) 474 _LoadDefaultSettings(); 475 476 if (xdpi != NULL) 477 *xdpi = fXResolution; 478 479 if (ydpi != NULL) 480 *ydpi = fYResolution; 481 } 482 483 484 int32 485 BPrintJob::FirstPage() 486 { 487 return fFirstPage; 488 } 489 490 491 int32 492 BPrintJob::LastPage() 493 { 494 return fLastPage; 495 } 496 497 498 int32 499 BPrintJob::PrinterType(void*) const 500 { 501 BMessenger printServer; 502 if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK) 503 return B_COLOR_PRINTER; // default 504 505 BMessage reply; 506 BMessage message(PSRV_GET_ACTIVE_PRINTER); 507 printServer.SendMessage(&message, &reply); 508 509 int32 type; 510 if (reply.FindInt32("color", &type) != B_OK) 511 return B_COLOR_PRINTER; // default 512 513 return type; 514 } 515 516 517 // #pragma mark - private 518 519 520 void 521 BPrintJob::_RecurseView(BView* view, BPoint origin, BPicture* picture, 522 BRect rect) 523 { 524 ASSERT(picture != NULL); 525 526 BRegion region; 527 region.Set(BRect(rect.left, rect.top, rect.right, rect.bottom)); 528 view->fState->print_rect = rect; 529 530 view->AppendToPicture(picture); 531 view->PushState(); 532 view->SetOrigin(origin); 533 view->ConstrainClippingRegion(®ion); 534 535 if (view->ViewColor() != B_TRANSPARENT_COLOR) { 536 rgb_color highColor = view->HighColor(); 537 view->SetHighColor(view->ViewColor()); 538 view->FillRect(rect); 539 view->SetHighColor(highColor); 540 } 541 542 if ((view->Flags() & B_WILL_DRAW) != 0) { 543 view->fIsPrinting = true; 544 view->Draw(rect); 545 view->fIsPrinting = false; 546 } 547 548 view->PopState(); 549 view->EndPicture(); 550 551 BView* child = view->ChildAt(0); 552 while (child != NULL) { 553 if (!child->IsHidden()) { 554 BPoint leftTop(view->Bounds().LeftTop() + child->Frame().LeftTop()); 555 BRect printRect(rect.OffsetToCopy(rect.LeftTop() - leftTop) 556 & child->Bounds()); 557 if (printRect.IsValid()) 558 _RecurseView(child, origin + leftTop, picture, printRect); 559 } 560 child = child->NextSibling(); 561 } 562 563 if ((view->Flags() & B_DRAW_ON_CHILDREN) != 0) { 564 view->AppendToPicture(picture); 565 view->PushState(); 566 view->SetOrigin(origin); 567 view->ConstrainClippingRegion(®ion); 568 view->fIsPrinting = true; 569 view->DrawAfterChildren(rect); 570 view->fIsPrinting = false; 571 view->PopState(); 572 view->EndPicture(); 573 } 574 } 575 576 577 void 578 BPrintJob::_GetMangledName(char* buffer, size_t bufferSize) const 579 { 580 snprintf(buffer, bufferSize, "%s@%" B_PRId64, fPrintJobName, 581 system_time() / 1000); 582 } 583 584 585 void 586 BPrintJob::_HandlePageSetup(BMessage* setup) 587 { 588 setup->FindRect(PSRV_FIELD_PRINTABLE_RECT, &fUsableSize); 589 setup->FindRect(PSRV_FIELD_PAPER_RECT, &fPaperSize); 590 591 // TODO verify data type (taken from libprint) 592 int64 valueInt64; 593 if (setup->FindInt64(PSRV_FIELD_XRES, &valueInt64) == B_OK) 594 fXResolution = (short)valueInt64; 595 596 if (setup->FindInt64(PSRV_FIELD_YRES, &valueInt64) == B_OK) 597 fYResolution = (short)valueInt64; 598 } 599 600 601 bool 602 BPrintJob::_HandlePrintSetup(BMessage* message) 603 { 604 _HandlePageSetup(message); 605 606 bool valid = true; 607 if (message->FindInt32(PSRV_FIELD_FIRST_PAGE, &fFirstPage) != B_OK) 608 valid = false; 609 610 if (message->FindInt32(PSRV_FIELD_LAST_PAGE, &fLastPage) != B_OK) 611 valid = false; 612 613 return valid; 614 } 615 616 617 void 618 BPrintJob::_NewPage() 619 { 620 // init, write new page_header 621 fCurrentPageHeader->next_page = 0; 622 fCurrentPageHeader->number_of_pictures = 0; 623 fCurrentPageHeaderOffset = fSpoolFile->Position(); 624 fSpoolFile->Write(fCurrentPageHeader, sizeof(_page_header_)); 625 } 626 627 628 void 629 BPrintJob::_EndLastPage() 630 { 631 if (!fSpoolFile) 632 return; 633 634 if (fCurrentPageHeader->number_of_pictures == 0) 635 return; 636 637 fSpoolFileHeader.page_count++; 638 fSpoolFile->Seek(0, SEEK_END); 639 if (fCurrentPageHeaderOffset) { 640 fCurrentPageHeader->next_page = 0; 641 fSpoolFile->Seek(fCurrentPageHeaderOffset, SEEK_SET); 642 fSpoolFile->Write(fCurrentPageHeader, sizeof(_page_header_)); 643 fSpoolFile->Seek(0, SEEK_END); 644 } 645 } 646 647 648 void 649 BPrintJob::_AddSetupSpec() 650 { 651 fSetupMessage->Flatten(fSpoolFile); 652 } 653 654 655 void 656 BPrintJob::_AddPicture(BPicture& picture, BRect& rect, BPoint& where) 657 { 658 ASSERT(fSpoolFile != NULL); 659 660 fCurrentPageHeader->number_of_pictures++; 661 fSpoolFile->Write(&where, sizeof(BRect)); 662 fSpoolFile->Write(&rect, sizeof(BPoint)); 663 picture.Flatten(fSpoolFile); 664 } 665 666 667 /*! Returns a copy of the applications default printer name or NULL if it 668 could not be obtained. Caller is responsible to free the string using 669 free(). 670 */ 671 char* 672 BPrintJob::_GetCurrentPrinterName() const 673 { 674 BMessenger printServer; 675 if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK) 676 return NULL; 677 678 const char* printerName = NULL; 679 680 BMessage reply; 681 BMessage message(PSRV_GET_ACTIVE_PRINTER); 682 if (printServer.SendMessage(&message, &reply) == B_OK) 683 reply.FindString("printer_name", &printerName); 684 685 if (printerName == NULL) 686 return NULL; 687 688 return strdup(printerName); 689 } 690 691 692 void 693 BPrintJob::_LoadDefaultSettings() 694 { 695 BMessenger printServer; 696 if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK) 697 return; 698 699 BMessage message(PSRV_GET_DEFAULT_SETTINGS); 700 BMessage* reply = new BMessage; 701 702 printServer.SendMessage(&message, reply); 703 704 // Only override our settings if we don't have any settings yet 705 if (fSetupMessage == NULL) 706 _HandlePrintSetup(reply); 707 708 delete fDefaultSetupMessage; 709 fDefaultSetupMessage = reply; 710 } 711 712 713 void BPrintJob::_ReservedPrintJob1() {} 714 void BPrintJob::_ReservedPrintJob2() {} 715 void BPrintJob::_ReservedPrintJob3() {} 716 void BPrintJob::_ReservedPrintJob4() {} 717 718 719 // #pragma mark -- PrintServerMessenger 720 721 722 namespace BPrivate { 723 724 725 PrintServerMessenger::PrintServerMessenger(uint32 what, BMessage *input) 726 : 727 fWhat(what), 728 fInput(input), 729 fRequest(NULL), 730 fResult(NULL), 731 fThreadCompleted(-1), 732 fHiddenApplicationModalWindow(NULL) 733 { 734 RejectUserInput(); 735 } 736 737 738 PrintServerMessenger::~PrintServerMessenger() 739 { 740 DeleteSemaphore(); 741 // in case SendRequest could not start the thread 742 delete fRequest; fRequest = NULL; 743 AllowUserInput(); 744 } 745 746 747 void 748 PrintServerMessenger::RejectUserInput() 749 { 750 fHiddenApplicationModalWindow = new BAlert("bogus", "app_modal", "OK"); 751 fHiddenApplicationModalWindow->DefaultButton()->SetEnabled(false); 752 fHiddenApplicationModalWindow->SetDefaultButton(NULL); 753 fHiddenApplicationModalWindow->SetFlags(fHiddenApplicationModalWindow->Flags() | B_CLOSE_ON_ESCAPE); 754 fHiddenApplicationModalWindow->MoveTo(-65000, -65000); 755 fHiddenApplicationModalWindow->Go(NULL); 756 } 757 758 759 void 760 PrintServerMessenger::AllowUserInput() 761 { 762 fHiddenApplicationModalWindow->Lock(); 763 fHiddenApplicationModalWindow->Quit(); 764 } 765 766 767 void 768 PrintServerMessenger::DeleteSemaphore() 769 { 770 if (fThreadCompleted >= B_OK) { 771 sem_id id = fThreadCompleted; 772 fThreadCompleted = -1; 773 delete_sem(id); 774 } 775 } 776 777 778 status_t 779 PrintServerMessenger::SendRequest() 780 { 781 fThreadCompleted = create_sem(0, "print_server_messenger_sem"); 782 if (fThreadCompleted < B_OK) 783 return B_ERROR; 784 785 thread_id id = spawn_thread(MessengerThread, "async_request", 786 B_NORMAL_PRIORITY, this); 787 if (id <= 0 || resume_thread(id) != B_OK) 788 return B_ERROR; 789 790 // Get the originating window, if it exists 791 BWindow* window = dynamic_cast<BWindow*>( 792 BLooper::LooperForThread(find_thread(NULL))); 793 if (window != NULL) { 794 status_t err; 795 while (true) { 796 do { 797 err = acquire_sem_etc(fThreadCompleted, 1, B_RELATIVE_TIMEOUT, 798 50000); 799 // We've (probably) had our time slice taken away from us 800 } while (err == B_INTERRUPTED); 801 802 // Semaphore was finally nuked in SetResult(BMessage *) 803 if (err == B_BAD_SEM_ID) 804 break; 805 window->UpdateIfNeeded(); 806 } 807 } else { 808 // No window to update, so just hang out until we're done. 809 while (acquire_sem(fThreadCompleted) == B_INTERRUPTED); 810 } 811 812 status_t status; 813 wait_for_thread(id, &status); 814 815 return Result() != NULL ? B_OK : B_ERROR; 816 } 817 818 819 BMessage* 820 PrintServerMessenger::Request() 821 { 822 if (fRequest != NULL) 823 return fRequest; 824 825 if (fInput != NULL) { 826 fRequest = new BMessage(*fInput); 827 fRequest->what = fWhat; 828 } else 829 fRequest = new BMessage(fWhat); 830 831 return fRequest; 832 } 833 834 835 void 836 PrintServerMessenger::SetResult(BMessage* result) 837 { 838 fResult = result; 839 DeleteSemaphore(); 840 // terminate loop in thread spawned by SendRequest 841 } 842 843 844 status_t 845 PrintServerMessenger::GetPrintServerMessenger(BMessenger& messenger) 846 { 847 messenger = BMessenger(PSRV_SIGNATURE_TYPE); 848 return messenger.IsValid() ? B_OK : B_ERROR; 849 } 850 851 852 status_t 853 PrintServerMessenger::MessengerThread(void* data) 854 { 855 PrintServerMessenger* messenger = static_cast<PrintServerMessenger*>(data); 856 857 BMessenger printServer; 858 if (messenger->GetPrintServerMessenger(printServer) != B_OK) { 859 ShowError(B_TRANSLATE("Print Server is not responding.")); 860 messenger->SetResult(NULL); 861 return B_ERROR; 862 } 863 864 BMessage* request = messenger->Request(); 865 if (request == NULL) { 866 messenger->SetResult(NULL); 867 return B_ERROR; 868 } 869 870 871 BMessage reply; 872 if (printServer.SendMessage(request, &reply) != B_OK 873 || reply.what != 'okok' ) { 874 messenger->SetResult(NULL); 875 return B_ERROR; 876 } 877 878 messenger->SetResult(new BMessage(reply)); 879 return B_OK; 880 } 881 882 883 } // namespace BPrivate 884