* Fixed bug #1009. Update window while in BPrintJob.ConfigPage() or

ConfigPage().
* Set mime type of spool file so print_server accepts the file.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20075 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer 2007-02-05 20:40:15 +00:00
parent c1c0c22091
commit c282eba324
1 changed files with 241 additions and 61 deletions

View File

@ -12,11 +12,14 @@
#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 <PrintJob.h>
#include <Roster.h>
@ -28,6 +31,11 @@
#include <stdlib.h>
#include <string.h>
static const int kSemTimeOut = 50000;
static const char *kPrintServerNotRespondingText = "Print Server is not responding.";
static const char *kNoPagesToPrintText = "No Pages to print!";
// Summery of spool file format:
// See articel "How to Write a BeOS R5 Printer Driver" for description
// of spool file format: http://haiku-os.org/node/82
@ -48,12 +56,174 @@ struct _page_header_ {
};
static status_t GetPrinterServerMessenger(BMessenger& messenger)
static status_t
GetPrinterServerMessenger(BMessenger& messenger)
{
messenger = BMessenger(PSRV_SIGNATURE_TYPE);
return messenger.IsValid() ? B_OK : B_ERROR;
}
static void
ShowError(const char *message)
{
BAlert* alert = new BAlert("Error", message, "OK");
alert->Go();
}
namespace BPrivate {
class Configuration {
public:
Configuration(uint32 what, BMessage *input);
~Configuration();
status_t SendRequest(thread_func function);
BMessage* Request();
void SetResult(BMessage* result);
BMessage* Result() const { return fResult; }
private:
void RejectUserInput();
void AllowUserInput();
void DeleteSemaphore();
uint32 fWhat;
BMessage *fInput;
BMessage *fRequest;
BMessage *fResult;
sem_id fThreadCompleted;
BAlert *fHiddenApplicationModalWindow;
};
Configuration::Configuration(uint32 what, BMessage *input)
: fWhat(what),
fInput(input),
fRequest(NULL),
fResult(NULL),
fThreadCompleted(-1),
fHiddenApplicationModalWindow(NULL)
{
RejectUserInput();
}
Configuration::~Configuration()
{
DeleteSemaphore();
// in case SendRequest could not start the thread
delete fRequest; fRequest = NULL;
AllowUserInput();
}
void
Configuration::RejectUserInput()
{
BAlert* alert = new BAlert("bogus", "app_modal_dialog", "OK");
fHiddenApplicationModalWindow = alert;
alert->DefaultButton()->SetEnabled(false);
alert->SetDefaultButton(NULL);
alert->MoveTo(-65000, -65000);
alert->Go(NULL);
}
void
Configuration::AllowUserInput()
{
fHiddenApplicationModalWindow->Lock();
fHiddenApplicationModalWindow->Quit();
}
void
Configuration::DeleteSemaphore()
{
if (fThreadCompleted >= B_OK) {
sem_id id = fThreadCompleted;
fThreadCompleted = -1;
delete_sem(id);
}
}
status_t
Configuration::SendRequest(thread_func function)
{
fThreadCompleted = create_sem(0, "Configuration");
if (fThreadCompleted < B_OK) {
return B_ERROR;
}
thread_id id = spawn_thread(function, "async_request", B_NORMAL_PRIORITY, this);
if (id <= 0 || resume_thread(id) != B_OK) {
return B_ERROR;
}
// Code copied from BAlert::Go()
BWindow* window = dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
// Get the originating window, if it exists
// Heavily modified from TextEntryAlert code; the original didn't let the
// blocked window ever draw.
if (window != NULL) {
status_t err;
for (;;) {
do {
err = acquire_sem_etc(fThreadCompleted, 1, B_RELATIVE_TIMEOUT,
kSemTimeOut);
// We've (probably) had our time slice taken away from us
} while (err == B_INTERRUPTED);
if (err == B_BAD_SEM_ID) {
// Semaphore was finally nuked in SetResult(BMessage *)
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 *
Configuration::Request()
{
if (fRequest != NULL)
return fRequest;
if (fInput != NULL) {
fRequest = new BMessage(*fInput);
fRequest->what = fWhat;
} else
fRequest = new BMessage(fWhat);
return fRequest;
}
void
Configuration::SetResult(BMessage *result)
{
fResult = result;
DeleteSemaphore();
// terminate loop in thread spawned by SendRequest
}
} // BPrivate
BPrintJob::BPrintJob(const char *job_name)
:
fPrintJobName(NULL),
@ -96,82 +266,90 @@ BPrintJob::~BPrintJob()
fCurrentPageHeader = NULL;
}
status_t
BPrintJob::ConfigPage()
static
status_t ConfigPageThread(void *data)
{
BPrivate::Configuration* configuration = static_cast<BPrivate::Configuration*>(data);
BMessenger printServer;
if (GetPrinterServerMessenger(printServer) != B_OK) {
BAlert* alert = new BAlert("Error", "Print Server is not responding.", "OK");
alert->Go();
ShowError(kPrintServerNotRespondingText);
configuration->SetResult(NULL);
return B_ERROR;
}
if (fSetupMessage == NULL) {
LoadDefaultSettings();
if (fDefaultSetupMessage == NULL) {
return B_ERROR;
}
fSetupMessage = new BMessage(*fDefaultSetupMessage);
}
BMessage request(*fSetupMessage);
request.what = PSRV_SHOW_PAGE_SETUP;
BMessage* reply = new BMessage();
if (printServer.SendMessage(&request, reply) != B_OK) {
delete reply;
BMessage *request = configuration->Request();
if (request == NULL) {
configuration->SetResult(NULL);
return B_ERROR;
}
if (reply->what != 'okok') {
delete reply;
BMessage reply;
if (printServer.SendMessage(request, &reply) != B_OK
|| reply.what != 'okok') {
configuration->SetResult(NULL);
return B_ERROR;
}
delete fSetupMessage;
fSetupMessage = reply;
HandlePageSetup(fSetupMessage);
configuration->SetResult(new BMessage(reply));
return B_OK;
}
status_t
BPrintJob::ConfigJob()
BPrintJob::ConfigPage()
{
BPrivate::Configuration configuration(PSRV_SHOW_PAGE_SETUP, fSetupMessage);
status_t status = configuration.SendRequest(ConfigPageThread);
if (status != B_OK)
return status;
delete fSetupMessage;
fSetupMessage = configuration.Result();
HandlePageSetup(fSetupMessage);
return B_OK;
}
static status_t
ConfigJobThread(void *data)
{
BPrivate::Configuration* configuration = static_cast<BPrivate::Configuration*>(data);
BMessenger printServer;
if (GetPrinterServerMessenger(printServer) != B_OK) {
BAlert* alert = new BAlert("Error", "Print Server is not responding.", "OK");
alert->Go();
ShowError(kPrintServerNotRespondingText);
configuration->SetResult(NULL);
return B_ERROR;
}
if (fSetupMessage == NULL) {
LoadDefaultSettings();
if (fDefaultSetupMessage == NULL) {
return B_ERROR;
}
fSetupMessage = new BMessage(*fDefaultSetupMessage);
}
BMessage request(*fSetupMessage);
request.what = PSRV_SHOW_PRINT_SETUP;
BMessage* reply = new BMessage();
if (printServer.SendMessage(&request, reply) != B_OK) {
delete reply;
BMessage *request = configuration->Request();
if (request == NULL) {
configuration->SetResult(NULL);
return B_ERROR;
}
if (reply->what != 'okok') {
delete reply;
BMessage reply;
if (printServer.SendMessage(request, &reply) != B_OK
|| reply.what != 'okok') {
configuration->SetResult(NULL);
return B_ERROR;
}
configuration->SetResult(new BMessage(reply));
return B_OK;
}
status_t
BPrintJob::ConfigJob()
{
BPrivate::Configuration configuration(PSRV_SHOW_PRINT_SETUP, fSetupMessage);
status_t status = configuration.SendRequest(ConfigJobThread);
if (status != B_OK)
return status;
delete fSetupMessage;
fSetupMessage = reply;
fSetupMessage = configuration.Result();
HandlePrintSetup(fSetupMessage);
return B_OK;
}
@ -260,8 +438,7 @@ BPrintJob::CommitJob()
}
if (fPageNumber <= 0) {
BAlert *alert = new BAlert("Alert", "No Pages to print!", "Okay");
alert->Go();
ShowError(kNoPagesToPrintText);
CancelJob();
return;
}
@ -279,6 +456,9 @@ BPrintJob::CommitJob()
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, &fPageNumber, 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);