* also struct _page_header_: on x86_64, these would align to 8 bytes, which the code doesn't handle well. * remove beos leftovers.
884 lines
19 KiB
C++
884 lines
19 KiB
C++
/*
|
|
* Copyright 2001-2009, Haiku.
|
|
* Distributed under the terms of the MIT license.
|
|
*
|
|
* Authors:
|
|
* I.R. Adema
|
|
* Stefano Ceccherini ([email protected])
|
|
* Michael Pfeiffer
|
|
* julun <[email protected]>
|
|
*/
|
|
|
|
|
|
#include <PrintJob.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <Alert.h>
|
|
#include <Application.h>
|
|
#include <Button.h>
|
|
#include <Debug.h>
|
|
#include <Entry.h>
|
|
#include <File.h>
|
|
#include <FindDirectory.h>
|
|
#include <Messenger.h>
|
|
#include <NodeInfo.h>
|
|
#include <OS.h>
|
|
#include <Path.h>
|
|
#include <Region.h>
|
|
#include <Roster.h>
|
|
#include <SystemCatalog.h>
|
|
#include <View.h>
|
|
|
|
#include <AutoDeleter.h>
|
|
#include <pr_server.h>
|
|
#include <ViewPrivate.h>
|
|
|
|
using BPrivate::gSystemCatalog;
|
|
|
|
#undef B_TRANSLATION_CONTEXT
|
|
#define B_TRANSLATION_CONTEXT "PrintJob"
|
|
|
|
#undef B_TRANSLATE
|
|
#define B_TRANSLATE(str) \
|
|
gSystemCatalog.GetString(B_TRANSLATE_MARK(str), "PrintJob")
|
|
|
|
|
|
/*! Summary of spool file:
|
|
|
|
|-----------------------------------|
|
|
| print_file_header |
|
|
|-----------------------------------|
|
|
| BMessage print_job_settings |
|
|
|-----------------------------------|
|
|
| |
|
|
| ********** (first page) ********* |
|
|
| * * |
|
|
| * _page_header_ * |
|
|
| * ----------------------------- * |
|
|
| * |---------------------------| * |
|
|
| * | BPoint where | * |
|
|
| * | BRect bounds | * |
|
|
| * | BPicture pic | * |
|
|
| * |---------------------------| * |
|
|
| * |---------------------------| * |
|
|
| * | BPoint where | * |
|
|
| * | BRect bounds | * |
|
|
| * | BPicture pic | * |
|
|
| * |---------------------------| * |
|
|
| ********************************* |
|
|
| |
|
|
| ********* (second page) ********* |
|
|
| * * |
|
|
| * _page_header_ * |
|
|
| * ----------------------------- * |
|
|
| * |---------------------------| * |
|
|
| * | BPoint where | * |
|
|
| * | BRect bounds | * |
|
|
| * | BPicture pic | * |
|
|
| * |---------------------------| * |
|
|
| ********************************* |
|
|
|-----------------------------------|
|
|
|
|
BeOS R5 print_file_header.version is 1 << 16
|
|
BeOS R5 print_file_header.first_page is -1
|
|
|
|
each page can consist of a collection of picture structures
|
|
remaining pages start at _page_header_.next_page of previous _page_header_
|
|
|
|
See also: "How to Write a BeOS R5 Printer Driver" for description of spool
|
|
file format: http://haiku-os.org/documents/dev/how_to_write_a_printer_driver
|
|
*/
|
|
|
|
|
|
struct _page_header_ {
|
|
int32 number_of_pictures;
|
|
off_t next_page;
|
|
int32 reserved[10];
|
|
} _PACKED;
|
|
|
|
|
|
static void
|
|
ShowError(const char* message)
|
|
{
|
|
BAlert* alert = new BAlert(B_TRANSLATE("Error"), message, B_TRANSLATE("OK"));
|
|
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
|
alert->Go();
|
|
}
|
|
|
|
|
|
// #pragma mark -- PrintServerMessenger
|
|
|
|
|
|
namespace BPrivate {
|
|
|
|
|
|
class PrintServerMessenger {
|
|
public:
|
|
PrintServerMessenger(uint32 what, BMessage* input);
|
|
~PrintServerMessenger();
|
|
|
|
BMessage* Request();
|
|
status_t SendRequest();
|
|
|
|
void SetResult(BMessage* result);
|
|
BMessage* Result() const { return fResult; }
|
|
|
|
static status_t GetPrintServerMessenger(BMessenger& messenger);
|
|
|
|
private:
|
|
void RejectUserInput();
|
|
void AllowUserInput();
|
|
void DeleteSemaphore();
|
|
static status_t MessengerThread(void* data);
|
|
|
|
uint32 fWhat;
|
|
BMessage* fInput;
|
|
BMessage* fRequest;
|
|
BMessage* fResult;
|
|
sem_id fThreadCompleted;
|
|
BAlert* fHiddenApplicationModalWindow;
|
|
};
|
|
|
|
|
|
} // namespace BPrivate
|
|
|
|
|
|
using namespace BPrivate;
|
|
|
|
|
|
// #pragma mark -- BPrintJob
|
|
|
|
|
|
BPrintJob::BPrintJob(const char* jobName)
|
|
:
|
|
fPrintJobName(NULL),
|
|
fSpoolFile(NULL),
|
|
fError(B_NO_INIT),
|
|
fSetupMessage(NULL),
|
|
fDefaultSetupMessage(NULL),
|
|
fAbort(0),
|
|
fCurrentPageHeader(NULL)
|
|
{
|
|
memset(&fSpoolFileHeader, 0, sizeof(print_file_header));
|
|
|
|
if (jobName != NULL && jobName[0])
|
|
fPrintJobName = strdup(jobName);
|
|
|
|
fCurrentPageHeader = new _page_header_;
|
|
if (fCurrentPageHeader != NULL)
|
|
memset(fCurrentPageHeader, 0, sizeof(_page_header_));
|
|
}
|
|
|
|
|
|
BPrintJob::~BPrintJob()
|
|
{
|
|
CancelJob();
|
|
|
|
free(fPrintJobName);
|
|
delete fSetupMessage;
|
|
delete fDefaultSetupMessage;
|
|
delete fCurrentPageHeader;
|
|
}
|
|
|
|
|
|
status_t
|
|
BPrintJob::ConfigPage()
|
|
{
|
|
PrintServerMessenger messenger(PSRV_SHOW_PAGE_SETUP, fSetupMessage);
|
|
status_t status = messenger.SendRequest();
|
|
if (status != B_OK)
|
|
return status;
|
|
|
|
delete fSetupMessage;
|
|
fSetupMessage = messenger.Result();
|
|
_HandlePageSetup(fSetupMessage);
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BPrintJob::ConfigJob()
|
|
{
|
|
PrintServerMessenger messenger(PSRV_SHOW_PRINT_SETUP, fSetupMessage);
|
|
status_t status = messenger.SendRequest();
|
|
if (status != B_OK)
|
|
return status;
|
|
|
|
delete fSetupMessage;
|
|
fSetupMessage = messenger.Result();
|
|
if (!_HandlePrintSetup(fSetupMessage))
|
|
return B_ERROR;
|
|
|
|
fError = B_OK;
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::BeginJob()
|
|
{
|
|
fError = B_ERROR;
|
|
|
|
// can not start a new job until it has been commited or cancelled
|
|
if (fSpoolFile != NULL || fCurrentPageHeader == NULL)
|
|
return;
|
|
|
|
// TODO show alert, setup message is required
|
|
if (fSetupMessage == NULL)
|
|
return;
|
|
|
|
// create spool file
|
|
BPath path;
|
|
status_t status = find_directory(B_USER_PRINTERS_DIRECTORY, &path);
|
|
if (status != B_OK)
|
|
return;
|
|
|
|
char *printer = _GetCurrentPrinterName();
|
|
if (printer == NULL)
|
|
return;
|
|
MemoryDeleter _(printer);
|
|
|
|
path.Append(printer);
|
|
|
|
char mangledName[B_FILE_NAME_LENGTH];
|
|
_GetMangledName(mangledName, B_FILE_NAME_LENGTH);
|
|
|
|
path.Append(mangledName);
|
|
if (path.InitCheck() != B_OK)
|
|
return;
|
|
|
|
// TODO: fSpoolFileName should store the name only (not path which can be
|
|
// 1024 bytes long)
|
|
strlcpy(fSpoolFileName, path.Path(), sizeof(fSpoolFileName));
|
|
fSpoolFile = new BFile(fSpoolFileName, B_READ_WRITE | B_CREATE_FILE);
|
|
|
|
if (fSpoolFile->InitCheck() != B_OK) {
|
|
CancelJob();
|
|
return;
|
|
}
|
|
|
|
// add print_file_header
|
|
// page_count is updated in CommitJob()
|
|
// on BeOS R5 the offset to the first page was always -1
|
|
fSpoolFileHeader.version = 1 << 16;
|
|
fSpoolFileHeader.page_count = 0;
|
|
fSpoolFileHeader.first_page = (off_t)-1;
|
|
|
|
if (fSpoolFile->Write(&fSpoolFileHeader, sizeof(print_file_header))
|
|
!= sizeof(print_file_header)) {
|
|
CancelJob();
|
|
return;
|
|
}
|
|
|
|
// add printer settings message
|
|
if (!fSetupMessage->HasString(PSRV_FIELD_CURRENT_PRINTER))
|
|
fSetupMessage->AddString(PSRV_FIELD_CURRENT_PRINTER, printer);
|
|
|
|
_AddSetupSpec();
|
|
_NewPage();
|
|
|
|
// state variables
|
|
fAbort = 0;
|
|
fError = B_OK;
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::CommitJob()
|
|
{
|
|
if (fSpoolFile == NULL)
|
|
return;
|
|
|
|
if (fSpoolFileHeader.page_count == 0) {
|
|
ShowError(B_TRANSLATE("No pages to print!"));
|
|
CancelJob();
|
|
return;
|
|
}
|
|
|
|
// update spool file
|
|
_EndLastPage();
|
|
|
|
// write spool file header
|
|
fSpoolFile->Seek(0, SEEK_SET);
|
|
fSpoolFile->Write(&fSpoolFileHeader, sizeof(print_file_header));
|
|
|
|
// set file attributes
|
|
app_info appInfo;
|
|
be_app->GetAppInfo(&appInfo);
|
|
const char* printerName = "";
|
|
fSetupMessage->FindString(PSRV_FIELD_CURRENT_PRINTER, &printerName);
|
|
|
|
BNodeInfo info(fSpoolFile);
|
|
info.SetType(PSRV_SPOOL_FILETYPE);
|
|
|
|
fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_PAGECOUNT, B_INT32_TYPE, 0,
|
|
&fSpoolFileHeader.page_count, sizeof(int32));
|
|
fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_DESCRIPTION, B_STRING_TYPE, 0,
|
|
fPrintJobName, strlen(fPrintJobName) + 1);
|
|
fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_PRINTER, B_STRING_TYPE, 0,
|
|
printerName, strlen(printerName) + 1);
|
|
fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_STATUS, B_STRING_TYPE, 0,
|
|
PSRV_JOB_STATUS_WAITING, strlen(PSRV_JOB_STATUS_WAITING) + 1);
|
|
fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_MIMETYPE, B_STRING_TYPE, 0,
|
|
appInfo.signature, strlen(appInfo.signature) + 1);
|
|
|
|
delete fSpoolFile;
|
|
fSpoolFile = NULL;
|
|
fError = B_ERROR;
|
|
|
|
// notify print server
|
|
BMessenger printServer;
|
|
if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK)
|
|
return;
|
|
|
|
BMessage request(PSRV_PRINT_SPOOLED_JOB);
|
|
request.AddString("JobName", fPrintJobName);
|
|
request.AddString("Spool File", fSpoolFileName);
|
|
|
|
BMessage reply;
|
|
printServer.SendMessage(&request, &reply);
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::CancelJob()
|
|
{
|
|
if (fSpoolFile == NULL)
|
|
return;
|
|
|
|
fAbort = 1;
|
|
BEntry(fSpoolFileName).Remove();
|
|
delete fSpoolFile;
|
|
fSpoolFile = NULL;
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::SpoolPage()
|
|
{
|
|
if (fSpoolFile == NULL)
|
|
return;
|
|
|
|
if (fCurrentPageHeader->number_of_pictures == 0)
|
|
return;
|
|
|
|
fSpoolFileHeader.page_count++;
|
|
fSpoolFile->Seek(0, SEEK_END);
|
|
if (fCurrentPageHeaderOffset) {
|
|
// update last written page_header
|
|
fCurrentPageHeader->next_page = fSpoolFile->Position();
|
|
fSpoolFile->Seek(fCurrentPageHeaderOffset, SEEK_SET);
|
|
fSpoolFile->Write(fCurrentPageHeader, sizeof(_page_header_));
|
|
fSpoolFile->Seek(fCurrentPageHeader->next_page, SEEK_SET);
|
|
}
|
|
|
|
_NewPage();
|
|
}
|
|
|
|
|
|
bool
|
|
BPrintJob::CanContinue()
|
|
{
|
|
// Check if our local error storage is still B_OK
|
|
return fError == B_OK && !fAbort;
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::DrawView(BView* view, BRect rect, BPoint where)
|
|
{
|
|
if (fSpoolFile == NULL)
|
|
return;
|
|
|
|
if (view == NULL)
|
|
return;
|
|
|
|
if (view->LockLooper()) {
|
|
BPicture picture;
|
|
_RecurseView(view, B_ORIGIN - rect.LeftTop(), &picture, rect);
|
|
_AddPicture(picture, rect, where);
|
|
view->UnlockLooper();
|
|
}
|
|
}
|
|
|
|
|
|
BMessage*
|
|
BPrintJob::Settings()
|
|
{
|
|
if (fSetupMessage == NULL)
|
|
return NULL;
|
|
|
|
return new BMessage(*fSetupMessage);
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::SetSettings(BMessage* message)
|
|
{
|
|
if (message != NULL)
|
|
_HandlePrintSetup(message);
|
|
|
|
delete fSetupMessage;
|
|
fSetupMessage = message;
|
|
}
|
|
|
|
|
|
bool
|
|
BPrintJob::IsSettingsMessageValid(BMessage* message) const
|
|
{
|
|
char* printerName = _GetCurrentPrinterName();
|
|
if (printerName == NULL)
|
|
return false;
|
|
|
|
const char* name = NULL;
|
|
// The passed message is valid if it contains the right printer name.
|
|
bool valid = message != NULL
|
|
&& message->FindString("printer_name", &name) == B_OK
|
|
&& strcmp(printerName, name) == 0;
|
|
|
|
free(printerName);
|
|
return valid;
|
|
}
|
|
|
|
|
|
// Either SetSettings() or ConfigPage() has to be called prior
|
|
// to any of the getters otherwise they return undefined values.
|
|
BRect
|
|
BPrintJob::PaperRect()
|
|
{
|
|
if (fDefaultSetupMessage == NULL)
|
|
_LoadDefaultSettings();
|
|
|
|
return fPaperSize;
|
|
}
|
|
|
|
|
|
BRect
|
|
BPrintJob::PrintableRect()
|
|
{
|
|
if (fDefaultSetupMessage == NULL)
|
|
_LoadDefaultSettings();
|
|
|
|
return fUsableSize;
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::GetResolution(int32* xdpi, int32* ydpi)
|
|
{
|
|
if (fDefaultSetupMessage == NULL)
|
|
_LoadDefaultSettings();
|
|
|
|
if (xdpi != NULL)
|
|
*xdpi = fXResolution;
|
|
|
|
if (ydpi != NULL)
|
|
*ydpi = fYResolution;
|
|
}
|
|
|
|
|
|
int32
|
|
BPrintJob::FirstPage()
|
|
{
|
|
return fFirstPage;
|
|
}
|
|
|
|
|
|
int32
|
|
BPrintJob::LastPage()
|
|
{
|
|
return fLastPage;
|
|
}
|
|
|
|
|
|
int32
|
|
BPrintJob::PrinterType(void*) const
|
|
{
|
|
BMessenger printServer;
|
|
if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK)
|
|
return B_COLOR_PRINTER; // default
|
|
|
|
BMessage reply;
|
|
BMessage message(PSRV_GET_ACTIVE_PRINTER);
|
|
printServer.SendMessage(&message, &reply);
|
|
|
|
int32 type;
|
|
if (reply.FindInt32("color", &type) != B_OK)
|
|
return B_COLOR_PRINTER; // default
|
|
|
|
return type;
|
|
}
|
|
|
|
|
|
// #pragma mark - private
|
|
|
|
|
|
void
|
|
BPrintJob::_RecurseView(BView* view, BPoint origin, BPicture* picture,
|
|
BRect rect)
|
|
{
|
|
ASSERT(picture != NULL);
|
|
|
|
BRegion region;
|
|
region.Set(BRect(rect.left, rect.top, rect.right, rect.bottom));
|
|
view->fState->print_rect = rect;
|
|
|
|
view->AppendToPicture(picture);
|
|
view->PushState();
|
|
view->SetOrigin(origin);
|
|
view->ConstrainClippingRegion(®ion);
|
|
|
|
if (view->ViewColor() != B_TRANSPARENT_COLOR) {
|
|
rgb_color highColor = view->HighColor();
|
|
view->SetHighColor(view->ViewColor());
|
|
view->FillRect(rect);
|
|
view->SetHighColor(highColor);
|
|
}
|
|
|
|
if ((view->Flags() & B_WILL_DRAW) != 0) {
|
|
view->fIsPrinting = true;
|
|
view->Draw(rect);
|
|
view->fIsPrinting = false;
|
|
}
|
|
|
|
view->PopState();
|
|
view->EndPicture();
|
|
|
|
BView* child = view->ChildAt(0);
|
|
while (child != NULL) {
|
|
if (!child->IsHidden()) {
|
|
BPoint leftTop(view->Bounds().LeftTop() + child->Frame().LeftTop());
|
|
BRect printRect(rect.OffsetToCopy(rect.LeftTop() - leftTop)
|
|
& child->Bounds());
|
|
if (printRect.IsValid())
|
|
_RecurseView(child, origin + leftTop, picture, printRect);
|
|
}
|
|
child = child->NextSibling();
|
|
}
|
|
|
|
if ((view->Flags() & B_DRAW_ON_CHILDREN) != 0) {
|
|
view->AppendToPicture(picture);
|
|
view->PushState();
|
|
view->SetOrigin(origin);
|
|
view->ConstrainClippingRegion(®ion);
|
|
view->fIsPrinting = true;
|
|
view->DrawAfterChildren(rect);
|
|
view->fIsPrinting = false;
|
|
view->PopState();
|
|
view->EndPicture();
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::_GetMangledName(char* buffer, size_t bufferSize) const
|
|
{
|
|
snprintf(buffer, bufferSize, "%s@%" B_PRId64, fPrintJobName,
|
|
system_time() / 1000);
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::_HandlePageSetup(BMessage* setup)
|
|
{
|
|
setup->FindRect(PSRV_FIELD_PRINTABLE_RECT, &fUsableSize);
|
|
setup->FindRect(PSRV_FIELD_PAPER_RECT, &fPaperSize);
|
|
|
|
// TODO verify data type (taken from libprint)
|
|
int64 valueInt64;
|
|
if (setup->FindInt64(PSRV_FIELD_XRES, &valueInt64) == B_OK)
|
|
fXResolution = (short)valueInt64;
|
|
|
|
if (setup->FindInt64(PSRV_FIELD_YRES, &valueInt64) == B_OK)
|
|
fYResolution = (short)valueInt64;
|
|
}
|
|
|
|
|
|
bool
|
|
BPrintJob::_HandlePrintSetup(BMessage* message)
|
|
{
|
|
_HandlePageSetup(message);
|
|
|
|
bool valid = true;
|
|
if (message->FindInt32(PSRV_FIELD_FIRST_PAGE, &fFirstPage) != B_OK)
|
|
valid = false;
|
|
|
|
if (message->FindInt32(PSRV_FIELD_LAST_PAGE, &fLastPage) != B_OK)
|
|
valid = false;
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::_NewPage()
|
|
{
|
|
// init, write new page_header
|
|
fCurrentPageHeader->next_page = 0;
|
|
fCurrentPageHeader->number_of_pictures = 0;
|
|
fCurrentPageHeaderOffset = fSpoolFile->Position();
|
|
fSpoolFile->Write(fCurrentPageHeader, sizeof(_page_header_));
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::_EndLastPage()
|
|
{
|
|
if (!fSpoolFile)
|
|
return;
|
|
|
|
if (fCurrentPageHeader->number_of_pictures == 0)
|
|
return;
|
|
|
|
fSpoolFileHeader.page_count++;
|
|
fSpoolFile->Seek(0, SEEK_END);
|
|
if (fCurrentPageHeaderOffset) {
|
|
fCurrentPageHeader->next_page = 0;
|
|
fSpoolFile->Seek(fCurrentPageHeaderOffset, SEEK_SET);
|
|
fSpoolFile->Write(fCurrentPageHeader, sizeof(_page_header_));
|
|
fSpoolFile->Seek(0, SEEK_END);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::_AddSetupSpec()
|
|
{
|
|
fSetupMessage->Flatten(fSpoolFile);
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::_AddPicture(BPicture& picture, BRect& rect, BPoint& where)
|
|
{
|
|
ASSERT(fSpoolFile != NULL);
|
|
|
|
fCurrentPageHeader->number_of_pictures++;
|
|
fSpoolFile->Write(&where, sizeof(BRect));
|
|
fSpoolFile->Write(&rect, sizeof(BPoint));
|
|
picture.Flatten(fSpoolFile);
|
|
}
|
|
|
|
|
|
/*! Returns a copy of the applications default printer name or NULL if it
|
|
could not be obtained. Caller is responsible to free the string using
|
|
free().
|
|
*/
|
|
char*
|
|
BPrintJob::_GetCurrentPrinterName() const
|
|
{
|
|
BMessenger printServer;
|
|
if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK)
|
|
return NULL;
|
|
|
|
const char* printerName = NULL;
|
|
|
|
BMessage reply;
|
|
BMessage message(PSRV_GET_ACTIVE_PRINTER);
|
|
if (printServer.SendMessage(&message, &reply) == B_OK)
|
|
reply.FindString("printer_name", &printerName);
|
|
|
|
if (printerName == NULL)
|
|
return NULL;
|
|
|
|
return strdup(printerName);
|
|
}
|
|
|
|
|
|
void
|
|
BPrintJob::_LoadDefaultSettings()
|
|
{
|
|
BMessenger printServer;
|
|
if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK)
|
|
return;
|
|
|
|
BMessage message(PSRV_GET_DEFAULT_SETTINGS);
|
|
BMessage* reply = new BMessage;
|
|
|
|
printServer.SendMessage(&message, reply);
|
|
|
|
// Only override our settings if we don't have any settings yet
|
|
if (fSetupMessage == NULL)
|
|
_HandlePrintSetup(reply);
|
|
|
|
delete fDefaultSetupMessage;
|
|
fDefaultSetupMessage = reply;
|
|
}
|
|
|
|
|
|
void BPrintJob::_ReservedPrintJob1() {}
|
|
void BPrintJob::_ReservedPrintJob2() {}
|
|
void BPrintJob::_ReservedPrintJob3() {}
|
|
void BPrintJob::_ReservedPrintJob4() {}
|
|
|
|
|
|
// #pragma mark -- PrintServerMessenger
|
|
|
|
|
|
namespace BPrivate {
|
|
|
|
|
|
PrintServerMessenger::PrintServerMessenger(uint32 what, BMessage *input)
|
|
:
|
|
fWhat(what),
|
|
fInput(input),
|
|
fRequest(NULL),
|
|
fResult(NULL),
|
|
fThreadCompleted(-1),
|
|
fHiddenApplicationModalWindow(NULL)
|
|
{
|
|
RejectUserInput();
|
|
}
|
|
|
|
|
|
PrintServerMessenger::~PrintServerMessenger()
|
|
{
|
|
DeleteSemaphore();
|
|
// in case SendRequest could not start the thread
|
|
delete fRequest; fRequest = NULL;
|
|
AllowUserInput();
|
|
}
|
|
|
|
|
|
void
|
|
PrintServerMessenger::RejectUserInput()
|
|
{
|
|
fHiddenApplicationModalWindow = new BAlert("bogus", "app_modal", "OK");
|
|
fHiddenApplicationModalWindow->DefaultButton()->SetEnabled(false);
|
|
fHiddenApplicationModalWindow->SetDefaultButton(NULL);
|
|
fHiddenApplicationModalWindow->SetFlags(fHiddenApplicationModalWindow->Flags() | B_CLOSE_ON_ESCAPE);
|
|
fHiddenApplicationModalWindow->MoveTo(-65000, -65000);
|
|
fHiddenApplicationModalWindow->Go(NULL);
|
|
}
|
|
|
|
|
|
void
|
|
PrintServerMessenger::AllowUserInput()
|
|
{
|
|
fHiddenApplicationModalWindow->Lock();
|
|
fHiddenApplicationModalWindow->Quit();
|
|
}
|
|
|
|
|
|
void
|
|
PrintServerMessenger::DeleteSemaphore()
|
|
{
|
|
if (fThreadCompleted >= B_OK) {
|
|
sem_id id = fThreadCompleted;
|
|
fThreadCompleted = -1;
|
|
delete_sem(id);
|
|
}
|
|
}
|
|
|
|
|
|
status_t
|
|
PrintServerMessenger::SendRequest()
|
|
{
|
|
fThreadCompleted = create_sem(0, "print_server_messenger_sem");
|
|
if (fThreadCompleted < B_OK)
|
|
return B_ERROR;
|
|
|
|
thread_id id = spawn_thread(MessengerThread, "async_request",
|
|
B_NORMAL_PRIORITY, this);
|
|
if (id <= 0 || resume_thread(id) != B_OK)
|
|
return B_ERROR;
|
|
|
|
// Get the originating window, if it exists
|
|
BWindow* window = dynamic_cast<BWindow*>(
|
|
BLooper::LooperForThread(find_thread(NULL)));
|
|
if (window != NULL) {
|
|
status_t err;
|
|
while (true) {
|
|
do {
|
|
err = acquire_sem_etc(fThreadCompleted, 1, B_RELATIVE_TIMEOUT,
|
|
50000);
|
|
// We've (probably) had our time slice taken away from us
|
|
} while (err == B_INTERRUPTED);
|
|
|
|
// Semaphore was finally nuked in SetResult(BMessage *)
|
|
if (err == B_BAD_SEM_ID)
|
|
break;
|
|
window->UpdateIfNeeded();
|
|
}
|
|
} else {
|
|
// No window to update, so just hang out until we're done.
|
|
while (acquire_sem(fThreadCompleted) == B_INTERRUPTED);
|
|
}
|
|
|
|
status_t status;
|
|
wait_for_thread(id, &status);
|
|
|
|
return Result() != NULL ? B_OK : B_ERROR;
|
|
}
|
|
|
|
|
|
BMessage*
|
|
PrintServerMessenger::Request()
|
|
{
|
|
if (fRequest != NULL)
|
|
return fRequest;
|
|
|
|
if (fInput != NULL) {
|
|
fRequest = new BMessage(*fInput);
|
|
fRequest->what = fWhat;
|
|
} else
|
|
fRequest = new BMessage(fWhat);
|
|
|
|
return fRequest;
|
|
}
|
|
|
|
|
|
void
|
|
PrintServerMessenger::SetResult(BMessage* result)
|
|
{
|
|
fResult = result;
|
|
DeleteSemaphore();
|
|
// terminate loop in thread spawned by SendRequest
|
|
}
|
|
|
|
|
|
status_t
|
|
PrintServerMessenger::GetPrintServerMessenger(BMessenger& messenger)
|
|
{
|
|
messenger = BMessenger(PSRV_SIGNATURE_TYPE);
|
|
return messenger.IsValid() ? B_OK : B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
PrintServerMessenger::MessengerThread(void* data)
|
|
{
|
|
PrintServerMessenger* messenger = static_cast<PrintServerMessenger*>(data);
|
|
|
|
BMessenger printServer;
|
|
if (messenger->GetPrintServerMessenger(printServer) != B_OK) {
|
|
ShowError(B_TRANSLATE("Print Server is not responding."));
|
|
messenger->SetResult(NULL);
|
|
return B_ERROR;
|
|
}
|
|
|
|
BMessage* request = messenger->Request();
|
|
if (request == NULL) {
|
|
messenger->SetResult(NULL);
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
BMessage reply;
|
|
if (printServer.SendMessage(request, &reply) != B_OK
|
|
|| reply.what != 'okok' ) {
|
|
messenger->SetResult(NULL);
|
|
return B_ERROR;
|
|
}
|
|
|
|
messenger->SetResult(new BMessage(reply));
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
} // namespace BPrivate
|